From f9fa7480240a30d1f92c5ab4244ec87878f8612e Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Wed, 29 Oct 2014 16:52:36 -0500 Subject: [PATCH 001/132] crud for openstack servers v2 --- builtin/bins/provider-openstack/main.go | 12 + builtin/providers/openstack/config.go | 39 +++ builtin/providers/openstack/provider.go | 93 ++++++ .../resource_openstack_compute_instance.go | 297 ++++++++++++++++++ 4 files changed, 441 insertions(+) create mode 100644 builtin/bins/provider-openstack/main.go create mode 100644 builtin/providers/openstack/config.go create mode 100644 builtin/providers/openstack/provider.go create mode 100644 builtin/providers/openstack/resource_openstack_compute_instance.go diff --git a/builtin/bins/provider-openstack/main.go b/builtin/bins/provider-openstack/main.go new file mode 100644 index 0000000000..f897f1c557 --- /dev/null +++ b/builtin/bins/provider-openstack/main.go @@ -0,0 +1,12 @@ +package main + +import ( + "github.com/hashicorp/terraform/builtin/providers/openstack" + "github.com/hashicorp/terraform/plugin" +) + +func main() { + plugin.Serve(&plugin.ServeOpts{ + ProviderFunc: openstack.Provider, + }) +} diff --git a/builtin/providers/openstack/config.go b/builtin/providers/openstack/config.go new file mode 100644 index 0000000000..cb06a98483 --- /dev/null +++ b/builtin/providers/openstack/config.go @@ -0,0 +1,39 @@ +package openstack + +import ( + "github.com/rackspace/gophercloud" + "github.com/rackspace/gophercloud/openstack" +) + +type Config struct { + Region string + Username string + Password string + IdentityEndpoint string + TenantName string + + computeV2Client *gophercloud.ServiceClient +} + +func (c *Config) loadAndValidate() error { + ao := gophercloud.AuthOptions{ + Username: c.Username, + Password: c.Password, + IdentityEndpoint: c.IdentityEndpoint, + TenantName: c.TenantName, + } + + client, err := openstack.AuthenticatedClient(ao) + if err != nil { + return err + } + + c.computeV2Client, err = openstack.NewComputeV2(client, gophercloud.EndpointOpts{ + Region: c.Region, + }) + if err != nil { + return err + } + + return nil +} diff --git a/builtin/providers/openstack/provider.go b/builtin/providers/openstack/provider.go new file mode 100644 index 0000000000..a134c3d078 --- /dev/null +++ b/builtin/providers/openstack/provider.go @@ -0,0 +1,93 @@ +package openstack + +import ( + "os" + + "github.com/hashicorp/terraform/helper/schema" + "github.com/hashicorp/terraform/terraform" +) + +// Provider returns a schema.Provider for OpenStack. +func Provider() terraform.ResourceProvider { + return &schema.Provider{ + Schema: map[string]*schema.Schema{ + "region": &schema.Schema{ + Type: schema.TypeString, + Required: true, + DefaultFunc: envDefaultFunc("OS_REGION"), + Description: descriptions["region"], + }, + + "auth_url": &schema.Schema{ + Type: schema.TypeString, + Required: true, + DefaultFunc: envDefaultFunc("OS_AUTH_URL"), + Description: descriptions["auth_url"], + }, + + "username": &schema.Schema{ + Type: schema.TypeString, + Required: true, + DefaultFunc: envDefaultFunc("OS_USERNAME"), + Description: descriptions["username"], + }, + + "tenant_name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + DefaultFunc: envDefaultFunc("OS_TENANT_NAME"), + //Description: descriptions["tenantname"], + }, + + "password": &schema.Schema{ + Type: schema.TypeString, + Required: true, + DefaultFunc: envDefaultFunc("OS_PASSWORD"), + Description: descriptions["password"], + }, + }, + + ResourcesMap: map[string]*schema.Resource{ + "openstack_compute_instance": resourceComputeInstance(), + }, + + ConfigureFunc: configureProvider, + } +} + +func configureProvider(d *schema.ResourceData) (interface{}, error) { + config := Config{ + Region: d.Get("region").(string), + IdentityEndpoint: d.Get("auth_url").(string), + Username: d.Get("username").(string), + Password: d.Get("password").(string), + TenantName: d.Get("tenant_name").(string), + } + + if err := config.loadAndValidate(); err != nil { + return nil, err + } + + return &config, nil +} + +func envDefaultFunc(k string) schema.SchemaDefaultFunc { + return func() (interface{}, error) { + if v := os.Getenv(k); v != "" { + return v, nil + } + + return nil, nil + } +} + +var descriptions map[string]string + +func init() { + descriptions = map[string]string{ + "region": "The region where OpenStack operations will take place.", + "auth_url": "The endpoint against which to authenticate.", + "username": "The username with which to authenticate.", + "password": "The password with which to authenticate.", + } +} diff --git a/builtin/providers/openstack/resource_openstack_compute_instance.go b/builtin/providers/openstack/resource_openstack_compute_instance.go new file mode 100644 index 0000000000..07bf040e90 --- /dev/null +++ b/builtin/providers/openstack/resource_openstack_compute_instance.go @@ -0,0 +1,297 @@ +package openstack + +import ( + "fmt" + "log" + "time" + + "github.com/hashicorp/terraform/helper/hashcode" + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/helper/schema" + "github.com/rackspace/gophercloud" + "github.com/rackspace/gophercloud/openstack/compute/v2/servers" +) + +func resourceComputeInstance() *schema.Resource { + return &schema.Resource{ + Create: resourceComputeInstanceCreate, + Read: resourceComputeInstanceRead, + Update: resourceComputeInstanceUpdate, + Delete: resourceComputeInstanceDelete, + + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: false, + }, + + "image_ref": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: false, + }, + + "flavor_ref": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: false, + }, + + "security_groups": &schema.Schema{ + Type: schema.TypeSet, + Optional: true, + ForceNew: false, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: func(v interface{}) int { + return hashcode.String(v.(string)) + }, + }, + + "availability_zone": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + + "networks": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + ForceNew: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "uuid": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + }, + + "port": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + }, + + "fixed_ip": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + + "metadata": &schema.Schema{ + Type: schema.TypeMap, + Optional: true, + }, + + "config_drive": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + ForceNew: true, + }, + + "access_ip_v4": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Optional: true, + ForceNew: false, + }, + + "access_ip_v6": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + Optional: true, + ForceNew: false, + }, + }, + } +} + +func resourceComputeInstanceCreate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + osClient := config.computeV2Client + + createOpts := &servers.CreateOpts{ + Name: d.Get("name").(string), + ImageRef: d.Get("image_ref").(string), + FlavorRef: d.Get("flavor_ref").(string), + //SecurityGroups []string + AvailabilityZone: d.Get("availability_zone").(string), + Networks: resourceInstanceNetworks(d), + Metadata: resourceInstanceMetadata(d), + ConfigDrive: d.Get("config_drive").(bool), + } + + log.Printf("[INFO] Requesting instance creation") + server, err := servers.Create(osClient, createOpts).Extract() + if err != nil { + return fmt.Errorf("Error creating OpenStack server: %s", err) + } + log.Printf("[INFO] Instance ID: %s", server.ID) + + // Store the ID now + d.SetId(server.ID) + + // Wait for the instance to become running so we can get some attributes + // that aren't available until later. + log.Printf( + "[DEBUG] Waiting for instance (%s) to become running", + server.ID) + + stateConf := &resource.StateChangeConf{ + Pending: []string{"BUILD"}, + Target: "ACTIVE", + Refresh: ServerStateRefreshFunc(osClient, server.ID), + Timeout: 10 * time.Minute, + Delay: 10 * time.Second, + MinTimeout: 3 * time.Second, + } + + serverRaw, err := stateConf.WaitForState() + if err != nil { + return fmt.Errorf( + "Error waiting for instance (%s) to become ready: %s", + server.ID, err) + } + + server = serverRaw.(*servers.Server) + + return resourceComputeInstanceRead(d, meta) +} + +func resourceComputeInstanceRead(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + osClient := config.computeV2Client + + server, err := servers.Get(osClient, d.Id()).Extract() + if err != nil { + return fmt.Errorf("Error retrieving OpenStack server: %s", err) + } + + log.Printf("[DEBUG] Retreived Server %s: %+v", d.Id(), server) + + d.Set("name", server.Name) + d.Set("access_ip_v4", server.AccessIPv4) + d.Set("access_ip_v6", server.AccessIPv6) + + host := server.AccessIPv4 + if host == "" { + if publicAddressesRaw, ok := server.Addresses["public"]; ok { + publicAddresses := publicAddressesRaw.([]interface{}) + for _, paRaw := range publicAddresses { + pa := paRaw.(map[string]interface{}) + if pa["version"].(float64) == 4 { + host = pa["addr"].(string) + } + } + } + } + + log.Printf("host: %s", host) + + // Initialize the connection info + d.SetConnInfo(map[string]string{ + "type": "ssh", + "host": host, + }) + + d.Set("metadata", server.Metadata) + + return nil +} + +func resourceComputeInstanceUpdate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + osClient := config.computeV2Client + + var updateOpts servers.UpdateOpts + // If the Metadata has changed, then update that. + if d.HasChange("name") { + updateOpts.Name = d.Get("name").(string) + } + if d.HasChange("access_ip_v4") { + updateOpts.AccessIPv4 = d.Get("access_ip_v4").(string) + } + if d.HasChange("access_ip_v6") { + updateOpts.AccessIPv4 = d.Get("access_ip_v6").(string) + } + + // If there's nothing to update, don't waste an HTTP call. + if updateOpts != (servers.UpdateOpts{}) { + log.Printf("[DEBUG] Updating Server %s with options: %+v", d.Id(), updateOpts) + + _, err := servers.Update(osClient, d.Id(), updateOpts).Extract() + if err != nil { + return fmt.Errorf("Error updating Openstack server: %s", err) + } + } + + return resourceComputeInstanceRead(d, meta) +} + +func resourceComputeInstanceDelete(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + osClient := config.computeV2Client + + err := servers.Delete(osClient, d.Id()).ExtractErr() + if err != nil { + return fmt.Errorf("Error deleting OpenStack server: %s", err) + } + + // Wait for the instance to delete before moving on. + log.Printf( + "[DEBUG] Waiting for instance (%s) to delete", + d.Id()) + + stateConf := &resource.StateChangeConf{ + Target: "", + Refresh: ServerStateRefreshFunc(osClient, d.Id()), + Timeout: 10 * time.Minute, + Delay: 10 * time.Second, + MinTimeout: 3 * time.Second, + } + + _, err = stateConf.WaitForState() + if err != nil { + return fmt.Errorf( + "Error waiting for instance (%s) to delete: %s", + d.Id(), err) + } + + d.SetId("") + return nil +} + +// ServerStateRefreshFunc returns a resource.StateRefreshFunc that is used to watch +// an OpenStack instance. +func ServerStateRefreshFunc(client *gophercloud.ServiceClient, instanceID string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + s, err := servers.Get(client, instanceID).Extract() + if err != nil { + return nil, "", err + } + + return s, s.Status, nil + } +} + +func resourceInstanceNetworks(d *schema.ResourceData) []servers.Network { + rawNetworks := d.Get("networks").([]interface{}) + networks := make([]servers.Network, len(rawNetworks)) + for i, raw := range rawNetworks { + rawMap := raw.(map[string]interface{}) + networks[i] = servers.Network{ + UUID: rawMap["uuid"].(string), + Port: rawMap["port"].(string), + FixedIP: rawMap["fixed_ip"].(string), + } + } + return networks +} + +func resourceInstanceMetadata(d *schema.ResourceData) map[string]string { + m := make(map[string]string) + for key, val := range d.Get("metadata").(map[string]interface{}) { + m[key] = val.(string) + } + return m +} From cc9ee787ac8402ac0f44f1fbfc8d20ccd9878999 Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Fri, 2 Jan 2015 12:40:42 -0700 Subject: [PATCH 002/132] update openstack server metadata --- .../resource_openstack_compute_instance.go | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/builtin/providers/openstack/resource_openstack_compute_instance.go b/builtin/providers/openstack/resource_openstack_compute_instance.go index 07bf040e90..e4d1407d7a 100644 --- a/builtin/providers/openstack/resource_openstack_compute_instance.go +++ b/builtin/providers/openstack/resource_openstack_compute_instance.go @@ -221,7 +221,21 @@ func resourceComputeInstanceUpdate(d *schema.ResourceData, meta interface{}) err _, err := servers.Update(osClient, d.Id(), updateOpts).Extract() if err != nil { - return fmt.Errorf("Error updating Openstack server: %s", err) + return fmt.Errorf("Error updating OpenStack server: %s", err) + } + } + + if d.HasChange("metadata") { + var metadataOpts servers.MetadataOpts + metadataOpts = make(servers.MetadataOpts) + newMetadata := d.Get("metadata").(map[string]interface{}) + for k, v := range newMetadata { + metadataOpts[k] = v.(string) + } + + _, err := servers.UpdateMetadata(osClient, d.Id(), metadataOpts).Extract() + if err != nil { + return fmt.Errorf("Error updating OpenStack server (%s) metadata: %s", d.Id(), err) } } From 3112103acf15c392565838496a187c2499b3be28 Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Sun, 4 Jan 2015 09:52:49 -0700 Subject: [PATCH 003/132] server keypair --- .../resource_openstack_compute_instance.go | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/builtin/providers/openstack/resource_openstack_compute_instance.go b/builtin/providers/openstack/resource_openstack_compute_instance.go index e4d1407d7a..54dbe1b67f 100644 --- a/builtin/providers/openstack/resource_openstack_compute_instance.go +++ b/builtin/providers/openstack/resource_openstack_compute_instance.go @@ -9,6 +9,7 @@ import ( "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/schema" "github.com/rackspace/gophercloud" + "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/keypairs" "github.com/rackspace/gophercloud/openstack/compute/v2/servers" ) @@ -81,6 +82,7 @@ func resourceComputeInstance() *schema.Resource { "metadata": &schema.Schema{ Type: schema.TypeMap, Optional: true, + ForceNew: false, }, "config_drive": &schema.Schema{ @@ -102,6 +104,12 @@ func resourceComputeInstance() *schema.Resource { Optional: true, ForceNew: false, }, + + "key_pair": &schema.Schema{ + Type: schema.TypeMap, + Optional: true, + ForceNew: true, + }, }, } } @@ -110,7 +118,9 @@ func resourceComputeInstanceCreate(d *schema.ResourceData, meta interface{}) err config := meta.(*Config) osClient := config.computeV2Client - createOpts := &servers.CreateOpts{ + var createOpts servers.CreateOptsBuilder + + serverCreateOpts := &servers.CreateOpts{ Name: d.Get("name").(string), ImageRef: d.Get("image_ref").(string), FlavorRef: d.Get("flavor_ref").(string), @@ -121,6 +131,15 @@ func resourceComputeInstanceCreate(d *schema.ResourceData, meta interface{}) err ConfigDrive: d.Get("config_drive").(bool), } + if kp, ok := d.Get("key_pair").(map[string]interface{}); ok && kp != nil { + if keyName, ok := kp["name"].(string); ok && keyName != "" { + createOpts = &keypairs.CreateOptsExt{ + serverCreateOpts, + keyName, + } + } + } + log.Printf("[INFO] Requesting instance creation") server, err := servers.Create(osClient, createOpts).Extract() if err != nil { From 48e92f8173063cb8214eef4a3175c547ad1965a1 Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Sun, 4 Jan 2015 15:26:57 -0700 Subject: [PATCH 004/132] OS_REGION -> OS_REGION_NAME (thank you @hartzell) --- builtin/providers/openstack/provider.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/builtin/providers/openstack/provider.go b/builtin/providers/openstack/provider.go index a134c3d078..356081d193 100644 --- a/builtin/providers/openstack/provider.go +++ b/builtin/providers/openstack/provider.go @@ -14,7 +14,7 @@ func Provider() terraform.ResourceProvider { "region": &schema.Schema{ Type: schema.TypeString, Required: true, - DefaultFunc: envDefaultFunc("OS_REGION"), + DefaultFunc: envDefaultFunc("OS_REGION_NAME"), Description: descriptions["region"], }, @@ -61,7 +61,7 @@ func configureProvider(d *schema.ResourceData) (interface{}, error) { IdentityEndpoint: d.Get("auth_url").(string), Username: d.Get("username").(string), Password: d.Get("password").(string), - TenantName: d.Get("tenant_name").(string), + TenantName: d.Get("tenant_name").(string), } if err := config.loadAndValidate(); err != nil { From 0bb0dad58ce628b3030ea07c8ed3cfd3fdec2c4f Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Sun, 4 Jan 2015 15:27:54 -0700 Subject: [PATCH 005/132] provider test --- builtin/providers/openstack/provider_test.go | 51 ++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 builtin/providers/openstack/provider_test.go diff --git a/builtin/providers/openstack/provider_test.go b/builtin/providers/openstack/provider_test.go new file mode 100644 index 0000000000..2819a45753 --- /dev/null +++ b/builtin/providers/openstack/provider_test.go @@ -0,0 +1,51 @@ +package openstack + +import ( + "os" + "testing" + + "github.com/hashicorp/terraform/helper/schema" + "github.com/hashicorp/terraform/terraform" +) + +var testAccProviders map[string]terraform.ResourceProvider +var testAccProvider *schema.Provider + +func init() { + testAccProvider = Provider().(*schema.Provider) + testAccProviders = map[string]terraform.ResourceProvider{ + "openstack": testAccProvider, + } +} + +func TestProvider(t *testing.T) { + if err := Provider().(*schema.Provider).InternalValidate(); err != nil { + t.Fatalf("err: %s", err) + } +} + +func TestProvider_impl(t *testing.T) { + var _ terraform.ResourceProvider = Provider() +} + +func testAccPreCheck(t *testing.T) { + if v := os.Getenv("OS_REGION_NAME"); v == "" { + t.Fatal("OS_REGION_NAME must be set for acceptance tests") + } + + if v := os.Getenv("OS_AUTH_URL"); v == "" { + t.Fatal("OS_AUTH_URL must be set for acceptance tests") + } + + if v := os.Getenv("OS_USERNAME"); v == "" { + t.Fatal("OS_USERNAME must be set for acceptance tests") + } + + if v := os.Getenv("OS_TENANT_NAME"); v != "us-central1" { + t.Fatal("OS_TENANT_NAME must be set to us-central1 for acceptance tests") + } + + if v := os.Getenv("OS_PASSWORD"); v != "us-central1" { + t.Fatal("OS_PASSWORD must be set to us-central1 for acceptance tests") + } +} From f17649e9dc1a60a357c9e22ae9bc2c0617e73a20 Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Mon, 5 Jan 2015 10:05:25 -0700 Subject: [PATCH 006/132] server resizing --- .../resource_openstack_compute_instance.go | 57 ++++++++++++++++++- 1 file changed, 54 insertions(+), 3 deletions(-) diff --git a/builtin/providers/openstack/resource_openstack_compute_instance.go b/builtin/providers/openstack/resource_openstack_compute_instance.go index 54dbe1b67f..9075a08aeb 100644 --- a/builtin/providers/openstack/resource_openstack_compute_instance.go +++ b/builtin/providers/openstack/resource_openstack_compute_instance.go @@ -214,6 +214,11 @@ func resourceComputeInstanceRead(d *schema.ResourceData, meta interface{}) error }) d.Set("metadata", server.Metadata) + newFlavor, ok := server.Flavor["id"].(string) + if !ok { + return fmt.Errorf("Error setting OpenStack server's flavor: %v", newFlavor) + } + d.Set("flavor_ref", newFlavor) return nil } @@ -258,6 +263,54 @@ func resourceComputeInstanceUpdate(d *schema.ResourceData, meta interface{}) err } } + if d.HasChange("flavor_ref") { + resizeOpts := &servers.ResizeOpts{ + FlavorRef: d.Get("flavor_ref").(string), + } + err := servers.Resize(osClient, d.Id(), resizeOpts).ExtractErr() + if err != nil { + return fmt.Errorf("Error resizing OpenStack server: %s", err) + } + + // Wait for the instance to finish resizing. + log.Printf("[DEBUG] Waiting for instance (%s) to finish resizing", d.Id()) + + stateConf := &resource.StateChangeConf{ + Pending: []string{"RESIZE"}, + Target: "VERIFY_RESIZE", + Refresh: ServerStateRefreshFunc(osClient, d.Id()), + Timeout: 3 * time.Minute, + Delay: 10 * time.Second, + MinTimeout: 3 * time.Second, + } + + _, err = stateConf.WaitForState() + if err != nil { + return fmt.Errorf("Error waiting for instance (%s) to resize: %s", d.Id(), err) + } + + // Confirm resize. + log.Printf("[DEBUG] Confirming resize") + err = servers.ConfirmResize(osClient, d.Id()).ExtractErr() + if err != nil { + return fmt.Errorf("Error confirming resize of OpenStack server: %s", err) + } + + stateConf = &resource.StateChangeConf{ + Pending: []string{"VERIFY_RESIZE"}, + Target: "ACTIVE", + Refresh: ServerStateRefreshFunc(osClient, d.Id()), + Timeout: 3 * time.Minute, + Delay: 10 * time.Second, + MinTimeout: 3 * time.Second, + } + + _, err = stateConf.WaitForState() + if err != nil { + return fmt.Errorf("Error waiting for instance (%s) to confirm resize: %s", d.Id(), err) + } + } + return resourceComputeInstanceRead(d, meta) } @@ -271,9 +324,7 @@ func resourceComputeInstanceDelete(d *schema.ResourceData, meta interface{}) err } // Wait for the instance to delete before moving on. - log.Printf( - "[DEBUG] Waiting for instance (%s) to delete", - d.Id()) + log.Printf("[DEBUG] Waiting for instance (%s) to delete", d.Id()) stateConf := &resource.StateChangeConf{ Target: "", From 04a9d47bcab1bd9fb6a1bf7d951deafdc3f06c5c Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Mon, 5 Jan 2015 12:16:33 -0700 Subject: [PATCH 007/132] add/update/remove sec groups from server --- .../resource_openstack_compute_instance.go | 62 +++++++++++++++++-- 1 file changed, 58 insertions(+), 4 deletions(-) diff --git a/builtin/providers/openstack/resource_openstack_compute_instance.go b/builtin/providers/openstack/resource_openstack_compute_instance.go index 9075a08aeb..57afbb3093 100644 --- a/builtin/providers/openstack/resource_openstack_compute_instance.go +++ b/builtin/providers/openstack/resource_openstack_compute_instance.go @@ -10,7 +10,9 @@ import ( "github.com/hashicorp/terraform/helper/schema" "github.com/rackspace/gophercloud" "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/keypairs" + "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/secgroups" "github.com/rackspace/gophercloud/openstack/compute/v2/servers" + "github.com/rackspace/gophercloud/pagination" ) func resourceComputeInstance() *schema.Resource { @@ -121,10 +123,10 @@ func resourceComputeInstanceCreate(d *schema.ResourceData, meta interface{}) err var createOpts servers.CreateOptsBuilder serverCreateOpts := &servers.CreateOpts{ - Name: d.Get("name").(string), - ImageRef: d.Get("image_ref").(string), - FlavorRef: d.Get("flavor_ref").(string), - //SecurityGroups []string + Name: d.Get("name").(string), + ImageRef: d.Get("image_ref").(string), + FlavorRef: d.Get("flavor_ref").(string), + SecurityGroups: resourceInstanceSecGroups(d), AvailabilityZone: d.Get("availability_zone").(string), Networks: resourceInstanceNetworks(d), Metadata: resourceInstanceMetadata(d), @@ -214,6 +216,22 @@ func resourceComputeInstanceRead(d *schema.ResourceData, meta interface{}) error }) d.Set("metadata", server.Metadata) + + var currentSG []string + err = secgroups.ListByServer(osClient, d.Id()).EachPage(func(page pagination.Page) (bool, error) { + secGrpList, err := secgroups.ExtractSecurityGroups(page) + if err != nil { + return false, fmt.Errorf("Error setting security groups for OpenStack server: %s", err) + } + + for _, sg := range secGrpList { + currentSG = append(currentSG, sg.Name) + } + + return true, nil + }) + d.Set("security_groups", currentSG) + newFlavor, ok := server.Flavor["id"].(string) if !ok { return fmt.Errorf("Error setting OpenStack server's flavor: %v", newFlavor) @@ -263,6 +281,33 @@ func resourceComputeInstanceUpdate(d *schema.ResourceData, meta interface{}) err } } + if d.HasChange("security_groups") { + oldSGRaw, newSGRaw := d.GetChange("security_groups") + oldSGSet, newSGSet := oldSGRaw.(*schema.Set), newSGRaw.(*schema.Set) + secgroupsToAdd := newSGSet.Difference(oldSGSet) + secgroupsToRemove := oldSGSet.Difference(newSGSet) + + log.Printf("[DEBUG] Security groups to add: %v", secgroupsToAdd) + + log.Printf("[DEBUG] Security groups to remove: %v", secgroupsToRemove) + + for _, g := range secgroupsToAdd.List() { + err := secgroups.AddServerToGroup(osClient, d.Id(), g.(string)).ExtractErr() + if err != nil { + return fmt.Errorf("Error adding security group to OpenStack server (%s): %s", d.Id(), err) + } + log.Printf("[DEBUG] Added security group (%s) to instance (%s)", g.(string), d.Id()) + } + + for _, g := range secgroupsToRemove.List() { + err := secgroups.RemoveServerFromGroup(osClient, d.Id(), g.(string)).ExtractErr() + if err != nil { + return fmt.Errorf("Error removing security group from OpenStack server (%s): %s", d.Id(), err) + } + log.Printf("[DEBUG] Removed security group (%s) from instance (%s)", g.(string), d.Id()) + } + } + if d.HasChange("flavor_ref") { resizeOpts := &servers.ResizeOpts{ FlavorRef: d.Get("flavor_ref").(string), @@ -358,6 +403,15 @@ func ServerStateRefreshFunc(client *gophercloud.ServiceClient, instanceID string } } +func resourceInstanceSecGroups(d *schema.ResourceData) []string { + rawSecGroups := d.Get("security_groups").(*schema.Set) + secgroups := make([]string, rawSecGroups.Len()) + for i, raw := range rawSecGroups.List() { + secgroups[i] = raw.(string) + } + return secgroups +} + func resourceInstanceNetworks(d *schema.ResourceData) []servers.Network { rawNetworks := d.Get("networks").([]interface{}) networks := make([]servers.Network, len(rawNetworks)) From edc280a8dc6ef702a34880502ec41d5852a4bab4 Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Wed, 7 Jan 2015 11:38:23 -0700 Subject: [PATCH 008/132] add/update admin pass on server; change key pair format from map to string --- .../resource_openstack_compute_instance.go | 28 ++++++++++++++----- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/builtin/providers/openstack/resource_openstack_compute_instance.go b/builtin/providers/openstack/resource_openstack_compute_instance.go index 57afbb3093..a57fda13b8 100644 --- a/builtin/providers/openstack/resource_openstack_compute_instance.go +++ b/builtin/providers/openstack/resource_openstack_compute_instance.go @@ -93,6 +93,12 @@ func resourceComputeInstance() *schema.Resource { ForceNew: true, }, + "admin_pass": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: false, + }, + "access_ip_v4": &schema.Schema{ Type: schema.TypeString, Computed: true, @@ -108,7 +114,7 @@ func resourceComputeInstance() *schema.Resource { }, "key_pair": &schema.Schema{ - Type: schema.TypeMap, + Type: schema.TypeString, Optional: true, ForceNew: true, }, @@ -131,14 +137,13 @@ func resourceComputeInstanceCreate(d *schema.ResourceData, meta interface{}) err Networks: resourceInstanceNetworks(d), Metadata: resourceInstanceMetadata(d), ConfigDrive: d.Get("config_drive").(bool), + AdminPass: d.Get("admin_pass").(string), } - if kp, ok := d.Get("key_pair").(map[string]interface{}); ok && kp != nil { - if keyName, ok := kp["name"].(string); ok && keyName != "" { - createOpts = &keypairs.CreateOptsExt{ - serverCreateOpts, - keyName, - } + if keyName, ok := d.Get("key_pair").(string); ok && keyName != "" { + createOpts = &keypairs.CreateOptsExt{ + serverCreateOpts, + keyName, } } @@ -308,6 +313,15 @@ func resourceComputeInstanceUpdate(d *schema.ResourceData, meta interface{}) err } } + if d.HasChange("admin_pass") { + if newPwd, ok := d.Get("admin_pass").(string); ok { + err := servers.ChangeAdminPassword(osClient, d.Id(), newPwd).ExtractErr() + if err != nil { + return fmt.Errorf("Error changing admin password of OpenStack server (%s): %s", d.Id(), err) + } + } + } + if d.HasChange("flavor_ref") { resizeOpts := &servers.ResizeOpts{ FlavorRef: d.Get("flavor_ref").(string), From 686cd4b02b683575d6609609e14c56bb7b5dce31 Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Wed, 7 Jan 2015 12:19:30 -0700 Subject: [PATCH 009/132] add OpenStack to list of IaaS providers --- website/source/docs/providers/index.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/source/docs/providers/index.html.markdown b/website/source/docs/providers/index.html.markdown index f03c17c54b..5365d0e86e 100644 --- a/website/source/docs/providers/index.html.markdown +++ b/website/source/docs/providers/index.html.markdown @@ -14,7 +14,7 @@ etc. Almost any infrastructure noun can be represented as a resource in Terrafor Terraform is agnostic to the underlying platforms by supporting providers. A provider is responsible for understanding API interactions and exposing resources. Providers -generally are an IaaS (e.g. AWS, DigitalOcean, GCE), PaaS (e.g. Heroku, CloudFoundry), +generally are an IaaS (e.g. AWS, DigitalOcean, GCE, OpenStack), PaaS (e.g. Heroku, CloudFoundry), or SaaS services (e.g. Atlas, DNSimple, CloudFlare). Use the navigation to the left to read about the available providers. From 47955b1d446e70e27b72f77f4dffe0dc15c40796 Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Wed, 7 Jan 2015 16:45:06 -0700 Subject: [PATCH 010/132] remove unneeded variables during server creation --- .../openstack/resource_openstack_compute_instance.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/builtin/providers/openstack/resource_openstack_compute_instance.go b/builtin/providers/openstack/resource_openstack_compute_instance.go index a57fda13b8..7ba4199fc6 100644 --- a/builtin/providers/openstack/resource_openstack_compute_instance.go +++ b/builtin/providers/openstack/resource_openstack_compute_instance.go @@ -172,15 +172,13 @@ func resourceComputeInstanceCreate(d *schema.ResourceData, meta interface{}) err MinTimeout: 3 * time.Second, } - serverRaw, err := stateConf.WaitForState() + _, err = stateConf.WaitForState() if err != nil { return fmt.Errorf( "Error waiting for instance (%s) to become ready: %s", server.ID, err) } - server = serverRaw.(*servers.Server) - return resourceComputeInstanceRead(d, meta) } From 01e41646d3796a04d35bba8312505b357938c33b Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Wed, 7 Jan 2015 16:45:57 -0700 Subject: [PATCH 011/132] add/get/delete keypairs --- builtin/providers/openstack/provider.go | 1 + .../resource_openstack_compute_keypair.go | 76 +++++++++++++++++++ 2 files changed, 77 insertions(+) create mode 100644 builtin/providers/openstack/resource_openstack_compute_keypair.go diff --git a/builtin/providers/openstack/provider.go b/builtin/providers/openstack/provider.go index 356081d193..2a5aad71b1 100644 --- a/builtin/providers/openstack/provider.go +++ b/builtin/providers/openstack/provider.go @@ -49,6 +49,7 @@ func Provider() terraform.ResourceProvider { ResourcesMap: map[string]*schema.Resource{ "openstack_compute_instance": resourceComputeInstance(), + "openstack_compute_keypair": resourceComputeKeypair(), }, ConfigureFunc: configureProvider, diff --git a/builtin/providers/openstack/resource_openstack_compute_keypair.go b/builtin/providers/openstack/resource_openstack_compute_keypair.go new file mode 100644 index 0000000000..a8ca16e083 --- /dev/null +++ b/builtin/providers/openstack/resource_openstack_compute_keypair.go @@ -0,0 +1,76 @@ +package openstack + +import ( + "fmt" + + "github.com/hashicorp/terraform/helper/schema" + "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/keypairs" +) + +func resourceComputeKeypair() *schema.Resource { + return &schema.Resource{ + Create: resourceComputeKeypairCreate, + Read: resourceComputeKeypairRead, + Delete: resourceComputeKeypairDelete, + + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "public_key": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + }, + } +} + +func resourceComputeKeypairCreate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + osClient := config.computeV2Client + + createOpts := keypairs.CreateOpts{ + Name: d.Get("name").(string), + PublicKey: d.Get("public_key").(string), + } + + kp, err := keypairs.Create(osClient, createOpts).Extract() + if err != nil { + return fmt.Errorf("Error creating OpenStack keypair: %s", err) + } + + d.SetId(kp.Name) + + return resourceComputeKeypairRead(d, meta) +} + +func resourceComputeKeypairRead(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + osClient := config.computeV2Client + + kp, err := keypairs.Get(osClient, d.Id()).Extract() + if err != nil { + return fmt.Errorf("Error retrieving OpenStack keypair: %s", err) + } + + d.Set("name", kp.Name) + d.Set("public_key", kp.PublicKey) + + return nil +} + +func resourceComputeKeypairDelete(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + osClient := config.computeV2Client + + err := keypairs.Delete(osClient, d.Id()).ExtractErr() + if err != nil { + return fmt.Errorf("Error deleting OpenStack keypair: %s", err) + } + d.SetId("") + return nil +} From 00ee96fb6fe4bd7289dd7f052ffbfee810ea49c2 Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Wed, 7 Jan 2015 17:09:25 -0700 Subject: [PATCH 012/132] openstack servers and keypairs docs --- .../providers/openstack/index.html.markdown | 47 +++++++++++ .../r/compute_instance.html.markdown | 80 +++++++++++++++++++ .../openstack/r/compute_keypair.html.markdown | 37 +++++++++ website/source/layouts/openstack.erb | 29 +++++++ 4 files changed, 193 insertions(+) create mode 100644 website/source/docs/providers/openstack/index.html.markdown create mode 100644 website/source/docs/providers/openstack/r/compute_instance.html.markdown create mode 100644 website/source/docs/providers/openstack/r/compute_keypair.html.markdown create mode 100644 website/source/layouts/openstack.erb diff --git a/website/source/docs/providers/openstack/index.html.markdown b/website/source/docs/providers/openstack/index.html.markdown new file mode 100644 index 0000000000..652523c5b4 --- /dev/null +++ b/website/source/docs/providers/openstack/index.html.markdown @@ -0,0 +1,47 @@ +--- +layout: "openstack" +page_title: "Provider: OpenStack" +sidebar_current: "docs-openstack-index" +description: |- + The OpenStack provider is used to interact with the many resources supported by OpenStack. The provider needs to be configured with the proper credentials before it can be used. +--- + +# OpenStack Provider + +The OpenStack provider is used to interact with the +many resources supported by OpenStack. The provider needs to be configured +with the proper credentials before it can be used. + +Use the navigation to the left to read about the available resources. + +## Example Usage + +``` +# Configure the OpenStack Provider +provider "openstack" { + username = "admin" + tenant_name = "admin" + password = "pwd" + auth_url = "http://myauthurl:5000/v2.0" + region = "RegionOne" +} + +# Create a web server +resource "openstack_compute_instance" "test-server" { + ... +} +``` + +## Configuration Reference + +The following arguments are supported: + +* `username` - (Required) + +* `tenant_name` - (Required) + +* `password` - (Required) + +* `auth_url` - (Required) + +* `region` - (Required) diff --git a/website/source/docs/providers/openstack/r/compute_instance.html.markdown b/website/source/docs/providers/openstack/r/compute_instance.html.markdown new file mode 100644 index 0000000000..f22624bf9c --- /dev/null +++ b/website/source/docs/providers/openstack/r/compute_instance.html.markdown @@ -0,0 +1,80 @@ +--- +layout: "openstack" +page_title: "OpenStack: openstack_compute_instance" +sidebar_current: "docs-openstack-resource-compute-instance" +description: |- + Manages a VM instance resource within OpenStack. +--- + +# openstack\_compute\_instance + +Manages a VM instance resource within OpenStack. + +## Example Usage + +``` +resource "openstack_compute_instance" "test-server" { + name = "tf-test" + image_ref = "ad091b52-742f-469e-8f3c-fd81cadf0743" + flavor_ref = "3" + metadata { + this = "that" + } + key_pair = "my_key_pair_name" + security_groups = ["test-group-1"] +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) A unique name for the resource. + +* `image_ref` - (Required) The image reference (ID) for the desired image for + the server. Changing this creates a new server. + +* `flavor_ref` - (Required) The flavor reference (ID) for the desired flavor + for the server. Changing this resizes the existing server. + +* `security_groups` - (Optional) An array of one or more security group names + to associate with the server. Changing this results in adding/removing + security groups from the existing server. + +* `availability_zone` - (Optional) The availability zone in which to create + the server. Changing this creates a new server. + +* `networks` - (Optional) An array of one or more networks to attach to the + instance. The network object structure is documented below. + +* `metadata` - (Optional) Metadata key/value pairs to make available from + within the instance. Changing this updates the existing server metadata. + +* `admin_pass` - (Optional) The administrative password to assign to the server. + Changing this changes the root password on the existing server. + +* `key_pair` - (Optional) The name of a key pair to put on the server. The key + pair must already be created and associated with the tenant's account. + Changing this creates a new server. + +The `network` block supports: + +* `uuid` - (Required unless `port` is provided) The network UUID to attach to + the server. + +* `port` - (Required unless `uuid` is provided) The port UUID of a network to + attach to the server. + +* `fixed_ip` - (Optional) Specifies a fixed IP address to be used on this + network. + +## Attributes Reference + +The following attributes are exported: + +* `name` - See Argument Reference above. +* `access_ip_v4` - See Argument Reference above. +* `access_ip_v6` - See Argument Reference above. +* `metadata` - See Argument Reference above. +* `security_groups` - See Argument Reference above. +* `flavor_ref` - See Argument Reference above. diff --git a/website/source/docs/providers/openstack/r/compute_keypair.html.markdown b/website/source/docs/providers/openstack/r/compute_keypair.html.markdown new file mode 100644 index 0000000000..15459a0ec7 --- /dev/null +++ b/website/source/docs/providers/openstack/r/compute_keypair.html.markdown @@ -0,0 +1,37 @@ +--- +layout: "openstack" +page_title: "OpenStack: openstack_compute_keypair" +sidebar_current: "docs-openstack-resource-compute-keypair" +description: |- + Manages a keypair resource within OpenStack. +--- + +# openstack\_compute\_keypair + +Manages a keypair resource within OpenStack. + +## Example Usage + +``` +resource "openstack_compute_keypair" "test-keypair" { + name = "my-keypair" + public_key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDAjpC1hwiOCCmKEWxJ4qzTTsJbKzndLotBCz5PcwtUnflmU+gHJtWMZKpuEGVi29h0A/+ydKek1O18k10Ff+4tyFjiHDQAnOfgWf7+b1yK+qDip3X1C0UPMbwHlTfSGWLGZqd9LvEFx9k3h/M+VtMvwR1lJ9LUyTAImnNjWG7TaIPmui30HvM2UiFEmqkr4ijq45MyX2+fLIePLRIF61p4whjHAQYufqyno3BS48icQb4p6iVEZPo4AE2o9oIyQvj2mx4dk5Y8CgSETOZTYDOR3rU2fZTRDRgPJDH9FWvQjF5tA0p3d9CoWWd2s6GKKbfoUIi8R/Db1BSPJwkqB" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) A unique name for the keypair. Changing this creates a new + keypair. + +* `public_key` - (Required) A pregenerated OpenSSH-formatted public key. + Changing this creates a new keypair. + +## Attributes Reference + +The following attributes are exported: + +* `name` - See Argument Reference above. +* `public_key` - See Argument Reference above. diff --git a/website/source/layouts/openstack.erb b/website/source/layouts/openstack.erb new file mode 100644 index 0000000000..7547a3b09a --- /dev/null +++ b/website/source/layouts/openstack.erb @@ -0,0 +1,29 @@ +<% wrap_layout :inner do %> + <% content_for :sidebar do %> + + <% end %> + + <%= yield %> + <% end %> From 23d425072ca0f9759e423a9f5b486848430a746d Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Thu, 8 Jan 2015 10:47:10 -0700 Subject: [PATCH 013/132] add/delete security groups and rules --- builtin/providers/openstack/provider.go | 6 +- .../openstack/resource_compute_secgroup.go | 103 ++++++++++++++++++ .../resource_compute_secgrouprule.go | 99 +++++++++++++++++ 3 files changed, 206 insertions(+), 2 deletions(-) create mode 100644 builtin/providers/openstack/resource_compute_secgroup.go create mode 100644 builtin/providers/openstack/resource_compute_secgrouprule.go diff --git a/builtin/providers/openstack/provider.go b/builtin/providers/openstack/provider.go index 2a5aad71b1..b9bb5d29b4 100644 --- a/builtin/providers/openstack/provider.go +++ b/builtin/providers/openstack/provider.go @@ -48,8 +48,10 @@ func Provider() terraform.ResourceProvider { }, ResourcesMap: map[string]*schema.Resource{ - "openstack_compute_instance": resourceComputeInstance(), - "openstack_compute_keypair": resourceComputeKeypair(), + "openstack_compute_instance": resourceComputeInstance(), + "openstack_compute_keypair": resourceComputeKeypair(), + "openstack_compute_secgroup": resourceComputeSecGroup(), + "openstack_compute_secgrouprule": resourceComputeSecGroupRule(), }, ConfigureFunc: configureProvider, diff --git a/builtin/providers/openstack/resource_compute_secgroup.go b/builtin/providers/openstack/resource_compute_secgroup.go new file mode 100644 index 0000000000..f6471eb811 --- /dev/null +++ b/builtin/providers/openstack/resource_compute_secgroup.go @@ -0,0 +1,103 @@ +package openstack + +import ( + "fmt" + "log" + + "github.com/hashicorp/terraform/helper/schema" + "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/secgroups" +) + +func resourceComputeSecGroup() *schema.Resource { + return &schema.Resource{ + Create: resourceComputeSecGroupCreate, + Read: resourceComputeSecGroupRead, + Update: resourceComputeSecGroupUpdate, + Delete: resourceComputeSecGroupDelete, + + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: false, + }, + + "description": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: false, + }, + }, + } +} + +func resourceComputeSecGroupCreate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + osClient := config.computeV2Client + + createOpts := secgroups.CreateOpts{ + Name: d.Get("name").(string), + Description: d.Get("description").(string), + } + + sg, err := secgroups.Create(osClient, createOpts).Extract() + if err != nil { + return fmt.Errorf("Error creating OpenStack security group: %s", err) + } + + d.SetId(sg.ID) + + return resourceComputeSecGroupRead(d, meta) +} + +func resourceComputeSecGroupRead(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + osClient := config.computeV2Client + + sg, err := secgroups.Get(osClient, d.Id()).Extract() + if err != nil { + return fmt.Errorf("Error retrieving OpenStack security group: %s", err) + } + + d.Set("name", sg.Name) + d.Set("description", sg.Description) + + return nil +} + +func resourceComputeSecGroupUpdate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + osClient := config.computeV2Client + + var updateOpts secgroups.UpdateOpts + if d.HasChange("name") { + updateOpts.Name = d.Get("name").(string) + } + if d.HasChange("description") { + updateOpts.Description = d.Get("description").(string) + } + + // If there's nothing to update, don't waste an HTTP call. + if updateOpts != (secgroups.UpdateOpts{}) { + log.Printf("[DEBUG] Updating Security Group (%s) with options: %+v", d.Id(), updateOpts) + + _, err := secgroups.Update(osClient, d.Id(), updateOpts).Extract() + if err != nil { + return fmt.Errorf("Error updating OpenStack security group (%s): %s", d.Id(), err) + } + } + + return resourceComputeSecGroupRead(d, meta) +} + +func resourceComputeSecGroupDelete(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + osClient := config.computeV2Client + + err := secgroups.Delete(osClient, d.Id()).ExtractErr() + if err != nil { + return fmt.Errorf("Error deleting OpenStack security group: %s", err) + } + d.SetId("") + return nil +} diff --git a/builtin/providers/openstack/resource_compute_secgrouprule.go b/builtin/providers/openstack/resource_compute_secgrouprule.go new file mode 100644 index 0000000000..1063e2df06 --- /dev/null +++ b/builtin/providers/openstack/resource_compute_secgrouprule.go @@ -0,0 +1,99 @@ +package openstack + +import ( + "fmt" + + "github.com/hashicorp/terraform/helper/schema" + "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/secgroups" +) + +func resourceComputeSecGroupRule() *schema.Resource { + return &schema.Resource{ + Create: resourceComputeSecGroupRuleCreate, + Read: resourceComputeSecGroupRuleRead, + Delete: resourceComputeSecGroupRuleDelete, + + Schema: map[string]*schema.Schema{ + "group_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "from_port": &schema.Schema{ + Type: schema.TypeInt, + Required: true, + ForceNew: true, + }, + + "to_port": &schema.Schema{ + Type: schema.TypeInt, + Required: true, + ForceNew: true, + }, + + "ip_protocol": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "cidr": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + + "from_group_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + }, + } +} + +func resourceComputeSecGroupRuleCreate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + osClient := config.computeV2Client + + createOpts := secgroups.CreateRuleOpts{ + ParentGroupID: d.Get("group_id").(string), + FromPort: d.Get("from_port").(int), + ToPort: d.Get("to_port").(int), + IPProtocol: d.Get("ip_protocol").(string), + CIDR: d.Get("cidr").(string), + FromGroupID: d.Get("from_group_id").(string), + } + + sgr, err := secgroups.CreateRule(osClient, createOpts).Extract() + if err != nil { + return fmt.Errorf("Error creating OpenStack security group rule: %s", err) + } + + d.SetId(sgr.ID) + d.Set("group_id", sgr.ParentGroupID) + d.Set("from_port", sgr.FromPort) + d.Set("to_port", sgr.ToPort) + d.Set("ip_protocol", sgr.IPProtocol) + d.Set("cidr", sgr.IPRange.CIDR) + d.Set("from_group_id", d.Get("from_group_id").(string)) + + return resourceComputeSecGroupRuleRead(d, meta) +} + +func resourceComputeSecGroupRuleRead(d *schema.ResourceData, meta interface{}) error { + return nil +} + +func resourceComputeSecGroupRuleDelete(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + osClient := config.computeV2Client + + err := secgroups.DeleteRule(osClient, d.Id()).ExtractErr() + if err != nil { + return fmt.Errorf("Error deleting OpenStack security group rule: %s", err) + } + d.SetId("") + return nil +} From d7560de2ddf46b6d587284718a7e7fb934770865 Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Thu, 8 Jan 2015 10:48:00 -0700 Subject: [PATCH 014/132] remove errant comment --- .../providers/openstack/resource_openstack_compute_instance.go | 1 - 1 file changed, 1 deletion(-) diff --git a/builtin/providers/openstack/resource_openstack_compute_instance.go b/builtin/providers/openstack/resource_openstack_compute_instance.go index 7ba4199fc6..e8aa718481 100644 --- a/builtin/providers/openstack/resource_openstack_compute_instance.go +++ b/builtin/providers/openstack/resource_openstack_compute_instance.go @@ -249,7 +249,6 @@ func resourceComputeInstanceUpdate(d *schema.ResourceData, meta interface{}) err osClient := config.computeV2Client var updateOpts servers.UpdateOpts - // If the Metadata has changed, then update that. if d.HasChange("name") { updateOpts.Name = d.Get("name").(string) } From fc344e90604a2639b31415c963a8c73eed171d59 Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Thu, 8 Jan 2015 14:11:58 -0700 Subject: [PATCH 015/132] sec group and sec group rule docs --- .../r/compute_secgroup.html.markdown | 37 +++++++++++ .../r/compute_secgrouprule.html.markdown | 63 +++++++++++++++++++ website/source/layouts/openstack.erb | 6 ++ 3 files changed, 106 insertions(+) create mode 100644 website/source/docs/providers/openstack/r/compute_secgroup.html.markdown create mode 100644 website/source/docs/providers/openstack/r/compute_secgrouprule.html.markdown diff --git a/website/source/docs/providers/openstack/r/compute_secgroup.html.markdown b/website/source/docs/providers/openstack/r/compute_secgroup.html.markdown new file mode 100644 index 0000000000..27045b62bb --- /dev/null +++ b/website/source/docs/providers/openstack/r/compute_secgroup.html.markdown @@ -0,0 +1,37 @@ +--- +layout: "openstack" +page_title: "OpenStack: openstack_compute_secgroup" +sidebar_current: "docs-openstack-resource-compute-secgroup" +description: |- + Manages a security group resource within OpenStack. +--- + +# openstack\_compute\_secgroup + +Manages a security group resource within OpenStack. + +## Example Usage + +``` +resource "openstack_compute_secgroup" "secgroup_1" { + name = "my_secgroup" + description = "my security group" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) A unique name for the security group. Changing this + updates the `name` of an existing security group. + +* `description` - (Required) A description for the security group. Changing this + updates the `description` of an existing security group. + +## Attributes Reference + +The following attributes are exported: + +* `name` - See Argument Reference above. +* `description` - See Argument Reference above. diff --git a/website/source/docs/providers/openstack/r/compute_secgrouprule.html.markdown b/website/source/docs/providers/openstack/r/compute_secgrouprule.html.markdown new file mode 100644 index 0000000000..95b92981c1 --- /dev/null +++ b/website/source/docs/providers/openstack/r/compute_secgrouprule.html.markdown @@ -0,0 +1,63 @@ +--- +layout: "openstack" +page_title: "OpenStack: openstack_compute_secgrouprule" +sidebar_current: "docs-openstack-resource-compute-secgrouprule" +description: |- + Manages a security group rule resource within OpenStack. +--- + +# openstack\_compute\_secgrouprule + +Manages a security group rule resource within OpenStack. + +## Example Usage + +``` +resource "openstack_compute_secgroup" "secgroup_1" { + name = "my_secgroup" + description = "my security group" +} + +resource "openstack_compute_secgrouprule" "secgrouprule_1" { + group_id = "${openstack_compute_secgroup.secgroup_1.id}" + from_port = 22 + to_port = 22 + ip_protocol = "TCP" + cidr = "0.0.0.0/0" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `group_id` - (Required) The ID of the group to which this rule will be added. + Changing this creates a new security group rule. + +* `from_port` - (Required) An integer representing the lower bound of the port + range to open. Changing this creates a new security group rule. + +* `to_port` - (Required) An integer representing the upper bound of the port + range to open. Changing this creates a new security group rule. + +* `ip_protocol` - (Required) The protocol type that will be allowed. Changing + this creates a new security group rule. + +* `cidr` - (Optional) Required is `from_group_id` is empty. The IP range that + will be the source of network traffic to the security group. Use 0.0.0.0./0 + to allow all IP addresses. Changing this creates a new security group rule. + +* `from_group_id - (Optional) Required is `cidr` is empty. The ID of a group + from which to forward traffic to the parent group. Changing + this creates a new security group rule. + +## Attributes Reference + +The following attributes are exported: + +* `group_id` - See Argument Reference above. +* `from_port` - See Argument Reference above. +* `to_port` - See Argument Reference above. +* `ip_protocol` - See Argument Reference above. +* `cidr` - See Argument Reference above. +* `from_group_id` - See Argument Reference above. diff --git a/website/source/layouts/openstack.erb b/website/source/layouts/openstack.erb index 7547a3b09a..69bc4ba2e4 100644 --- a/website/source/layouts/openstack.erb +++ b/website/source/layouts/openstack.erb @@ -19,6 +19,12 @@ > openstack_compute_keypair + > + openstack_compute_keypair + + > + openstack_compute_keypair + From 457bbe661a92c0eee531a659979944373e03ff48 Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Sat, 10 Jan 2015 14:58:41 -0700 Subject: [PATCH 016/132] resource_compute_secgroup -> resource_openstack_compute_secgroup --- ...compute_secgroup.go => resource_openstack_compute_secgroup.go} | 0 ...secgrouprule.go => resource_openstack_compute_secgrouprule.go} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename builtin/providers/openstack/{resource_compute_secgroup.go => resource_openstack_compute_secgroup.go} (100%) rename builtin/providers/openstack/{resource_compute_secgrouprule.go => resource_openstack_compute_secgrouprule.go} (100%) diff --git a/builtin/providers/openstack/resource_compute_secgroup.go b/builtin/providers/openstack/resource_openstack_compute_secgroup.go similarity index 100% rename from builtin/providers/openstack/resource_compute_secgroup.go rename to builtin/providers/openstack/resource_openstack_compute_secgroup.go diff --git a/builtin/providers/openstack/resource_compute_secgrouprule.go b/builtin/providers/openstack/resource_openstack_compute_secgrouprule.go similarity index 100% rename from builtin/providers/openstack/resource_compute_secgrouprule.go rename to builtin/providers/openstack/resource_openstack_compute_secgrouprule.go From 45c4868f902afe7ff2623ff0804d28bce39b3417 Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Sat, 10 Jan 2015 14:59:59 -0700 Subject: [PATCH 017/132] fix comment --- .../providers/openstack/resource_openstack_compute_instance.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin/providers/openstack/resource_openstack_compute_instance.go b/builtin/providers/openstack/resource_openstack_compute_instance.go index e8aa718481..62d14b6361 100644 --- a/builtin/providers/openstack/resource_openstack_compute_instance.go +++ b/builtin/providers/openstack/resource_openstack_compute_instance.go @@ -237,7 +237,7 @@ func resourceComputeInstanceRead(d *schema.ResourceData, meta interface{}) error newFlavor, ok := server.Flavor["id"].(string) if !ok { - return fmt.Errorf("Error setting OpenStack server's flavor: %v", newFlavor) + return fmt.Errorf("Error setting OpenStack server's flavor: %v", server.Flavor) } d.Set("flavor_ref", newFlavor) From 476107579034ebc5f1befbbb4044f4f472b16b21 Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Sat, 10 Jan 2015 15:02:19 -0700 Subject: [PATCH 018/132] crud for neutron networks --- builtin/providers/openstack/config.go | 18 +- builtin/providers/openstack/provider.go | 2 + .../resource_openstack_networking_network.go | 188 ++++++++++++++++++ 3 files changed, 200 insertions(+), 8 deletions(-) create mode 100644 builtin/providers/openstack/resource_openstack_networking_network.go diff --git a/builtin/providers/openstack/config.go b/builtin/providers/openstack/config.go index cb06a98483..d877fcd80a 100644 --- a/builtin/providers/openstack/config.go +++ b/builtin/providers/openstack/config.go @@ -10,17 +10,18 @@ type Config struct { Username string Password string IdentityEndpoint string - TenantName string + TenantName string - computeV2Client *gophercloud.ServiceClient + computeV2Client *gophercloud.ServiceClient + networkingV2Client *gophercloud.ServiceClient } func (c *Config) loadAndValidate() error { ao := gophercloud.AuthOptions{ - Username: c.Username, - Password: c.Password, + Username: c.Username, + Password: c.Password, IdentityEndpoint: c.IdentityEndpoint, - TenantName: c.TenantName, + TenantName: c.TenantName, } client, err := openstack.AuthenticatedClient(ao) @@ -31,9 +32,10 @@ func (c *Config) loadAndValidate() error { c.computeV2Client, err = openstack.NewComputeV2(client, gophercloud.EndpointOpts{ Region: c.Region, }) - if err != nil { - return err - } + + c.networkingV2Client, err = openstack.NewNetworkV2(client, gophercloud.EndpointOpts{ + Region: c.Region, + }) return nil } diff --git a/builtin/providers/openstack/provider.go b/builtin/providers/openstack/provider.go index b9bb5d29b4..b9f756ef9b 100644 --- a/builtin/providers/openstack/provider.go +++ b/builtin/providers/openstack/provider.go @@ -52,6 +52,8 @@ func Provider() terraform.ResourceProvider { "openstack_compute_keypair": resourceComputeKeypair(), "openstack_compute_secgroup": resourceComputeSecGroup(), "openstack_compute_secgrouprule": resourceComputeSecGroupRule(), + "openstack_networking_network": resourceNetworkingNetwork(), + "openstack_networking_subnet": resourceNetworkingSubnet(), }, ConfigureFunc: configureProvider, diff --git a/builtin/providers/openstack/resource_openstack_networking_network.go b/builtin/providers/openstack/resource_openstack_networking_network.go new file mode 100644 index 0000000000..c819aa0f48 --- /dev/null +++ b/builtin/providers/openstack/resource_openstack_networking_network.go @@ -0,0 +1,188 @@ +package openstack + +import ( + "fmt" + "log" + "strconv" + + "github.com/hashicorp/terraform/helper/schema" + "github.com/rackspace/gophercloud/openstack/networking/v2/networks" +) + +func resourceNetworkingNetwork() *schema.Resource { + return &schema.Resource{ + Create: resourceNetworkingNetworkCreate, + Read: resourceNetworkingNetworkRead, + Update: resourceNetworkingNetworkUpdate, + Delete: resourceNetworkingNetworkDelete, + + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: false, + }, + + "admin_state_up": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: false, + }, + + "shared": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: false, + }, + + "tenant_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: false, + }, + }, + } +} + +func resourceNetworkingNetworkCreate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + osClient := config.networkingV2Client + + createOpts := networks.CreateOpts{ + Name: d.Get("name").(string), + TenantID: d.Get("tenant_id").(string), + } + + asuRaw := d.Get("admin_state_up").(string) + if asuRaw != "" { + asu, err := strconv.ParseBool(asuRaw) + if err != nil { + return fmt.Errorf("admin_state_up, if provided, must be either 'true' or 'false'") + } + createOpts.AdminStateUp = &asu + } + + sharedRaw := d.Get("shared").(string) + if sharedRaw != "" { + shared, err := strconv.ParseBool(sharedRaw) + if err != nil { + return fmt.Errorf("shared, if provided, must be either 'true' or 'false': %v", err) + } + createOpts.Shared = &shared + } + + log.Printf("[INFO] Requesting network creation") + n, err := networks.Create(osClient, createOpts).Extract() + if err != nil { + return fmt.Errorf("Error creating OpenStack Neutron network: %s", err) + } + log.Printf("[INFO] Network ID: %s", n.ID) + + d.SetId(n.ID) + + return resourceNetworkingNetworkRead(d, meta) +} + +func resourceNetworkingNetworkRead(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + osClient := config.networkingV2Client + + n, err := networks.Get(osClient, d.Id()).Extract() + if err != nil { + return fmt.Errorf("Error retrieving OpenStack Neutron Network: %s", err) + } + + log.Printf("[DEBUG] Retreived Network %s: %+v", d.Id(), n) + + if _, exists := d.GetOk("name"); exists { + if d.HasChange("name") { + d.Set("name", n.Name) + } + } else { + d.Set("name", "") + } + + if _, exists := d.GetOk("admin_state_up"); exists { + if d.HasChange("admin_state_up") { + d.Set("admin_state_up", strconv.FormatBool(n.AdminStateUp)) + } + } else { + d.Set("admin_state_up", "") + } + + if _, exists := d.GetOk("shared"); exists { + if d.HasChange("shared") { + d.Set("shared", strconv.FormatBool(n.Shared)) + } + } else { + d.Set("shared", "") + } + + if _, exists := d.GetOk("tenant_id"); exists { + if d.HasChange("tenant_id") { + d.Set("tenant_id", n.TenantID) + } + } else { + d.Set("tenant_id", "") + } + + return nil +} + +func resourceNetworkingNetworkUpdate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + osClient := config.networkingV2Client + + var updateOpts networks.UpdateOpts + if d.HasChange("name") { + updateOpts.Name = d.Get("name").(string) + } + if d.HasChange("admin_state_up") { + asuRaw := d.Get("admin_state_up").(string) + if asuRaw != "" { + asu, err := strconv.ParseBool(asuRaw) + if err != nil { + return fmt.Errorf("admin_state_up, if provided, must be either 'true' or 'false'") + } + updateOpts.AdminStateUp = &asu + } + } + if d.HasChange("shared") { + sharedRaw := d.Get("shared").(string) + if sharedRaw != "" { + shared, err := strconv.ParseBool(sharedRaw) + if err != nil { + return fmt.Errorf("shared, if provided, must be either 'true' or 'false': %v", err) + } + updateOpts.Shared = &shared + } + } + if d.HasChange("tenant_id") { + updateOpts.TenantID = d.Get("tenant_id").(string) + } + + // If there's nothing to update, don't waste an HTTP call. + if updateOpts != (networks.UpdateOpts{}) { + log.Printf("[DEBUG] Updating Network %s with options: %+v", d.Id(), updateOpts) + + _, err := networks.Update(osClient, d.Id(), updateOpts).Extract() + if err != nil { + return fmt.Errorf("Error updating OpenStack Neutron Network: %s", err) + } + } + + return resourceNetworkingNetworkRead(d, meta) +} + +func resourceNetworkingNetworkDelete(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + osClient := config.networkingV2Client + + err := networks.Delete(osClient, d.Id()).ExtractErr() + if err != nil { + return fmt.Errorf("Error deleting OpenStack Neutron Network: %s", err) + } + + d.SetId("") + return nil +} From 4424828d25520542e3fda8f7fcfdd6d610869ea9 Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Sat, 10 Jan 2015 15:03:01 -0700 Subject: [PATCH 019/132] crud for neutron subnets --- .../resource_openstack_networking_subnet.go | 294 ++++++++++++++++++ 1 file changed, 294 insertions(+) create mode 100644 builtin/providers/openstack/resource_openstack_networking_subnet.go diff --git a/builtin/providers/openstack/resource_openstack_networking_subnet.go b/builtin/providers/openstack/resource_openstack_networking_subnet.go new file mode 100644 index 0000000000..bedad55723 --- /dev/null +++ b/builtin/providers/openstack/resource_openstack_networking_subnet.go @@ -0,0 +1,294 @@ +package openstack + +import ( + "fmt" + "log" + "strconv" + + "github.com/hashicorp/terraform/helper/schema" + "github.com/jrperritt/terraform/helper/hashcode" + "github.com/rackspace/gophercloud/openstack/networking/v2/subnets" +) + +func resourceNetworkingSubnet() *schema.Resource { + return &schema.Resource{ + Create: resourceNetworkingSubnetCreate, + Read: resourceNetworkingSubnetRead, + Update: resourceNetworkingSubnetUpdate, + Delete: resourceNetworkingSubnetDelete, + + Schema: map[string]*schema.Schema{ + "network_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "cidr": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: false, + }, + + "tenant_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + + "allocation_pools": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + ForceNew: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "start": &schema.Schema{ + Type: schema.TypeString, + Required: true, + }, + + "end": &schema.Schema{ + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, + + "gateway_ip": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: false, + }, + + "ip_version": &schema.Schema{ + Type: schema.TypeInt, + Required: true, + ForceNew: true, + }, + + "enable_dhcp": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: false, + }, + + "dns_nameservers": &schema.Schema{ + Type: schema.TypeSet, + Optional: true, + ForceNew: false, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: func(v interface{}) int { + return hashcode.String(v.(string)) + }, + }, + + "host_routes": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + ForceNew: false, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "destination_cidr": &schema.Schema{ + Type: schema.TypeString, + Required: true, + }, + + "next_hop": &schema.Schema{ + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, + }, + } +} + +func resourceNetworkingSubnetCreate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + osClient := config.networkingV2Client + + createOpts := subnets.CreateOpts{ + NetworkID: d.Get("network_id").(string), + CIDR: d.Get("cidr").(string), + Name: d.Get("name").(string), + TenantID: d.Get("tenant_id").(string), + AllocationPools: resourceSubnetAllocationPools(d), + GatewayIP: d.Get("gateway_ip").(string), + IPVersion: d.Get("ip_version").(int), + DNSNameservers: resourceSubnetDNSNameservers(d), + HostRoutes: resourceSubnetHostRoutes(d), + } + + edRaw := d.Get("enable_dhcp").(string) + if edRaw != "" { + ed, err := strconv.ParseBool(edRaw) + if err != nil { + return fmt.Errorf("enable_dhcp, if provided, must be either 'true' or 'false'") + } + createOpts.EnableDHCP = &ed + } + + log.Printf("[INFO] Requesting subnet creation") + s, err := subnets.Create(osClient, createOpts).Extract() + if err != nil { + return fmt.Errorf("Error creating OpenStack Neutron subnet: %s", err) + } + log.Printf("[INFO] Subnet ID: %s", s.ID) + + d.SetId(s.ID) + + return resourceNetworkingSubnetRead(d, meta) +} + +func resourceNetworkingSubnetRead(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + osClient := config.networkingV2Client + + s, err := subnets.Get(osClient, d.Id()).Extract() + if err != nil { + return fmt.Errorf("Error retrieving OpenStack Neutron Subnet: %s", err) + } + + log.Printf("[DEBUG] Retreived Subnet %s: %+v", d.Id(), s) + + d.Set("newtork_id", s.NetworkID) + d.Set("cidr", s.CIDR) + d.Set("ip_version", s.IPVersion) + + if _, exists := d.GetOk("name"); exists { + if d.HasChange("name") { + d.Set("name", s.Name) + } + } else { + d.Set("name", "") + } + + if _, exists := d.GetOk("tenant_id"); exists { + if d.HasChange("tenant_id") { + d.Set("tenant_id", s.Name) + } + } else { + d.Set("tenant_id", "") + } + + if _, exists := d.GetOk("allocation_pools"); exists { + d.Set("allocation_pools", s.AllocationPools) + } + + if _, exists := d.GetOk("gateway_ip"); exists { + if d.HasChange("gateway_ip") { + d.Set("gateway_ip", s.Name) + } + } else { + d.Set("gateway_ip", "") + } + + if _, exists := d.GetOk("enable_dhcp"); exists { + if d.HasChange("enable_dhcp") { + d.Set("enable_dhcp", strconv.FormatBool(s.EnableDHCP)) + } + } else { + d.Set("enable_dhcp", "") + } + + if _, exists := d.GetOk("dns_nameservers"); exists { + d.Set("dns_nameservers", s.DNSNameservers) + } + + if _, exists := d.GetOk("host_routes"); exists { + d.Set("host_routes", s.HostRoutes) + } + + return nil +} + +func resourceNetworkingSubnetUpdate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + osClient := config.networkingV2Client + + var updateOpts subnets.UpdateOpts + + if d.HasChange("name") { + updateOpts.Name = d.Get("name").(string) + } + + if d.HasChange("gateway_ip") { + updateOpts.GatewayIP = d.Get("gateway_ip").(string) + } + + if d.HasChange("dns_nameservers") { + updateOpts.DNSNameservers = resourceSubnetDNSNameservers(d) + } + + if d.HasChange("host_routes") { + updateOpts.HostRoutes = resourceSubnetHostRoutes(d) + } + + if d.HasChange("enable_dhcp") { + edRaw := d.Get("enable_dhcp").(string) + if edRaw != "" { + ed, err := strconv.ParseBool(edRaw) + if err != nil { + return fmt.Errorf("enable_dhcp, if provided, must be either 'true' or 'false'") + } + updateOpts.EnableDHCP = &ed + } + } + + log.Printf("[DEBUG] Updating Subnet %s with options: %+v", d.Id(), updateOpts) + + _, err := subnets.Update(osClient, d.Id(), updateOpts).Extract() + if err != nil { + return fmt.Errorf("Error updating OpenStack Neutron Subnet: %s", err) + } + + return resourceNetworkingSubnetRead(d, meta) +} + +func resourceNetworkingSubnetDelete(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + osClient := config.networkingV2Client + + err := subnets.Delete(osClient, d.Id()).ExtractErr() + if err != nil { + return fmt.Errorf("Error deleting OpenStack Neutron Subnet: %s", err) + } + + d.SetId("") + return nil +} + +func resourceSubnetAllocationPools(d *schema.ResourceData) []subnets.AllocationPool { + rawAPs := d.Get("allocation_pools").([]interface{}) + aps := make([]subnets.AllocationPool, len(rawAPs)) + for i, raw := range rawAPs { + aps[i] = raw.(subnets.AllocationPool) + } + return aps +} + +func resourceSubnetDNSNameservers(d *schema.ResourceData) []string { + rawDNSN := d.Get("dns_nameservers").(*schema.Set) + dnsn := make([]string, rawDNSN.Len()) + for i, raw := range rawDNSN.List() { + dnsn[i] = raw.(string) + } + return dnsn +} + +func resourceSubnetHostRoutes(d *schema.ResourceData) []subnets.HostRoute { + rawHR := d.Get("host_routes").([]interface{}) + hr := make([]subnets.HostRoute, len(rawHR)) + for i, raw := range rawHR { + hr[i] = raw.(subnets.HostRoute) + } + return hr +} From ac79c76b132ce5d0c00690d9f47c4af6b21627b3 Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Wed, 14 Jan 2015 11:53:34 -0700 Subject: [PATCH 020/132] add lb resources --- builtin/providers/openstack/provider.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/builtin/providers/openstack/provider.go b/builtin/providers/openstack/provider.go index b9f756ef9b..9426fc23a6 100644 --- a/builtin/providers/openstack/provider.go +++ b/builtin/providers/openstack/provider.go @@ -52,6 +52,10 @@ func Provider() terraform.ResourceProvider { "openstack_compute_keypair": resourceComputeKeypair(), "openstack_compute_secgroup": resourceComputeSecGroup(), "openstack_compute_secgrouprule": resourceComputeSecGroupRule(), + "openstack_lb_member": resourceLBMember(), + "openstack_lb_monitor": resourceLBMonitor(), + "openstack_lb_pool": resourceLBPool(), + "openstack_lb_vip": resourceLBVip(), "openstack_networking_network": resourceNetworkingNetwork(), "openstack_networking_subnet": resourceNetworkingSubnet(), }, From 9077b6604528327ad4d4294d286682ccbdb1e00b Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Wed, 14 Jan 2015 11:54:27 -0700 Subject: [PATCH 021/132] lb member operations --- .../openstack/resource_openstack_lb_member.go | 131 ++++++++++++++++++ .../openstack/r/lb_member.html.markdown | 52 +++++++ 2 files changed, 183 insertions(+) create mode 100644 builtin/providers/openstack/resource_openstack_lb_member.go create mode 100644 website/source/docs/providers/openstack/r/lb_member.html.markdown diff --git a/builtin/providers/openstack/resource_openstack_lb_member.go b/builtin/providers/openstack/resource_openstack_lb_member.go new file mode 100644 index 0000000000..c628ee2b4d --- /dev/null +++ b/builtin/providers/openstack/resource_openstack_lb_member.go @@ -0,0 +1,131 @@ +package openstack + +import ( + "fmt" + "log" + + "github.com/hashicorp/terraform/helper/schema" + "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/lbaas/members" +) + +func resourceLBMember() *schema.Resource { + return &schema.Resource{ + Create: resourceLBMemberCreate, + Read: resourceLBMemberRead, + Update: resourceLBMemberUpdate, + Delete: resourceLBMemberDelete, + + Schema: map[string]*schema.Schema{ + "tenant_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + + "address": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "port": &schema.Schema{ + Type: schema.TypeInt, + Required: true, + ForceNew: true, + }, + + "pool_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "admin_state_up": &schema.Schema{ + Type: schema.TypeBool, + Required: true, + ForceNew: false, + }, + }, + } +} + +func resourceLBMemberCreate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + osClient := config.networkingV2Client + + createOpts := members.CreateOpts{ + //TenantID: d.Get("tenant_id").(string), + Address: d.Get("address").(string), + ProtocolPort: d.Get("port").(int), + PoolID: d.Get("pool_id").(string), + } + + log.Printf("[INFO] Requesting lb member creation") + p, err := members.Create(osClient, createOpts).Extract() + if err != nil { + return fmt.Errorf("Error creating OpenStack LB member: %s", err) + } + log.Printf("[INFO] LB Member ID: %s", p.ID) + + d.SetId(p.ID) + + return resourceLBMemberRead(d, meta) +} + +func resourceLBMemberRead(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + osClient := config.networkingV2Client + + p, err := members.Get(osClient, d.Id()).Extract() + if err != nil { + return fmt.Errorf("Error retrieving OpenStack LB Member: %s", err) + } + + log.Printf("[DEBUG] Retreived OpenStack LB Member %s: %+v", d.Id(), p) + + d.Set("address", p.Address) + d.Set("port", p.ProtocolPort) + d.Set("pool_id", p.PoolID) + + if _, exists := d.GetOk("tenant_id"); exists { + if d.HasChange("tenant_id") { + d.Set("tenant_id", p.TenantID) + } + } else { + d.Set("tenant_id", "") + } + + return nil +} + +func resourceLBMemberUpdate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + osClient := config.networkingV2Client + + var updateOpts members.UpdateOpts + if d.HasChange("admin_state_up") { + updateOpts.AdminStateUp = d.Get("admin_state_up").(bool) + } + + log.Printf("[DEBUG] Updating OpenStack LB Member %s with options: %+v", d.Id(), updateOpts) + + _, err := members.Update(osClient, d.Id(), updateOpts).Extract() + if err != nil { + return fmt.Errorf("Error updating OpenStack LB Member: %s", err) + } + + return resourceLBMemberRead(d, meta) +} + +func resourceLBMemberDelete(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + osClient := config.networkingV2Client + + err := members.Delete(osClient, d.Id()).ExtractErr() + if err != nil { + return fmt.Errorf("Error deleting OpenStack LB Member: %s", err) + } + + d.SetId("") + return nil +} diff --git a/website/source/docs/providers/openstack/r/lb_member.html.markdown b/website/source/docs/providers/openstack/r/lb_member.html.markdown new file mode 100644 index 0000000000..0607ca840c --- /dev/null +++ b/website/source/docs/providers/openstack/r/lb_member.html.markdown @@ -0,0 +1,52 @@ +--- +layout: "openstack" +page_title: "OpenStack: openstack_lb_member" +sidebar_current: "docs-openstack-resource-lb-member" +description: |- + Manages a load balancer member resource within OpenStack. +--- + +# openstack\_lb\_member + +Manages a load balancer member resource within OpenStack. + +## Example Usage + +``` +resource "openstack_lb_member" "node_1" { + address = "196.172.0.1" + port = 80 + pool_id = "$12345" + admin_state_up = true +} +``` + +## Argument Reference + +The following arguments are supported: + +* `address` - (Required) The IP address of the member. Changing this creates a + new member. + +* `port` - (Required) An integer representing the port on which the member is + hosted. Changing this creates a new member. + +* `pool_id` - (Required) The pool to which this member will belong. Changing + this creates a new member. + +* `admin_state_up` - (Optional) The administrative state of the member. + Acceptable values are 'true' and 'false'. Changing this value updates the + state of the existing member. + +* `tenant_id` - (Optional) The owner of the member. Required if admin wants to + create a pool member for another tenant. Changing this creates a new member. + +## Attributes Reference + +The following attributes are exported: + +* `address` - See Argument Reference above. +* `port` - See Argument Reference above. +* `pool_id` - See Argument Reference above. +* `admin_state_up` - See Argument Reference above. +* `tenant_id` - See Argument Reference above. From 966c8420d1bd8a5ab23c96d6d148e3a233100d1e Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Wed, 14 Jan 2015 11:54:52 -0700 Subject: [PATCH 022/132] lb monitor operations --- .../resource_openstack_lb_monitor.go | 227 ++++++++++++++++++ .../openstack/r/lb_monitor.html.markdown | 76 ++++++ 2 files changed, 303 insertions(+) create mode 100644 builtin/providers/openstack/resource_openstack_lb_monitor.go create mode 100644 website/source/docs/providers/openstack/r/lb_monitor.html.markdown diff --git a/builtin/providers/openstack/resource_openstack_lb_monitor.go b/builtin/providers/openstack/resource_openstack_lb_monitor.go new file mode 100644 index 0000000000..b2cb98641b --- /dev/null +++ b/builtin/providers/openstack/resource_openstack_lb_monitor.go @@ -0,0 +1,227 @@ +package openstack + +import ( + "fmt" + "log" + "strconv" + + "github.com/hashicorp/terraform/helper/schema" + "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/lbaas/monitors" +) + +func resourceLBMonitor() *schema.Resource { + return &schema.Resource{ + Create: resourceLBMonitorCreate, + Read: resourceLBMonitorRead, + Update: resourceLBMonitorUpdate, + Delete: resourceLBMonitorDelete, + + Schema: map[string]*schema.Schema{ + "tenant_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + + "type": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "delay": &schema.Schema{ + Type: schema.TypeInt, + Required: true, + ForceNew: false, + }, + + "timeout": &schema.Schema{ + Type: schema.TypeInt, + Required: true, + ForceNew: false, + }, + + "max_retries": &schema.Schema{ + Type: schema.TypeInt, + Required: true, + ForceNew: false, + }, + + "url_path": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: false, + }, + + "http_method": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: false, + }, + + "expected_codes": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: false, + }, + + "admin_state_up": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: false, + }, + }, + } +} + +func resourceLBMonitorCreate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + osClient := config.networkingV2Client + + createOpts := monitors.CreateOpts{ + TenantID: d.Get("tenant_id").(string), + Type: d.Get("type").(string), + Delay: d.Get("delay").(int), + Timeout: d.Get("timeout").(int), + MaxRetries: d.Get("max_retries").(int), + URLPath: d.Get("url_path").(string), + ExpectedCodes: d.Get("expected_codes").(string), + HTTPMethod: d.Get("http_method").(string), + } + + asuRaw := d.Get("admin_state_up").(string) + if asuRaw != "" { + asu, err := strconv.ParseBool(asuRaw) + if err != nil { + return fmt.Errorf("admin_state_up, if provided, must be either 'true' or 'false'") + } + createOpts.AdminStateUp = &asu + } + + log.Printf("[INFO] Requesting lb monitor creation") + m, err := monitors.Create(osClient, createOpts).Extract() + if err != nil { + return fmt.Errorf("Error creating OpenStack LB Monitor: %s", err) + } + log.Printf("[INFO] LB Monitor ID: %s", m.ID) + + d.SetId(m.ID) + + return resourceLBMonitorRead(d, meta) +} + +func resourceLBMonitorRead(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + osClient := config.networkingV2Client + + m, err := monitors.Get(osClient, d.Id()).Extract() + if err != nil { + return fmt.Errorf("Error retrieving OpenStack LB Monitor: %s", err) + } + + log.Printf("[DEBUG] Retreived OpenStack LB Monitor %s: %+v", d.Id(), m) + + d.Set("type", m.Type) + d.Set("delay", m.Delay) + d.Set("timeout", m.Timeout) + d.Set("max_retries", m.MaxRetries) + + if _, exists := d.GetOk("tenant_id"); exists { + if d.HasChange("tenant_id") { + d.Set("tenant_id", m.TenantID) + } + } else { + d.Set("tenant_id", "") + } + + if _, exists := d.GetOk("url_path"); exists { + if d.HasChange("url_path") { + d.Set("url_path", m.URLPath) + } + } else { + d.Set("url_path", "") + } + + if _, exists := d.GetOk("http_method"); exists { + if d.HasChange("http_method") { + d.Set("http_method", m.HTTPMethod) + } + } else { + d.Set("http_method", "") + } + + if _, exists := d.GetOk("expected_codes"); exists { + if d.HasChange("expected_codes") { + d.Set("expected_codes", m.ExpectedCodes) + } + } else { + d.Set("expected_codes", "") + } + + if _, exists := d.GetOk("admin_state_up"); exists { + if d.HasChange("admin_state_up") { + d.Set("admin_state_up", strconv.FormatBool(m.AdminStateUp)) + } + } else { + d.Set("admin_state_up", "") + } + + return nil +} + +func resourceLBMonitorUpdate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + osClient := config.networkingV2Client + + var updateOpts monitors.UpdateOpts + if d.HasChange("delay") { + updateOpts.Delay = d.Get("delay").(int) + } + if d.HasChange("timeout") { + updateOpts.Timeout = d.Get("timeout").(int) + } + if d.HasChange("max_retries") { + updateOpts.MaxRetries = d.Get("max_retries").(int) + } + if d.HasChange("url_path") { + updateOpts.URLPath = d.Get("url_path").(string) + } + if d.HasChange("http_method") { + updateOpts.HTTPMethod = d.Get("http_method").(string) + } + if d.HasChange("expected_codes") { + updateOpts.ExpectedCodes = d.Get("expected_codes").(string) + } + if d.HasChange("admin_state_up") { + asuRaw := d.Get("admin_state_up").(string) + if asuRaw != "" { + asu, err := strconv.ParseBool(asuRaw) + if err != nil { + return fmt.Errorf("admin_state_up, if provided, must be either 'true' or 'false'") + } + updateOpts.AdminStateUp = &asu + } + } + + log.Printf("[DEBUG] Updating OpenStack LB Monitor %s with options: %+v", d.Id(), updateOpts) + + _, err := monitors.Update(osClient, d.Id(), updateOpts).Extract() + if err != nil { + return fmt.Errorf("Error updating OpenStack LB Monitor: %s", err) + } + + return resourceLBMonitorRead(d, meta) +} + +func resourceLBMonitorDelete(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + osClient := config.networkingV2Client + + err := monitors.Delete(osClient, d.Id()).ExtractErr() + if err != nil { + return fmt.Errorf("Error deleting OpenStack LB Monitor: %s", err) + } + + d.SetId("") + return nil +} diff --git a/website/source/docs/providers/openstack/r/lb_monitor.html.markdown b/website/source/docs/providers/openstack/r/lb_monitor.html.markdown new file mode 100644 index 0000000000..36b8142749 --- /dev/null +++ b/website/source/docs/providers/openstack/r/lb_monitor.html.markdown @@ -0,0 +1,76 @@ +--- +layout: "openstack" +page_title: "OpenStack: openstack_lb_monitor" +sidebar_current: "docs-openstack-resource-lb-monitor" +description: |- + Manages a load balancer monitor resource within OpenStack. +--- + +# openstack\_lb\_monitor + +Manages a load balancer monitor resource within OpenStack. + +## Example Usage + +``` +resource "openstack_lb_monitor" "monitor_1" { + type = "PING" + delay = 30 + timeout = 5 + max_retries = 3 + admin_state_up = "true" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `type` - (Required) The type of probe, which is PING, TCP, HTTP, or HTTPS, + that is sent by the monitor to verify the member state. Changing this + creates a new monitor. + +* `delay` - (Required) The time, in seconds, between sending probes to members. + Changing this creates a new monitor. + +* `timeout` - (Required) Maximum number of seconds for a monitor to wait for a + ping reply before it times out. The value must be less than the delay value. + Changing this updates the timeout of the existing monitor. + +* `max_retries` - (Required) Number of permissible ping failures before changing + the member's status to INACTIVE. Must be a number between 1 and 10. Changing + this updates the max_retries of the existing monitor. + +* `url_path` - (Optional) Required for HTTP(S) types. URI path that will be + accessed if monitor type is HTTP or HTTPS. Changing this updates the + url_path of the existing monitor. + +* `http_method` - (Optional) Required for HTTP(S) types. The HTTP method used + for requests by the monitor. If this attribute is not specified, it defaults + to "GET". Changing this updates the http_method of the existing monitor. + +* `expected_codes` - (Optional) equired for HTTP(S) types. Expected HTTP codes + for a passing HTTP(S) monitor. You can either specify a single status like + "200", or a range like "200-202". Changing this updates the expected_codes + of the existing monitor. + +* `admin_state_up` - (Optional) The administrative state of the monitor. + Acceptable values are "true" and "false". Changing this value updates the + state of the existing monitor. + +* `tenant_id` - (Optional) The owner of the monitor. Required if admin wants to + create a monitor for another tenant. Changing this creates a new monitor. + +## Attributes Reference + +The following attributes are exported: + +* `type` - See Argument Reference above. +* `delay` - See Argument Reference above. +* `timeout` - See Argument Reference above. +* `max_retries` - See Argument Reference above. +* `url_path` - See Argument Reference above. +* `http_method` - See Argument Reference above. +* `expected_codes` - See Argument Reference above. +* `admin_state_up` - See Argument Reference above. +* `tenant_id` - See Argument Reference above. From 7132b02a84035ea1d16ad246bb7d78b439ebb392 Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Wed, 14 Jan 2015 11:55:17 -0700 Subject: [PATCH 023/132] lb pool operations --- .../openstack/resource_openstack_lb_pool.go | 194 ++++++++++++++++++ .../openstack/r/lb_pool.html.markdown | 58 ++++++ 2 files changed, 252 insertions(+) create mode 100644 builtin/providers/openstack/resource_openstack_lb_pool.go create mode 100644 website/source/docs/providers/openstack/r/lb_pool.html.markdown diff --git a/builtin/providers/openstack/resource_openstack_lb_pool.go b/builtin/providers/openstack/resource_openstack_lb_pool.go new file mode 100644 index 0000000000..0fb42463ed --- /dev/null +++ b/builtin/providers/openstack/resource_openstack_lb_pool.go @@ -0,0 +1,194 @@ +package openstack + +import ( + "fmt" + "log" + + "github.com/hashicorp/terraform/helper/schema" + "github.com/jrperritt/terraform/helper/hashcode" + "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/lbaas/pools" +) + +func resourceLBPool() *schema.Resource { + return &schema.Resource{ + Create: resourceLBPoolCreate, + Read: resourceLBPoolRead, + Update: resourceLBPoolUpdate, + Delete: resourceLBPoolDelete, + + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: false, + }, + + "protocol": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "subnet_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "lb_method": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: false, + }, + + "tenant_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + + "monitor_ids": &schema.Schema{ + Type: schema.TypeSet, + Optional: true, + ForceNew: false, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: func(v interface{}) int { + return hashcode.String(v.(string)) + }, + }, + }, + } +} + +func resourceLBPoolCreate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + osClient := config.networkingV2Client + + createOpts := pools.CreateOpts{ + Name: d.Get("name").(string), + Protocol: d.Get("protocol").(string), + SubnetID: d.Get("subnet_id").(string), + LBMethod: d.Get("lb_method").(string), + TenantID: d.Get("tenant_id").(string), + } + + log.Printf("[INFO] Requesting lb pool creation") + p, err := pools.Create(osClient, createOpts).Extract() + if err != nil { + return fmt.Errorf("Error creating OpenStack LB pool: %s", err) + } + log.Printf("[INFO] LB Pool ID: %s", p.ID) + + d.SetId(p.ID) + + if mIDs := resourcePoolMonitorIDs(d); mIDs != nil { + for _, mID := range mIDs { + _, err := pools.AssociateMonitor(osClient, p.ID, mID).Extract() + if err != nil { + return fmt.Errorf("Error associating monitor (%s) with OpenStack LB pool (%s): %s", mID, p.ID, err) + } + } + } + + return resourceLBPoolRead(d, meta) +} + +func resourceLBPoolRead(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + osClient := config.networkingV2Client + + p, err := pools.Get(osClient, d.Id()).Extract() + if err != nil { + return fmt.Errorf("Error retrieving OpenStack LB Pool: %s", err) + } + + log.Printf("[DEBUG] Retreived OpenStack LB Pool %s: %+v", d.Id(), p) + + d.Set("name", p.Name) + d.Set("protocol", p.Protocol) + d.Set("subnet_id", p.SubnetID) + d.Set("lb_method", p.LBMethod) + + if _, exists := d.GetOk("tenant_id"); exists { + if d.HasChange("tenant_id") { + d.Set("tenant_id", p.TenantID) + } + } else { + d.Set("tenant_id", "") + } + + d.Set("monitor_ids", p.MonitorIDs) + + return nil +} + +func resourceLBPoolUpdate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + osClient := config.networkingV2Client + + var updateOpts pools.UpdateOpts + if d.HasChange("name") { + updateOpts.Name = d.Get("name").(string) + } + if d.HasChange("lb_method") { + updateOpts.LBMethod = d.Get("lb_method").(string) + } + + log.Printf("[DEBUG] Updating OpenStack LB Pool %s with options: %+v", d.Id(), updateOpts) + + _, err := pools.Update(osClient, d.Id(), updateOpts).Extract() + if err != nil { + return fmt.Errorf("Error updating OpenStack LB Pool: %s", err) + } + + if d.HasChange("monitor_ids") { + oldMIDsRaw, newMIDsRaw := d.GetChange("security_groups") + oldMIDsSet, newMIDsSet := oldMIDsRaw.(*schema.Set), newMIDsRaw.(*schema.Set) + monitorsToAdd := newMIDsSet.Difference(oldMIDsSet) + monitorsToRemove := oldMIDsSet.Difference(newMIDsSet) + + log.Printf("[DEBUG] Monitors to add: %v", monitorsToAdd) + + log.Printf("[DEBUG] Monitors to remove: %v", monitorsToRemove) + + for _, m := range monitorsToAdd.List() { + _, err := pools.AssociateMonitor(osClient, d.Id(), m.(string)).Extract() + if err != nil { + return fmt.Errorf("Error associating monitor (%s) with OpenStack server (%s): %s", m.(string), d.Id(), err) + } + log.Printf("[DEBUG] Associated monitor (%s) with pool (%s)", m.(string), d.Id()) + } + + for _, m := range monitorsToRemove.List() { + _, err := pools.DisassociateMonitor(osClient, d.Id(), m.(string)).Extract() + if err != nil { + return fmt.Errorf("Error disassociating monitor (%s) from OpenStack server (%s): %s", m.(string), d.Id(), err) + } + log.Printf("[DEBUG] Disassociated monitor (%s) from pool (%s)", m.(string), d.Id()) + } + } + + return resourceLBPoolRead(d, meta) +} + +func resourceLBPoolDelete(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + osClient := config.networkingV2Client + + err := pools.Delete(osClient, d.Id()).ExtractErr() + if err != nil { + return fmt.Errorf("Error deleting OpenStack LB Pool: %s", err) + } + + d.SetId("") + return nil +} + +func resourcePoolMonitorIDs(d *schema.ResourceData) []string { + mIDsRaw := d.Get("monitor_ids").(*schema.Set) + mIDs := make([]string, mIDsRaw.Len()) + for i, raw := range mIDsRaw.List() { + mIDs[i] = raw.(string) + } + return mIDs +} diff --git a/website/source/docs/providers/openstack/r/lb_pool.html.markdown b/website/source/docs/providers/openstack/r/lb_pool.html.markdown new file mode 100644 index 0000000000..90e3ed0c93 --- /dev/null +++ b/website/source/docs/providers/openstack/r/lb_pool.html.markdown @@ -0,0 +1,58 @@ +--- +layout: "openstack" +page_title: "OpenStack: openstack_lb_pool" +sidebar_current: "docs-openstack-resource-lb-pool" +description: |- + Manages a load balancer pool resource within OpenStack. +--- + +# openstack\_lb\_pool + +Manages a load balancer pool resource within OpenStack. + +## Example Usage + +``` +resource "openstack_lb_pool" "pool_1" { + name = "tf_test_lb_pool" + protocol = "HTTP" + subnet_id = "12345" + lb_method = "ROUND_ROBIN" + monitor_id = "67890" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) The name of the pool. Changing this updates the name of + the existing pool. + +* `protocol` - (Required) The protocol used by the pool members, you can use + either 'TCP, 'HTTP', or 'HTTPS'. Changing this creates a new pool. + +* `subnet_id` - (Required) The network on which the members of the pool will be + located. Only members that are on this network can be added to the pool. + Changing this creates a new pool. + +* `lb_method` - (Required) The algorithm used to distribute load between the + members of the pool. The current specification supports 'ROUND_ROBIN' and + 'LEAST_CONNECTIONS' as valid values for this attribute. + +* `tenant_id` - (Optional) The owner of the pool. Required if admin wants to + create a pool member for another tenant. Changing this creates a new pool. + +* `monitor_ids` - (Optional) A list of IDs of monitors to associate with the + pool. + +## Attributes Reference + +The following attributes are exported: + +* `name` - See Argument Reference above. +* `protocol` - See Argument Reference above. +* `subnet_id` - See Argument Reference above. +* `lb_method` - See Argument Reference above. +* `tenant_id` - See Argument Reference above. +* `monitor_id` - See Argument Reference above. From c2230a8aaa1b67cbdcbb85b154b73cc53ff3528f Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Wed, 14 Jan 2015 11:55:36 -0700 Subject: [PATCH 024/132] lb vip operations --- .../openstack/resource_openstack_lb_vip.go | 256 ++++++++++++++++++ .../openstack/r/lb_vip.html.markdown | 89 ++++++ 2 files changed, 345 insertions(+) create mode 100644 builtin/providers/openstack/resource_openstack_lb_vip.go create mode 100644 website/source/docs/providers/openstack/r/lb_vip.html.markdown diff --git a/builtin/providers/openstack/resource_openstack_lb_vip.go b/builtin/providers/openstack/resource_openstack_lb_vip.go new file mode 100644 index 0000000000..405d01a19b --- /dev/null +++ b/builtin/providers/openstack/resource_openstack_lb_vip.go @@ -0,0 +1,256 @@ +package openstack + +import ( + "fmt" + "log" + "strconv" + + "github.com/hashicorp/terraform/helper/schema" + "github.com/rackspace/gophercloud" + "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/lbaas/vips" +) + +func resourceLBVip() *schema.Resource { + return &schema.Resource{ + Create: resourceLBVipCreate, + Read: resourceLBVipRead, + Update: resourceLBVipUpdate, + Delete: resourceLBVipDelete, + + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: false, + }, + + "subnet_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "protocol": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "port": &schema.Schema{ + Type: schema.TypeInt, + Required: true, + ForceNew: true, + }, + + "pool_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: false, + }, + + "tenant_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + + "address": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + + "description": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: false, + }, + + "persistence": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: false, + }, + + "conn_limit": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + ForceNew: false, + }, + + "admin_state_up": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: false, + }, + }, + } +} + +func resourceLBVipCreate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + osClient := config.networkingV2Client + + createOpts := vips.CreateOpts{ + Name: d.Get("name").(string), + SubnetID: d.Get("subnet_id").(string), + Protocol: d.Get("protocol").(string), + ProtocolPort: d.Get("port").(int), + PoolID: d.Get("pool_id").(string), + TenantID: d.Get("tenant_id").(string), + Address: d.Get("address").(string), + Description: d.Get("description").(string), + Persistence: resourceVipPersistence(d), + ConnLimit: gophercloud.MaybeInt(d.Get("conn_limit").(int)), + } + + asuRaw := d.Get("admin_state_up").(string) + if asuRaw != "" { + asu, err := strconv.ParseBool(asuRaw) + if err != nil { + return fmt.Errorf("admin_state_up, if provided, must be either 'true' or 'false'") + } + createOpts.AdminStateUp = &asu + } + + log.Printf("[INFO] Requesting lb vip creation") + p, err := vips.Create(osClient, createOpts).Extract() + if err != nil { + return fmt.Errorf("Error creating OpenStack LB VIP: %s", err) + } + log.Printf("[INFO] LB VIP ID: %s", p.ID) + + d.SetId(p.ID) + + return resourceLBVipRead(d, meta) +} + +func resourceLBVipRead(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + osClient := config.networkingV2Client + + p, err := vips.Get(osClient, d.Id()).Extract() + if err != nil { + return fmt.Errorf("Error retrieving OpenStack LB VIP: %s", err) + } + + log.Printf("[DEBUG] Retreived OpenStack LB VIP %s: %+v", d.Id(), p) + + d.Set("name", p.Name) + d.Set("subnet_id", p.SubnetID) + d.Set("protocol", p.Protocol) + d.Set("port", p.ProtocolPort) + d.Set("pool_id", p.PoolID) + + if _, exists := d.GetOk("tenant_id"); exists { + if d.HasChange("tenant_id") { + d.Set("tenant_id", p.TenantID) + } + } else { + d.Set("tenant_id", "") + } + + if _, exists := d.GetOk("address"); exists { + if d.HasChange("address") { + d.Set("address", p.Address) + } + } else { + d.Set("address", "") + } + + if _, exists := d.GetOk("description"); exists { + if d.HasChange("description") { + d.Set("description", p.Description) + } + } else { + d.Set("description", "") + } + + if _, exists := d.GetOk("persistence"); exists { + if d.HasChange("persistence") { + d.Set("persistence", p.Description) + } + } + + if _, exists := d.GetOk("conn_limit"); exists { + if d.HasChange("conn_limit") { + d.Set("conn_limit", p.ConnLimit) + } + } else { + d.Set("conn_limit", "") + } + + if _, exists := d.GetOk("admin_state_up"); exists { + if d.HasChange("admin_state_up") { + d.Set("admin_state_up", strconv.FormatBool(p.AdminStateUp)) + } + } else { + d.Set("admin_state_up", "") + } + + return nil +} + +func resourceLBVipUpdate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + osClient := config.networkingV2Client + + var updateOpts vips.UpdateOpts + if d.HasChange("name") { + updateOpts.Name = d.Get("name").(string) + } + if d.HasChange("pool_id") { + updateOpts.PoolID = d.Get("pool_id").(string) + } + if d.HasChange("description") { + updateOpts.Description = d.Get("description").(string) + } + if d.HasChange("persistence") { + updateOpts.Persistence = resourceVipPersistence(d) + } + if d.HasChange("conn_limit") { + updateOpts.ConnLimit = gophercloud.MaybeInt(d.Get("conn_limit").(int)) + } + if d.HasChange("admin_state_up") { + asuRaw := d.Get("admin_state_up").(string) + if asuRaw != "" { + asu, err := strconv.ParseBool(asuRaw) + if err != nil { + return fmt.Errorf("admin_state_up, if provided, must be either 'true' or 'false'") + } + updateOpts.AdminStateUp = &asu + } + } + + log.Printf("[DEBUG] Updating OpenStack LB VIP %s with options: %+v", d.Id(), updateOpts) + + _, err := vips.Update(osClient, d.Id(), updateOpts).Extract() + if err != nil { + return fmt.Errorf("Error updating OpenStack LB VIP: %s", err) + } + + return resourceLBVipRead(d, meta) +} + +func resourceLBVipDelete(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + osClient := config.networkingV2Client + + err := vips.Delete(osClient, d.Id()).ExtractErr() + if err != nil { + return fmt.Errorf("Error deleting OpenStack LB VIP: %s", err) + } + + d.SetId("") + return nil +} + +func resourceVipPersistence(d *schema.ResourceData) *vips.SessionPersistence { + rawP := d.Get("persistence").(interface{}) + rawMap := rawP.(map[string]interface{}) + p := vips.SessionPersistence{ + Type: rawMap["type"].(string), + CookieName: rawMap["cookie_name"].(string), + } + return &p +} diff --git a/website/source/docs/providers/openstack/r/lb_vip.html.markdown b/website/source/docs/providers/openstack/r/lb_vip.html.markdown new file mode 100644 index 0000000000..0eddcaa5f0 --- /dev/null +++ b/website/source/docs/providers/openstack/r/lb_vip.html.markdown @@ -0,0 +1,89 @@ +--- +layout: "openstack" +page_title: "OpenStack: openstack_lb_vip" +sidebar_current: "docs-openstack-resource-lb-vip" +description: |- + Manages a load balancer vip resource within OpenStack. +--- + +# openstack\_lb\_vip + +Manages a load balancer vip resource within OpenStack. + +## Example Usage + +``` +resource "openstack_lb_vip" "vip_1" { + name = "tf_test_lb_vip" + subnet_id = "12345" + protocol = "HTTP" + port = 80 + pool_id = "67890" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) The name of the vip. Changing this updates the name of + the existing vip. + +* `subnet_id` - (Required) The network on which to allocate the vip's address. A + tenant can only create vips on networks authorized by policy (e.g. networks + that belong to them or networks that are shared). Changing this creates a + new vip. + +* `protocol` - (Required) The protocol - can be either 'TCP, 'HTTP', or + HTTPS'. Changing this creates a new vip. + +* `port` - (Required) The port on which to listen for client traffic. Changing + this creates a new vip. + +* `pool_id` - (Required) The ID of the pool with which the vip is associated. + Changing this updates the pool_id of the existing vip. + +* `tenant_id` - (Optional) The owner of the vip. Required if admin wants to + create a vip member for another tenant. Changing this creates a new vip. + +* `address` - (Optional) The IP address of the vip. Changing this creates a new + vip. + +* `description` - (Optional) Human-readable description for the vip. Changing + this updates the description of the existing vip. + +* `persistence` - (Optional) Omit this field to prevent session persistence. + The persistence object structure is documented below. Changing this updates + the persistence of the existing vip. + +* `conn_limit` - (Optional) The maximum number of connections allowed for the + vip. Default is -1, meaning no limit. Changing this updates the conn_limit + of the existing vip. + +* `admin_state_up` - (Optional) The administrative state of the vip. + Acceptable values are "true" and "false". Changing this value updates the + state of the existing vip. + +The `persistence` block supports: + +* `type` - (Required) The type of persistence mode. Valid values are "SOURCE_IP", + "HTTP_COOKIE", or "APP_COOKIE". + +* `cookie_name` - (Optional) The name of the cookie if persistence mode is set + appropriately. + +## Attributes Reference + +The following attributes are exported: + +* `name` - See Argument Reference above. +* `subnet_id` - See Argument Reference above. +* `protocol` - See Argument Reference above. +* `port` - See Argument Reference above. +* `pool_id` - See Argument Reference above. +* `tenant_id` - See Argument Reference above. +* `address` - See Argument Reference above. +* `description` - See Argument Reference above. +* `persistence` - See Argument Reference above. +* `conn_limit` - See Argument Reference above. +* `admin_state_up` - See Argument Reference above. From ef3ee11045e09925f40009acc72be023c1e7fdbe Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Wed, 14 Jan 2015 11:56:52 -0700 Subject: [PATCH 025/132] neutron network operations --- .../resource_openstack_networking_network.go | 16 ++----- .../r/networking_network.html.markdown | 47 +++++++++++++++++++ 2 files changed, 52 insertions(+), 11 deletions(-) create mode 100644 website/source/docs/providers/openstack/r/networking_network.html.markdown diff --git a/builtin/providers/openstack/resource_openstack_networking_network.go b/builtin/providers/openstack/resource_openstack_networking_network.go index c819aa0f48..8f262e3699 100644 --- a/builtin/providers/openstack/resource_openstack_networking_network.go +++ b/builtin/providers/openstack/resource_openstack_networking_network.go @@ -38,7 +38,7 @@ func resourceNetworkingNetwork() *schema.Resource { "tenant_id": &schema.Schema{ Type: schema.TypeString, Optional: true, - ForceNew: false, + ForceNew: true, }, }, } @@ -157,18 +157,12 @@ func resourceNetworkingNetworkUpdate(d *schema.ResourceData, meta interface{}) e updateOpts.Shared = &shared } } - if d.HasChange("tenant_id") { - updateOpts.TenantID = d.Get("tenant_id").(string) - } - // If there's nothing to update, don't waste an HTTP call. - if updateOpts != (networks.UpdateOpts{}) { - log.Printf("[DEBUG] Updating Network %s with options: %+v", d.Id(), updateOpts) + log.Printf("[DEBUG] Updating Network %s with options: %+v", d.Id(), updateOpts) - _, err := networks.Update(osClient, d.Id(), updateOpts).Extract() - if err != nil { - return fmt.Errorf("Error updating OpenStack Neutron Network: %s", err) - } + _, err := networks.Update(osClient, d.Id(), updateOpts).Extract() + if err != nil { + return fmt.Errorf("Error updating OpenStack Neutron Network: %s", err) } return resourceNetworkingNetworkRead(d, meta) diff --git a/website/source/docs/providers/openstack/r/networking_network.html.markdown b/website/source/docs/providers/openstack/r/networking_network.html.markdown new file mode 100644 index 0000000000..eb765cac0c --- /dev/null +++ b/website/source/docs/providers/openstack/r/networking_network.html.markdown @@ -0,0 +1,47 @@ +--- +layout: "openstack" +page_title: "OpenStack: openstack_networking_network" +sidebar_current: "docs-openstack-resource-networking-network" +description: |- + Manages a Neutron network resource within OpenStack. +--- + +# openstack\_networking\_network + +Manages a Neutron network resource within OpenStack. + +## Example Usage + +``` +resource "openstack_networking_network" "network_1" { + name = "tf_test_network" + admin_state_up = "true" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Optional) The name of the network. Changing this updates the name of + the existing network. + +* `shared` - (Optional) Specifies whether the network resource can be accessed + by any tenant or not. Changing this updates the sharing capabalities of the + existing network. + +* `tenant_id` - (Optional) The owner of the newtork. Required if admin wants to + create a network for another tenant. Changing this creates a new network. + +* `admin_state_up` - (Optional) The administrative state of the network. + Acceptable values are "true" and "false". Changing this value updates the + state of the existing network. + +## Attributes Reference + +The following attributes are exported: + +* `name` - See Argument Reference above. +* `shared` - See Argument Reference above. +* `tenant_id` - See Argument Reference above. +* `admin_state_up` - See Argument Reference above. From 8e6e7909cbb5658978d9adf962d1b8927df0a4eb Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Wed, 14 Jan 2015 11:57:47 -0700 Subject: [PATCH 026/132] neutron subnet operations --- .../resource_openstack_networking_subnet.go | 12 ++- .../r/networking_subnet.html.markdown | 92 +++++++++++++++++++ 2 files changed, 102 insertions(+), 2 deletions(-) create mode 100644 website/source/docs/providers/openstack/r/networking_subnet.html.markdown diff --git a/builtin/providers/openstack/resource_openstack_networking_subnet.go b/builtin/providers/openstack/resource_openstack_networking_subnet.go index bedad55723..0f52c0be23 100644 --- a/builtin/providers/openstack/resource_openstack_networking_subnet.go +++ b/builtin/providers/openstack/resource_openstack_networking_subnet.go @@ -270,7 +270,11 @@ func resourceSubnetAllocationPools(d *schema.ResourceData) []subnets.AllocationP rawAPs := d.Get("allocation_pools").([]interface{}) aps := make([]subnets.AllocationPool, len(rawAPs)) for i, raw := range rawAPs { - aps[i] = raw.(subnets.AllocationPool) + rawMap := raw.(map[string]interface{}) + aps[i] = subnets.AllocationPool{ + Start: rawMap["start"].(string), + End: rawMap["end"].(string), + } } return aps } @@ -288,7 +292,11 @@ func resourceSubnetHostRoutes(d *schema.ResourceData) []subnets.HostRoute { rawHR := d.Get("host_routes").([]interface{}) hr := make([]subnets.HostRoute, len(rawHR)) for i, raw := range rawHR { - hr[i] = raw.(subnets.HostRoute) + rawMap := raw.(map[string]interface{}) + hr[i] = subnets.HostRoute{ + DestinationCIDR: rawMap["destination_cidr"].(string), + NextHop: rawMap["next_hop"].(string), + } } return hr } diff --git a/website/source/docs/providers/openstack/r/networking_subnet.html.markdown b/website/source/docs/providers/openstack/r/networking_subnet.html.markdown new file mode 100644 index 0000000000..f9ab4f6ed0 --- /dev/null +++ b/website/source/docs/providers/openstack/r/networking_subnet.html.markdown @@ -0,0 +1,92 @@ +--- +layout: "openstack" +page_title: "OpenStack: openstack_networking_subnet" +sidebar_current: "docs-openstack-resource-networking-subnet" +description: |- + Manages a Neutron subnet resource within OpenStack. +--- + +# openstack\_networking\_subnet + +Manages a Neutron subnet resource within OpenStack. + +## Example Usage + +``` +resource "openstack_networking_network" "network_1" { + name = "tf_test_network" + admin_state_up = "true" +} + +resource "openstack_networking_subnet" "subnet_1" { + network_id = "${openstack_networking_network.network_1.id}" + cidr = "192.168.199.0/24" + ip_version = 4 +} +``` + +## Argument Reference + +The following arguments are supported: + +* `network_id` - (Required) The UUID of the parent network. Changing this + creates a new subnet. + +* `cidr` - (Required) CIDR representing IP range for this subnet, based on IP + version. Changing this creates a new subnet. + +* `ip_version` - (Required) IP version, either 4 or 6. Changing this creates a + new subnet. + +* `name` - (Optional) The name of the subnet. Changing this updates the name of + the existing subnet. + +* `tenant_id` - (Optional) The owner of the subnet. Required if admin wants to + create a subnet for another tenant. Changing this creates a new subnet. + +* `allocation_pools` - (Optional) An array of sub-ranges of CIDR available for + dynamic allocation to ports. The allocation_pool object structure is + documented below. Changing this creates a new subnet. + +* `gateway_ip` - (Optional) Default gateway used by devices in this subnet. + Changing this updates the gateway IP of the existing subnet. + +* `enable_dhcp` - (Optional) The administrative state of the network. + Acceptable values are "true" and "false". Changing this value enables or + disables the DHCP capabilities of the existing subnet. + +* `dns_nameservers` - (Optional) An array of DNS name server names used by hosts + in this subnet. Changing this updates the DNS name servers for the existing + subnet. + +* `host_routes` - (Optional) An array of routes that should be used by devices + with IPs from this subnet (not including local subnet route). The host_route + object structure is documented below. Changing this updates the host routes + for the existing subnet. + +The `allocation_pools` block supports: + +* `start` - (Required) The starting address. + +* `end` - (Required) The ending address. + +The `host_routes` block supports: + +* `destination_cidr` - (Required) The destination CIDR. + +* `next_hop` - (Required) The next hop in the route. + +## Attributes Reference + +The following attributes are exported: + +* `network_id` - See Argument Reference above. +* `cidr` - See Argument Reference above. +* `ip_version` - See Argument Reference above. +* `name` - See Argument Reference above. +* `tenant_id` - See Argument Reference above. +* `allocation_pools` - See Argument Reference above. +* `gateway_ip` - See Argument Reference above. +* `enable_dhcp` - See Argument Reference above. +* `dns_nameservers` - See Argument Reference above. +* `host_routes` - See Argument Reference above. From dd4155fa80093b52a38cd678c967d383e4678fcd Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Wed, 14 Jan 2015 11:58:52 -0700 Subject: [PATCH 027/132] set host in read function --- .../providers/openstack/resource_openstack_compute_instance.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/builtin/providers/openstack/resource_openstack_compute_instance.go b/builtin/providers/openstack/resource_openstack_compute_instance.go index 62d14b6361..e101e45f78 100644 --- a/builtin/providers/openstack/resource_openstack_compute_instance.go +++ b/builtin/providers/openstack/resource_openstack_compute_instance.go @@ -205,10 +205,12 @@ func resourceComputeInstanceRead(d *schema.ResourceData, meta interface{}) error pa := paRaw.(map[string]interface{}) if pa["version"].(float64) == 4 { host = pa["addr"].(string) + d.Set("access_ip_v4", host) } } } } + d.Set("host", host) log.Printf("host: %s", host) From 2a4570e382ea7e38e75f54e54684657dea5c33e3 Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Wed, 14 Jan 2015 12:00:39 -0700 Subject: [PATCH 028/132] add comment for changing 'networks' attribute --- .../docs/providers/openstack/r/compute_instance.html.markdown | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/website/source/docs/providers/openstack/r/compute_instance.html.markdown b/website/source/docs/providers/openstack/r/compute_instance.html.markdown index f22624bf9c..7de1cd1b90 100644 --- a/website/source/docs/providers/openstack/r/compute_instance.html.markdown +++ b/website/source/docs/providers/openstack/r/compute_instance.html.markdown @@ -45,7 +45,8 @@ The following arguments are supported: the server. Changing this creates a new server. * `networks` - (Optional) An array of one or more networks to attach to the - instance. The network object structure is documented below. + instance. The network object structure is documented below. Changing this + creates a new server. * `metadata` - (Optional) Metadata key/value pairs to make available from within the instance. Changing this updates the existing server metadata. From bf92b1647fa1ce86e142a45a3fe972548e25bb11 Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Wed, 14 Jan 2015 12:01:20 -0700 Subject: [PATCH 029/132] fix typo --- .../providers/openstack/r/compute_secgrouprule.html.markdown | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/website/source/docs/providers/openstack/r/compute_secgrouprule.html.markdown b/website/source/docs/providers/openstack/r/compute_secgrouprule.html.markdown index 95b92981c1..60ffb347cc 100644 --- a/website/source/docs/providers/openstack/r/compute_secgrouprule.html.markdown +++ b/website/source/docs/providers/openstack/r/compute_secgrouprule.html.markdown @@ -43,11 +43,11 @@ The following arguments are supported: * `ip_protocol` - (Required) The protocol type that will be allowed. Changing this creates a new security group rule. -* `cidr` - (Optional) Required is `from_group_id` is empty. The IP range that +* `cidr` - (Optional) Required if `from_group_id` is empty. The IP range that will be the source of network traffic to the security group. Use 0.0.0.0./0 to allow all IP addresses. Changing this creates a new security group rule. -* `from_group_id - (Optional) Required is `cidr` is empty. The ID of a group +* `from_group_id - (Optional) Required if `cidr` is empty. The ID of a group from which to forward traffic to the parent group. Changing this creates a new security group rule. From f4a22ae47ff7d75c392e81b237cb963df96f9fc9 Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Wed, 14 Jan 2015 12:01:52 -0700 Subject: [PATCH 030/132] add neutron and lb resources --- website/source/layouts/openstack.erb | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/website/source/layouts/openstack.erb b/website/source/layouts/openstack.erb index 69bc4ba2e4..b7878887c9 100644 --- a/website/source/layouts/openstack.erb +++ b/website/source/layouts/openstack.erb @@ -20,10 +20,28 @@ openstack_compute_keypair > - openstack_compute_keypair + openstack_compute_secgroup > - openstack_compute_keypair + openstack_compute_secgrouprule + + > + openstack_lb_member + + > + openstack_lb_monitor + + > + openstack_lb_pool + + > + openstack_lb_vip + + > + openstack_networking_network + + > + openstack_networking_subnet From cc1445d760495ee7ae0cbdd18a8a2c9d4e634048 Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Sun, 18 Jan 2015 20:11:20 -0700 Subject: [PATCH 031/132] if update func called, there's something to update --- .../openstack/resource_openstack_compute_instance.go | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/builtin/providers/openstack/resource_openstack_compute_instance.go b/builtin/providers/openstack/resource_openstack_compute_instance.go index e101e45f78..5ef061c54c 100644 --- a/builtin/providers/openstack/resource_openstack_compute_instance.go +++ b/builtin/providers/openstack/resource_openstack_compute_instance.go @@ -261,14 +261,11 @@ func resourceComputeInstanceUpdate(d *schema.ResourceData, meta interface{}) err updateOpts.AccessIPv4 = d.Get("access_ip_v6").(string) } - // If there's nothing to update, don't waste an HTTP call. - if updateOpts != (servers.UpdateOpts{}) { - log.Printf("[DEBUG] Updating Server %s with options: %+v", d.Id(), updateOpts) + log.Printf("[DEBUG] Updating Server %s with options: %+v", d.Id(), updateOpts) - _, err := servers.Update(osClient, d.Id(), updateOpts).Extract() - if err != nil { - return fmt.Errorf("Error updating OpenStack server: %s", err) - } + _, err := servers.Update(osClient, d.Id(), updateOpts).Extract() + if err != nil { + return fmt.Errorf("Error updating OpenStack server: %s", err) } if d.HasChange("metadata") { From b1b693e46136da3a8dfc5fa00b4b15e1b1670ff7 Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Sun, 25 Jan 2015 20:13:39 -0700 Subject: [PATCH 032/132] region is resource-specific; doesn't belong with auth --- builtin/providers/openstack/provider.go | 8 -------- 1 file changed, 8 deletions(-) diff --git a/builtin/providers/openstack/provider.go b/builtin/providers/openstack/provider.go index 9426fc23a6..764266cd44 100644 --- a/builtin/providers/openstack/provider.go +++ b/builtin/providers/openstack/provider.go @@ -11,13 +11,6 @@ import ( func Provider() terraform.ResourceProvider { return &schema.Provider{ Schema: map[string]*schema.Schema{ - "region": &schema.Schema{ - Type: schema.TypeString, - Required: true, - DefaultFunc: envDefaultFunc("OS_REGION_NAME"), - Description: descriptions["region"], - }, - "auth_url": &schema.Schema{ Type: schema.TypeString, Required: true, @@ -36,7 +29,6 @@ func Provider() terraform.ResourceProvider { Type: schema.TypeString, Optional: true, DefaultFunc: envDefaultFunc("OS_TENANT_NAME"), - //Description: descriptions["tenantname"], }, "password": &schema.Schema{ From b0e8cd5dd3ac7f18d87cd9c0a6452a3be0c22da2 Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Sun, 25 Jan 2015 20:59:01 -0700 Subject: [PATCH 033/132] a more general way of generating provider clients --- builtin/providers/openstack/clients.go | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 builtin/providers/openstack/clients.go diff --git a/builtin/providers/openstack/clients.go b/builtin/providers/openstack/clients.go new file mode 100644 index 0000000000..b088044673 --- /dev/null +++ b/builtin/providers/openstack/clients.go @@ -0,0 +1,25 @@ +package openstack + +import ( + "github.com/rackspace/gophercloud" + "github.com/rackspace/gophercloud/openstack" +) + +func newClient(c *Config, service, region string, version int) (*gophercloud.ServiceClient, error) { + var serviceClient *gophercloud.ServiceClient + switch service { + case "compute": + if version == 2 { + serviceClient, err = openstack.NewComputeV2(c.osClient, gophercloud.EndpointOpts{ + Region: region, + }) + } + case "networking": + if version == 2 { + serviceClient, err = openstack.NewNetworkV2(c.osClient, gophercloud.EndpointOpts{ + Region: region, + }) + } + } + return serviceClient, err +} From bfe492d4077ba2cedca46d9fc4b858d1afa7ed83 Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Sun, 25 Jan 2015 21:00:57 -0700 Subject: [PATCH 034/132] add options for openstack identity v3 --- builtin/providers/openstack/config.go | 22 +++++----- builtin/providers/openstack/provider.go | 56 +++++++++++++++---------- 2 files changed, 46 insertions(+), 32 deletions(-) diff --git a/builtin/providers/openstack/config.go b/builtin/providers/openstack/config.go index d877fcd80a..215817bdda 100644 --- a/builtin/providers/openstack/config.go +++ b/builtin/providers/openstack/config.go @@ -6,22 +6,30 @@ import ( ) type Config struct { - Region string Username string + UserID string Password string + APIKey string IdentityEndpoint string + TenantID string TenantName string + DomainID string + DomainName string - computeV2Client *gophercloud.ServiceClient - networkingV2Client *gophercloud.ServiceClient + osClient *gophercloud.ProviderClient } func (c *Config) loadAndValidate() error { ao := gophercloud.AuthOptions{ Username: c.Username, + UserID: c.UserID, Password: c.Password, + APIKey: c.APIKey, IdentityEndpoint: c.IdentityEndpoint, + TenantID: c.TenantID, TenantName: c.TenantName, + DomainID: c.DomainID, + DomainName: c.DomainName, } client, err := openstack.AuthenticatedClient(ao) @@ -29,13 +37,7 @@ func (c *Config) loadAndValidate() error { return err } - c.computeV2Client, err = openstack.NewComputeV2(client, gophercloud.EndpointOpts{ - Region: c.Region, - }) - - c.networkingV2Client, err = openstack.NewNetworkV2(client, gophercloud.EndpointOpts{ - Region: c.Region, - }) + c.osClient = client return nil } diff --git a/builtin/providers/openstack/provider.go b/builtin/providers/openstack/provider.go index 764266cd44..8b3e37a58e 100644 --- a/builtin/providers/openstack/provider.go +++ b/builtin/providers/openstack/provider.go @@ -15,27 +15,46 @@ func Provider() terraform.ResourceProvider { Type: schema.TypeString, Required: true, DefaultFunc: envDefaultFunc("OS_AUTH_URL"), - Description: descriptions["auth_url"], }, - - "username": &schema.Schema{ + "user_name": &schema.Schema{ Type: schema.TypeString, - Required: true, + Optional: true, DefaultFunc: envDefaultFunc("OS_USERNAME"), - Description: descriptions["username"], }, - + "user_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + DefaultFunc: envDefaultFunc("OS_USERID"), + }, + "tenant_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + DefaultFunc: envDefaultFunc("OS_TENANT_ID"), + }, "tenant_name": &schema.Schema{ Type: schema.TypeString, Optional: true, DefaultFunc: envDefaultFunc("OS_TENANT_NAME"), }, - "password": &schema.Schema{ Type: schema.TypeString, - Required: true, + Optional: true, DefaultFunc: envDefaultFunc("OS_PASSWORD"), - Description: descriptions["password"], + }, + "api_key": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + DefaultFunc: envDefaultFunc("OS_API_KEY"), + }, + "domain_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + DefaultFunc: envDefaultFunc("OS_DOMAIN_ID"), + }, + "domain_name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + DefaultFunc: envDefaultFunc("OS_DOMAIN_NAME"), }, }, @@ -58,11 +77,15 @@ func Provider() terraform.ResourceProvider { func configureProvider(d *schema.ResourceData) (interface{}, error) { config := Config{ - Region: d.Get("region").(string), IdentityEndpoint: d.Get("auth_url").(string), - Username: d.Get("username").(string), + Username: d.Get("user_name").(string), + UserID: d.Get("user_id").(string), Password: d.Get("password").(string), + APIKey: d.Get("api_key").(string), + TenantID: d.Get("tenant_id").(string), TenantName: d.Get("tenant_name").(string), + DomainID: d.Get("domain_id").(string), + DomainName: d.Get("domain_name").(string), } if err := config.loadAndValidate(); err != nil { @@ -81,14 +104,3 @@ func envDefaultFunc(k string) schema.SchemaDefaultFunc { return nil, nil } } - -var descriptions map[string]string - -func init() { - descriptions = map[string]string{ - "region": "The region where OpenStack operations will take place.", - "auth_url": "The endpoint against which to authenticate.", - "username": "The username with which to authenticate.", - "password": "The password with which to authenticate.", - } -} From 8579c8693adf887ee97695383ff7a321d0478ac1 Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Mon, 26 Jan 2015 10:54:07 -0700 Subject: [PATCH 035/132] make 'region' resource-specific; create new client for each crud operation --- builtin/providers/openstack/clients.go | 25 ------ ...resource_openstack_compute_instance_v2.go} | 79 +++++++++++-------- ... resource_openstack_compute_keypair_v2.go} | 36 +++++++-- ...resource_openstack_compute_secgroup_v2.go} | 54 +++++++++---- ...urce_openstack_compute_secgrouprule_v2.go} | 31 +++++--- ....go => resource_openstack_lb_member_v1.go} | 48 ++++++++--- ...go => resource_openstack_lb_monitor_v1.go} | 52 ++++++++---- ...ol.go => resource_openstack_lb_pool_v1.go} | 56 +++++++++---- ...vip.go => resource_openstack_lb_vip_v1.go} | 53 ++++++++----- ...source_openstack_networking_network_v2.go} | 47 ++++++++--- ...esource_openstack_networking_subnet_v2.go} | 57 ++++++++----- 11 files changed, 357 insertions(+), 181 deletions(-) delete mode 100644 builtin/providers/openstack/clients.go rename builtin/providers/openstack/{resource_openstack_compute_instance.go => resource_openstack_compute_instance_v2.go} (83%) rename builtin/providers/openstack/{resource_openstack_compute_keypair.go => resource_openstack_compute_keypair_v2.go} (57%) rename builtin/providers/openstack/{resource_openstack_compute_secgroup.go => resource_openstack_compute_secgroup_v2.go} (55%) rename builtin/providers/openstack/{resource_openstack_compute_secgrouprule.go => resource_openstack_compute_secgrouprule_v2.go} (73%) rename builtin/providers/openstack/{resource_openstack_lb_member.go => resource_openstack_lb_member_v1.go} (65%) rename builtin/providers/openstack/{resource_openstack_lb_monitor.go => resource_openstack_lb_monitor_v1.go} (78%) rename builtin/providers/openstack/{resource_openstack_lb_pool.go => resource_openstack_lb_pool_v1.go} (72%) rename builtin/providers/openstack/{resource_openstack_lb_vip.go => resource_openstack_lb_vip_v1.go} (80%) rename builtin/providers/openstack/{resource_openstack_networking_network.go => resource_openstack_networking_network_v2.go} (74%) rename builtin/providers/openstack/{resource_openstack_networking_subnet.go => resource_openstack_networking_subnet_v2.go} (82%) diff --git a/builtin/providers/openstack/clients.go b/builtin/providers/openstack/clients.go deleted file mode 100644 index b088044673..0000000000 --- a/builtin/providers/openstack/clients.go +++ /dev/null @@ -1,25 +0,0 @@ -package openstack - -import ( - "github.com/rackspace/gophercloud" - "github.com/rackspace/gophercloud/openstack" -) - -func newClient(c *Config, service, region string, version int) (*gophercloud.ServiceClient, error) { - var serviceClient *gophercloud.ServiceClient - switch service { - case "compute": - if version == 2 { - serviceClient, err = openstack.NewComputeV2(c.osClient, gophercloud.EndpointOpts{ - Region: region, - }) - } - case "networking": - if version == 2 { - serviceClient, err = openstack.NewNetworkV2(c.osClient, gophercloud.EndpointOpts{ - Region: region, - }) - } - } - return serviceClient, err -} diff --git a/builtin/providers/openstack/resource_openstack_compute_instance.go b/builtin/providers/openstack/resource_openstack_compute_instance_v2.go similarity index 83% rename from builtin/providers/openstack/resource_openstack_compute_instance.go rename to builtin/providers/openstack/resource_openstack_compute_instance_v2.go index 5ef061c54c..cf434566d2 100644 --- a/builtin/providers/openstack/resource_openstack_compute_instance.go +++ b/builtin/providers/openstack/resource_openstack_compute_instance_v2.go @@ -9,6 +9,7 @@ import ( "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/schema" "github.com/rackspace/gophercloud" + "github.com/rackspace/gophercloud/openstack" "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/keypairs" "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/secgroups" "github.com/rackspace/gophercloud/openstack/compute/v2/servers" @@ -23,24 +24,27 @@ func resourceComputeInstance() *schema.Resource { Delete: resourceComputeInstanceDelete, Schema: map[string]*schema.Schema{ + "region": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + DefaultFunc: envDefaultFunc("OS_REGION_NAME"), + }, "name": &schema.Schema{ Type: schema.TypeString, Required: true, ForceNew: false, }, - "image_ref": &schema.Schema{ Type: schema.TypeString, Required: true, ForceNew: false, }, - "flavor_ref": &schema.Schema{ Type: schema.TypeString, Required: true, ForceNew: false, }, - "security_groups": &schema.Schema{ Type: schema.TypeSet, Optional: true, @@ -50,13 +54,11 @@ func resourceComputeInstance() *schema.Resource { return hashcode.String(v.(string)) }, }, - "availability_zone": &schema.Schema{ Type: schema.TypeString, Optional: true, ForceNew: true, }, - "networks": &schema.Schema{ Type: schema.TypeList, Optional: true, @@ -67,12 +69,10 @@ func resourceComputeInstance() *schema.Resource { Type: schema.TypeString, Optional: true, }, - "port": &schema.Schema{ Type: schema.TypeString, Optional: true, }, - "fixed_ip": &schema.Schema{ Type: schema.TypeString, Optional: true, @@ -80,39 +80,33 @@ func resourceComputeInstance() *schema.Resource { }, }, }, - "metadata": &schema.Schema{ Type: schema.TypeMap, Optional: true, ForceNew: false, }, - "config_drive": &schema.Schema{ Type: schema.TypeBool, Optional: true, ForceNew: true, }, - "admin_pass": &schema.Schema{ Type: schema.TypeString, Optional: true, ForceNew: false, }, - "access_ip_v4": &schema.Schema{ Type: schema.TypeString, Computed: true, Optional: true, ForceNew: false, }, - "access_ip_v6": &schema.Schema{ Type: schema.TypeString, Computed: true, Optional: true, ForceNew: false, }, - "key_pair": &schema.Schema{ Type: schema.TypeString, Optional: true, @@ -124,7 +118,13 @@ func resourceComputeInstance() *schema.Resource { func resourceComputeInstanceCreate(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - osClient := config.computeV2Client + computeClient, err := openstack.NewComputeV2(config.osClient, gophercloud.EndpointOpts{ + Region: d.Get("region").(string), + }) + if err != nil { + return fmt.Errorf("Error creating OpenStack compute client: %s", err) + } + var createOpts servers.CreateOptsBuilder @@ -148,7 +148,7 @@ func resourceComputeInstanceCreate(d *schema.ResourceData, meta interface{}) err } log.Printf("[INFO] Requesting instance creation") - server, err := servers.Create(osClient, createOpts).Extract() + server, err := servers.Create(computeClient, createOpts).Extract() if err != nil { return fmt.Errorf("Error creating OpenStack server: %s", err) } @@ -166,7 +166,7 @@ func resourceComputeInstanceCreate(d *schema.ResourceData, meta interface{}) err stateConf := &resource.StateChangeConf{ Pending: []string{"BUILD"}, Target: "ACTIVE", - Refresh: ServerStateRefreshFunc(osClient, server.ID), + Refresh: ServerStateRefreshFunc(computeClient, server.ID), Timeout: 10 * time.Minute, Delay: 10 * time.Second, MinTimeout: 3 * time.Second, @@ -184,9 +184,14 @@ func resourceComputeInstanceCreate(d *schema.ResourceData, meta interface{}) err func resourceComputeInstanceRead(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - osClient := config.computeV2Client + computeClient, err := openstack.NewComputeV2(config.osClient, gophercloud.EndpointOpts{ + Region: d.Get("region").(string), + }) + if err != nil { + return fmt.Errorf("Error creating OpenStack compute client: %s", err) + } - server, err := servers.Get(osClient, d.Id()).Extract() + server, err := servers.Get(computeClient, d.Id()).Extract() if err != nil { return fmt.Errorf("Error retrieving OpenStack server: %s", err) } @@ -223,7 +228,7 @@ func resourceComputeInstanceRead(d *schema.ResourceData, meta interface{}) error d.Set("metadata", server.Metadata) var currentSG []string - err = secgroups.ListByServer(osClient, d.Id()).EachPage(func(page pagination.Page) (bool, error) { + err = secgroups.ListByServer(computeClient, d.Id()).EachPage(func(page pagination.Page) (bool, error) { secGrpList, err := secgroups.ExtractSecurityGroups(page) if err != nil { return false, fmt.Errorf("Error setting security groups for OpenStack server: %s", err) @@ -248,7 +253,12 @@ func resourceComputeInstanceRead(d *schema.ResourceData, meta interface{}) error func resourceComputeInstanceUpdate(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - osClient := config.computeV2Client + computeClient, err := openstack.NewComputeV2(config.osClient, gophercloud.EndpointOpts{ + Region: d.Get("region").(string), + }) + if err != nil { + return fmt.Errorf("Error creating OpenStack compute client: %s", err) + } var updateOpts servers.UpdateOpts if d.HasChange("name") { @@ -263,7 +273,7 @@ func resourceComputeInstanceUpdate(d *schema.ResourceData, meta interface{}) err log.Printf("[DEBUG] Updating Server %s with options: %+v", d.Id(), updateOpts) - _, err := servers.Update(osClient, d.Id(), updateOpts).Extract() + _, err = servers.Update(computeClient, d.Id(), updateOpts).Extract() if err != nil { return fmt.Errorf("Error updating OpenStack server: %s", err) } @@ -276,7 +286,7 @@ func resourceComputeInstanceUpdate(d *schema.ResourceData, meta interface{}) err metadataOpts[k] = v.(string) } - _, err := servers.UpdateMetadata(osClient, d.Id(), metadataOpts).Extract() + _, err := servers.UpdateMetadata(computeClient, d.Id(), metadataOpts).Extract() if err != nil { return fmt.Errorf("Error updating OpenStack server (%s) metadata: %s", d.Id(), err) } @@ -293,7 +303,7 @@ func resourceComputeInstanceUpdate(d *schema.ResourceData, meta interface{}) err log.Printf("[DEBUG] Security groups to remove: %v", secgroupsToRemove) for _, g := range secgroupsToAdd.List() { - err := secgroups.AddServerToGroup(osClient, d.Id(), g.(string)).ExtractErr() + err := secgroups.AddServerToGroup(computeClient, d.Id(), g.(string)).ExtractErr() if err != nil { return fmt.Errorf("Error adding security group to OpenStack server (%s): %s", d.Id(), err) } @@ -301,7 +311,7 @@ func resourceComputeInstanceUpdate(d *schema.ResourceData, meta interface{}) err } for _, g := range secgroupsToRemove.List() { - err := secgroups.RemoveServerFromGroup(osClient, d.Id(), g.(string)).ExtractErr() + err := secgroups.RemoveServerFromGroup(computeClient, d.Id(), g.(string)).ExtractErr() if err != nil { return fmt.Errorf("Error removing security group from OpenStack server (%s): %s", d.Id(), err) } @@ -311,7 +321,7 @@ func resourceComputeInstanceUpdate(d *schema.ResourceData, meta interface{}) err if d.HasChange("admin_pass") { if newPwd, ok := d.Get("admin_pass").(string); ok { - err := servers.ChangeAdminPassword(osClient, d.Id(), newPwd).ExtractErr() + err := servers.ChangeAdminPassword(computeClient, d.Id(), newPwd).ExtractErr() if err != nil { return fmt.Errorf("Error changing admin password of OpenStack server (%s): %s", d.Id(), err) } @@ -322,7 +332,7 @@ func resourceComputeInstanceUpdate(d *schema.ResourceData, meta interface{}) err resizeOpts := &servers.ResizeOpts{ FlavorRef: d.Get("flavor_ref").(string), } - err := servers.Resize(osClient, d.Id(), resizeOpts).ExtractErr() + err := servers.Resize(computeClient, d.Id(), resizeOpts).ExtractErr() if err != nil { return fmt.Errorf("Error resizing OpenStack server: %s", err) } @@ -333,7 +343,7 @@ func resourceComputeInstanceUpdate(d *schema.ResourceData, meta interface{}) err stateConf := &resource.StateChangeConf{ Pending: []string{"RESIZE"}, Target: "VERIFY_RESIZE", - Refresh: ServerStateRefreshFunc(osClient, d.Id()), + Refresh: ServerStateRefreshFunc(computeClient, d.Id()), Timeout: 3 * time.Minute, Delay: 10 * time.Second, MinTimeout: 3 * time.Second, @@ -346,7 +356,7 @@ func resourceComputeInstanceUpdate(d *schema.ResourceData, meta interface{}) err // Confirm resize. log.Printf("[DEBUG] Confirming resize") - err = servers.ConfirmResize(osClient, d.Id()).ExtractErr() + err = servers.ConfirmResize(computeClient, d.Id()).ExtractErr() if err != nil { return fmt.Errorf("Error confirming resize of OpenStack server: %s", err) } @@ -354,7 +364,7 @@ func resourceComputeInstanceUpdate(d *schema.ResourceData, meta interface{}) err stateConf = &resource.StateChangeConf{ Pending: []string{"VERIFY_RESIZE"}, Target: "ACTIVE", - Refresh: ServerStateRefreshFunc(osClient, d.Id()), + Refresh: ServerStateRefreshFunc(computeClient, d.Id()), Timeout: 3 * time.Minute, Delay: 10 * time.Second, MinTimeout: 3 * time.Second, @@ -371,9 +381,14 @@ func resourceComputeInstanceUpdate(d *schema.ResourceData, meta interface{}) err func resourceComputeInstanceDelete(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - osClient := config.computeV2Client + computeClient, err := openstack.NewComputeV2(config.osClient, gophercloud.EndpointOpts{ + Region: d.Get("region").(string), + }) + if err != nil { + return fmt.Errorf("Error creating OpenStack compute client: %s", err) + } - err := servers.Delete(osClient, d.Id()).ExtractErr() + err = servers.Delete(computeClient, d.Id()).ExtractErr() if err != nil { return fmt.Errorf("Error deleting OpenStack server: %s", err) } @@ -383,7 +398,7 @@ func resourceComputeInstanceDelete(d *schema.ResourceData, meta interface{}) err stateConf := &resource.StateChangeConf{ Target: "", - Refresh: ServerStateRefreshFunc(osClient, d.Id()), + Refresh: ServerStateRefreshFunc(computeClient, d.Id()), Timeout: 10 * time.Minute, Delay: 10 * time.Second, MinTimeout: 3 * time.Second, diff --git a/builtin/providers/openstack/resource_openstack_compute_keypair.go b/builtin/providers/openstack/resource_openstack_compute_keypair_v2.go similarity index 57% rename from builtin/providers/openstack/resource_openstack_compute_keypair.go rename to builtin/providers/openstack/resource_openstack_compute_keypair_v2.go index a8ca16e083..d27a348d4b 100644 --- a/builtin/providers/openstack/resource_openstack_compute_keypair.go +++ b/builtin/providers/openstack/resource_openstack_compute_keypair_v2.go @@ -4,6 +4,8 @@ import ( "fmt" "github.com/hashicorp/terraform/helper/schema" + "github.com/rackspace/gophercloud" + "github.com/rackspace/gophercloud/openstack" "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/keypairs" ) @@ -14,12 +16,17 @@ func resourceComputeKeypair() *schema.Resource { Delete: resourceComputeKeypairDelete, Schema: map[string]*schema.Schema{ + "region": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + DefaultFunc: envDefaultFunc("OS_REGION_NAME"), + }, "name": &schema.Schema{ Type: schema.TypeString, Required: true, ForceNew: true, }, - "public_key": &schema.Schema{ Type: schema.TypeString, Optional: true, @@ -31,14 +38,19 @@ func resourceComputeKeypair() *schema.Resource { func resourceComputeKeypairCreate(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - osClient := config.computeV2Client + computeClient, err := openstack.NewComputeV2(config.osClient, gophercloud.EndpointOpts{ + Region: d.Get("region").(string), + }) + if err != nil { + return fmt.Errorf("Error creating OpenStack compute client: %s", err) + } createOpts := keypairs.CreateOpts{ Name: d.Get("name").(string), PublicKey: d.Get("public_key").(string), } - kp, err := keypairs.Create(osClient, createOpts).Extract() + kp, err := keypairs.Create(computeClient, createOpts).Extract() if err != nil { return fmt.Errorf("Error creating OpenStack keypair: %s", err) } @@ -50,9 +62,14 @@ func resourceComputeKeypairCreate(d *schema.ResourceData, meta interface{}) erro func resourceComputeKeypairRead(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - osClient := config.computeV2Client + computeClient, err := openstack.NewComputeV2(config.osClient, gophercloud.EndpointOpts{ + Region: d.Get("region").(string), + }) + if err != nil { + return fmt.Errorf("Error creating OpenStack compute client: %s", err) + } - kp, err := keypairs.Get(osClient, d.Id()).Extract() + kp, err := keypairs.Get(computeClient, d.Id()).Extract() if err != nil { return fmt.Errorf("Error retrieving OpenStack keypair: %s", err) } @@ -65,9 +82,14 @@ func resourceComputeKeypairRead(d *schema.ResourceData, meta interface{}) error func resourceComputeKeypairDelete(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - osClient := config.computeV2Client + computeClient, err := openstack.NewComputeV2(config.osClient, gophercloud.EndpointOpts{ + Region: d.Get("region").(string), + }) + if err != nil { + return fmt.Errorf("Error creating OpenStack compute client: %s", err) + } - err := keypairs.Delete(osClient, d.Id()).ExtractErr() + err = keypairs.Delete(computeClient, d.Id()).ExtractErr() if err != nil { return fmt.Errorf("Error deleting OpenStack keypair: %s", err) } diff --git a/builtin/providers/openstack/resource_openstack_compute_secgroup.go b/builtin/providers/openstack/resource_openstack_compute_secgroup_v2.go similarity index 55% rename from builtin/providers/openstack/resource_openstack_compute_secgroup.go rename to builtin/providers/openstack/resource_openstack_compute_secgroup_v2.go index f6471eb811..559f96cbff 100644 --- a/builtin/providers/openstack/resource_openstack_compute_secgroup.go +++ b/builtin/providers/openstack/resource_openstack_compute_secgroup_v2.go @@ -5,6 +5,8 @@ import ( "log" "github.com/hashicorp/terraform/helper/schema" + "github.com/rackspace/gophercloud" + "github.com/rackspace/gophercloud/openstack" "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/secgroups" ) @@ -16,12 +18,17 @@ func resourceComputeSecGroup() *schema.Resource { Delete: resourceComputeSecGroupDelete, Schema: map[string]*schema.Schema{ + "region": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + DefaultFunc: envDefaultFunc("OS_REGION_NAME"), + }, "name": &schema.Schema{ Type: schema.TypeString, Required: true, ForceNew: false, }, - "description": &schema.Schema{ Type: schema.TypeString, Required: true, @@ -33,14 +40,19 @@ func resourceComputeSecGroup() *schema.Resource { func resourceComputeSecGroupCreate(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - osClient := config.computeV2Client + computeClient, err := openstack.NewComputeV2(config.osClient, gophercloud.EndpointOpts{ + Region: d.Get("region").(string), + }) + if err != nil { + return fmt.Errorf("Error creating OpenStack compute client: %s", err) + } createOpts := secgroups.CreateOpts{ Name: d.Get("name").(string), Description: d.Get("description").(string), } - sg, err := secgroups.Create(osClient, createOpts).Extract() + sg, err := secgroups.Create(computeClient, createOpts).Extract() if err != nil { return fmt.Errorf("Error creating OpenStack security group: %s", err) } @@ -52,9 +64,14 @@ func resourceComputeSecGroupCreate(d *schema.ResourceData, meta interface{}) err func resourceComputeSecGroupRead(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - osClient := config.computeV2Client + computeClient, err := openstack.NewComputeV2(config.osClient, gophercloud.EndpointOpts{ + Region: d.Get("region").(string), + }) + if err != nil { + return fmt.Errorf("Error creating OpenStack compute client: %s", err) + } - sg, err := secgroups.Get(osClient, d.Id()).Extract() + sg, err := secgroups.Get(computeClient, d.Id()).Extract() if err != nil { return fmt.Errorf("Error retrieving OpenStack security group: %s", err) } @@ -67,7 +84,12 @@ func resourceComputeSecGroupRead(d *schema.ResourceData, meta interface{}) error func resourceComputeSecGroupUpdate(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - osClient := config.computeV2Client + computeClient, err := openstack.NewComputeV2(config.osClient, gophercloud.EndpointOpts{ + Region: d.Get("region").(string), + }) + if err != nil { + return fmt.Errorf("Error creating OpenStack compute client: %s", err) + } var updateOpts secgroups.UpdateOpts if d.HasChange("name") { @@ -77,14 +99,11 @@ func resourceComputeSecGroupUpdate(d *schema.ResourceData, meta interface{}) err updateOpts.Description = d.Get("description").(string) } - // If there's nothing to update, don't waste an HTTP call. - if updateOpts != (secgroups.UpdateOpts{}) { - log.Printf("[DEBUG] Updating Security Group (%s) with options: %+v", d.Id(), updateOpts) + log.Printf("[DEBUG] Updating Security Group (%s) with options: %+v", d.Id(), updateOpts) - _, err := secgroups.Update(osClient, d.Id(), updateOpts).Extract() - if err != nil { - return fmt.Errorf("Error updating OpenStack security group (%s): %s", d.Id(), err) - } + _, err = secgroups.Update(computeClient, d.Id(), updateOpts).Extract() + if err != nil { + return fmt.Errorf("Error updating OpenStack security group (%s): %s", d.Id(), err) } return resourceComputeSecGroupRead(d, meta) @@ -92,9 +111,14 @@ func resourceComputeSecGroupUpdate(d *schema.ResourceData, meta interface{}) err func resourceComputeSecGroupDelete(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - osClient := config.computeV2Client + computeClient, err := openstack.NewComputeV2(config.osClient, gophercloud.EndpointOpts{ + Region: d.Get("region").(string), + }) + if err != nil { + return fmt.Errorf("Error creating OpenStack compute client: %s", err) + } - err := secgroups.Delete(osClient, d.Id()).ExtractErr() + err = secgroups.Delete(computeClient, d.Id()).ExtractErr() if err != nil { return fmt.Errorf("Error deleting OpenStack security group: %s", err) } diff --git a/builtin/providers/openstack/resource_openstack_compute_secgrouprule.go b/builtin/providers/openstack/resource_openstack_compute_secgrouprule_v2.go similarity index 73% rename from builtin/providers/openstack/resource_openstack_compute_secgrouprule.go rename to builtin/providers/openstack/resource_openstack_compute_secgrouprule_v2.go index 1063e2df06..77c14f6f8c 100644 --- a/builtin/providers/openstack/resource_openstack_compute_secgrouprule.go +++ b/builtin/providers/openstack/resource_openstack_compute_secgrouprule_v2.go @@ -4,6 +4,8 @@ import ( "fmt" "github.com/hashicorp/terraform/helper/schema" + "github.com/rackspace/gophercloud" + "github.com/rackspace/gophercloud/openstack" "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/secgroups" ) @@ -14,36 +16,37 @@ func resourceComputeSecGroupRule() *schema.Resource { Delete: resourceComputeSecGroupRuleDelete, Schema: map[string]*schema.Schema{ + "region": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + DefaultFunc: envDefaultFunc("OS_REGION_NAME"), + }, "group_id": &schema.Schema{ Type: schema.TypeString, Required: true, ForceNew: true, }, - "from_port": &schema.Schema{ Type: schema.TypeInt, Required: true, ForceNew: true, }, - "to_port": &schema.Schema{ Type: schema.TypeInt, Required: true, ForceNew: true, }, - "ip_protocol": &schema.Schema{ Type: schema.TypeString, Required: true, ForceNew: true, }, - "cidr": &schema.Schema{ Type: schema.TypeString, Optional: true, ForceNew: true, }, - "from_group_id": &schema.Schema{ Type: schema.TypeString, Optional: true, @@ -55,7 +58,12 @@ func resourceComputeSecGroupRule() *schema.Resource { func resourceComputeSecGroupRuleCreate(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - osClient := config.computeV2Client + computeClient, err := openstack.NewComputeV2(config.osClient, gophercloud.EndpointOpts{ + Region: d.Get("region").(string), + }) + if err != nil { + return fmt.Errorf("Error creating OpenStack compute client: %s", err) + } createOpts := secgroups.CreateRuleOpts{ ParentGroupID: d.Get("group_id").(string), @@ -66,7 +74,7 @@ func resourceComputeSecGroupRuleCreate(d *schema.ResourceData, meta interface{}) FromGroupID: d.Get("from_group_id").(string), } - sgr, err := secgroups.CreateRule(osClient, createOpts).Extract() + sgr, err := secgroups.CreateRule(computeClient, createOpts).Extract() if err != nil { return fmt.Errorf("Error creating OpenStack security group rule: %s", err) } @@ -88,9 +96,14 @@ func resourceComputeSecGroupRuleRead(d *schema.ResourceData, meta interface{}) e func resourceComputeSecGroupRuleDelete(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - osClient := config.computeV2Client + computeClient, err := openstack.NewComputeV2(config.osClient, gophercloud.EndpointOpts{ + Region: d.Get("region").(string), + }) + if err != nil { + return fmt.Errorf("Error creating OpenStack compute client: %s", err) + } - err := secgroups.DeleteRule(osClient, d.Id()).ExtractErr() + err = secgroups.DeleteRule(computeClient, d.Id()).ExtractErr() if err != nil { return fmt.Errorf("Error deleting OpenStack security group rule: %s", err) } diff --git a/builtin/providers/openstack/resource_openstack_lb_member.go b/builtin/providers/openstack/resource_openstack_lb_member_v1.go similarity index 65% rename from builtin/providers/openstack/resource_openstack_lb_member.go rename to builtin/providers/openstack/resource_openstack_lb_member_v1.go index c628ee2b4d..fdad89a005 100644 --- a/builtin/providers/openstack/resource_openstack_lb_member.go +++ b/builtin/providers/openstack/resource_openstack_lb_member_v1.go @@ -5,6 +5,8 @@ import ( "log" "github.com/hashicorp/terraform/helper/schema" + "github.com/rackspace/gophercloud" + "github.com/rackspace/gophercloud/openstack" "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/lbaas/members" ) @@ -16,30 +18,32 @@ func resourceLBMember() *schema.Resource { Delete: resourceLBMemberDelete, Schema: map[string]*schema.Schema{ + "region": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + DefaultFunc: envDefaultFunc("OS_REGION_NAME"), + }, "tenant_id": &schema.Schema{ Type: schema.TypeString, Optional: true, ForceNew: true, }, - "address": &schema.Schema{ Type: schema.TypeString, Required: true, ForceNew: true, }, - "port": &schema.Schema{ Type: schema.TypeInt, Required: true, ForceNew: true, }, - "pool_id": &schema.Schema{ Type: schema.TypeString, Required: true, ForceNew: true, }, - "admin_state_up": &schema.Schema{ Type: schema.TypeBool, Required: true, @@ -51,7 +55,12 @@ func resourceLBMember() *schema.Resource { func resourceLBMemberCreate(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - osClient := config.networkingV2Client + networkingClient, err := openstack.NewNetworkV2(config.osClient, gophercloud.EndpointOpts{ + Region: d.Get("region").(string), + }) + if err != nil { + return fmt.Errorf("Error creating OpenStack networking client: %s", err) + } createOpts := members.CreateOpts{ //TenantID: d.Get("tenant_id").(string), @@ -61,7 +70,7 @@ func resourceLBMemberCreate(d *schema.ResourceData, meta interface{}) error { } log.Printf("[INFO] Requesting lb member creation") - p, err := members.Create(osClient, createOpts).Extract() + p, err := members.Create(networkingClient, createOpts).Extract() if err != nil { return fmt.Errorf("Error creating OpenStack LB member: %s", err) } @@ -74,9 +83,14 @@ func resourceLBMemberCreate(d *schema.ResourceData, meta interface{}) error { func resourceLBMemberRead(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - osClient := config.networkingV2Client + networkingClient, err := openstack.NewNetworkV2(config.osClient, gophercloud.EndpointOpts{ + Region: d.Get("region").(string), + }) + if err != nil { + return fmt.Errorf("Error creating OpenStack networking client: %s", err) + } - p, err := members.Get(osClient, d.Id()).Extract() + p, err := members.Get(networkingClient, d.Id()).Extract() if err != nil { return fmt.Errorf("Error retrieving OpenStack LB Member: %s", err) } @@ -100,7 +114,12 @@ func resourceLBMemberRead(d *schema.ResourceData, meta interface{}) error { func resourceLBMemberUpdate(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - osClient := config.networkingV2Client + networkingClient, err := openstack.NewNetworkV2(config.osClient, gophercloud.EndpointOpts{ + Region: d.Get("region").(string), + }) + if err != nil { + return fmt.Errorf("Error creating OpenStack networking client: %s", err) + } var updateOpts members.UpdateOpts if d.HasChange("admin_state_up") { @@ -109,7 +128,7 @@ func resourceLBMemberUpdate(d *schema.ResourceData, meta interface{}) error { log.Printf("[DEBUG] Updating OpenStack LB Member %s with options: %+v", d.Id(), updateOpts) - _, err := members.Update(osClient, d.Id(), updateOpts).Extract() + _, err = members.Update(networkingClient, d.Id(), updateOpts).Extract() if err != nil { return fmt.Errorf("Error updating OpenStack LB Member: %s", err) } @@ -119,9 +138,14 @@ func resourceLBMemberUpdate(d *schema.ResourceData, meta interface{}) error { func resourceLBMemberDelete(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - osClient := config.networkingV2Client + networkingClient, err := openstack.NewNetworkV2(config.osClient, gophercloud.EndpointOpts{ + Region: d.Get("region").(string), + }) + if err != nil { + return fmt.Errorf("Error creating OpenStack networking client: %s", err) + } - err := members.Delete(osClient, d.Id()).ExtractErr() + err = members.Delete(networkingClient, d.Id()).ExtractErr() if err != nil { return fmt.Errorf("Error deleting OpenStack LB Member: %s", err) } diff --git a/builtin/providers/openstack/resource_openstack_lb_monitor.go b/builtin/providers/openstack/resource_openstack_lb_monitor_v1.go similarity index 78% rename from builtin/providers/openstack/resource_openstack_lb_monitor.go rename to builtin/providers/openstack/resource_openstack_lb_monitor_v1.go index b2cb98641b..cdf380319f 100644 --- a/builtin/providers/openstack/resource_openstack_lb_monitor.go +++ b/builtin/providers/openstack/resource_openstack_lb_monitor_v1.go @@ -6,6 +6,8 @@ import ( "strconv" "github.com/hashicorp/terraform/helper/schema" + "github.com/rackspace/gophercloud" + "github.com/rackspace/gophercloud/openstack" "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/lbaas/monitors" ) @@ -17,54 +19,52 @@ func resourceLBMonitor() *schema.Resource { Delete: resourceLBMonitorDelete, Schema: map[string]*schema.Schema{ + "region": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + DefaultFunc: envDefaultFunc("OS_REGION_NAME"), + }, "tenant_id": &schema.Schema{ Type: schema.TypeString, Optional: true, ForceNew: true, }, - "type": &schema.Schema{ Type: schema.TypeString, Required: true, ForceNew: true, }, - "delay": &schema.Schema{ Type: schema.TypeInt, Required: true, ForceNew: false, }, - "timeout": &schema.Schema{ Type: schema.TypeInt, Required: true, ForceNew: false, }, - "max_retries": &schema.Schema{ Type: schema.TypeInt, Required: true, ForceNew: false, }, - "url_path": &schema.Schema{ Type: schema.TypeString, Optional: true, ForceNew: false, }, - "http_method": &schema.Schema{ Type: schema.TypeString, Optional: true, ForceNew: false, }, - "expected_codes": &schema.Schema{ Type: schema.TypeString, Optional: true, ForceNew: false, }, - "admin_state_up": &schema.Schema{ Type: schema.TypeString, Optional: true, @@ -76,7 +76,12 @@ func resourceLBMonitor() *schema.Resource { func resourceLBMonitorCreate(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - osClient := config.networkingV2Client + networkingClient, err := openstack.NewNetworkV2(config.osClient, gophercloud.EndpointOpts{ + Region: d.Get("region").(string), + }) + if err != nil { + return fmt.Errorf("Error creating OpenStack networking client: %s", err) + } createOpts := monitors.CreateOpts{ TenantID: d.Get("tenant_id").(string), @@ -99,7 +104,7 @@ func resourceLBMonitorCreate(d *schema.ResourceData, meta interface{}) error { } log.Printf("[INFO] Requesting lb monitor creation") - m, err := monitors.Create(osClient, createOpts).Extract() + m, err := monitors.Create(networkingClient, createOpts).Extract() if err != nil { return fmt.Errorf("Error creating OpenStack LB Monitor: %s", err) } @@ -112,9 +117,14 @@ func resourceLBMonitorCreate(d *schema.ResourceData, meta interface{}) error { func resourceLBMonitorRead(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - osClient := config.networkingV2Client + networkingClient, err := openstack.NewNetworkV2(config.osClient, gophercloud.EndpointOpts{ + Region: d.Get("region").(string), + }) + if err != nil { + return fmt.Errorf("Error creating OpenStack networking client: %s", err) + } - m, err := monitors.Get(osClient, d.Id()).Extract() + m, err := monitors.Get(networkingClient, d.Id()).Extract() if err != nil { return fmt.Errorf("Error retrieving OpenStack LB Monitor: %s", err) } @@ -171,7 +181,12 @@ func resourceLBMonitorRead(d *schema.ResourceData, meta interface{}) error { func resourceLBMonitorUpdate(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - osClient := config.networkingV2Client + networkingClient, err := openstack.NewNetworkV2(config.osClient, gophercloud.EndpointOpts{ + Region: d.Get("region").(string), + }) + if err != nil { + return fmt.Errorf("Error creating OpenStack networking client: %s", err) + } var updateOpts monitors.UpdateOpts if d.HasChange("delay") { @@ -205,7 +220,7 @@ func resourceLBMonitorUpdate(d *schema.ResourceData, meta interface{}) error { log.Printf("[DEBUG] Updating OpenStack LB Monitor %s with options: %+v", d.Id(), updateOpts) - _, err := monitors.Update(osClient, d.Id(), updateOpts).Extract() + _, err = monitors.Update(networkingClient, d.Id(), updateOpts).Extract() if err != nil { return fmt.Errorf("Error updating OpenStack LB Monitor: %s", err) } @@ -215,9 +230,14 @@ func resourceLBMonitorUpdate(d *schema.ResourceData, meta interface{}) error { func resourceLBMonitorDelete(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - osClient := config.networkingV2Client + networkingClient, err := openstack.NewNetworkV2(config.osClient, gophercloud.EndpointOpts{ + Region: d.Get("region").(string), + }) + if err != nil { + return fmt.Errorf("Error creating OpenStack networking client: %s", err) + } - err := monitors.Delete(osClient, d.Id()).ExtractErr() + err = monitors.Delete(networkingClient, d.Id()).ExtractErr() if err != nil { return fmt.Errorf("Error deleting OpenStack LB Monitor: %s", err) } diff --git a/builtin/providers/openstack/resource_openstack_lb_pool.go b/builtin/providers/openstack/resource_openstack_lb_pool_v1.go similarity index 72% rename from builtin/providers/openstack/resource_openstack_lb_pool.go rename to builtin/providers/openstack/resource_openstack_lb_pool_v1.go index 0fb42463ed..180bcb8fda 100644 --- a/builtin/providers/openstack/resource_openstack_lb_pool.go +++ b/builtin/providers/openstack/resource_openstack_lb_pool_v1.go @@ -5,7 +5,9 @@ import ( "log" "github.com/hashicorp/terraform/helper/schema" - "github.com/jrperritt/terraform/helper/hashcode" + "github.com/hashicorp/terraform/helper/hashcode" + "github.com/rackspace/gophercloud" + "github.com/rackspace/gophercloud/openstack" "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/lbaas/pools" ) @@ -17,18 +19,22 @@ func resourceLBPool() *schema.Resource { Delete: resourceLBPoolDelete, Schema: map[string]*schema.Schema{ + "region": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + DefaultFunc: envDefaultFunc("OS_REGION_NAME"), + }, "name": &schema.Schema{ Type: schema.TypeString, Required: true, ForceNew: false, }, - "protocol": &schema.Schema{ Type: schema.TypeString, Required: true, ForceNew: true, }, - "subnet_id": &schema.Schema{ Type: schema.TypeString, Required: true, @@ -40,13 +46,11 @@ func resourceLBPool() *schema.Resource { Required: true, ForceNew: false, }, - "tenant_id": &schema.Schema{ Type: schema.TypeString, Optional: true, ForceNew: true, }, - "monitor_ids": &schema.Schema{ Type: schema.TypeSet, Optional: true, @@ -62,7 +66,12 @@ func resourceLBPool() *schema.Resource { func resourceLBPoolCreate(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - osClient := config.networkingV2Client + networkingClient, err := openstack.NewNetworkV2(config.osClient, gophercloud.EndpointOpts{ + Region: d.Get("region").(string), + }) + if err != nil { + return fmt.Errorf("Error creating OpenStack networking client: %s", err) + } createOpts := pools.CreateOpts{ Name: d.Get("name").(string), @@ -73,7 +82,7 @@ func resourceLBPoolCreate(d *schema.ResourceData, meta interface{}) error { } log.Printf("[INFO] Requesting lb pool creation") - p, err := pools.Create(osClient, createOpts).Extract() + p, err := pools.Create(networkingClient, createOpts).Extract() if err != nil { return fmt.Errorf("Error creating OpenStack LB pool: %s", err) } @@ -83,7 +92,7 @@ func resourceLBPoolCreate(d *schema.ResourceData, meta interface{}) error { if mIDs := resourcePoolMonitorIDs(d); mIDs != nil { for _, mID := range mIDs { - _, err := pools.AssociateMonitor(osClient, p.ID, mID).Extract() + _, err := pools.AssociateMonitor(networkingClient, p.ID, mID).Extract() if err != nil { return fmt.Errorf("Error associating monitor (%s) with OpenStack LB pool (%s): %s", mID, p.ID, err) } @@ -95,9 +104,14 @@ func resourceLBPoolCreate(d *schema.ResourceData, meta interface{}) error { func resourceLBPoolRead(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - osClient := config.networkingV2Client + networkingClient, err := openstack.NewNetworkV2(config.osClient, gophercloud.EndpointOpts{ + Region: d.Get("region").(string), + }) + if err != nil { + return fmt.Errorf("Error creating OpenStack networking client: %s", err) + } - p, err := pools.Get(osClient, d.Id()).Extract() + p, err := pools.Get(networkingClient, d.Id()).Extract() if err != nil { return fmt.Errorf("Error retrieving OpenStack LB Pool: %s", err) } @@ -124,7 +138,12 @@ func resourceLBPoolRead(d *schema.ResourceData, meta interface{}) error { func resourceLBPoolUpdate(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - osClient := config.networkingV2Client + networkingClient, err := openstack.NewNetworkV2(config.osClient, gophercloud.EndpointOpts{ + Region: d.Get("region").(string), + }) + if err != nil { + return fmt.Errorf("Error creating OpenStack networking client: %s", err) + } var updateOpts pools.UpdateOpts if d.HasChange("name") { @@ -136,7 +155,7 @@ func resourceLBPoolUpdate(d *schema.ResourceData, meta interface{}) error { log.Printf("[DEBUG] Updating OpenStack LB Pool %s with options: %+v", d.Id(), updateOpts) - _, err := pools.Update(osClient, d.Id(), updateOpts).Extract() + _, err = pools.Update(networkingClient, d.Id(), updateOpts).Extract() if err != nil { return fmt.Errorf("Error updating OpenStack LB Pool: %s", err) } @@ -152,7 +171,7 @@ func resourceLBPoolUpdate(d *schema.ResourceData, meta interface{}) error { log.Printf("[DEBUG] Monitors to remove: %v", monitorsToRemove) for _, m := range monitorsToAdd.List() { - _, err := pools.AssociateMonitor(osClient, d.Id(), m.(string)).Extract() + _, err := pools.AssociateMonitor(networkingClient, d.Id(), m.(string)).Extract() if err != nil { return fmt.Errorf("Error associating monitor (%s) with OpenStack server (%s): %s", m.(string), d.Id(), err) } @@ -160,7 +179,7 @@ func resourceLBPoolUpdate(d *schema.ResourceData, meta interface{}) error { } for _, m := range monitorsToRemove.List() { - _, err := pools.DisassociateMonitor(osClient, d.Id(), m.(string)).Extract() + _, err := pools.DisassociateMonitor(networkingClient, d.Id(), m.(string)).Extract() if err != nil { return fmt.Errorf("Error disassociating monitor (%s) from OpenStack server (%s): %s", m.(string), d.Id(), err) } @@ -173,9 +192,14 @@ func resourceLBPoolUpdate(d *schema.ResourceData, meta interface{}) error { func resourceLBPoolDelete(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - osClient := config.networkingV2Client + networkingClient, err := openstack.NewNetworkV2(config.osClient, gophercloud.EndpointOpts{ + Region: d.Get("region").(string), + }) + if err != nil { + return fmt.Errorf("Error creating OpenStack networking client: %s", err) + } - err := pools.Delete(osClient, d.Id()).ExtractErr() + err = pools.Delete(networkingClient, d.Id()).ExtractErr() if err != nil { return fmt.Errorf("Error deleting OpenStack LB Pool: %s", err) } diff --git a/builtin/providers/openstack/resource_openstack_lb_vip.go b/builtin/providers/openstack/resource_openstack_lb_vip_v1.go similarity index 80% rename from builtin/providers/openstack/resource_openstack_lb_vip.go rename to builtin/providers/openstack/resource_openstack_lb_vip_v1.go index 405d01a19b..ad95767cd4 100644 --- a/builtin/providers/openstack/resource_openstack_lb_vip.go +++ b/builtin/providers/openstack/resource_openstack_lb_vip_v1.go @@ -7,6 +7,7 @@ import ( "github.com/hashicorp/terraform/helper/schema" "github.com/rackspace/gophercloud" + "github.com/rackspace/gophercloud/openstack" "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/lbaas/vips" ) @@ -18,66 +19,62 @@ func resourceLBVip() *schema.Resource { Delete: resourceLBVipDelete, Schema: map[string]*schema.Schema{ + "region": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + DefaultFunc: envDefaultFunc("OS_REGION_NAME"), + }, "name": &schema.Schema{ Type: schema.TypeString, Required: true, ForceNew: false, }, - "subnet_id": &schema.Schema{ Type: schema.TypeString, Required: true, ForceNew: true, }, - "protocol": &schema.Schema{ Type: schema.TypeString, Required: true, ForceNew: true, }, - "port": &schema.Schema{ Type: schema.TypeInt, Required: true, ForceNew: true, }, - "pool_id": &schema.Schema{ Type: schema.TypeString, Required: true, ForceNew: false, }, - "tenant_id": &schema.Schema{ Type: schema.TypeString, Optional: true, ForceNew: true, }, - "address": &schema.Schema{ Type: schema.TypeString, Optional: true, ForceNew: true, }, - "description": &schema.Schema{ Type: schema.TypeString, Optional: true, ForceNew: false, }, - "persistence": &schema.Schema{ Type: schema.TypeString, Optional: true, ForceNew: false, }, - "conn_limit": &schema.Schema{ Type: schema.TypeInt, Optional: true, ForceNew: false, }, - "admin_state_up": &schema.Schema{ Type: schema.TypeString, Optional: true, @@ -89,7 +86,12 @@ func resourceLBVip() *schema.Resource { func resourceLBVipCreate(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - osClient := config.networkingV2Client + networkingClient, err := openstack.NewNetworkV2(config.osClient, gophercloud.EndpointOpts{ + Region: d.Get("region").(string), + }) + if err != nil { + return fmt.Errorf("Error creating OpenStack networking client: %s", err) + } createOpts := vips.CreateOpts{ Name: d.Get("name").(string), @@ -114,7 +116,7 @@ func resourceLBVipCreate(d *schema.ResourceData, meta interface{}) error { } log.Printf("[INFO] Requesting lb vip creation") - p, err := vips.Create(osClient, createOpts).Extract() + p, err := vips.Create(networkingClient, createOpts).Extract() if err != nil { return fmt.Errorf("Error creating OpenStack LB VIP: %s", err) } @@ -127,9 +129,14 @@ func resourceLBVipCreate(d *schema.ResourceData, meta interface{}) error { func resourceLBVipRead(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - osClient := config.networkingV2Client + networkingClient, err := openstack.NewNetworkV2(config.osClient, gophercloud.EndpointOpts{ + Region: d.Get("region").(string), + }) + if err != nil { + return fmt.Errorf("Error creating OpenStack networking client: %s", err) + } - p, err := vips.Get(osClient, d.Id()).Extract() + p, err := vips.Get(networkingClient, d.Id()).Extract() if err != nil { return fmt.Errorf("Error retrieving OpenStack LB VIP: %s", err) } @@ -193,7 +200,12 @@ func resourceLBVipRead(d *schema.ResourceData, meta interface{}) error { func resourceLBVipUpdate(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - osClient := config.networkingV2Client + networkingClient, err := openstack.NewNetworkV2(config.osClient, gophercloud.EndpointOpts{ + Region: d.Get("region").(string), + }) + if err != nil { + return fmt.Errorf("Error creating OpenStack networking client: %s", err) + } var updateOpts vips.UpdateOpts if d.HasChange("name") { @@ -224,7 +236,7 @@ func resourceLBVipUpdate(d *schema.ResourceData, meta interface{}) error { log.Printf("[DEBUG] Updating OpenStack LB VIP %s with options: %+v", d.Id(), updateOpts) - _, err := vips.Update(osClient, d.Id(), updateOpts).Extract() + _, err = vips.Update(networkingClient, d.Id(), updateOpts).Extract() if err != nil { return fmt.Errorf("Error updating OpenStack LB VIP: %s", err) } @@ -234,9 +246,14 @@ func resourceLBVipUpdate(d *schema.ResourceData, meta interface{}) error { func resourceLBVipDelete(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - osClient := config.networkingV2Client + networkingClient, err := openstack.NewNetworkV2(config.osClient, gophercloud.EndpointOpts{ + Region: d.Get("region").(string), + }) + if err != nil { + return fmt.Errorf("Error creating OpenStack networking client: %s", err) + } - err := vips.Delete(osClient, d.Id()).ExtractErr() + err = vips.Delete(networkingClient, d.Id()).ExtractErr() if err != nil { return fmt.Errorf("Error deleting OpenStack LB VIP: %s", err) } diff --git a/builtin/providers/openstack/resource_openstack_networking_network.go b/builtin/providers/openstack/resource_openstack_networking_network_v2.go similarity index 74% rename from builtin/providers/openstack/resource_openstack_networking_network.go rename to builtin/providers/openstack/resource_openstack_networking_network_v2.go index 8f262e3699..3ce51fbb05 100644 --- a/builtin/providers/openstack/resource_openstack_networking_network.go +++ b/builtin/providers/openstack/resource_openstack_networking_network_v2.go @@ -6,6 +6,8 @@ import ( "strconv" "github.com/hashicorp/terraform/helper/schema" + "github.com/rackspace/gophercloud" + "github.com/rackspace/gophercloud/openstack" "github.com/rackspace/gophercloud/openstack/networking/v2/networks" ) @@ -17,24 +19,27 @@ func resourceNetworkingNetwork() *schema.Resource { Delete: resourceNetworkingNetworkDelete, Schema: map[string]*schema.Schema{ + "region": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + DefaultFunc: envDefaultFunc("OS_REGION_NAME"), + }, "name": &schema.Schema{ Type: schema.TypeString, Optional: true, ForceNew: false, }, - "admin_state_up": &schema.Schema{ Type: schema.TypeString, Optional: true, ForceNew: false, }, - "shared": &schema.Schema{ Type: schema.TypeString, Optional: true, ForceNew: false, }, - "tenant_id": &schema.Schema{ Type: schema.TypeString, Optional: true, @@ -46,7 +51,12 @@ func resourceNetworkingNetwork() *schema.Resource { func resourceNetworkingNetworkCreate(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - osClient := config.networkingV2Client + networkingClient, err := openstack.NewNetworkV2(config.osClient, gophercloud.EndpointOpts{ + Region: d.Get("region").(string), + }) + if err != nil { + return fmt.Errorf("Error creating OpenStack networking client: %s", err) + } createOpts := networks.CreateOpts{ Name: d.Get("name").(string), @@ -72,7 +82,7 @@ func resourceNetworkingNetworkCreate(d *schema.ResourceData, meta interface{}) e } log.Printf("[INFO] Requesting network creation") - n, err := networks.Create(osClient, createOpts).Extract() + n, err := networks.Create(networkingClient, createOpts).Extract() if err != nil { return fmt.Errorf("Error creating OpenStack Neutron network: %s", err) } @@ -85,9 +95,14 @@ func resourceNetworkingNetworkCreate(d *schema.ResourceData, meta interface{}) e func resourceNetworkingNetworkRead(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - osClient := config.networkingV2Client + networkingClient, err := openstack.NewNetworkV2(config.osClient, gophercloud.EndpointOpts{ + Region: d.Get("region").(string), + }) + if err != nil { + return fmt.Errorf("Error creating OpenStack networking client: %s", err) + } - n, err := networks.Get(osClient, d.Id()).Extract() + n, err := networks.Get(networkingClient, d.Id()).Extract() if err != nil { return fmt.Errorf("Error retrieving OpenStack Neutron Network: %s", err) } @@ -131,7 +146,12 @@ func resourceNetworkingNetworkRead(d *schema.ResourceData, meta interface{}) err func resourceNetworkingNetworkUpdate(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - osClient := config.networkingV2Client + networkingClient, err := openstack.NewNetworkV2(config.osClient, gophercloud.EndpointOpts{ + Region: d.Get("region").(string), + }) + if err != nil { + return fmt.Errorf("Error creating OpenStack networking client: %s", err) + } var updateOpts networks.UpdateOpts if d.HasChange("name") { @@ -160,7 +180,7 @@ func resourceNetworkingNetworkUpdate(d *schema.ResourceData, meta interface{}) e log.Printf("[DEBUG] Updating Network %s with options: %+v", d.Id(), updateOpts) - _, err := networks.Update(osClient, d.Id(), updateOpts).Extract() + _, err = networks.Update(networkingClient, d.Id(), updateOpts).Extract() if err != nil { return fmt.Errorf("Error updating OpenStack Neutron Network: %s", err) } @@ -170,9 +190,14 @@ func resourceNetworkingNetworkUpdate(d *schema.ResourceData, meta interface{}) e func resourceNetworkingNetworkDelete(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - osClient := config.networkingV2Client + networkingClient, err := openstack.NewNetworkV2(config.osClient, gophercloud.EndpointOpts{ + Region: d.Get("region").(string), + }) + if err != nil { + return fmt.Errorf("Error creating OpenStack networking client: %s", err) + } - err := networks.Delete(osClient, d.Id()).ExtractErr() + err = networks.Delete(networkingClient, d.Id()).ExtractErr() if err != nil { return fmt.Errorf("Error deleting OpenStack Neutron Network: %s", err) } diff --git a/builtin/providers/openstack/resource_openstack_networking_subnet.go b/builtin/providers/openstack/resource_openstack_networking_subnet_v2.go similarity index 82% rename from builtin/providers/openstack/resource_openstack_networking_subnet.go rename to builtin/providers/openstack/resource_openstack_networking_subnet_v2.go index 0f52c0be23..ab337ec30b 100644 --- a/builtin/providers/openstack/resource_openstack_networking_subnet.go +++ b/builtin/providers/openstack/resource_openstack_networking_subnet_v2.go @@ -6,7 +6,9 @@ import ( "strconv" "github.com/hashicorp/terraform/helper/schema" - "github.com/jrperritt/terraform/helper/hashcode" + "github.com/hashicorp/terraform/helper/hashcode" + "github.com/rackspace/gophercloud" + "github.com/rackspace/gophercloud/openstack" "github.com/rackspace/gophercloud/openstack/networking/v2/subnets" ) @@ -18,30 +20,32 @@ func resourceNetworkingSubnet() *schema.Resource { Delete: resourceNetworkingSubnetDelete, Schema: map[string]*schema.Schema{ + "region": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + DefaultFunc: envDefaultFunc("OS_REGION_NAME"), + }, "network_id": &schema.Schema{ Type: schema.TypeString, Required: true, ForceNew: true, }, - "cidr": &schema.Schema{ Type: schema.TypeString, Required: true, ForceNew: true, }, - "name": &schema.Schema{ Type: schema.TypeString, Optional: true, ForceNew: false, }, - "tenant_id": &schema.Schema{ Type: schema.TypeString, Optional: true, ForceNew: true, }, - "allocation_pools": &schema.Schema{ Type: schema.TypeList, Optional: true, @@ -52,7 +56,6 @@ func resourceNetworkingSubnet() *schema.Resource { Type: schema.TypeString, Required: true, }, - "end": &schema.Schema{ Type: schema.TypeString, Required: true, @@ -60,25 +63,21 @@ func resourceNetworkingSubnet() *schema.Resource { }, }, }, - "gateway_ip": &schema.Schema{ Type: schema.TypeString, Optional: true, ForceNew: false, }, - "ip_version": &schema.Schema{ Type: schema.TypeInt, Required: true, ForceNew: true, }, - "enable_dhcp": &schema.Schema{ Type: schema.TypeString, Optional: true, ForceNew: false, }, - "dns_nameservers": &schema.Schema{ Type: schema.TypeSet, Optional: true, @@ -88,7 +87,6 @@ func resourceNetworkingSubnet() *schema.Resource { return hashcode.String(v.(string)) }, }, - "host_routes": &schema.Schema{ Type: schema.TypeList, Optional: true, @@ -99,7 +97,6 @@ func resourceNetworkingSubnet() *schema.Resource { Type: schema.TypeString, Required: true, }, - "next_hop": &schema.Schema{ Type: schema.TypeString, Required: true, @@ -113,7 +110,12 @@ func resourceNetworkingSubnet() *schema.Resource { func resourceNetworkingSubnetCreate(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - osClient := config.networkingV2Client + networkingClient, err := openstack.NewNetworkV2(config.osClient, gophercloud.EndpointOpts{ + Region: d.Get("region").(string), + }) + if err != nil { + return fmt.Errorf("Error creating OpenStack networking client: %s", err) + } createOpts := subnets.CreateOpts{ NetworkID: d.Get("network_id").(string), @@ -137,7 +139,7 @@ func resourceNetworkingSubnetCreate(d *schema.ResourceData, meta interface{}) er } log.Printf("[INFO] Requesting subnet creation") - s, err := subnets.Create(osClient, createOpts).Extract() + s, err := subnets.Create(networkingClient, createOpts).Extract() if err != nil { return fmt.Errorf("Error creating OpenStack Neutron subnet: %s", err) } @@ -150,9 +152,14 @@ func resourceNetworkingSubnetCreate(d *schema.ResourceData, meta interface{}) er func resourceNetworkingSubnetRead(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - osClient := config.networkingV2Client + networkingClient, err := openstack.NewNetworkV2(config.osClient, gophercloud.EndpointOpts{ + Region: d.Get("region").(string), + }) + if err != nil { + return fmt.Errorf("Error creating OpenStack networking client: %s", err) + } - s, err := subnets.Get(osClient, d.Id()).Extract() + s, err := subnets.Get(networkingClient, d.Id()).Extract() if err != nil { return fmt.Errorf("Error retrieving OpenStack Neutron Subnet: %s", err) } @@ -212,7 +219,12 @@ func resourceNetworkingSubnetRead(d *schema.ResourceData, meta interface{}) erro func resourceNetworkingSubnetUpdate(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - osClient := config.networkingV2Client + networkingClient, err := openstack.NewNetworkV2(config.osClient, gophercloud.EndpointOpts{ + Region: d.Get("region").(string), + }) + if err != nil { + return fmt.Errorf("Error creating OpenStack networking client: %s", err) + } var updateOpts subnets.UpdateOpts @@ -245,7 +257,7 @@ func resourceNetworkingSubnetUpdate(d *schema.ResourceData, meta interface{}) er log.Printf("[DEBUG] Updating Subnet %s with options: %+v", d.Id(), updateOpts) - _, err := subnets.Update(osClient, d.Id(), updateOpts).Extract() + _, err = subnets.Update(networkingClient, d.Id(), updateOpts).Extract() if err != nil { return fmt.Errorf("Error updating OpenStack Neutron Subnet: %s", err) } @@ -255,9 +267,14 @@ func resourceNetworkingSubnetUpdate(d *schema.ResourceData, meta interface{}) er func resourceNetworkingSubnetDelete(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - osClient := config.networkingV2Client + networkingClient, err := openstack.NewNetworkV2(config.osClient, gophercloud.EndpointOpts{ + Region: d.Get("region").(string), + }) + if err != nil { + return fmt.Errorf("Error creating OpenStack networking client: %s", err) + } - err := subnets.Delete(osClient, d.Id()).ExtractErr() + err = subnets.Delete(networkingClient, d.Id()).ExtractErr() if err != nil { return fmt.Errorf("Error deleting OpenStack Neutron Subnet: %s", err) } From dc99dd1f051a5001896c0ba36cb6f79f7fbc932f Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Mon, 26 Jan 2015 11:09:27 -0700 Subject: [PATCH 036/132] add versioning to files --- builtin/providers/openstack/provider.go | 20 ++++----- .../resource_openstack_compute_instance_v2.go | 44 +++++++++---------- .../resource_openstack_compute_keypair_v2.go | 16 +++---- .../resource_openstack_compute_secgroup_v2.go | 22 +++++----- ...ource_openstack_compute_secgrouprule_v2.go | 16 +++---- .../resource_openstack_lb_member_v1.go | 22 +++++----- .../resource_openstack_lb_monitor_v1.go | 22 +++++----- .../resource_openstack_lb_pool_v1.go | 26 +++++------ .../openstack/resource_openstack_lb_vip_v1.go | 42 ++++++++++-------- ...esource_openstack_networking_network_v2.go | 22 +++++----- ...resource_openstack_networking_subnet_v2.go | 38 ++++++++-------- 11 files changed, 148 insertions(+), 142 deletions(-) diff --git a/builtin/providers/openstack/provider.go b/builtin/providers/openstack/provider.go index 8b3e37a58e..27a6321fa4 100644 --- a/builtin/providers/openstack/provider.go +++ b/builtin/providers/openstack/provider.go @@ -59,16 +59,16 @@ func Provider() terraform.ResourceProvider { }, ResourcesMap: map[string]*schema.Resource{ - "openstack_compute_instance": resourceComputeInstance(), - "openstack_compute_keypair": resourceComputeKeypair(), - "openstack_compute_secgroup": resourceComputeSecGroup(), - "openstack_compute_secgrouprule": resourceComputeSecGroupRule(), - "openstack_lb_member": resourceLBMember(), - "openstack_lb_monitor": resourceLBMonitor(), - "openstack_lb_pool": resourceLBPool(), - "openstack_lb_vip": resourceLBVip(), - "openstack_networking_network": resourceNetworkingNetwork(), - "openstack_networking_subnet": resourceNetworkingSubnet(), + "openstack_compute_instance_v2": resourceComputeInstanceV2(), + "openstack_compute_keypair_v2": resourceComputeKeypairV2(), + "openstack_compute_secgroup_v2": resourceComputeSecGroupV2(), + "openstack_compute_secgrouprule_v2": resourceComputeSecGroupRuleV2(), + "openstack_lb_member_v1": resourceLBMemberV1(), + "openstack_lb_monitor_v1": resourceLBMonitorV1(), + "openstack_lb_pool_v1": resourceLBPoolV1(), + "openstack_lb_vip_v1": resourceLBVipV1(), + "openstack_networking_network_v2": resourceNetworkingNetworkV2(), + "openstack_networking_subnet_v2": resourceNetworkingSubnetV2(), }, ConfigureFunc: configureProvider, diff --git a/builtin/providers/openstack/resource_openstack_compute_instance_v2.go b/builtin/providers/openstack/resource_openstack_compute_instance_v2.go index cf434566d2..38c3b9af79 100644 --- a/builtin/providers/openstack/resource_openstack_compute_instance_v2.go +++ b/builtin/providers/openstack/resource_openstack_compute_instance_v2.go @@ -16,12 +16,12 @@ import ( "github.com/rackspace/gophercloud/pagination" ) -func resourceComputeInstance() *schema.Resource { +func resourceComputeInstanceV2() *schema.Resource { return &schema.Resource{ - Create: resourceComputeInstanceCreate, - Read: resourceComputeInstanceRead, - Update: resourceComputeInstanceUpdate, - Delete: resourceComputeInstanceDelete, + Create: resourceComputeInstanceV2Create, + Read: resourceComputeInstanceV2Read, + Update: resourceComputeInstanceV2Update, + Delete: resourceComputeInstanceV2Delete, Schema: map[string]*schema.Schema{ "region": &schema.Schema{ @@ -116,7 +116,7 @@ func resourceComputeInstance() *schema.Resource { } } -func resourceComputeInstanceCreate(d *schema.ResourceData, meta interface{}) error { +func resourceComputeInstanceV2Create(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) computeClient, err := openstack.NewComputeV2(config.osClient, gophercloud.EndpointOpts{ Region: d.Get("region").(string), @@ -132,10 +132,10 @@ func resourceComputeInstanceCreate(d *schema.ResourceData, meta interface{}) err Name: d.Get("name").(string), ImageRef: d.Get("image_ref").(string), FlavorRef: d.Get("flavor_ref").(string), - SecurityGroups: resourceInstanceSecGroups(d), + SecurityGroups: resourceInstanceSecGroupsV2(d), AvailabilityZone: d.Get("availability_zone").(string), - Networks: resourceInstanceNetworks(d), - Metadata: resourceInstanceMetadata(d), + Networks: resourceInstanceNetworksV2(d), + Metadata: resourceInstanceMetadataV2(d), ConfigDrive: d.Get("config_drive").(bool), AdminPass: d.Get("admin_pass").(string), } @@ -166,7 +166,7 @@ func resourceComputeInstanceCreate(d *schema.ResourceData, meta interface{}) err stateConf := &resource.StateChangeConf{ Pending: []string{"BUILD"}, Target: "ACTIVE", - Refresh: ServerStateRefreshFunc(computeClient, server.ID), + Refresh: ServerV2StateRefreshFunc(computeClient, server.ID), Timeout: 10 * time.Minute, Delay: 10 * time.Second, MinTimeout: 3 * time.Second, @@ -179,10 +179,10 @@ func resourceComputeInstanceCreate(d *schema.ResourceData, meta interface{}) err server.ID, err) } - return resourceComputeInstanceRead(d, meta) + return resourceComputeInstanceV2Read(d, meta) } -func resourceComputeInstanceRead(d *schema.ResourceData, meta interface{}) error { +func resourceComputeInstanceV2Read(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) computeClient, err := openstack.NewComputeV2(config.osClient, gophercloud.EndpointOpts{ Region: d.Get("region").(string), @@ -251,7 +251,7 @@ func resourceComputeInstanceRead(d *schema.ResourceData, meta interface{}) error return nil } -func resourceComputeInstanceUpdate(d *schema.ResourceData, meta interface{}) error { +func resourceComputeInstanceV2Update(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) computeClient, err := openstack.NewComputeV2(config.osClient, gophercloud.EndpointOpts{ Region: d.Get("region").(string), @@ -343,7 +343,7 @@ func resourceComputeInstanceUpdate(d *schema.ResourceData, meta interface{}) err stateConf := &resource.StateChangeConf{ Pending: []string{"RESIZE"}, Target: "VERIFY_RESIZE", - Refresh: ServerStateRefreshFunc(computeClient, d.Id()), + Refresh: ServerV2StateRefreshFunc(computeClient, d.Id()), Timeout: 3 * time.Minute, Delay: 10 * time.Second, MinTimeout: 3 * time.Second, @@ -364,7 +364,7 @@ func resourceComputeInstanceUpdate(d *schema.ResourceData, meta interface{}) err stateConf = &resource.StateChangeConf{ Pending: []string{"VERIFY_RESIZE"}, Target: "ACTIVE", - Refresh: ServerStateRefreshFunc(computeClient, d.Id()), + Refresh: ServerV2StateRefreshFunc(computeClient, d.Id()), Timeout: 3 * time.Minute, Delay: 10 * time.Second, MinTimeout: 3 * time.Second, @@ -376,10 +376,10 @@ func resourceComputeInstanceUpdate(d *schema.ResourceData, meta interface{}) err } } - return resourceComputeInstanceRead(d, meta) + return resourceComputeInstanceV2Read(d, meta) } -func resourceComputeInstanceDelete(d *schema.ResourceData, meta interface{}) error { +func resourceComputeInstanceV2Delete(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) computeClient, err := openstack.NewComputeV2(config.osClient, gophercloud.EndpointOpts{ Region: d.Get("region").(string), @@ -398,7 +398,7 @@ func resourceComputeInstanceDelete(d *schema.ResourceData, meta interface{}) err stateConf := &resource.StateChangeConf{ Target: "", - Refresh: ServerStateRefreshFunc(computeClient, d.Id()), + Refresh: ServerV2StateRefreshFunc(computeClient, d.Id()), Timeout: 10 * time.Minute, Delay: 10 * time.Second, MinTimeout: 3 * time.Second, @@ -417,7 +417,7 @@ func resourceComputeInstanceDelete(d *schema.ResourceData, meta interface{}) err // ServerStateRefreshFunc returns a resource.StateRefreshFunc that is used to watch // an OpenStack instance. -func ServerStateRefreshFunc(client *gophercloud.ServiceClient, instanceID string) resource.StateRefreshFunc { +func ServerV2StateRefreshFunc(client *gophercloud.ServiceClient, instanceID string) resource.StateRefreshFunc { return func() (interface{}, string, error) { s, err := servers.Get(client, instanceID).Extract() if err != nil { @@ -428,7 +428,7 @@ func ServerStateRefreshFunc(client *gophercloud.ServiceClient, instanceID string } } -func resourceInstanceSecGroups(d *schema.ResourceData) []string { +func resourceInstanceSecGroupsV2(d *schema.ResourceData) []string { rawSecGroups := d.Get("security_groups").(*schema.Set) secgroups := make([]string, rawSecGroups.Len()) for i, raw := range rawSecGroups.List() { @@ -437,7 +437,7 @@ func resourceInstanceSecGroups(d *schema.ResourceData) []string { return secgroups } -func resourceInstanceNetworks(d *schema.ResourceData) []servers.Network { +func resourceInstanceNetworksV2(d *schema.ResourceData) []servers.Network { rawNetworks := d.Get("networks").([]interface{}) networks := make([]servers.Network, len(rawNetworks)) for i, raw := range rawNetworks { @@ -451,7 +451,7 @@ func resourceInstanceNetworks(d *schema.ResourceData) []servers.Network { return networks } -func resourceInstanceMetadata(d *schema.ResourceData) map[string]string { +func resourceInstanceMetadataV2(d *schema.ResourceData) map[string]string { m := make(map[string]string) for key, val := range d.Get("metadata").(map[string]interface{}) { m[key] = val.(string) diff --git a/builtin/providers/openstack/resource_openstack_compute_keypair_v2.go b/builtin/providers/openstack/resource_openstack_compute_keypair_v2.go index d27a348d4b..6fdaef6319 100644 --- a/builtin/providers/openstack/resource_openstack_compute_keypair_v2.go +++ b/builtin/providers/openstack/resource_openstack_compute_keypair_v2.go @@ -9,11 +9,11 @@ import ( "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/keypairs" ) -func resourceComputeKeypair() *schema.Resource { +func resourceComputeKeypairV2() *schema.Resource { return &schema.Resource{ - Create: resourceComputeKeypairCreate, - Read: resourceComputeKeypairRead, - Delete: resourceComputeKeypairDelete, + Create: resourceComputeKeypairV2Create, + Read: resourceComputeKeypairV2Read, + Delete: resourceComputeKeypairV2Delete, Schema: map[string]*schema.Schema{ "region": &schema.Schema{ @@ -36,7 +36,7 @@ func resourceComputeKeypair() *schema.Resource { } } -func resourceComputeKeypairCreate(d *schema.ResourceData, meta interface{}) error { +func resourceComputeKeypairV2Create(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) computeClient, err := openstack.NewComputeV2(config.osClient, gophercloud.EndpointOpts{ Region: d.Get("region").(string), @@ -57,10 +57,10 @@ func resourceComputeKeypairCreate(d *schema.ResourceData, meta interface{}) erro d.SetId(kp.Name) - return resourceComputeKeypairRead(d, meta) + return resourceComputeKeypairV2Read(d, meta) } -func resourceComputeKeypairRead(d *schema.ResourceData, meta interface{}) error { +func resourceComputeKeypairV2Read(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) computeClient, err := openstack.NewComputeV2(config.osClient, gophercloud.EndpointOpts{ Region: d.Get("region").(string), @@ -80,7 +80,7 @@ func resourceComputeKeypairRead(d *schema.ResourceData, meta interface{}) error return nil } -func resourceComputeKeypairDelete(d *schema.ResourceData, meta interface{}) error { +func resourceComputeKeypairV2Delete(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) computeClient, err := openstack.NewComputeV2(config.osClient, gophercloud.EndpointOpts{ Region: d.Get("region").(string), diff --git a/builtin/providers/openstack/resource_openstack_compute_secgroup_v2.go b/builtin/providers/openstack/resource_openstack_compute_secgroup_v2.go index 559f96cbff..d6802e99d1 100644 --- a/builtin/providers/openstack/resource_openstack_compute_secgroup_v2.go +++ b/builtin/providers/openstack/resource_openstack_compute_secgroup_v2.go @@ -10,12 +10,12 @@ import ( "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/secgroups" ) -func resourceComputeSecGroup() *schema.Resource { +func resourceComputeSecGroupV2() *schema.Resource { return &schema.Resource{ - Create: resourceComputeSecGroupCreate, - Read: resourceComputeSecGroupRead, - Update: resourceComputeSecGroupUpdate, - Delete: resourceComputeSecGroupDelete, + Create: resourceComputeSecGroupV2Create, + Read: resourceComputeSecGroupV2Read, + Update: resourceComputeSecGroupV2Update, + Delete: resourceComputeSecGroupV2Delete, Schema: map[string]*schema.Schema{ "region": &schema.Schema{ @@ -38,7 +38,7 @@ func resourceComputeSecGroup() *schema.Resource { } } -func resourceComputeSecGroupCreate(d *schema.ResourceData, meta interface{}) error { +func resourceComputeSecGroupV2Create(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) computeClient, err := openstack.NewComputeV2(config.osClient, gophercloud.EndpointOpts{ Region: d.Get("region").(string), @@ -59,10 +59,10 @@ func resourceComputeSecGroupCreate(d *schema.ResourceData, meta interface{}) err d.SetId(sg.ID) - return resourceComputeSecGroupRead(d, meta) + return resourceComputeSecGroupV2Read(d, meta) } -func resourceComputeSecGroupRead(d *schema.ResourceData, meta interface{}) error { +func resourceComputeSecGroupV2Read(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) computeClient, err := openstack.NewComputeV2(config.osClient, gophercloud.EndpointOpts{ Region: d.Get("region").(string), @@ -82,7 +82,7 @@ func resourceComputeSecGroupRead(d *schema.ResourceData, meta interface{}) error return nil } -func resourceComputeSecGroupUpdate(d *schema.ResourceData, meta interface{}) error { +func resourceComputeSecGroupV2Update(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) computeClient, err := openstack.NewComputeV2(config.osClient, gophercloud.EndpointOpts{ Region: d.Get("region").(string), @@ -106,10 +106,10 @@ func resourceComputeSecGroupUpdate(d *schema.ResourceData, meta interface{}) err return fmt.Errorf("Error updating OpenStack security group (%s): %s", d.Id(), err) } - return resourceComputeSecGroupRead(d, meta) + return resourceComputeSecGroupV2Read(d, meta) } -func resourceComputeSecGroupDelete(d *schema.ResourceData, meta interface{}) error { +func resourceComputeSecGroupV2Delete(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) computeClient, err := openstack.NewComputeV2(config.osClient, gophercloud.EndpointOpts{ Region: d.Get("region").(string), diff --git a/builtin/providers/openstack/resource_openstack_compute_secgrouprule_v2.go b/builtin/providers/openstack/resource_openstack_compute_secgrouprule_v2.go index 77c14f6f8c..9a890d6733 100644 --- a/builtin/providers/openstack/resource_openstack_compute_secgrouprule_v2.go +++ b/builtin/providers/openstack/resource_openstack_compute_secgrouprule_v2.go @@ -9,11 +9,11 @@ import ( "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/secgroups" ) -func resourceComputeSecGroupRule() *schema.Resource { +func resourceComputeSecGroupRuleV2() *schema.Resource { return &schema.Resource{ - Create: resourceComputeSecGroupRuleCreate, - Read: resourceComputeSecGroupRuleRead, - Delete: resourceComputeSecGroupRuleDelete, + Create: resourceComputeSecGroupRuleV2Create, + Read: resourceComputeSecGroupRuleV2Read, + Delete: resourceComputeSecGroupRuleV2Delete, Schema: map[string]*schema.Schema{ "region": &schema.Schema{ @@ -56,7 +56,7 @@ func resourceComputeSecGroupRule() *schema.Resource { } } -func resourceComputeSecGroupRuleCreate(d *schema.ResourceData, meta interface{}) error { +func resourceComputeSecGroupRuleV2Create(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) computeClient, err := openstack.NewComputeV2(config.osClient, gophercloud.EndpointOpts{ Region: d.Get("region").(string), @@ -87,14 +87,14 @@ func resourceComputeSecGroupRuleCreate(d *schema.ResourceData, meta interface{}) d.Set("cidr", sgr.IPRange.CIDR) d.Set("from_group_id", d.Get("from_group_id").(string)) - return resourceComputeSecGroupRuleRead(d, meta) + return resourceComputeSecGroupRuleV2Read(d, meta) } -func resourceComputeSecGroupRuleRead(d *schema.ResourceData, meta interface{}) error { +func resourceComputeSecGroupRuleV2Read(d *schema.ResourceData, meta interface{}) error { return nil } -func resourceComputeSecGroupRuleDelete(d *schema.ResourceData, meta interface{}) error { +func resourceComputeSecGroupRuleV2Delete(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) computeClient, err := openstack.NewComputeV2(config.osClient, gophercloud.EndpointOpts{ Region: d.Get("region").(string), diff --git a/builtin/providers/openstack/resource_openstack_lb_member_v1.go b/builtin/providers/openstack/resource_openstack_lb_member_v1.go index fdad89a005..0a6f478b79 100644 --- a/builtin/providers/openstack/resource_openstack_lb_member_v1.go +++ b/builtin/providers/openstack/resource_openstack_lb_member_v1.go @@ -10,12 +10,12 @@ import ( "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/lbaas/members" ) -func resourceLBMember() *schema.Resource { +func resourceLBMemberV1() *schema.Resource { return &schema.Resource{ - Create: resourceLBMemberCreate, - Read: resourceLBMemberRead, - Update: resourceLBMemberUpdate, - Delete: resourceLBMemberDelete, + Create: resourceLBMemberV1Create, + Read: resourceLBMemberV1Read, + Update: resourceLBMemberV1Update, + Delete: resourceLBMemberV1Delete, Schema: map[string]*schema.Schema{ "region": &schema.Schema{ @@ -53,7 +53,7 @@ func resourceLBMember() *schema.Resource { } } -func resourceLBMemberCreate(d *schema.ResourceData, meta interface{}) error { +func resourceLBMemberV1Create(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) networkingClient, err := openstack.NewNetworkV2(config.osClient, gophercloud.EndpointOpts{ Region: d.Get("region").(string), @@ -78,10 +78,10 @@ func resourceLBMemberCreate(d *schema.ResourceData, meta interface{}) error { d.SetId(p.ID) - return resourceLBMemberRead(d, meta) + return resourceLBMemberV1Read(d, meta) } -func resourceLBMemberRead(d *schema.ResourceData, meta interface{}) error { +func resourceLBMemberV1Read(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) networkingClient, err := openstack.NewNetworkV2(config.osClient, gophercloud.EndpointOpts{ Region: d.Get("region").(string), @@ -112,7 +112,7 @@ func resourceLBMemberRead(d *schema.ResourceData, meta interface{}) error { return nil } -func resourceLBMemberUpdate(d *schema.ResourceData, meta interface{}) error { +func resourceLBMemberV1Update(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) networkingClient, err := openstack.NewNetworkV2(config.osClient, gophercloud.EndpointOpts{ Region: d.Get("region").(string), @@ -133,10 +133,10 @@ func resourceLBMemberUpdate(d *schema.ResourceData, meta interface{}) error { return fmt.Errorf("Error updating OpenStack LB Member: %s", err) } - return resourceLBMemberRead(d, meta) + return resourceLBMemberV1Read(d, meta) } -func resourceLBMemberDelete(d *schema.ResourceData, meta interface{}) error { +func resourceLBMemberV1Delete(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) networkingClient, err := openstack.NewNetworkV2(config.osClient, gophercloud.EndpointOpts{ Region: d.Get("region").(string), diff --git a/builtin/providers/openstack/resource_openstack_lb_monitor_v1.go b/builtin/providers/openstack/resource_openstack_lb_monitor_v1.go index cdf380319f..9d82e7e268 100644 --- a/builtin/providers/openstack/resource_openstack_lb_monitor_v1.go +++ b/builtin/providers/openstack/resource_openstack_lb_monitor_v1.go @@ -11,12 +11,12 @@ import ( "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/lbaas/monitors" ) -func resourceLBMonitor() *schema.Resource { +func resourceLBMonitorV1() *schema.Resource { return &schema.Resource{ - Create: resourceLBMonitorCreate, - Read: resourceLBMonitorRead, - Update: resourceLBMonitorUpdate, - Delete: resourceLBMonitorDelete, + Create: resourceLBMonitorV1Create, + Read: resourceLBMonitorV1Read, + Update: resourceLBMonitorV1Update, + Delete: resourceLBMonitorV1Delete, Schema: map[string]*schema.Schema{ "region": &schema.Schema{ @@ -74,7 +74,7 @@ func resourceLBMonitor() *schema.Resource { } } -func resourceLBMonitorCreate(d *schema.ResourceData, meta interface{}) error { +func resourceLBMonitorV1Create(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) networkingClient, err := openstack.NewNetworkV2(config.osClient, gophercloud.EndpointOpts{ Region: d.Get("region").(string), @@ -112,10 +112,10 @@ func resourceLBMonitorCreate(d *schema.ResourceData, meta interface{}) error { d.SetId(m.ID) - return resourceLBMonitorRead(d, meta) + return resourceLBMonitorV1Read(d, meta) } -func resourceLBMonitorRead(d *schema.ResourceData, meta interface{}) error { +func resourceLBMonitorV1Read(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) networkingClient, err := openstack.NewNetworkV2(config.osClient, gophercloud.EndpointOpts{ Region: d.Get("region").(string), @@ -179,7 +179,7 @@ func resourceLBMonitorRead(d *schema.ResourceData, meta interface{}) error { return nil } -func resourceLBMonitorUpdate(d *schema.ResourceData, meta interface{}) error { +func resourceLBMonitorV1Update(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) networkingClient, err := openstack.NewNetworkV2(config.osClient, gophercloud.EndpointOpts{ Region: d.Get("region").(string), @@ -225,10 +225,10 @@ func resourceLBMonitorUpdate(d *schema.ResourceData, meta interface{}) error { return fmt.Errorf("Error updating OpenStack LB Monitor: %s", err) } - return resourceLBMonitorRead(d, meta) + return resourceLBMonitorV1Read(d, meta) } -func resourceLBMonitorDelete(d *schema.ResourceData, meta interface{}) error { +func resourceLBMonitorV1Delete(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) networkingClient, err := openstack.NewNetworkV2(config.osClient, gophercloud.EndpointOpts{ Region: d.Get("region").(string), diff --git a/builtin/providers/openstack/resource_openstack_lb_pool_v1.go b/builtin/providers/openstack/resource_openstack_lb_pool_v1.go index 180bcb8fda..c5275c6e89 100644 --- a/builtin/providers/openstack/resource_openstack_lb_pool_v1.go +++ b/builtin/providers/openstack/resource_openstack_lb_pool_v1.go @@ -11,12 +11,12 @@ import ( "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/lbaas/pools" ) -func resourceLBPool() *schema.Resource { +func resourceLBPoolV1() *schema.Resource { return &schema.Resource{ - Create: resourceLBPoolCreate, - Read: resourceLBPoolRead, - Update: resourceLBPoolUpdate, - Delete: resourceLBPoolDelete, + Create: resourceLBPoolV1Create, + Read: resourceLBPoolV1Read, + Update: resourceLBPoolV1Update, + Delete: resourceLBPoolV1Delete, Schema: map[string]*schema.Schema{ "region": &schema.Schema{ @@ -64,7 +64,7 @@ func resourceLBPool() *schema.Resource { } } -func resourceLBPoolCreate(d *schema.ResourceData, meta interface{}) error { +func resourceLBPoolV1Create(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) networkingClient, err := openstack.NewNetworkV2(config.osClient, gophercloud.EndpointOpts{ Region: d.Get("region").(string), @@ -90,7 +90,7 @@ func resourceLBPoolCreate(d *schema.ResourceData, meta interface{}) error { d.SetId(p.ID) - if mIDs := resourcePoolMonitorIDs(d); mIDs != nil { + if mIDs := resourcePoolMonitorIDsV1(d); mIDs != nil { for _, mID := range mIDs { _, err := pools.AssociateMonitor(networkingClient, p.ID, mID).Extract() if err != nil { @@ -99,10 +99,10 @@ func resourceLBPoolCreate(d *schema.ResourceData, meta interface{}) error { } } - return resourceLBPoolRead(d, meta) + return resourceLBPoolV1Read(d, meta) } -func resourceLBPoolRead(d *schema.ResourceData, meta interface{}) error { +func resourceLBPoolV1Read(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) networkingClient, err := openstack.NewNetworkV2(config.osClient, gophercloud.EndpointOpts{ Region: d.Get("region").(string), @@ -136,7 +136,7 @@ func resourceLBPoolRead(d *schema.ResourceData, meta interface{}) error { return nil } -func resourceLBPoolUpdate(d *schema.ResourceData, meta interface{}) error { +func resourceLBPoolV1Update(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) networkingClient, err := openstack.NewNetworkV2(config.osClient, gophercloud.EndpointOpts{ Region: d.Get("region").(string), @@ -187,10 +187,10 @@ func resourceLBPoolUpdate(d *schema.ResourceData, meta interface{}) error { } } - return resourceLBPoolRead(d, meta) + return resourceLBPoolV1Read(d, meta) } -func resourceLBPoolDelete(d *schema.ResourceData, meta interface{}) error { +func resourceLBPoolV1Delete(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) networkingClient, err := openstack.NewNetworkV2(config.osClient, gophercloud.EndpointOpts{ Region: d.Get("region").(string), @@ -208,7 +208,7 @@ func resourceLBPoolDelete(d *schema.ResourceData, meta interface{}) error { return nil } -func resourcePoolMonitorIDs(d *schema.ResourceData) []string { +func resourcePoolMonitorIDsV1(d *schema.ResourceData) []string { mIDsRaw := d.Get("monitor_ids").(*schema.Set) mIDs := make([]string, mIDsRaw.Len()) for i, raw := range mIDsRaw.List() { diff --git a/builtin/providers/openstack/resource_openstack_lb_vip_v1.go b/builtin/providers/openstack/resource_openstack_lb_vip_v1.go index ad95767cd4..09c63bc41d 100644 --- a/builtin/providers/openstack/resource_openstack_lb_vip_v1.go +++ b/builtin/providers/openstack/resource_openstack_lb_vip_v1.go @@ -11,12 +11,12 @@ import ( "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/lbaas/vips" ) -func resourceLBVip() *schema.Resource { +func resourceLBVipV1() *schema.Resource { return &schema.Resource{ - Create: resourceLBVipCreate, - Read: resourceLBVipRead, - Update: resourceLBVipUpdate, - Delete: resourceLBVipDelete, + Create: resourceLBVipV1Create, + Read: resourceLBVipV1Read, + Update: resourceLBVipV1Update, + Delete: resourceLBVipV1Delete, Schema: map[string]*schema.Schema{ "region": &schema.Schema{ @@ -84,7 +84,7 @@ func resourceLBVip() *schema.Resource { } } -func resourceLBVipCreate(d *schema.ResourceData, meta interface{}) error { +func resourceLBVipV1Create(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) networkingClient, err := openstack.NewNetworkV2(config.osClient, gophercloud.EndpointOpts{ Region: d.Get("region").(string), @@ -102,7 +102,7 @@ func resourceLBVipCreate(d *schema.ResourceData, meta interface{}) error { TenantID: d.Get("tenant_id").(string), Address: d.Get("address").(string), Description: d.Get("description").(string), - Persistence: resourceVipPersistence(d), + Persistence: resourceVipPersistenceV1(d), ConnLimit: gophercloud.MaybeInt(d.Get("conn_limit").(int)), } @@ -124,10 +124,10 @@ func resourceLBVipCreate(d *schema.ResourceData, meta interface{}) error { d.SetId(p.ID) - return resourceLBVipRead(d, meta) + return resourceLBVipV1Read(d, meta) } -func resourceLBVipRead(d *schema.ResourceData, meta interface{}) error { +func resourceLBVipV1Read(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) networkingClient, err := openstack.NewNetworkV2(config.osClient, gophercloud.EndpointOpts{ Region: d.Get("region").(string), @@ -198,7 +198,7 @@ func resourceLBVipRead(d *schema.ResourceData, meta interface{}) error { return nil } -func resourceLBVipUpdate(d *schema.ResourceData, meta interface{}) error { +func resourceLBVipV1Update(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) networkingClient, err := openstack.NewNetworkV2(config.osClient, gophercloud.EndpointOpts{ Region: d.Get("region").(string), @@ -218,7 +218,7 @@ func resourceLBVipUpdate(d *schema.ResourceData, meta interface{}) error { updateOpts.Description = d.Get("description").(string) } if d.HasChange("persistence") { - updateOpts.Persistence = resourceVipPersistence(d) + updateOpts.Persistence = resourceVipPersistenceV1(d) } if d.HasChange("conn_limit") { updateOpts.ConnLimit = gophercloud.MaybeInt(d.Get("conn_limit").(int)) @@ -241,10 +241,10 @@ func resourceLBVipUpdate(d *schema.ResourceData, meta interface{}) error { return fmt.Errorf("Error updating OpenStack LB VIP: %s", err) } - return resourceLBVipRead(d, meta) + return resourceLBVipV1Read(d, meta) } -func resourceLBVipDelete(d *schema.ResourceData, meta interface{}) error { +func resourceLBVipV1Delete(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) networkingClient, err := openstack.NewNetworkV2(config.osClient, gophercloud.EndpointOpts{ Region: d.Get("region").(string), @@ -262,12 +262,18 @@ func resourceLBVipDelete(d *schema.ResourceData, meta interface{}) error { return nil } -func resourceVipPersistence(d *schema.ResourceData) *vips.SessionPersistence { +func resourceVipPersistenceV1(d *schema.ResourceData) *vips.SessionPersistence { rawP := d.Get("persistence").(interface{}) rawMap := rawP.(map[string]interface{}) - p := vips.SessionPersistence{ - Type: rawMap["type"].(string), - CookieName: rawMap["cookie_name"].(string), + if rawMap != nil { + p := vips.SessionPersistence{} + if t, ok := rawMap["type"]; ok { + p.Type = t.(string) + } + if c, ok := rawMap["cookie_name"]; ok { + p.CookieName = c.(string) + } + return &p } - return &p + return nil } diff --git a/builtin/providers/openstack/resource_openstack_networking_network_v2.go b/builtin/providers/openstack/resource_openstack_networking_network_v2.go index 3ce51fbb05..3c33315c79 100644 --- a/builtin/providers/openstack/resource_openstack_networking_network_v2.go +++ b/builtin/providers/openstack/resource_openstack_networking_network_v2.go @@ -11,12 +11,12 @@ import ( "github.com/rackspace/gophercloud/openstack/networking/v2/networks" ) -func resourceNetworkingNetwork() *schema.Resource { +func resourceNetworkingNetworkV2() *schema.Resource { return &schema.Resource{ - Create: resourceNetworkingNetworkCreate, - Read: resourceNetworkingNetworkRead, - Update: resourceNetworkingNetworkUpdate, - Delete: resourceNetworkingNetworkDelete, + Create: resourceNetworkingNetworkV2Create, + Read: resourceNetworkingNetworkV2Read, + Update: resourceNetworkingNetworkV2Update, + Delete: resourceNetworkingNetworkV2Delete, Schema: map[string]*schema.Schema{ "region": &schema.Schema{ @@ -49,7 +49,7 @@ func resourceNetworkingNetwork() *schema.Resource { } } -func resourceNetworkingNetworkCreate(d *schema.ResourceData, meta interface{}) error { +func resourceNetworkingNetworkV2Create(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) networkingClient, err := openstack.NewNetworkV2(config.osClient, gophercloud.EndpointOpts{ Region: d.Get("region").(string), @@ -90,10 +90,10 @@ func resourceNetworkingNetworkCreate(d *schema.ResourceData, meta interface{}) e d.SetId(n.ID) - return resourceNetworkingNetworkRead(d, meta) + return resourceNetworkingNetworkV2Read(d, meta) } -func resourceNetworkingNetworkRead(d *schema.ResourceData, meta interface{}) error { +func resourceNetworkingNetworkV2Read(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) networkingClient, err := openstack.NewNetworkV2(config.osClient, gophercloud.EndpointOpts{ Region: d.Get("region").(string), @@ -144,7 +144,7 @@ func resourceNetworkingNetworkRead(d *schema.ResourceData, meta interface{}) err return nil } -func resourceNetworkingNetworkUpdate(d *schema.ResourceData, meta interface{}) error { +func resourceNetworkingNetworkV2Update(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) networkingClient, err := openstack.NewNetworkV2(config.osClient, gophercloud.EndpointOpts{ Region: d.Get("region").(string), @@ -185,10 +185,10 @@ func resourceNetworkingNetworkUpdate(d *schema.ResourceData, meta interface{}) e return fmt.Errorf("Error updating OpenStack Neutron Network: %s", err) } - return resourceNetworkingNetworkRead(d, meta) + return resourceNetworkingNetworkV2Read(d, meta) } -func resourceNetworkingNetworkDelete(d *schema.ResourceData, meta interface{}) error { +func resourceNetworkingNetworkV2Delete(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) networkingClient, err := openstack.NewNetworkV2(config.osClient, gophercloud.EndpointOpts{ Region: d.Get("region").(string), diff --git a/builtin/providers/openstack/resource_openstack_networking_subnet_v2.go b/builtin/providers/openstack/resource_openstack_networking_subnet_v2.go index ab337ec30b..af25c4497f 100644 --- a/builtin/providers/openstack/resource_openstack_networking_subnet_v2.go +++ b/builtin/providers/openstack/resource_openstack_networking_subnet_v2.go @@ -12,12 +12,12 @@ import ( "github.com/rackspace/gophercloud/openstack/networking/v2/subnets" ) -func resourceNetworkingSubnet() *schema.Resource { +func resourceNetworkingSubnetV2() *schema.Resource { return &schema.Resource{ - Create: resourceNetworkingSubnetCreate, - Read: resourceNetworkingSubnetRead, - Update: resourceNetworkingSubnetUpdate, - Delete: resourceNetworkingSubnetDelete, + Create: resourceNetworkingSubnetV2Create, + Read: resourceNetworkingSubnetV2Read, + Update: resourceNetworkingSubnetV2Update, + Delete: resourceNetworkingSubnetV2Delete, Schema: map[string]*schema.Schema{ "region": &schema.Schema{ @@ -108,7 +108,7 @@ func resourceNetworkingSubnet() *schema.Resource { } } -func resourceNetworkingSubnetCreate(d *schema.ResourceData, meta interface{}) error { +func resourceNetworkingSubnetV2Create(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) networkingClient, err := openstack.NewNetworkV2(config.osClient, gophercloud.EndpointOpts{ Region: d.Get("region").(string), @@ -122,11 +122,11 @@ func resourceNetworkingSubnetCreate(d *schema.ResourceData, meta interface{}) er CIDR: d.Get("cidr").(string), Name: d.Get("name").(string), TenantID: d.Get("tenant_id").(string), - AllocationPools: resourceSubnetAllocationPools(d), + AllocationPools: resourceSubnetAllocationPoolsV2(d), GatewayIP: d.Get("gateway_ip").(string), IPVersion: d.Get("ip_version").(int), - DNSNameservers: resourceSubnetDNSNameservers(d), - HostRoutes: resourceSubnetHostRoutes(d), + DNSNameservers: resourceSubnetDNSNameserversV2(d), + HostRoutes: resourceSubnetHostRoutesV2(d), } edRaw := d.Get("enable_dhcp").(string) @@ -147,10 +147,10 @@ func resourceNetworkingSubnetCreate(d *schema.ResourceData, meta interface{}) er d.SetId(s.ID) - return resourceNetworkingSubnetRead(d, meta) + return resourceNetworkingSubnetV2Read(d, meta) } -func resourceNetworkingSubnetRead(d *schema.ResourceData, meta interface{}) error { +func resourceNetworkingSubnetV2Read(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) networkingClient, err := openstack.NewNetworkV2(config.osClient, gophercloud.EndpointOpts{ Region: d.Get("region").(string), @@ -217,7 +217,7 @@ func resourceNetworkingSubnetRead(d *schema.ResourceData, meta interface{}) erro return nil } -func resourceNetworkingSubnetUpdate(d *schema.ResourceData, meta interface{}) error { +func resourceNetworkingSubnetV2Update(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) networkingClient, err := openstack.NewNetworkV2(config.osClient, gophercloud.EndpointOpts{ Region: d.Get("region").(string), @@ -237,11 +237,11 @@ func resourceNetworkingSubnetUpdate(d *schema.ResourceData, meta interface{}) er } if d.HasChange("dns_nameservers") { - updateOpts.DNSNameservers = resourceSubnetDNSNameservers(d) + updateOpts.DNSNameservers = resourceSubnetDNSNameserversV2(d) } if d.HasChange("host_routes") { - updateOpts.HostRoutes = resourceSubnetHostRoutes(d) + updateOpts.HostRoutes = resourceSubnetHostRoutesV2(d) } if d.HasChange("enable_dhcp") { @@ -262,10 +262,10 @@ func resourceNetworkingSubnetUpdate(d *schema.ResourceData, meta interface{}) er return fmt.Errorf("Error updating OpenStack Neutron Subnet: %s", err) } - return resourceNetworkingSubnetRead(d, meta) + return resourceNetworkingSubnetV2Read(d, meta) } -func resourceNetworkingSubnetDelete(d *schema.ResourceData, meta interface{}) error { +func resourceNetworkingSubnetV2Delete(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) networkingClient, err := openstack.NewNetworkV2(config.osClient, gophercloud.EndpointOpts{ Region: d.Get("region").(string), @@ -283,7 +283,7 @@ func resourceNetworkingSubnetDelete(d *schema.ResourceData, meta interface{}) er return nil } -func resourceSubnetAllocationPools(d *schema.ResourceData) []subnets.AllocationPool { +func resourceSubnetAllocationPoolsV2(d *schema.ResourceData) []subnets.AllocationPool { rawAPs := d.Get("allocation_pools").([]interface{}) aps := make([]subnets.AllocationPool, len(rawAPs)) for i, raw := range rawAPs { @@ -296,7 +296,7 @@ func resourceSubnetAllocationPools(d *schema.ResourceData) []subnets.AllocationP return aps } -func resourceSubnetDNSNameservers(d *schema.ResourceData) []string { +func resourceSubnetDNSNameserversV2(d *schema.ResourceData) []string { rawDNSN := d.Get("dns_nameservers").(*schema.Set) dnsn := make([]string, rawDNSN.Len()) for i, raw := range rawDNSN.List() { @@ -305,7 +305,7 @@ func resourceSubnetDNSNameservers(d *schema.ResourceData) []string { return dnsn } -func resourceSubnetHostRoutes(d *schema.ResourceData) []subnets.HostRoute { +func resourceSubnetHostRoutesV2(d *schema.ResourceData) []subnets.HostRoute { rawHR := d.Get("host_routes").([]interface{}) hr := make([]subnets.HostRoute, len(rawHR)) for i, raw := range rawHR { From 9b54c569cc2b20f0eb5a6a3c0f268d5ff2f6aa68 Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Mon, 26 Jan 2015 11:38:02 -0700 Subject: [PATCH 037/132] use 'Default' to forgo prompt --- builtin/providers/openstack/provider.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/builtin/providers/openstack/provider.go b/builtin/providers/openstack/provider.go index 27a6321fa4..53f63f5d70 100644 --- a/builtin/providers/openstack/provider.go +++ b/builtin/providers/openstack/provider.go @@ -24,17 +24,17 @@ func Provider() terraform.ResourceProvider { "user_id": &schema.Schema{ Type: schema.TypeString, Optional: true, - DefaultFunc: envDefaultFunc("OS_USERID"), + Default: "", }, "tenant_id": &schema.Schema{ Type: schema.TypeString, Optional: true, - DefaultFunc: envDefaultFunc("OS_TENANT_ID"), + Default: "", }, "tenant_name": &schema.Schema{ Type: schema.TypeString, Optional: true, - DefaultFunc: envDefaultFunc("OS_TENANT_NAME"), + Default: "", }, "password": &schema.Schema{ Type: schema.TypeString, @@ -44,17 +44,17 @@ func Provider() terraform.ResourceProvider { "api_key": &schema.Schema{ Type: schema.TypeString, Optional: true, - DefaultFunc: envDefaultFunc("OS_API_KEY"), + Default: "", }, "domain_id": &schema.Schema{ Type: schema.TypeString, Optional: true, - DefaultFunc: envDefaultFunc("OS_DOMAIN_ID"), + Default: "", }, "domain_name": &schema.Schema{ Type: schema.TypeString, Optional: true, - DefaultFunc: envDefaultFunc("OS_DOMAIN_NAME"), + Default: "", }, }, From 46a7949c9d01a4e3daab631fb029b0c09451ccd0 Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Mon, 26 Jan 2015 11:38:33 -0700 Subject: [PATCH 038/132] fix bug in SessionPersistence logic --- builtin/providers/openstack/resource_openstack_lb_vip_v1.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/builtin/providers/openstack/resource_openstack_lb_vip_v1.go b/builtin/providers/openstack/resource_openstack_lb_vip_v1.go index 09c63bc41d..9c49b32765 100644 --- a/builtin/providers/openstack/resource_openstack_lb_vip_v1.go +++ b/builtin/providers/openstack/resource_openstack_lb_vip_v1.go @@ -66,7 +66,7 @@ func resourceLBVipV1() *schema.Resource { ForceNew: false, }, "persistence": &schema.Schema{ - Type: schema.TypeString, + Type: schema.TypeMap, Optional: true, ForceNew: false, }, @@ -265,7 +265,7 @@ func resourceLBVipV1Delete(d *schema.ResourceData, meta interface{}) error { func resourceVipPersistenceV1(d *schema.ResourceData) *vips.SessionPersistence { rawP := d.Get("persistence").(interface{}) rawMap := rawP.(map[string]interface{}) - if rawMap != nil { + if len(rawMap) != 0 { p := vips.SessionPersistence{} if t, ok := rawMap["type"]; ok { p.Type = t.(string) From 2214331b3cbdefffd324d6d23563b8aef170fe28 Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Mon, 26 Jan 2015 11:58:19 -0700 Subject: [PATCH 039/132] export 'region' from 'Read' operations --- .../openstack/resource_openstack_compute_instance_v2.go | 1 + .../openstack/resource_openstack_compute_keypair_v2.go | 1 + .../openstack/resource_openstack_compute_secgroup_v2.go | 1 + .../openstack/resource_openstack_compute_secgrouprule_v2.go | 1 + builtin/providers/openstack/resource_openstack_lb_member_v1.go | 1 + builtin/providers/openstack/resource_openstack_lb_monitor_v1.go | 1 + builtin/providers/openstack/resource_openstack_lb_pool_v1.go | 1 + builtin/providers/openstack/resource_openstack_lb_vip_v1.go | 1 + .../openstack/resource_openstack_networking_network_v2.go | 2 ++ .../openstack/resource_openstack_networking_subnet_v2.go | 1 + 10 files changed, 11 insertions(+) diff --git a/builtin/providers/openstack/resource_openstack_compute_instance_v2.go b/builtin/providers/openstack/resource_openstack_compute_instance_v2.go index 38c3b9af79..660679a0ba 100644 --- a/builtin/providers/openstack/resource_openstack_compute_instance_v2.go +++ b/builtin/providers/openstack/resource_openstack_compute_instance_v2.go @@ -198,6 +198,7 @@ func resourceComputeInstanceV2Read(d *schema.ResourceData, meta interface{}) err log.Printf("[DEBUG] Retreived Server %s: %+v", d.Id(), server) + d.Set("region", d.Get("region").(string)) d.Set("name", server.Name) d.Set("access_ip_v4", server.AccessIPv4) d.Set("access_ip_v6", server.AccessIPv6) diff --git a/builtin/providers/openstack/resource_openstack_compute_keypair_v2.go b/builtin/providers/openstack/resource_openstack_compute_keypair_v2.go index 6fdaef6319..e2d189a070 100644 --- a/builtin/providers/openstack/resource_openstack_compute_keypair_v2.go +++ b/builtin/providers/openstack/resource_openstack_compute_keypair_v2.go @@ -74,6 +74,7 @@ func resourceComputeKeypairV2Read(d *schema.ResourceData, meta interface{}) erro return fmt.Errorf("Error retrieving OpenStack keypair: %s", err) } + d.Set("region", d.Get("region").(string)) d.Set("name", kp.Name) d.Set("public_key", kp.PublicKey) diff --git a/builtin/providers/openstack/resource_openstack_compute_secgroup_v2.go b/builtin/providers/openstack/resource_openstack_compute_secgroup_v2.go index d6802e99d1..c896865757 100644 --- a/builtin/providers/openstack/resource_openstack_compute_secgroup_v2.go +++ b/builtin/providers/openstack/resource_openstack_compute_secgroup_v2.go @@ -76,6 +76,7 @@ func resourceComputeSecGroupV2Read(d *schema.ResourceData, meta interface{}) err return fmt.Errorf("Error retrieving OpenStack security group: %s", err) } + d.Set("region", d.Get("region").(string)) d.Set("name", sg.Name) d.Set("description", sg.Description) diff --git a/builtin/providers/openstack/resource_openstack_compute_secgrouprule_v2.go b/builtin/providers/openstack/resource_openstack_compute_secgrouprule_v2.go index 9a890d6733..fce40e6218 100644 --- a/builtin/providers/openstack/resource_openstack_compute_secgrouprule_v2.go +++ b/builtin/providers/openstack/resource_openstack_compute_secgrouprule_v2.go @@ -80,6 +80,7 @@ func resourceComputeSecGroupRuleV2Create(d *schema.ResourceData, meta interface{ } d.SetId(sgr.ID) + d.Set("region", d.Get("region").(string)) d.Set("group_id", sgr.ParentGroupID) d.Set("from_port", sgr.FromPort) d.Set("to_port", sgr.ToPort) diff --git a/builtin/providers/openstack/resource_openstack_lb_member_v1.go b/builtin/providers/openstack/resource_openstack_lb_member_v1.go index 0a6f478b79..6fab4df80f 100644 --- a/builtin/providers/openstack/resource_openstack_lb_member_v1.go +++ b/builtin/providers/openstack/resource_openstack_lb_member_v1.go @@ -97,6 +97,7 @@ func resourceLBMemberV1Read(d *schema.ResourceData, meta interface{}) error { log.Printf("[DEBUG] Retreived OpenStack LB Member %s: %+v", d.Id(), p) + d.Set("region", d.Get("region").(string)) d.Set("address", p.Address) d.Set("port", p.ProtocolPort) d.Set("pool_id", p.PoolID) diff --git a/builtin/providers/openstack/resource_openstack_lb_monitor_v1.go b/builtin/providers/openstack/resource_openstack_lb_monitor_v1.go index 9d82e7e268..7883aa7dc6 100644 --- a/builtin/providers/openstack/resource_openstack_lb_monitor_v1.go +++ b/builtin/providers/openstack/resource_openstack_lb_monitor_v1.go @@ -131,6 +131,7 @@ func resourceLBMonitorV1Read(d *schema.ResourceData, meta interface{}) error { log.Printf("[DEBUG] Retreived OpenStack LB Monitor %s: %+v", d.Id(), m) + d.Set("region", d.Get("region").(string)) d.Set("type", m.Type) d.Set("delay", m.Delay) d.Set("timeout", m.Timeout) diff --git a/builtin/providers/openstack/resource_openstack_lb_pool_v1.go b/builtin/providers/openstack/resource_openstack_lb_pool_v1.go index c5275c6e89..219608eaff 100644 --- a/builtin/providers/openstack/resource_openstack_lb_pool_v1.go +++ b/builtin/providers/openstack/resource_openstack_lb_pool_v1.go @@ -118,6 +118,7 @@ func resourceLBPoolV1Read(d *schema.ResourceData, meta interface{}) error { log.Printf("[DEBUG] Retreived OpenStack LB Pool %s: %+v", d.Id(), p) + d.Set("region", d.Get("region").(string)) d.Set("name", p.Name) d.Set("protocol", p.Protocol) d.Set("subnet_id", p.SubnetID) diff --git a/builtin/providers/openstack/resource_openstack_lb_vip_v1.go b/builtin/providers/openstack/resource_openstack_lb_vip_v1.go index 9c49b32765..83ba829c58 100644 --- a/builtin/providers/openstack/resource_openstack_lb_vip_v1.go +++ b/builtin/providers/openstack/resource_openstack_lb_vip_v1.go @@ -143,6 +143,7 @@ func resourceLBVipV1Read(d *schema.ResourceData, meta interface{}) error { log.Printf("[DEBUG] Retreived OpenStack LB VIP %s: %+v", d.Id(), p) + d.Set("region", d.Get("region").(string)) d.Set("name", p.Name) d.Set("subnet_id", p.SubnetID) d.Set("protocol", p.Protocol) diff --git a/builtin/providers/openstack/resource_openstack_networking_network_v2.go b/builtin/providers/openstack/resource_openstack_networking_network_v2.go index 3c33315c79..ebb95efa48 100644 --- a/builtin/providers/openstack/resource_openstack_networking_network_v2.go +++ b/builtin/providers/openstack/resource_openstack_networking_network_v2.go @@ -109,6 +109,8 @@ func resourceNetworkingNetworkV2Read(d *schema.ResourceData, meta interface{}) e log.Printf("[DEBUG] Retreived Network %s: %+v", d.Id(), n) + d.Set("region", d.Get("region").(string)) + if _, exists := d.GetOk("name"); exists { if d.HasChange("name") { d.Set("name", n.Name) diff --git a/builtin/providers/openstack/resource_openstack_networking_subnet_v2.go b/builtin/providers/openstack/resource_openstack_networking_subnet_v2.go index af25c4497f..d84f532db2 100644 --- a/builtin/providers/openstack/resource_openstack_networking_subnet_v2.go +++ b/builtin/providers/openstack/resource_openstack_networking_subnet_v2.go @@ -166,6 +166,7 @@ func resourceNetworkingSubnetV2Read(d *schema.ResourceData, meta interface{}) er log.Printf("[DEBUG] Retreived Subnet %s: %+v", d.Id(), s) + d.Set("region", d.Get("region").(string)) d.Set("newtork_id", s.NetworkID) d.Set("cidr", s.CIDR) d.Set("ip_version", s.IPVersion) From d51ee3111e4b7b53d03537530857b2f9ef64be93 Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Mon, 26 Jan 2015 12:59:38 -0700 Subject: [PATCH 040/132] always need both name and description when updating --- .../openstack/resource_openstack_compute_secgroup_v2.go | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/builtin/providers/openstack/resource_openstack_compute_secgroup_v2.go b/builtin/providers/openstack/resource_openstack_compute_secgroup_v2.go index c896865757..5f61c267ff 100644 --- a/builtin/providers/openstack/resource_openstack_compute_secgroup_v2.go +++ b/builtin/providers/openstack/resource_openstack_compute_secgroup_v2.go @@ -92,12 +92,9 @@ func resourceComputeSecGroupV2Update(d *schema.ResourceData, meta interface{}) e return fmt.Errorf("Error creating OpenStack compute client: %s", err) } - var updateOpts secgroups.UpdateOpts - if d.HasChange("name") { - updateOpts.Name = d.Get("name").(string) - } - if d.HasChange("description") { - updateOpts.Description = d.Get("description").(string) + updateOpts := secgroups.UpdateOpts{ + Name: d.Get("name").(string), + Description: d.Get("description").(string), } log.Printf("[DEBUG] Updating Security Group (%s) with options: %+v", d.Id(), updateOpts) From 5d2fe153c0149bed505bb6fd817a563ea803e59e Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Mon, 26 Jan 2015 15:45:05 -0700 Subject: [PATCH 041/132] go fmt --- builtin/providers/openstack/provider.go | 36 +++++++++---------- .../resource_openstack_compute_instance_v2.go | 22 +++++------- .../resource_openstack_compute_keypair_v2.go | 1 - .../resource_openstack_compute_secgroup_v2.go | 3 +- .../resource_openstack_lb_pool_v1.go | 2 +- ...esource_openstack_networking_network_v2.go | 7 ++-- ...resource_openstack_networking_subnet_v2.go | 3 +- 7 files changed, 32 insertions(+), 42 deletions(-) diff --git a/builtin/providers/openstack/provider.go b/builtin/providers/openstack/provider.go index 53f63f5d70..48029afc72 100644 --- a/builtin/providers/openstack/provider.go +++ b/builtin/providers/openstack/provider.go @@ -22,19 +22,19 @@ func Provider() terraform.ResourceProvider { DefaultFunc: envDefaultFunc("OS_USERNAME"), }, "user_id": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Default: "", + Type: schema.TypeString, + Optional: true, + Default: "", }, "tenant_id": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Default: "", + Type: schema.TypeString, + Optional: true, + Default: "", }, "tenant_name": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Default: "", + Type: schema.TypeString, + Optional: true, + Default: "", }, "password": &schema.Schema{ Type: schema.TypeString, @@ -42,19 +42,19 @@ func Provider() terraform.ResourceProvider { DefaultFunc: envDefaultFunc("OS_PASSWORD"), }, "api_key": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Default: "", + Type: schema.TypeString, + Optional: true, + Default: "", }, "domain_id": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Default: "", + Type: schema.TypeString, + Optional: true, + Default: "", }, "domain_name": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - Default: "", + Type: schema.TypeString, + Optional: true, + Default: "", }, }, diff --git a/builtin/providers/openstack/resource_openstack_compute_instance_v2.go b/builtin/providers/openstack/resource_openstack_compute_instance_v2.go index 660679a0ba..5d87e2cb54 100644 --- a/builtin/providers/openstack/resource_openstack_compute_instance_v2.go +++ b/builtin/providers/openstack/resource_openstack_compute_instance_v2.go @@ -28,7 +28,6 @@ func resourceComputeInstanceV2() *schema.Resource { Type: schema.TypeString, Required: true, ForceNew: true, - DefaultFunc: envDefaultFunc("OS_REGION_NAME"), }, "name": &schema.Schema{ Type: schema.TypeString, @@ -125,7 +124,6 @@ func resourceComputeInstanceV2Create(d *schema.ResourceData, meta interface{}) e return fmt.Errorf("Error creating OpenStack compute client: %s", err) } - var createOpts servers.CreateOptsBuilder serverCreateOpts := &servers.CreateOpts{ @@ -228,20 +226,16 @@ func resourceComputeInstanceV2Read(d *schema.ResourceData, meta interface{}) err d.Set("metadata", server.Metadata) - var currentSG []string err = secgroups.ListByServer(computeClient, d.Id()).EachPage(func(page pagination.Page) (bool, error) { secGrpList, err := secgroups.ExtractSecurityGroups(page) if err != nil { - return false, fmt.Errorf("Error setting security groups for OpenStack server: %s", err) + return false, fmt.Errorf("Error getting security groups for OpenStack server: %s", err) } - - for _, sg := range secGrpList { - currentSG = append(currentSG, sg.Name) + for i, sg := range secGrpList { + d.Set(fmt.Sprintf("security_groups.%d", i), sg.Name) } - return true, nil }) - d.Set("security_groups", currentSG) newFlavor, ok := server.Flavor["id"].(string) if !ok { @@ -272,11 +266,11 @@ func resourceComputeInstanceV2Update(d *schema.ResourceData, meta interface{}) e updateOpts.AccessIPv4 = d.Get("access_ip_v6").(string) } - log.Printf("[DEBUG] Updating Server %s with options: %+v", d.Id(), updateOpts) - - _, err = servers.Update(computeClient, d.Id(), updateOpts).Extract() - if err != nil { - return fmt.Errorf("Error updating OpenStack server: %s", err) + if updateOpts != (servers.UpdateOpts{}) { + _, err := servers.Update(computeClient, d.Id(), updateOpts).Extract() + if err != nil { + return fmt.Errorf("Error updating OpenStack server: %s", err) + } } if d.HasChange("metadata") { diff --git a/builtin/providers/openstack/resource_openstack_compute_keypair_v2.go b/builtin/providers/openstack/resource_openstack_compute_keypair_v2.go index e2d189a070..11cca95ba4 100644 --- a/builtin/providers/openstack/resource_openstack_compute_keypair_v2.go +++ b/builtin/providers/openstack/resource_openstack_compute_keypair_v2.go @@ -20,7 +20,6 @@ func resourceComputeKeypairV2() *schema.Resource { Type: schema.TypeString, Required: true, ForceNew: true, - DefaultFunc: envDefaultFunc("OS_REGION_NAME"), }, "name": &schema.Schema{ Type: schema.TypeString, diff --git a/builtin/providers/openstack/resource_openstack_compute_secgroup_v2.go b/builtin/providers/openstack/resource_openstack_compute_secgroup_v2.go index 5f61c267ff..7dcbb48fb4 100644 --- a/builtin/providers/openstack/resource_openstack_compute_secgroup_v2.go +++ b/builtin/providers/openstack/resource_openstack_compute_secgroup_v2.go @@ -22,7 +22,6 @@ func resourceComputeSecGroupV2() *schema.Resource { Type: schema.TypeString, Required: true, ForceNew: true, - DefaultFunc: envDefaultFunc("OS_REGION_NAME"), }, "name": &schema.Schema{ Type: schema.TypeString, @@ -93,7 +92,7 @@ func resourceComputeSecGroupV2Update(d *schema.ResourceData, meta interface{}) e } updateOpts := secgroups.UpdateOpts{ - Name: d.Get("name").(string), + Name: d.Get("name").(string), Description: d.Get("description").(string), } diff --git a/builtin/providers/openstack/resource_openstack_lb_pool_v1.go b/builtin/providers/openstack/resource_openstack_lb_pool_v1.go index 219608eaff..674110a8fe 100644 --- a/builtin/providers/openstack/resource_openstack_lb_pool_v1.go +++ b/builtin/providers/openstack/resource_openstack_lb_pool_v1.go @@ -4,8 +4,8 @@ import ( "fmt" "log" - "github.com/hashicorp/terraform/helper/schema" "github.com/hashicorp/terraform/helper/hashcode" + "github.com/hashicorp/terraform/helper/schema" "github.com/rackspace/gophercloud" "github.com/rackspace/gophercloud/openstack" "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/lbaas/pools" diff --git a/builtin/providers/openstack/resource_openstack_networking_network_v2.go b/builtin/providers/openstack/resource_openstack_networking_network_v2.go index ebb95efa48..3119baaddb 100644 --- a/builtin/providers/openstack/resource_openstack_networking_network_v2.go +++ b/builtin/providers/openstack/resource_openstack_networking_network_v2.go @@ -20,10 +20,9 @@ func resourceNetworkingNetworkV2() *schema.Resource { Schema: map[string]*schema.Schema{ "region": &schema.Schema{ - Type: schema.TypeString, - Required: true, - ForceNew: true, - DefaultFunc: envDefaultFunc("OS_REGION_NAME"), + Type: schema.TypeString, + Required: true, + ForceNew: true, }, "name": &schema.Schema{ Type: schema.TypeString, diff --git a/builtin/providers/openstack/resource_openstack_networking_subnet_v2.go b/builtin/providers/openstack/resource_openstack_networking_subnet_v2.go index d84f532db2..ecb2a4ea36 100644 --- a/builtin/providers/openstack/resource_openstack_networking_subnet_v2.go +++ b/builtin/providers/openstack/resource_openstack_networking_subnet_v2.go @@ -5,8 +5,8 @@ import ( "log" "strconv" - "github.com/hashicorp/terraform/helper/schema" "github.com/hashicorp/terraform/helper/hashcode" + "github.com/hashicorp/terraform/helper/schema" "github.com/rackspace/gophercloud" "github.com/rackspace/gophercloud/openstack" "github.com/rackspace/gophercloud/openstack/networking/v2/subnets" @@ -24,7 +24,6 @@ func resourceNetworkingSubnetV2() *schema.Resource { Type: schema.TypeString, Required: true, ForceNew: true, - DefaultFunc: envDefaultFunc("OS_REGION_NAME"), }, "network_id": &schema.Schema{ Type: schema.TypeString, From d86cb6be1c540db76adf496a012a26d1a88d138b Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Mon, 26 Jan 2015 18:28:01 -0700 Subject: [PATCH 042/132] fix diff bug in 'Read' functions --- .../resource_openstack_compute_instance_v2.go | 8 +++-- .../resource_openstack_compute_keypair_v2.go | 1 + .../resource_openstack_compute_secgroup_v2.go | 1 + .../resource_openstack_lb_member_v1.go | 6 ++-- .../resource_openstack_lb_monitor_v1.go | 30 ++++++---------- .../resource_openstack_lb_pool_v1.go | 6 ++-- .../openstack/resource_openstack_lb_vip_v1.go | 34 ++++++------------- ...esource_openstack_networking_network_v2.go | 25 +++++--------- ...resource_openstack_networking_subnet_v2.go | 25 +++++--------- 9 files changed, 51 insertions(+), 85 deletions(-) diff --git a/builtin/providers/openstack/resource_openstack_compute_instance_v2.go b/builtin/providers/openstack/resource_openstack_compute_instance_v2.go index 5d87e2cb54..f6a922f43d 100644 --- a/builtin/providers/openstack/resource_openstack_compute_instance_v2.go +++ b/builtin/providers/openstack/resource_openstack_compute_instance_v2.go @@ -28,6 +28,7 @@ func resourceComputeInstanceV2() *schema.Resource { Type: schema.TypeString, Required: true, ForceNew: true, + DefaultFunc: envDefaultFunc("OS_REGION_NAME"), }, "name": &schema.Schema{ Type: schema.TypeString, @@ -226,16 +227,19 @@ func resourceComputeInstanceV2Read(d *schema.ResourceData, meta interface{}) err d.Set("metadata", server.Metadata) + secGrpNum := 0 err = secgroups.ListByServer(computeClient, d.Id()).EachPage(func(page pagination.Page) (bool, error) { secGrpList, err := secgroups.ExtractSecurityGroups(page) if err != nil { return false, fmt.Errorf("Error getting security groups for OpenStack server: %s", err) } - for i, sg := range secGrpList { - d.Set(fmt.Sprintf("security_groups.%d", i), sg.Name) + for _, sg := range secGrpList { + d.Set(fmt.Sprintf("security_groups.%d", secGrpNum), sg.Name) + secGrpNum++ } return true, nil }) + d.Set("security_groups.#", secGrpNum) newFlavor, ok := server.Flavor["id"].(string) if !ok { diff --git a/builtin/providers/openstack/resource_openstack_compute_keypair_v2.go b/builtin/providers/openstack/resource_openstack_compute_keypair_v2.go index 11cca95ba4..e2d189a070 100644 --- a/builtin/providers/openstack/resource_openstack_compute_keypair_v2.go +++ b/builtin/providers/openstack/resource_openstack_compute_keypair_v2.go @@ -20,6 +20,7 @@ func resourceComputeKeypairV2() *schema.Resource { Type: schema.TypeString, Required: true, ForceNew: true, + DefaultFunc: envDefaultFunc("OS_REGION_NAME"), }, "name": &schema.Schema{ Type: schema.TypeString, diff --git a/builtin/providers/openstack/resource_openstack_compute_secgroup_v2.go b/builtin/providers/openstack/resource_openstack_compute_secgroup_v2.go index 7dcbb48fb4..a79a6a88b4 100644 --- a/builtin/providers/openstack/resource_openstack_compute_secgroup_v2.go +++ b/builtin/providers/openstack/resource_openstack_compute_secgroup_v2.go @@ -22,6 +22,7 @@ func resourceComputeSecGroupV2() *schema.Resource { Type: schema.TypeString, Required: true, ForceNew: true, + DefaultFunc: envDefaultFunc("OS_REGION_NAME"), }, "name": &schema.Schema{ Type: schema.TypeString, diff --git a/builtin/providers/openstack/resource_openstack_lb_member_v1.go b/builtin/providers/openstack/resource_openstack_lb_member_v1.go index 6fab4df80f..2d615ed765 100644 --- a/builtin/providers/openstack/resource_openstack_lb_member_v1.go +++ b/builtin/providers/openstack/resource_openstack_lb_member_v1.go @@ -102,10 +102,8 @@ func resourceLBMemberV1Read(d *schema.ResourceData, meta interface{}) error { d.Set("port", p.ProtocolPort) d.Set("pool_id", p.PoolID) - if _, exists := d.GetOk("tenant_id"); exists { - if d.HasChange("tenant_id") { - d.Set("tenant_id", p.TenantID) - } + if t, exists := d.GetOk("tenant_id"); exists && t != "" { + d.Set("tenant_id", p.TenantID) } else { d.Set("tenant_id", "") } diff --git a/builtin/providers/openstack/resource_openstack_lb_monitor_v1.go b/builtin/providers/openstack/resource_openstack_lb_monitor_v1.go index 7883aa7dc6..f6c097d23c 100644 --- a/builtin/providers/openstack/resource_openstack_lb_monitor_v1.go +++ b/builtin/providers/openstack/resource_openstack_lb_monitor_v1.go @@ -137,42 +137,32 @@ func resourceLBMonitorV1Read(d *schema.ResourceData, meta interface{}) error { d.Set("timeout", m.Timeout) d.Set("max_retries", m.MaxRetries) - if _, exists := d.GetOk("tenant_id"); exists { - if d.HasChange("tenant_id") { - d.Set("tenant_id", m.TenantID) - } + if t, exists := d.GetOk("tenant_id"); exists && t != "" { + d.Set("tenant_id", m.TenantID) } else { d.Set("tenant_id", "") } - if _, exists := d.GetOk("url_path"); exists { - if d.HasChange("url_path") { - d.Set("url_path", m.URLPath) - } + if t, exists := d.GetOk("url_path"); exists && t != "" { + d.Set("url_path", m.URLPath) } else { d.Set("url_path", "") } - if _, exists := d.GetOk("http_method"); exists { - if d.HasChange("http_method") { - d.Set("http_method", m.HTTPMethod) - } + if t, exists := d.GetOk("http_method"); exists && t != "" { + d.Set("http_method", m.HTTPMethod) } else { d.Set("http_method", "") } - if _, exists := d.GetOk("expected_codes"); exists { - if d.HasChange("expected_codes") { - d.Set("expected_codes", m.ExpectedCodes) - } + if t, exists := d.GetOk("expected_codes"); exists && t != "" { + d.Set("expected_codes", m.ExpectedCodes) } else { d.Set("expected_codes", "") } - if _, exists := d.GetOk("admin_state_up"); exists { - if d.HasChange("admin_state_up") { - d.Set("admin_state_up", strconv.FormatBool(m.AdminStateUp)) - } + if t, exists := d.GetOk("admin_state_up"); exists && t != "" { + d.Set("admin_state_up", strconv.FormatBool(m.AdminStateUp)) } else { d.Set("admin_state_up", "") } diff --git a/builtin/providers/openstack/resource_openstack_lb_pool_v1.go b/builtin/providers/openstack/resource_openstack_lb_pool_v1.go index 674110a8fe..6ca79a802f 100644 --- a/builtin/providers/openstack/resource_openstack_lb_pool_v1.go +++ b/builtin/providers/openstack/resource_openstack_lb_pool_v1.go @@ -124,10 +124,8 @@ func resourceLBPoolV1Read(d *schema.ResourceData, meta interface{}) error { d.Set("subnet_id", p.SubnetID) d.Set("lb_method", p.LBMethod) - if _, exists := d.GetOk("tenant_id"); exists { - if d.HasChange("tenant_id") { - d.Set("tenant_id", p.TenantID) - } + if t, exists := d.GetOk("tenant_id"); exists && t != "" { + d.Set("tenant_id", p.TenantID) } else { d.Set("tenant_id", "") } diff --git a/builtin/providers/openstack/resource_openstack_lb_vip_v1.go b/builtin/providers/openstack/resource_openstack_lb_vip_v1.go index 83ba829c58..748ed8d6a1 100644 --- a/builtin/providers/openstack/resource_openstack_lb_vip_v1.go +++ b/builtin/providers/openstack/resource_openstack_lb_vip_v1.go @@ -150,48 +150,36 @@ func resourceLBVipV1Read(d *schema.ResourceData, meta interface{}) error { d.Set("port", p.ProtocolPort) d.Set("pool_id", p.PoolID) - if _, exists := d.GetOk("tenant_id"); exists { - if d.HasChange("tenant_id") { - d.Set("tenant_id", p.TenantID) - } + if t, exists := d.GetOk("tenant_id"); exists && t != "" { + d.Set("tenant_id", p.TenantID) } else { d.Set("tenant_id", "") } - if _, exists := d.GetOk("address"); exists { - if d.HasChange("address") { - d.Set("address", p.Address) - } + if t, exists := d.GetOk("address"); exists && t != "" { + d.Set("address", p.Address) } else { d.Set("address", "") } - if _, exists := d.GetOk("description"); exists { - if d.HasChange("description") { - d.Set("description", p.Description) - } + if t, exists := d.GetOk("description"); exists && t != "" { + d.Set("description", p.Description) } else { d.Set("description", "") } - if _, exists := d.GetOk("persistence"); exists { - if d.HasChange("persistence") { + if t, exists := d.GetOk("persistence"); exists && t != "" { d.Set("persistence", p.Description) - } } - if _, exists := d.GetOk("conn_limit"); exists { - if d.HasChange("conn_limit") { - d.Set("conn_limit", p.ConnLimit) - } + if t, exists := d.GetOk("conn_limit"); exists && t != "" { + d.Set("conn_limit", p.ConnLimit) } else { d.Set("conn_limit", "") } - if _, exists := d.GetOk("admin_state_up"); exists { - if d.HasChange("admin_state_up") { - d.Set("admin_state_up", strconv.FormatBool(p.AdminStateUp)) - } + if t, exists := d.GetOk("admin_state_up"); exists && t != "" { + d.Set("admin_state_up", strconv.FormatBool(p.AdminStateUp)) } else { d.Set("admin_state_up", "") } diff --git a/builtin/providers/openstack/resource_openstack_networking_network_v2.go b/builtin/providers/openstack/resource_openstack_networking_network_v2.go index 3119baaddb..92e02e0319 100644 --- a/builtin/providers/openstack/resource_openstack_networking_network_v2.go +++ b/builtin/providers/openstack/resource_openstack_networking_network_v2.go @@ -23,6 +23,7 @@ func resourceNetworkingNetworkV2() *schema.Resource { Type: schema.TypeString, Required: true, ForceNew: true, + DefaultFunc: envDefaultFunc("OS_REGION_NAME"), }, "name": &schema.Schema{ Type: schema.TypeString, @@ -110,34 +111,26 @@ func resourceNetworkingNetworkV2Read(d *schema.ResourceData, meta interface{}) e d.Set("region", d.Get("region").(string)) - if _, exists := d.GetOk("name"); exists { - if d.HasChange("name") { - d.Set("name", n.Name) - } + if t, exists := d.GetOk("name"); exists && t != ""{ + d.Set("name", n.Name) } else { d.Set("name", "") } - if _, exists := d.GetOk("admin_state_up"); exists { - if d.HasChange("admin_state_up") { - d.Set("admin_state_up", strconv.FormatBool(n.AdminStateUp)) - } + if t, exists := d.GetOk("admin_state_up"); exists && t != "" { + d.Set("admin_state_up", strconv.FormatBool(n.AdminStateUp)) } else { d.Set("admin_state_up", "") } - if _, exists := d.GetOk("shared"); exists { - if d.HasChange("shared") { - d.Set("shared", strconv.FormatBool(n.Shared)) - } + if t, exists := d.GetOk("shared"); exists && t != "" { + d.Set("shared", strconv.FormatBool(n.Shared)) } else { d.Set("shared", "") } - if _, exists := d.GetOk("tenant_id"); exists { - if d.HasChange("tenant_id") { - d.Set("tenant_id", n.TenantID) - } + if t, exists := d.GetOk("tenant_id"); exists && t != "" { + d.Set("tenant_id", n.TenantID) } else { d.Set("tenant_id", "") } diff --git a/builtin/providers/openstack/resource_openstack_networking_subnet_v2.go b/builtin/providers/openstack/resource_openstack_networking_subnet_v2.go index ecb2a4ea36..0e72ce98d1 100644 --- a/builtin/providers/openstack/resource_openstack_networking_subnet_v2.go +++ b/builtin/providers/openstack/resource_openstack_networking_subnet_v2.go @@ -24,6 +24,7 @@ func resourceNetworkingSubnetV2() *schema.Resource { Type: schema.TypeString, Required: true, ForceNew: true, + DefaultFunc: envDefaultFunc("OS_REGION_NAME"), }, "network_id": &schema.Schema{ Type: schema.TypeString, @@ -170,18 +171,14 @@ func resourceNetworkingSubnetV2Read(d *schema.ResourceData, meta interface{}) er d.Set("cidr", s.CIDR) d.Set("ip_version", s.IPVersion) - if _, exists := d.GetOk("name"); exists { - if d.HasChange("name") { - d.Set("name", s.Name) - } + if t, exists := d.GetOk("name"); exists && t != "" { + d.Set("name", s.Name) } else { d.Set("name", "") } - if _, exists := d.GetOk("tenant_id"); exists { - if d.HasChange("tenant_id") { - d.Set("tenant_id", s.Name) - } + if t, exists := d.GetOk("tenant_id"); exists && t != "" { + d.Set("tenant_id", s.TenantID) } else { d.Set("tenant_id", "") } @@ -190,18 +187,14 @@ func resourceNetworkingSubnetV2Read(d *schema.ResourceData, meta interface{}) er d.Set("allocation_pools", s.AllocationPools) } - if _, exists := d.GetOk("gateway_ip"); exists { - if d.HasChange("gateway_ip") { - d.Set("gateway_ip", s.Name) - } + if t, exists := d.GetOk("gateway_ip"); exists && t != "" { + d.Set("gateway_ip", s.GatewayIP) } else { d.Set("gateway_ip", "") } - if _, exists := d.GetOk("enable_dhcp"); exists { - if d.HasChange("enable_dhcp") { - d.Set("enable_dhcp", strconv.FormatBool(s.EnableDHCP)) - } + if t, exists := d.GetOk("enable_dhcp"); exists && t != "" { + d.Set("enable_dhcp", strconv.FormatBool(s.EnableDHCP)) } else { d.Set("enable_dhcp", "") } From d80a02c12d9710ec934429839af6dbd23c5707a6 Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Mon, 26 Jan 2015 19:26:53 -0700 Subject: [PATCH 043/132] update docs to reflect resource region and versioning --- .../providers/openstack/index.html.markdown | 27 ++++++++----- ...down => compute_instance_v2.html.markdown} | 17 +++++--- ...kdown => compute_keypair_v2.html.markdown} | 18 ++++++--- ...down => compute_secgroup_v2.html.markdown} | 18 ++++++--- ... => compute_secgrouprule_v2.html.markdown} | 22 ++++++---- ...ml.markdown => lb_member_v1.html.markdown} | 20 ++++++---- ...l.markdown => lb_monitor_v1.html.markdown} | 18 ++++++--- ...html.markdown => lb_pool_v1.html.markdown} | 18 ++++++--- ....html.markdown => lb_vip_v1.html.markdown} | 18 ++++++--- ...wn => networking_network_v2.html.markdown} | 18 ++++++--- ...own => networking_subnet_v2.html.markdown} | 22 ++++++---- website/source/layouts/openstack.erb | 40 +++++++++---------- 12 files changed, 161 insertions(+), 95 deletions(-) rename website/source/docs/providers/openstack/r/{compute_instance.html.markdown => compute_instance_v2.html.markdown} (81%) rename website/source/docs/providers/openstack/r/{compute_keypair.html.markdown => compute_keypair_v2.html.markdown} (59%) rename website/source/docs/providers/openstack/r/{compute_secgroup.html.markdown => compute_secgroup_v2.html.markdown} (50%) rename website/source/docs/providers/openstack/r/{compute_secgrouprule.html.markdown => compute_secgrouprule_v2.html.markdown} (67%) rename website/source/docs/providers/openstack/r/{lb_member.html.markdown => lb_member_v1.html.markdown} (65%) rename website/source/docs/providers/openstack/r/{lb_monitor.html.markdown => lb_monitor_v1.html.markdown} (80%) rename website/source/docs/providers/openstack/r/{lb_pool.html.markdown => lb_pool_v1.html.markdown} (72%) rename website/source/docs/providers/openstack/r/{lb_vip.html.markdown => lb_vip_v1.html.markdown} (82%) rename website/source/docs/providers/openstack/r/{networking_network.html.markdown => networking_network_v2.html.markdown} (63%) rename website/source/docs/providers/openstack/r/{networking_subnet.html.markdown => networking_subnet_v2.html.markdown} (78%) diff --git a/website/source/docs/providers/openstack/index.html.markdown b/website/source/docs/providers/openstack/index.html.markdown index 652523c5b4..da6d1fb79d 100644 --- a/website/source/docs/providers/openstack/index.html.markdown +++ b/website/source/docs/providers/openstack/index.html.markdown @@ -19,15 +19,14 @@ Use the navigation to the left to read about the available resources. ``` # Configure the OpenStack Provider provider "openstack" { - username = "admin" + user_name = "admin" tenant_name = "admin" password = "pwd" auth_url = "http://myauthurl:5000/v2.0" - region = "RegionOne" } # Create a web server -resource "openstack_compute_instance" "test-server" { +resource "openstack_compute_instance_v2" "test-server" { ... } ``` @@ -36,12 +35,20 @@ resource "openstack_compute_instance" "test-server" { The following arguments are supported: -* `username` - (Required) - -* `tenant_name` - (Required) - -* `password` - (Required) - * `auth_url` - (Required) -* `region` - (Required) +* `user_name` - (Optional; Required for Identity V2) + +* `user_id` - (Optional) + +* `password` - (Optional; Required if not using `api_key`) + +* `api_key` - (Optional; Required if not using `password`) + +* `domain_id` - (Optional) + +* `domain_name` - (Optional) + +* `tenant_id` - (Optional) + +* `tenant_name` - (Optional) diff --git a/website/source/docs/providers/openstack/r/compute_instance.html.markdown b/website/source/docs/providers/openstack/r/compute_instance_v2.html.markdown similarity index 81% rename from website/source/docs/providers/openstack/r/compute_instance.html.markdown rename to website/source/docs/providers/openstack/r/compute_instance_v2.html.markdown index 7de1cd1b90..4429174fb4 100644 --- a/website/source/docs/providers/openstack/r/compute_instance.html.markdown +++ b/website/source/docs/providers/openstack/r/compute_instance_v2.html.markdown @@ -1,19 +1,19 @@ --- layout: "openstack" -page_title: "OpenStack: openstack_compute_instance" -sidebar_current: "docs-openstack-resource-compute-instance" +page_title: "OpenStack: openstack_compute_instance_v2" +sidebar_current: "docs-openstack-resource-compute-instance-v2" description: |- - Manages a VM instance resource within OpenStack. + Manages a V2 VM instance resource within OpenStack. --- -# openstack\_compute\_instance +# openstack\_compute\_instance_v2 -Manages a VM instance resource within OpenStack. +Manages a V2 VM instance resource within OpenStack. ## Example Usage ``` -resource "openstack_compute_instance" "test-server" { +resource "openstack_compute_instance_v2" "test-server" { name = "tf-test" image_ref = "ad091b52-742f-469e-8f3c-fd81cadf0743" flavor_ref = "3" @@ -29,6 +29,10 @@ resource "openstack_compute_instance" "test-server" { The following arguments are supported: +* `region` - (Required) The region in which to create the server instance. If + omitted, the `OS_REGION_NAME` environment variable is used. Changing this + creates a new server. + * `name` - (Required) A unique name for the resource. * `image_ref` - (Required) The image reference (ID) for the desired image for @@ -73,6 +77,7 @@ The `network` block supports: The following attributes are exported: +* `region` - See Argument Reference above. * `name` - See Argument Reference above. * `access_ip_v4` - See Argument Reference above. * `access_ip_v6` - See Argument Reference above. diff --git a/website/source/docs/providers/openstack/r/compute_keypair.html.markdown b/website/source/docs/providers/openstack/r/compute_keypair_v2.html.markdown similarity index 59% rename from website/source/docs/providers/openstack/r/compute_keypair.html.markdown rename to website/source/docs/providers/openstack/r/compute_keypair_v2.html.markdown index 15459a0ec7..0c3beae279 100644 --- a/website/source/docs/providers/openstack/r/compute_keypair.html.markdown +++ b/website/source/docs/providers/openstack/r/compute_keypair_v2.html.markdown @@ -1,19 +1,19 @@ --- layout: "openstack" -page_title: "OpenStack: openstack_compute_keypair" -sidebar_current: "docs-openstack-resource-compute-keypair" +page_title: "OpenStack: openstack_compute_keypair_v2" +sidebar_current: "docs-openstack-resource-compute-keypair-v2" description: |- - Manages a keypair resource within OpenStack. + Manages a V2 keypair resource within OpenStack. --- -# openstack\_compute\_keypair +# openstack\_compute\_keypair_v2 -Manages a keypair resource within OpenStack. +Manages a V2 keypair resource within OpenStack. ## Example Usage ``` -resource "openstack_compute_keypair" "test-keypair" { +resource "openstack_compute_keypair_v2" "test-keypair" { name = "my-keypair" public_key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDAjpC1hwiOCCmKEWxJ4qzTTsJbKzndLotBCz5PcwtUnflmU+gHJtWMZKpuEGVi29h0A/+ydKek1O18k10Ff+4tyFjiHDQAnOfgWf7+b1yK+qDip3X1C0UPMbwHlTfSGWLGZqd9LvEFx9k3h/M+VtMvwR1lJ9LUyTAImnNjWG7TaIPmui30HvM2UiFEmqkr4ijq45MyX2+fLIePLRIF61p4whjHAQYufqyno3BS48icQb4p6iVEZPo4AE2o9oIyQvj2mx4dk5Y8CgSETOZTYDOR3rU2fZTRDRgPJDH9FWvQjF5tA0p3d9CoWWd2s6GKKbfoUIi8R/Db1BSPJwkqB" } @@ -23,6 +23,11 @@ resource "openstack_compute_keypair" "test-keypair" { The following arguments are supported: +* `region` - (Required) The region in which to obtain the V2 Compute client. + Keypairs are associated with accounts, but a Compute client is needed to + create one. If omitted, the `OS_REGION_NAME` environment variable is used. + Changing this creates a new keypair. + * `name` - (Required) A unique name for the keypair. Changing this creates a new keypair. @@ -33,5 +38,6 @@ The following arguments are supported: The following attributes are exported: +* `region` - See Argument Reference above. * `name` - See Argument Reference above. * `public_key` - See Argument Reference above. diff --git a/website/source/docs/providers/openstack/r/compute_secgroup.html.markdown b/website/source/docs/providers/openstack/r/compute_secgroup_v2.html.markdown similarity index 50% rename from website/source/docs/providers/openstack/r/compute_secgroup.html.markdown rename to website/source/docs/providers/openstack/r/compute_secgroup_v2.html.markdown index 27045b62bb..86f546ed25 100644 --- a/website/source/docs/providers/openstack/r/compute_secgroup.html.markdown +++ b/website/source/docs/providers/openstack/r/compute_secgroup_v2.html.markdown @@ -1,19 +1,19 @@ --- layout: "openstack" -page_title: "OpenStack: openstack_compute_secgroup" -sidebar_current: "docs-openstack-resource-compute-secgroup" +page_title: "OpenStack: openstack_compute_secgroup_v2" +sidebar_current: "docs-openstack-resource-compute-secgroup-2" description: |- - Manages a security group resource within OpenStack. + Manages a V2 security group resource within OpenStack. --- -# openstack\_compute\_secgroup +# openstack\_compute\_secgroup_v2 -Manages a security group resource within OpenStack. +Manages a V2 security group resource within OpenStack. ## Example Usage ``` -resource "openstack_compute_secgroup" "secgroup_1" { +resource "openstack_compute_secgroup_v2" "secgroup_1" { name = "my_secgroup" description = "my security group" } @@ -23,6 +23,11 @@ resource "openstack_compute_secgroup" "secgroup_1" { The following arguments are supported: +* `region` - (Required) The region in which to obtain the V2 Compute client. + A Compute client is needed to create a security group. If omitted, the + `OS_REGION_NAME` environment variable is used. Changing this creates a new + security group. + * `name` - (Required) A unique name for the security group. Changing this updates the `name` of an existing security group. @@ -33,5 +38,6 @@ The following arguments are supported: The following attributes are exported: +* `region` - See Argument Reference above. * `name` - See Argument Reference above. * `description` - See Argument Reference above. diff --git a/website/source/docs/providers/openstack/r/compute_secgrouprule.html.markdown b/website/source/docs/providers/openstack/r/compute_secgrouprule_v2.html.markdown similarity index 67% rename from website/source/docs/providers/openstack/r/compute_secgrouprule.html.markdown rename to website/source/docs/providers/openstack/r/compute_secgrouprule_v2.html.markdown index 60ffb347cc..06385a6c87 100644 --- a/website/source/docs/providers/openstack/r/compute_secgrouprule.html.markdown +++ b/website/source/docs/providers/openstack/r/compute_secgrouprule_v2.html.markdown @@ -1,25 +1,25 @@ --- layout: "openstack" -page_title: "OpenStack: openstack_compute_secgrouprule" -sidebar_current: "docs-openstack-resource-compute-secgrouprule" +page_title: "OpenStack: openstack_compute_secgrouprule_v2" +sidebar_current: "docs-openstack-resource-compute-secgrouprule-v2" description: |- - Manages a security group rule resource within OpenStack. + Manages a V2 security group rule resource within OpenStack. --- -# openstack\_compute\_secgrouprule +# openstack\_compute\_secgrouprule_v2 -Manages a security group rule resource within OpenStack. +Manages a V2 security group rule resource within OpenStack. ## Example Usage ``` -resource "openstack_compute_secgroup" "secgroup_1" { +resource "openstack_compute_secgroup_v2" "secgroup_1" { name = "my_secgroup" description = "my security group" } -resource "openstack_compute_secgrouprule" "secgrouprule_1" { - group_id = "${openstack_compute_secgroup.secgroup_1.id}" +resource "openstack_compute_secgrouprule_v2" "secgrouprule_1" { + group_id = "${openstack_compute_secgroup_v2.secgroup_1.id}" from_port = 22 to_port = 22 ip_protocol = "TCP" @@ -31,6 +31,11 @@ resource "openstack_compute_secgrouprule" "secgrouprule_1" { The following arguments are supported: +* `region` - (Required) The region in which to obtain the V2 Compute client. + A Compute client is needed to create a security group rule. If omitted, the + `OS_REGION_NAME` environment variable is used. Changing this creates a new + security group rule. + * `group_id` - (Required) The ID of the group to which this rule will be added. Changing this creates a new security group rule. @@ -55,6 +60,7 @@ The following arguments are supported: The following attributes are exported: +* `region` - See Argument Reference above. * `group_id` - See Argument Reference above. * `from_port` - See Argument Reference above. * `to_port` - See Argument Reference above. diff --git a/website/source/docs/providers/openstack/r/lb_member.html.markdown b/website/source/docs/providers/openstack/r/lb_member_v1.html.markdown similarity index 65% rename from website/source/docs/providers/openstack/r/lb_member.html.markdown rename to website/source/docs/providers/openstack/r/lb_member_v1.html.markdown index 0607ca840c..2d1be74dc2 100644 --- a/website/source/docs/providers/openstack/r/lb_member.html.markdown +++ b/website/source/docs/providers/openstack/r/lb_member_v1.html.markdown @@ -1,22 +1,22 @@ --- layout: "openstack" -page_title: "OpenStack: openstack_lb_member" -sidebar_current: "docs-openstack-resource-lb-member" +page_title: "OpenStack: openstack_lb_member_v1" +sidebar_current: "docs-openstack-resource-lb-member-v1" description: |- - Manages a load balancer member resource within OpenStack. + Manages a V1 load balancer member resource within OpenStack. --- -# openstack\_lb\_member +# openstack\_lb\_member_v1 -Manages a load balancer member resource within OpenStack. +Manages a V1 load balancer member resource within OpenStack. ## Example Usage ``` -resource "openstack_lb_member" "node_1" { +resource "openstack_lb_member_v1" "node_1" { address = "196.172.0.1" port = 80 - pool_id = "$12345" + pool_id = "12345" admin_state_up = true } ``` @@ -25,6 +25,11 @@ resource "openstack_lb_member" "node_1" { The following arguments are supported: +* `region` - (Required) The region in which to obtain the V2 Networking client. + A Networking client is needed to create an LB member. If omitted, the + `OS_REGION_NAME` environment variable is used. Changing this creates a new + LB member. + * `address` - (Required) The IP address of the member. Changing this creates a new member. @@ -45,6 +50,7 @@ The following arguments are supported: The following attributes are exported: +* `region` - See Argument Reference above. * `address` - See Argument Reference above. * `port` - See Argument Reference above. * `pool_id` - See Argument Reference above. diff --git a/website/source/docs/providers/openstack/r/lb_monitor.html.markdown b/website/source/docs/providers/openstack/r/lb_monitor_v1.html.markdown similarity index 80% rename from website/source/docs/providers/openstack/r/lb_monitor.html.markdown rename to website/source/docs/providers/openstack/r/lb_monitor_v1.html.markdown index 36b8142749..cbf6b2b873 100644 --- a/website/source/docs/providers/openstack/r/lb_monitor.html.markdown +++ b/website/source/docs/providers/openstack/r/lb_monitor_v1.html.markdown @@ -1,19 +1,19 @@ --- layout: "openstack" -page_title: "OpenStack: openstack_lb_monitor" -sidebar_current: "docs-openstack-resource-lb-monitor" +page_title: "OpenStack: openstack_lb_monitor_v1" +sidebar_current: "docs-openstack-resource-lb-monitor-v1" description: |- - Manages a load balancer monitor resource within OpenStack. + Manages a V1 load balancer monitor resource within OpenStack. --- -# openstack\_lb\_monitor +# openstack\_lb\_monitor_v1 -Manages a load balancer monitor resource within OpenStack. +Manages a V1 load balancer monitor resource within OpenStack. ## Example Usage ``` -resource "openstack_lb_monitor" "monitor_1" { +resource "openstack_lb_monitor_v1" "monitor_1" { type = "PING" delay = 30 timeout = 5 @@ -26,6 +26,11 @@ resource "openstack_lb_monitor" "monitor_1" { The following arguments are supported: +* `region` - (Required) The region in which to obtain the V2 Networking client. + A Networking client is needed to create an LB monitor. If omitted, the + `OS_REGION_NAME` environment variable is used. Changing this creates a new + LB monitor. + * `type` - (Required) The type of probe, which is PING, TCP, HTTP, or HTTPS, that is sent by the monitor to verify the member state. Changing this creates a new monitor. @@ -65,6 +70,7 @@ The following arguments are supported: The following attributes are exported: +* `region` - See Argument Reference above. * `type` - See Argument Reference above. * `delay` - See Argument Reference above. * `timeout` - See Argument Reference above. diff --git a/website/source/docs/providers/openstack/r/lb_pool.html.markdown b/website/source/docs/providers/openstack/r/lb_pool_v1.html.markdown similarity index 72% rename from website/source/docs/providers/openstack/r/lb_pool.html.markdown rename to website/source/docs/providers/openstack/r/lb_pool_v1.html.markdown index 90e3ed0c93..f0de6917a2 100644 --- a/website/source/docs/providers/openstack/r/lb_pool.html.markdown +++ b/website/source/docs/providers/openstack/r/lb_pool_v1.html.markdown @@ -1,19 +1,19 @@ --- layout: "openstack" -page_title: "OpenStack: openstack_lb_pool" -sidebar_current: "docs-openstack-resource-lb-pool" +page_title: "OpenStack: openstack_lb_pool_v1" +sidebar_current: "docs-openstack-resource-lb-pool-v1" description: |- - Manages a load balancer pool resource within OpenStack. + Manages a V1 load balancer pool resource within OpenStack. --- -# openstack\_lb\_pool +# openstack\_lb\_pool_v1 -Manages a load balancer pool resource within OpenStack. +Manages a V1 load balancer pool resource within OpenStack. ## Example Usage ``` -resource "openstack_lb_pool" "pool_1" { +resource "openstack_lb_pool_v1" "pool_1" { name = "tf_test_lb_pool" protocol = "HTTP" subnet_id = "12345" @@ -26,6 +26,11 @@ resource "openstack_lb_pool" "pool_1" { The following arguments are supported: +* `region` - (Required) The region in which to obtain the V2 Networking client. + A Networking client is needed to create an LB pool. If omitted, the + `OS_REGION_NAME` environment variable is used. Changing this creates a new + LB pool. + * `name` - (Required) The name of the pool. Changing this updates the name of the existing pool. @@ -50,6 +55,7 @@ The following arguments are supported: The following attributes are exported: +* `region` - See Argument Reference above. * `name` - See Argument Reference above. * `protocol` - See Argument Reference above. * `subnet_id` - See Argument Reference above. diff --git a/website/source/docs/providers/openstack/r/lb_vip.html.markdown b/website/source/docs/providers/openstack/r/lb_vip_v1.html.markdown similarity index 82% rename from website/source/docs/providers/openstack/r/lb_vip.html.markdown rename to website/source/docs/providers/openstack/r/lb_vip_v1.html.markdown index 0eddcaa5f0..7a9bc3d4b0 100644 --- a/website/source/docs/providers/openstack/r/lb_vip.html.markdown +++ b/website/source/docs/providers/openstack/r/lb_vip_v1.html.markdown @@ -1,19 +1,19 @@ --- layout: "openstack" -page_title: "OpenStack: openstack_lb_vip" -sidebar_current: "docs-openstack-resource-lb-vip" +page_title: "OpenStack: openstack_lb_vip_v1" +sidebar_current: "docs-openstack-resource-lb-vip-v1" description: |- - Manages a load balancer vip resource within OpenStack. + Manages a V1 load balancer vip resource within OpenStack. --- -# openstack\_lb\_vip +# openstack\_lb\_vip_v1 -Manages a load balancer vip resource within OpenStack. +Manages a V1 load balancer vip resource within OpenStack. ## Example Usage ``` -resource "openstack_lb_vip" "vip_1" { +resource "openstack_lb_vip_v1" "vip_1" { name = "tf_test_lb_vip" subnet_id = "12345" protocol = "HTTP" @@ -26,6 +26,11 @@ resource "openstack_lb_vip" "vip_1" { The following arguments are supported: +* `region` - (Required) The region in which to obtain the V2 Networking client. + A Networking client is needed to create a VIP. If omitted, the + `OS_REGION_NAME` environment variable is used. Changing this creates a new + VIP. + * `name` - (Required) The name of the vip. Changing this updates the name of the existing vip. @@ -76,6 +81,7 @@ The `persistence` block supports: The following attributes are exported: +* `region` - See Argument Reference above. * `name` - See Argument Reference above. * `subnet_id` - See Argument Reference above. * `protocol` - See Argument Reference above. diff --git a/website/source/docs/providers/openstack/r/networking_network.html.markdown b/website/source/docs/providers/openstack/r/networking_network_v2.html.markdown similarity index 63% rename from website/source/docs/providers/openstack/r/networking_network.html.markdown rename to website/source/docs/providers/openstack/r/networking_network_v2.html.markdown index eb765cac0c..699cd1ae9b 100644 --- a/website/source/docs/providers/openstack/r/networking_network.html.markdown +++ b/website/source/docs/providers/openstack/r/networking_network_v2.html.markdown @@ -1,19 +1,19 @@ --- layout: "openstack" -page_title: "OpenStack: openstack_networking_network" -sidebar_current: "docs-openstack-resource-networking-network" +page_title: "OpenStack: openstack_networking_network_v2" +sidebar_current: "docs-openstack-resource-networking-network-v2" description: |- - Manages a Neutron network resource within OpenStack. + Manages a V2 Neutron network resource within OpenStack. --- -# openstack\_networking\_network +# openstack\_networking\_network_v2 -Manages a Neutron network resource within OpenStack. +Manages a V2 Neutron network resource within OpenStack. ## Example Usage ``` -resource "openstack_networking_network" "network_1" { +resource "openstack_networking_network_v2" "network_1" { name = "tf_test_network" admin_state_up = "true" } @@ -23,6 +23,11 @@ resource "openstack_networking_network" "network_1" { The following arguments are supported: +* `region` - (Required) The region in which to obtain the V2 Networking client. + A Networking client is needed to create a Neutron network. If omitted, the + `OS_REGION_NAME` environment variable is used. Changing this creates a new + network. + * `name` - (Optional) The name of the network. Changing this updates the name of the existing network. @@ -41,6 +46,7 @@ The following arguments are supported: The following attributes are exported: +* `region` - See Argument Reference above. * `name` - See Argument Reference above. * `shared` - See Argument Reference above. * `tenant_id` - See Argument Reference above. diff --git a/website/source/docs/providers/openstack/r/networking_subnet.html.markdown b/website/source/docs/providers/openstack/r/networking_subnet_v2.html.markdown similarity index 78% rename from website/source/docs/providers/openstack/r/networking_subnet.html.markdown rename to website/source/docs/providers/openstack/r/networking_subnet_v2.html.markdown index f9ab4f6ed0..a8243a8178 100644 --- a/website/source/docs/providers/openstack/r/networking_subnet.html.markdown +++ b/website/source/docs/providers/openstack/r/networking_subnet_v2.html.markdown @@ -1,25 +1,25 @@ --- layout: "openstack" -page_title: "OpenStack: openstack_networking_subnet" -sidebar_current: "docs-openstack-resource-networking-subnet" +page_title: "OpenStack: openstack_networking_subnet_v2" +sidebar_current: "docs-openstack-resource-networking-subnet-v2" description: |- - Manages a Neutron subnet resource within OpenStack. + Manages a V2 Neutron subnet resource within OpenStack. --- -# openstack\_networking\_subnet +# openstack\_networking\_subnet_v2 -Manages a Neutron subnet resource within OpenStack. +Manages a V2 Neutron subnet resource within OpenStack. ## Example Usage ``` -resource "openstack_networking_network" "network_1" { +resource "openstack_networking_network_v2" "network_1" { name = "tf_test_network" admin_state_up = "true" } -resource "openstack_networking_subnet" "subnet_1" { - network_id = "${openstack_networking_network.network_1.id}" +resource "openstack_networking_subnet_v2" "subnet_1" { + network_id = "${openstack_networking_network_v2.network_1.id}" cidr = "192.168.199.0/24" ip_version = 4 } @@ -29,6 +29,11 @@ resource "openstack_networking_subnet" "subnet_1" { The following arguments are supported: +* `region` - (Required) The region in which to obtain the V2 Networking client. + A Networking client is needed to create a Neutron subnet. If omitted, the + `OS_REGION_NAME` environment variable is used. Changing this creates a new + subnet. + * `network_id` - (Required) The UUID of the parent network. Changing this creates a new subnet. @@ -80,6 +85,7 @@ The `host_routes` block supports: The following attributes are exported: +* `region` - See Argument Reference above. * `network_id` - See Argument Reference above. * `cidr` - See Argument Reference above. * `ip_version` - See Argument Reference above. diff --git a/website/source/layouts/openstack.erb b/website/source/layouts/openstack.erb index b7878887c9..37b0c2a7c5 100644 --- a/website/source/layouts/openstack.erb +++ b/website/source/layouts/openstack.erb @@ -13,35 +13,35 @@ > Resources From e6f3a192842806b509b343cbe7f5ae541fdd4935 Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Mon, 26 Jan 2015 22:33:34 -0700 Subject: [PATCH 044/132] add defaultFunc for 'tenant_name' --- builtin/providers/openstack/provider.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin/providers/openstack/provider.go b/builtin/providers/openstack/provider.go index 48029afc72..37a6e9b4cb 100644 --- a/builtin/providers/openstack/provider.go +++ b/builtin/providers/openstack/provider.go @@ -34,7 +34,7 @@ func Provider() terraform.ResourceProvider { "tenant_name": &schema.Schema{ Type: schema.TypeString, Optional: true, - Default: "", + DefaultFunc: envDefaultFunc("OS_TENANT_NAME"), }, "password": &schema.Schema{ Type: schema.TypeString, From 59b5efc25aee9d7af40307789543dd40d29d9f1f Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Mon, 26 Jan 2015 22:35:18 -0700 Subject: [PATCH 045/132] add defaultFuncs; fix bug with server createOpts --- .../openstack/resource_openstack_compute_instance_v2.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/builtin/providers/openstack/resource_openstack_compute_instance_v2.go b/builtin/providers/openstack/resource_openstack_compute_instance_v2.go index f6a922f43d..bacf3707e2 100644 --- a/builtin/providers/openstack/resource_openstack_compute_instance_v2.go +++ b/builtin/providers/openstack/resource_openstack_compute_instance_v2.go @@ -39,11 +39,13 @@ func resourceComputeInstanceV2() *schema.Resource { Type: schema.TypeString, Required: true, ForceNew: false, + DefaultFunc: envDefaultFunc("OS_IMAGE_ID"), }, "flavor_ref": &schema.Schema{ Type: schema.TypeString, Required: true, ForceNew: false, + DefaultFunc: envDefaultFunc("OS_FLAVOR_ID"), }, "security_groups": &schema.Schema{ Type: schema.TypeSet, @@ -127,7 +129,7 @@ func resourceComputeInstanceV2Create(d *schema.ResourceData, meta interface{}) e var createOpts servers.CreateOptsBuilder - serverCreateOpts := &servers.CreateOpts{ + createOpts = &servers.CreateOpts{ Name: d.Get("name").(string), ImageRef: d.Get("image_ref").(string), FlavorRef: d.Get("flavor_ref").(string), @@ -141,7 +143,7 @@ func resourceComputeInstanceV2Create(d *schema.ResourceData, meta interface{}) e if keyName, ok := d.Get("key_pair").(string); ok && keyName != "" { createOpts = &keypairs.CreateOptsExt{ - serverCreateOpts, + createOpts, keyName, } } From e278f852b34122de1d1e874026047c0823c00943 Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Mon, 26 Jan 2015 22:36:08 -0700 Subject: [PATCH 046/132] add image_ref and flavor_ref checks --- builtin/providers/openstack/provider_test.go | 32 ++++++++++++-------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/builtin/providers/openstack/provider_test.go b/builtin/providers/openstack/provider_test.go index 2819a45753..57257f5d07 100644 --- a/builtin/providers/openstack/provider_test.go +++ b/builtin/providers/openstack/provider_test.go @@ -8,6 +8,11 @@ import ( "github.com/hashicorp/terraform/terraform" ) + +var ( + OS_REGION_NAME = "" +) + var testAccProviders map[string]terraform.ResourceProvider var testAccProvider *schema.Provider @@ -29,23 +34,24 @@ func TestProvider_impl(t *testing.T) { } func testAccPreCheck(t *testing.T) { - if v := os.Getenv("OS_REGION_NAME"); v == "" { - t.Fatal("OS_REGION_NAME must be set for acceptance tests") - } - - if v := os.Getenv("OS_AUTH_URL"); v == "" { + v := os.Getenv("OS_AUTH_URL") + if v == "" { t.Fatal("OS_AUTH_URL must be set for acceptance tests") } - if v := os.Getenv("OS_USERNAME"); v == "" { - t.Fatal("OS_USERNAME must be set for acceptance tests") + v = os.Getenv("OS_REGION_NAME") + if v == "" { + t.Fatal("OS_REGION_NAME must be set for acceptance tests") + } + OS_REGION_NAME = v + + v = os.Getenv("OS_IMAGE_ID") + if v == "" { + t.Fatal("OS_IMAGE_ID must be set for acceptance tests") } - if v := os.Getenv("OS_TENANT_NAME"); v != "us-central1" { - t.Fatal("OS_TENANT_NAME must be set to us-central1 for acceptance tests") - } - - if v := os.Getenv("OS_PASSWORD"); v != "us-central1" { - t.Fatal("OS_PASSWORD must be set to us-central1 for acceptance tests") + v = os.Getenv("OS_FLAVOR_ID") + if v == "" { + t.Fatal("OS_FLAVOR_ID must be set for acceptance tests") } } From a707f8414cec65c19ec0867999bae6a08f83b6d5 Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Mon, 26 Jan 2015 22:36:39 -0700 Subject: [PATCH 047/132] compute instance v2 acceptance tests --- ...urce_openstack_compute_instance_v2_test.go | 123 ++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 builtin/providers/openstack/resource_openstack_compute_instance_v2_test.go diff --git a/builtin/providers/openstack/resource_openstack_compute_instance_v2_test.go b/builtin/providers/openstack/resource_openstack_compute_instance_v2_test.go new file mode 100644 index 0000000000..4b73957d2e --- /dev/null +++ b/builtin/providers/openstack/resource_openstack_compute_instance_v2_test.go @@ -0,0 +1,123 @@ +package openstack + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" + + "github.com/rackspace/gophercloud" + "github.com/rackspace/gophercloud/openstack" + "github.com/rackspace/gophercloud/openstack/compute/v2/servers" +) + +func TestAccComputeV2Instance_basic(t *testing.T) { + var instance servers.Server + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckComputeV2InstanceDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccComputeV2Instance_basic, + Check: resource.ComposeTestCheckFunc( + testAccCheckComputeV2InstanceExists(t, "openstack_compute_instance_v2.foo", &instance), + testAccCheckComputeV2InstanceMetadata(&instance, "foo", "bar"), + ), + }, + }, + }) +} + +func testAccCheckComputeV2InstanceDestroy(s *terraform.State) error { + config := testAccProvider.Meta().(*Config) + computeClient, err := openstack.NewComputeV2(config.osClient, gophercloud.EndpointOpts{ + Region: OS_REGION_NAME, + }) + if err != nil { + return fmt.Errorf("(testAccCheckComputeV2InstanceDestroy) Error creating OpenStack compute client: %s", err) + } + + for _, rs := range s.RootModule().Resources { + if rs.Type != "openstack_compute_instance_v2" { + continue + } + + _, err := servers.Get(computeClient, rs.Primary.ID).Extract() + if err == nil { + return fmt.Errorf("Instance still exists") + } + } + + return nil +} + +func testAccCheckComputeV2InstanceExists(t *testing.T, n string, instance *servers.Server) 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 ID is set") + } + + osClient := testAccProvider.Meta().(*Config).osClient + computeClient, err := openstack.NewComputeV2(osClient, gophercloud.EndpointOpts{ + Region: OS_REGION_NAME, + }) + if err != nil { + return fmt.Errorf("(testAccCheckComputeV2InstanceExists) Error creating OpenStack compute client: %s", err) + } + + + found, err := servers.Get(computeClient, rs.Primary.ID).Extract() + if err != nil { + return err + } + + if found.ID != rs.Primary.ID { + return fmt.Errorf("Instance not found") + } + + *instance = *found + + return nil + } +} + +func testAccCheckComputeV2InstanceMetadata( + instance *servers.Server, k string, v string) resource.TestCheckFunc { + return func(s *terraform.State) error { + if instance.Metadata == nil { + return fmt.Errorf("No metadata") + } + + for key, value := range instance.Metadata { + if k != key { + continue + } + + if v == value.(string) { + return nil + } + + return fmt.Errorf("Bad value for %s: %s", k, value) + } + + return fmt.Errorf("Metadata not found: %s", k) + } +} + +var testAccComputeV2Instance_basic = fmt.Sprintf(` + resource "openstack_compute_instance_v2" "foo" { + region = "%s" + name = "terraform-test" + metadata { + foo = "bar" + } + }`, + OS_REGION_NAME) From 17b137c972ad647581531d23ea061de391957c91 Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Tue, 27 Jan 2015 10:19:11 -0700 Subject: [PATCH 048/132] go fmt --- builtin/providers/openstack/provider.go | 6 +++--- builtin/providers/openstack/provider_test.go | 1 - .../resource_openstack_compute_instance_v2.go | 12 ++++++------ .../resource_openstack_compute_instance_v2_test.go | 3 +-- .../openstack/resource_openstack_lb_vip_v1.go | 2 +- .../resource_openstack_networking_network_v2.go | 8 ++++---- 6 files changed, 15 insertions(+), 17 deletions(-) diff --git a/builtin/providers/openstack/provider.go b/builtin/providers/openstack/provider.go index 37a6e9b4cb..b28c330bca 100644 --- a/builtin/providers/openstack/provider.go +++ b/builtin/providers/openstack/provider.go @@ -32,9 +32,9 @@ func Provider() terraform.ResourceProvider { Default: "", }, "tenant_name": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - DefaultFunc: envDefaultFunc("OS_TENANT_NAME"), + Type: schema.TypeString, + Optional: true, + DefaultFunc: envDefaultFunc("OS_TENANT_NAME"), }, "password": &schema.Schema{ Type: schema.TypeString, diff --git a/builtin/providers/openstack/provider_test.go b/builtin/providers/openstack/provider_test.go index 57257f5d07..9e90bb4ea7 100644 --- a/builtin/providers/openstack/provider_test.go +++ b/builtin/providers/openstack/provider_test.go @@ -8,7 +8,6 @@ import ( "github.com/hashicorp/terraform/terraform" ) - var ( OS_REGION_NAME = "" ) diff --git a/builtin/providers/openstack/resource_openstack_compute_instance_v2.go b/builtin/providers/openstack/resource_openstack_compute_instance_v2.go index bacf3707e2..8b23c5a878 100644 --- a/builtin/providers/openstack/resource_openstack_compute_instance_v2.go +++ b/builtin/providers/openstack/resource_openstack_compute_instance_v2.go @@ -36,15 +36,15 @@ func resourceComputeInstanceV2() *schema.Resource { ForceNew: false, }, "image_ref": &schema.Schema{ - Type: schema.TypeString, - Required: true, - ForceNew: false, + Type: schema.TypeString, + Required: true, + ForceNew: false, DefaultFunc: envDefaultFunc("OS_IMAGE_ID"), }, "flavor_ref": &schema.Schema{ - Type: schema.TypeString, - Required: true, - ForceNew: false, + Type: schema.TypeString, + Required: true, + ForceNew: false, DefaultFunc: envDefaultFunc("OS_FLAVOR_ID"), }, "security_groups": &schema.Schema{ diff --git a/builtin/providers/openstack/resource_openstack_compute_instance_v2_test.go b/builtin/providers/openstack/resource_openstack_compute_instance_v2_test.go index 4b73957d2e..ff2457d095 100644 --- a/builtin/providers/openstack/resource_openstack_compute_instance_v2_test.go +++ b/builtin/providers/openstack/resource_openstack_compute_instance_v2_test.go @@ -73,7 +73,6 @@ func testAccCheckComputeV2InstanceExists(t *testing.T, n string, instance *serve return fmt.Errorf("(testAccCheckComputeV2InstanceExists) Error creating OpenStack compute client: %s", err) } - found, err := servers.Get(computeClient, rs.Primary.ID).Extract() if err != nil { return err @@ -120,4 +119,4 @@ var testAccComputeV2Instance_basic = fmt.Sprintf(` foo = "bar" } }`, - OS_REGION_NAME) + OS_REGION_NAME) diff --git a/builtin/providers/openstack/resource_openstack_lb_vip_v1.go b/builtin/providers/openstack/resource_openstack_lb_vip_v1.go index 748ed8d6a1..eefe239be2 100644 --- a/builtin/providers/openstack/resource_openstack_lb_vip_v1.go +++ b/builtin/providers/openstack/resource_openstack_lb_vip_v1.go @@ -169,7 +169,7 @@ func resourceLBVipV1Read(d *schema.ResourceData, meta interface{}) error { } if t, exists := d.GetOk("persistence"); exists && t != "" { - d.Set("persistence", p.Description) + d.Set("persistence", p.Description) } if t, exists := d.GetOk("conn_limit"); exists && t != "" { diff --git a/builtin/providers/openstack/resource_openstack_networking_network_v2.go b/builtin/providers/openstack/resource_openstack_networking_network_v2.go index 92e02e0319..e32db9697c 100644 --- a/builtin/providers/openstack/resource_openstack_networking_network_v2.go +++ b/builtin/providers/openstack/resource_openstack_networking_network_v2.go @@ -20,9 +20,9 @@ func resourceNetworkingNetworkV2() *schema.Resource { Schema: map[string]*schema.Schema{ "region": &schema.Schema{ - Type: schema.TypeString, - Required: true, - ForceNew: true, + Type: schema.TypeString, + Required: true, + ForceNew: true, DefaultFunc: envDefaultFunc("OS_REGION_NAME"), }, "name": &schema.Schema{ @@ -111,7 +111,7 @@ func resourceNetworkingNetworkV2Read(d *schema.ResourceData, meta interface{}) e d.Set("region", d.Get("region").(string)) - if t, exists := d.GetOk("name"); exists && t != ""{ + if t, exists := d.GetOk("name"); exists && t != "" { d.Set("name", n.Name) } else { d.Set("name", "") From 3a6107d0ab5a877a69070d241ba1241f3864ace5 Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Tue, 27 Jan 2015 10:19:45 -0700 Subject: [PATCH 049/132] keypairs v2 acceptance tests --- ...ource_openstack_compute_keypair_v2_test.go | 96 +++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 builtin/providers/openstack/resource_openstack_compute_keypair_v2_test.go diff --git a/builtin/providers/openstack/resource_openstack_compute_keypair_v2_test.go b/builtin/providers/openstack/resource_openstack_compute_keypair_v2_test.go new file mode 100644 index 0000000000..19e5cf6559 --- /dev/null +++ b/builtin/providers/openstack/resource_openstack_compute_keypair_v2_test.go @@ -0,0 +1,96 @@ +package openstack + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" + + "github.com/rackspace/gophercloud" + "github.com/rackspace/gophercloud/openstack" + "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/keypairs" +) + +func TestAccComputeV2Keypair_basic(t *testing.T) { + var keypair keypairs.KeyPair + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckComputeV2KeypairDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccComputeV2Keypair_basic, + Check: resource.ComposeTestCheckFunc( + testAccCheckComputeV2KeypairExists(t, "openstack_compute_keypair_v2.foo", &keypair), + ), + }, + }, + }) +} + +func testAccCheckComputeV2KeypairDestroy(s *terraform.State) error { + config := testAccProvider.Meta().(*Config) + computeClient, err := openstack.NewComputeV2(config.osClient, gophercloud.EndpointOpts{ + Region: OS_REGION_NAME, + }) + if err != nil { + return fmt.Errorf("(testAccCheckComputeV2InstanceDestroy) Error creating OpenStack compute client: %s", err) + } + + for _, rs := range s.RootModule().Resources { + if rs.Type != "openstack_compute_keypair_v2" { + continue + } + + _, err := keypairs.Get(computeClient, rs.Primary.ID).Extract() + if err == nil { + return fmt.Errorf("Keypair still exists") + } + } + + return nil +} + +func testAccCheckComputeV2KeypairExists(t *testing.T, n string, kp *keypairs.KeyPair) 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 ID is set") + } + + osClient := testAccProvider.Meta().(*Config).osClient + computeClient, err := openstack.NewComputeV2(osClient, gophercloud.EndpointOpts{ + Region: OS_REGION_NAME, + }) + if err != nil { + return fmt.Errorf("(testAccCheckComputeV2KeypairExists) Error creating OpenStack compute client: %s", err) + } + + found, err := keypairs.Get(computeClient, rs.Primary.ID).Extract() + if err != nil { + return err + } + + if found.Name != rs.Primary.ID { + return fmt.Errorf("Keypair not found") + } + + *kp = *found + + return nil + } +} + +var testAccComputeV2Keypair_basic = fmt.Sprintf(` + resource "openstack_compute_keypair_v2" "foo" { + region = "%s" + name = "test-keypair-tf" + public_key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDAjpC1hwiOCCmKEWxJ4qzTTsJbKzndLo1BCz5PcwtUnflmU+gHJtWMZKpuEGVi29h0A/+ydKek1O18k10Ff+4tyFjiHDQAT9+OfgWf7+b1yK+qDip3X1C0UPMbwHlTfSGWLGZquwhvEFx9k3h/M+VtMvwR1lJ9LUyTAImnNjWG7TAIPmui30HvM2UiFEmqkr4ijq45MyX2+fLIePLRIFuu1p4whjHAQYufqyno3BS48icQb4p6iVEZPo4AE2o9oIyQvj2mx4dk5Y8CgSETOZTYDOR3rU2fZTRDRgPJDH9FWvQjF5tA0p3d9CoWWd2s6GKKbfoUIi8R/Db1BSPJwkqB jrp-hp-pc" + }`, + OS_REGION_NAME) From ea7c075273ef8a3237c67208f506115149245a04 Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Thu, 29 Jan 2015 21:54:07 -0700 Subject: [PATCH 050/132] add security group rules ops to security groups file --- .../resource_openstack_compute_secgroup_v2.go | 117 ++++++++++++++++++ 1 file changed, 117 insertions(+) diff --git a/builtin/providers/openstack/resource_openstack_compute_secgroup_v2.go b/builtin/providers/openstack/resource_openstack_compute_secgroup_v2.go index a79a6a88b4..dd5aafd091 100644 --- a/builtin/providers/openstack/resource_openstack_compute_secgroup_v2.go +++ b/builtin/providers/openstack/resource_openstack_compute_secgroup_v2.go @@ -1,9 +1,11 @@ package openstack import ( + "bytes" "fmt" "log" + "github.com/hashicorp/terraform/helper/hashcode" "github.com/hashicorp/terraform/helper/schema" "github.com/rackspace/gophercloud" "github.com/rackspace/gophercloud/openstack" @@ -34,6 +36,40 @@ func resourceComputeSecGroupV2() *schema.Resource { Required: true, ForceNew: false, }, + "rules": &schema.Schema{ + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "from_port": &schema.Schema{ + Type: schema.TypeInt, + Required: true, + ForceNew: true, + }, + "to_port": &schema.Schema{ + Type: schema.TypeInt, + Required: true, + ForceNew: true, + }, + "ip_protocol": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "cidr": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "from_group_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + }, + }, + Set: resourceSecGroupRuleHash, + }, }, } } @@ -59,6 +95,14 @@ func resourceComputeSecGroupV2Create(d *schema.ResourceData, meta interface{}) e d.SetId(sg.ID) + createRuleOptsList := resourceSecGroupRulesV2(d) + for _, createRuleOpts := range createRuleOptsList { + _, err := secgroups.CreateRule(computeClient, createRuleOpts).Extract() + if err != nil { + return fmt.Errorf("Error creating OpenStack security group rule: %s", err) + } + } + return resourceComputeSecGroupV2Read(d, meta) } @@ -79,6 +123,7 @@ func resourceComputeSecGroupV2Read(d *schema.ResourceData, meta interface{}) err d.Set("region", d.Get("region").(string)) d.Set("name", sg.Name) d.Set("description", sg.Description) + d.Set("rules", sg.Rules) return nil } @@ -104,6 +149,35 @@ func resourceComputeSecGroupV2Update(d *schema.ResourceData, meta interface{}) e return fmt.Errorf("Error updating OpenStack security group (%s): %s", d.Id(), err) } + if d.HasChange("rules") { + oldSGRaw, newSGRaw := d.GetChange("rules") + oldSGRSet, newSGRSet := oldSGRaw.(*schema.Set), newSGRaw.(*schema.Set) + secgrouprulesToAdd := newSGRSet.Difference(oldSGRSet) + secgrouprulesToRemove := oldSGRSet.Difference(newSGRSet) + + log.Printf("[DEBUG] Security group rules to add: %v", secgrouprulesToAdd) + + log.Printf("[DEBUG] Security groups to remove: %v", secgrouprulesToRemove) + + for _, rawRule := range secgrouprulesToAdd.List() { + createRuleOpts := resourceSecGroupRuleV2(d, rawRule) + rule, err := secgroups.CreateRule(computeClient, createRuleOpts).Extract() + if err != nil { + return fmt.Errorf("Error adding rule to OpenStack security group (%s): %s", d.Id(), err) + } + log.Printf("[DEBUG] Added rule (%s) to OpenStack security group (%s) ", rule.ID, d.Id()) + } + + for _, r := range secgrouprulesToRemove.List() { + rule := r.(secgroups.Rule) + err := secgroups.DeleteRule(computeClient, "").ExtractErr() + if err != nil { + return fmt.Errorf("Error removing rule (%s) from OpenStack security group (%s): %s", rule.ID, d.Id(), err) + } + log.Printf("[DEBUG] Removed rule (%s) from OpenStack security group (%s)", rule.ID, d.Id()) + } + } + return resourceComputeSecGroupV2Read(d, meta) } @@ -123,3 +197,46 @@ func resourceComputeSecGroupV2Delete(d *schema.ResourceData, meta interface{}) e d.SetId("") return nil } + +func resourceSecGroupRuleHash(v interface{}) int { + var buf bytes.Buffer + m := v.(map[string]interface{}) + buf.WriteString(fmt.Sprintf("%d-", m["from_port"].(int))) + buf.WriteString(fmt.Sprintf("%d-", m["to_port"].(int))) + buf.WriteString(fmt.Sprintf("%s-", m["ip_protocol"].(string))) + buf.WriteString(fmt.Sprintf("%s-", m["cidr"].(string))) + buf.WriteString(fmt.Sprintf("%s-", m["from_group_id"].(string))) + + return hashcode.String(buf.String()) +} + +func resourceSecGroupRulesV2(d *schema.ResourceData) []secgroups.CreateRuleOpts { + rawRules := (d.Get("rules")).(*schema.Set) + createRuleOptsList := make([]secgroups.CreateRuleOpts, rawRules.Len()) + for i, raw := range rawRules.List() { + rawMap := raw.(map[string]interface{}) + createRuleOptsList[i] = secgroups.CreateRuleOpts{ + ParentGroupID: d.Id(), + FromPort: rawMap["from_port"].(int), + ToPort: rawMap["to_port"].(int), + IPProtocol: rawMap["ip_protocol"].(string), + CIDR: rawMap["cidr"].(string), + FromGroupID: rawMap["from_group_id"].(string), + } + } + return createRuleOptsList +} + +func resourceSecGroupRuleV2(d *schema.ResourceData, raw interface{}) secgroups.CreateRuleOpts { + rawMap := raw.(map[string]interface{}) + createRuleOpts := secgroups.CreateRuleOpts{ + ParentGroupID: d.Id(), + FromPort: rawMap["from_port"].(int), + ToPort: rawMap["to_port"].(int), + IPProtocol: rawMap["ip_protocol"].(string), + CIDR: rawMap["cidr"].(string), + FromGroupID: rawMap["from_group_id"].(string), + } + + return createRuleOpts +} From c233c7f7f02f4664c3ec11f6ab42ca62612cec00 Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Thu, 29 Jan 2015 21:56:40 -0700 Subject: [PATCH 051/132] fix typo in comment --- .../openstack/resource_openstack_compute_keypair_v2_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin/providers/openstack/resource_openstack_compute_keypair_v2_test.go b/builtin/providers/openstack/resource_openstack_compute_keypair_v2_test.go index 19e5cf6559..0456341df8 100644 --- a/builtin/providers/openstack/resource_openstack_compute_keypair_v2_test.go +++ b/builtin/providers/openstack/resource_openstack_compute_keypair_v2_test.go @@ -36,7 +36,7 @@ func testAccCheckComputeV2KeypairDestroy(s *terraform.State) error { Region: OS_REGION_NAME, }) if err != nil { - return fmt.Errorf("(testAccCheckComputeV2InstanceDestroy) Error creating OpenStack compute client: %s", err) + return fmt.Errorf("(testAccCheckComputeV2KeypairDestroy) Error creating OpenStack compute client: %s", err) } for _, rs := range s.RootModule().Resources { From a2d2f927417bb1bb711a676bdaaacc397b0ba163 Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Thu, 29 Jan 2015 21:57:14 -0700 Subject: [PATCH 052/132] remove security group rule file --- ...ource_openstack_compute_secgrouprule_v2.go | 113 ------------------ 1 file changed, 113 deletions(-) delete mode 100644 builtin/providers/openstack/resource_openstack_compute_secgrouprule_v2.go diff --git a/builtin/providers/openstack/resource_openstack_compute_secgrouprule_v2.go b/builtin/providers/openstack/resource_openstack_compute_secgrouprule_v2.go deleted file mode 100644 index fce40e6218..0000000000 --- a/builtin/providers/openstack/resource_openstack_compute_secgrouprule_v2.go +++ /dev/null @@ -1,113 +0,0 @@ -package openstack - -import ( - "fmt" - - "github.com/hashicorp/terraform/helper/schema" - "github.com/rackspace/gophercloud" - "github.com/rackspace/gophercloud/openstack" - "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/secgroups" -) - -func resourceComputeSecGroupRuleV2() *schema.Resource { - return &schema.Resource{ - Create: resourceComputeSecGroupRuleV2Create, - Read: resourceComputeSecGroupRuleV2Read, - Delete: resourceComputeSecGroupRuleV2Delete, - - Schema: map[string]*schema.Schema{ - "region": &schema.Schema{ - Type: schema.TypeString, - Required: true, - ForceNew: true, - DefaultFunc: envDefaultFunc("OS_REGION_NAME"), - }, - "group_id": &schema.Schema{ - Type: schema.TypeString, - Required: true, - ForceNew: true, - }, - "from_port": &schema.Schema{ - Type: schema.TypeInt, - Required: true, - ForceNew: true, - }, - "to_port": &schema.Schema{ - Type: schema.TypeInt, - Required: true, - ForceNew: true, - }, - "ip_protocol": &schema.Schema{ - Type: schema.TypeString, - Required: true, - ForceNew: true, - }, - "cidr": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - ForceNew: true, - }, - "from_group_id": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - ForceNew: true, - }, - }, - } -} - -func resourceComputeSecGroupRuleV2Create(d *schema.ResourceData, meta interface{}) error { - config := meta.(*Config) - computeClient, err := openstack.NewComputeV2(config.osClient, gophercloud.EndpointOpts{ - Region: d.Get("region").(string), - }) - if err != nil { - return fmt.Errorf("Error creating OpenStack compute client: %s", err) - } - - createOpts := secgroups.CreateRuleOpts{ - ParentGroupID: d.Get("group_id").(string), - FromPort: d.Get("from_port").(int), - ToPort: d.Get("to_port").(int), - IPProtocol: d.Get("ip_protocol").(string), - CIDR: d.Get("cidr").(string), - FromGroupID: d.Get("from_group_id").(string), - } - - sgr, err := secgroups.CreateRule(computeClient, createOpts).Extract() - if err != nil { - return fmt.Errorf("Error creating OpenStack security group rule: %s", err) - } - - d.SetId(sgr.ID) - d.Set("region", d.Get("region").(string)) - d.Set("group_id", sgr.ParentGroupID) - d.Set("from_port", sgr.FromPort) - d.Set("to_port", sgr.ToPort) - d.Set("ip_protocol", sgr.IPProtocol) - d.Set("cidr", sgr.IPRange.CIDR) - d.Set("from_group_id", d.Get("from_group_id").(string)) - - return resourceComputeSecGroupRuleV2Read(d, meta) -} - -func resourceComputeSecGroupRuleV2Read(d *schema.ResourceData, meta interface{}) error { - return nil -} - -func resourceComputeSecGroupRuleV2Delete(d *schema.ResourceData, meta interface{}) error { - config := meta.(*Config) - computeClient, err := openstack.NewComputeV2(config.osClient, gophercloud.EndpointOpts{ - Region: d.Get("region").(string), - }) - if err != nil { - return fmt.Errorf("Error creating OpenStack compute client: %s", err) - } - - err = secgroups.DeleteRule(computeClient, d.Id()).ExtractErr() - if err != nil { - return fmt.Errorf("Error deleting OpenStack security group rule: %s", err) - } - d.SetId("") - return nil -} From 3627368fc040bfc39e7b38557931025071665e00 Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Thu, 29 Jan 2015 22:09:59 -0700 Subject: [PATCH 053/132] remove security group rule option from provider --- builtin/providers/openstack/provider.go | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/builtin/providers/openstack/provider.go b/builtin/providers/openstack/provider.go index b28c330bca..65496d5346 100644 --- a/builtin/providers/openstack/provider.go +++ b/builtin/providers/openstack/provider.go @@ -59,16 +59,15 @@ func Provider() terraform.ResourceProvider { }, ResourcesMap: map[string]*schema.Resource{ - "openstack_compute_instance_v2": resourceComputeInstanceV2(), - "openstack_compute_keypair_v2": resourceComputeKeypairV2(), - "openstack_compute_secgroup_v2": resourceComputeSecGroupV2(), - "openstack_compute_secgrouprule_v2": resourceComputeSecGroupRuleV2(), - "openstack_lb_member_v1": resourceLBMemberV1(), - "openstack_lb_monitor_v1": resourceLBMonitorV1(), - "openstack_lb_pool_v1": resourceLBPoolV1(), - "openstack_lb_vip_v1": resourceLBVipV1(), - "openstack_networking_network_v2": resourceNetworkingNetworkV2(), - "openstack_networking_subnet_v2": resourceNetworkingSubnetV2(), + "openstack_compute_instance_v2": resourceComputeInstanceV2(), + "openstack_compute_keypair_v2": resourceComputeKeypairV2(), + "openstack_compute_secgroup_v2": resourceComputeSecGroupV2(), + "openstack_lb_member_v1": resourceLBMemberV1(), + "openstack_lb_monitor_v1": resourceLBMonitorV1(), + "openstack_lb_pool_v1": resourceLBPoolV1(), + "openstack_lb_vip_v1": resourceLBVipV1(), + "openstack_networking_network_v2": resourceNetworkingNetworkV2(), + "openstack_networking_subnet_v2": resourceNetworkingSubnetV2(), }, ConfigureFunc: configureProvider, From 1aba665ad79dc426af72aa31799a09daa5d70c56 Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Sat, 31 Jan 2015 14:33:54 -0700 Subject: [PATCH 054/132] refactor service clients to *Config --- builtin/providers/openstack/config.go | 12 ++++++++++++ .../resource_openstack_compute_instance_v2.go | 17 ++++------------- .../resource_openstack_compute_keypair_v2.go | 14 +++----------- .../resource_openstack_compute_secgroup_v2.go | 18 ++++-------------- .../resource_openstack_lb_member_v1.go | 18 ++++-------------- .../resource_openstack_lb_monitor_v1.go | 18 ++++-------------- .../openstack/resource_openstack_lb_pool_v1.go | 18 ++++-------------- .../openstack/resource_openstack_lb_vip_v1.go | 17 ++++------------- ...resource_openstack_networking_network_v2.go | 18 ++++-------------- .../resource_openstack_networking_subnet_v2.go | 18 ++++-------------- 10 files changed, 47 insertions(+), 121 deletions(-) diff --git a/builtin/providers/openstack/config.go b/builtin/providers/openstack/config.go index 215817bdda..2e37c4fd0f 100644 --- a/builtin/providers/openstack/config.go +++ b/builtin/providers/openstack/config.go @@ -41,3 +41,15 @@ func (c *Config) loadAndValidate() error { return nil } + +func (c *Config) computeV2Client(region string) (*gophercloud.ServiceClient, error) { + return openstack.NewComputeV2(c.osClient, gophercloud.EndpointOpts{ + Region: region, + }) +} + +func (c *Config) networkingV2Client(region string) (*gophercloud.ServiceClient, error) { + return openstack.NewNetworkV2(c.osClient, gophercloud.EndpointOpts{ + Region: region, + }) +} diff --git a/builtin/providers/openstack/resource_openstack_compute_instance_v2.go b/builtin/providers/openstack/resource_openstack_compute_instance_v2.go index 8b23c5a878..a2e66ca2e5 100644 --- a/builtin/providers/openstack/resource_openstack_compute_instance_v2.go +++ b/builtin/providers/openstack/resource_openstack_compute_instance_v2.go @@ -9,7 +9,6 @@ import ( "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/schema" "github.com/rackspace/gophercloud" - "github.com/rackspace/gophercloud/openstack" "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/keypairs" "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/secgroups" "github.com/rackspace/gophercloud/openstack/compute/v2/servers" @@ -120,9 +119,7 @@ func resourceComputeInstanceV2() *schema.Resource { func resourceComputeInstanceV2Create(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - computeClient, err := openstack.NewComputeV2(config.osClient, gophercloud.EndpointOpts{ - Region: d.Get("region").(string), - }) + computeClient, err := config.computeV2Client(d.Get("region").(string)) if err != nil { return fmt.Errorf("Error creating OpenStack compute client: %s", err) } @@ -185,9 +182,7 @@ func resourceComputeInstanceV2Create(d *schema.ResourceData, meta interface{}) e func resourceComputeInstanceV2Read(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - computeClient, err := openstack.NewComputeV2(config.osClient, gophercloud.EndpointOpts{ - Region: d.Get("region").(string), - }) + computeClient, err := config.computeV2Client(d.Get("region").(string)) if err != nil { return fmt.Errorf("Error creating OpenStack compute client: %s", err) } @@ -254,9 +249,7 @@ func resourceComputeInstanceV2Read(d *schema.ResourceData, meta interface{}) err func resourceComputeInstanceV2Update(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - computeClient, err := openstack.NewComputeV2(config.osClient, gophercloud.EndpointOpts{ - Region: d.Get("region").(string), - }) + computeClient, err := config.computeV2Client(d.Get("region").(string)) if err != nil { return fmt.Errorf("Error creating OpenStack compute client: %s", err) } @@ -382,9 +375,7 @@ func resourceComputeInstanceV2Update(d *schema.ResourceData, meta interface{}) e func resourceComputeInstanceV2Delete(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - computeClient, err := openstack.NewComputeV2(config.osClient, gophercloud.EndpointOpts{ - Region: d.Get("region").(string), - }) + computeClient, err := config.computeV2Client(d.Get("region").(string)) if err != nil { return fmt.Errorf("Error creating OpenStack compute client: %s", err) } diff --git a/builtin/providers/openstack/resource_openstack_compute_keypair_v2.go b/builtin/providers/openstack/resource_openstack_compute_keypair_v2.go index e2d189a070..8cdc849139 100644 --- a/builtin/providers/openstack/resource_openstack_compute_keypair_v2.go +++ b/builtin/providers/openstack/resource_openstack_compute_keypair_v2.go @@ -4,8 +4,6 @@ import ( "fmt" "github.com/hashicorp/terraform/helper/schema" - "github.com/rackspace/gophercloud" - "github.com/rackspace/gophercloud/openstack" "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/keypairs" ) @@ -38,9 +36,7 @@ func resourceComputeKeypairV2() *schema.Resource { func resourceComputeKeypairV2Create(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - computeClient, err := openstack.NewComputeV2(config.osClient, gophercloud.EndpointOpts{ - Region: d.Get("region").(string), - }) + computeClient, err := config.computeV2Client(d.Get("region").(string)) if err != nil { return fmt.Errorf("Error creating OpenStack compute client: %s", err) } @@ -62,9 +58,7 @@ func resourceComputeKeypairV2Create(d *schema.ResourceData, meta interface{}) er func resourceComputeKeypairV2Read(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - computeClient, err := openstack.NewComputeV2(config.osClient, gophercloud.EndpointOpts{ - Region: d.Get("region").(string), - }) + computeClient, err := config.computeV2Client(d.Get("region").(string)) if err != nil { return fmt.Errorf("Error creating OpenStack compute client: %s", err) } @@ -83,9 +77,7 @@ func resourceComputeKeypairV2Read(d *schema.ResourceData, meta interface{}) erro func resourceComputeKeypairV2Delete(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - computeClient, err := openstack.NewComputeV2(config.osClient, gophercloud.EndpointOpts{ - Region: d.Get("region").(string), - }) + computeClient, err := config.computeV2Client(d.Get("region").(string)) if err != nil { return fmt.Errorf("Error creating OpenStack compute client: %s", err) } diff --git a/builtin/providers/openstack/resource_openstack_compute_secgroup_v2.go b/builtin/providers/openstack/resource_openstack_compute_secgroup_v2.go index dd5aafd091..f83ce84c7e 100644 --- a/builtin/providers/openstack/resource_openstack_compute_secgroup_v2.go +++ b/builtin/providers/openstack/resource_openstack_compute_secgroup_v2.go @@ -7,8 +7,6 @@ import ( "github.com/hashicorp/terraform/helper/hashcode" "github.com/hashicorp/terraform/helper/schema" - "github.com/rackspace/gophercloud" - "github.com/rackspace/gophercloud/openstack" "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/secgroups" ) @@ -76,9 +74,7 @@ func resourceComputeSecGroupV2() *schema.Resource { func resourceComputeSecGroupV2Create(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - computeClient, err := openstack.NewComputeV2(config.osClient, gophercloud.EndpointOpts{ - Region: d.Get("region").(string), - }) + computeClient, err := config.computeV2Client(d.Get("region").(string)) if err != nil { return fmt.Errorf("Error creating OpenStack compute client: %s", err) } @@ -108,9 +104,7 @@ func resourceComputeSecGroupV2Create(d *schema.ResourceData, meta interface{}) e func resourceComputeSecGroupV2Read(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - computeClient, err := openstack.NewComputeV2(config.osClient, gophercloud.EndpointOpts{ - Region: d.Get("region").(string), - }) + computeClient, err := config.computeV2Client(d.Get("region").(string)) if err != nil { return fmt.Errorf("Error creating OpenStack compute client: %s", err) } @@ -130,9 +124,7 @@ func resourceComputeSecGroupV2Read(d *schema.ResourceData, meta interface{}) err func resourceComputeSecGroupV2Update(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - computeClient, err := openstack.NewComputeV2(config.osClient, gophercloud.EndpointOpts{ - Region: d.Get("region").(string), - }) + computeClient, err := config.computeV2Client(d.Get("region").(string)) if err != nil { return fmt.Errorf("Error creating OpenStack compute client: %s", err) } @@ -183,9 +175,7 @@ func resourceComputeSecGroupV2Update(d *schema.ResourceData, meta interface{}) e func resourceComputeSecGroupV2Delete(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - computeClient, err := openstack.NewComputeV2(config.osClient, gophercloud.EndpointOpts{ - Region: d.Get("region").(string), - }) + computeClient, err := config.computeV2Client(d.Get("region").(string)) if err != nil { return fmt.Errorf("Error creating OpenStack compute client: %s", err) } diff --git a/builtin/providers/openstack/resource_openstack_lb_member_v1.go b/builtin/providers/openstack/resource_openstack_lb_member_v1.go index 2d615ed765..9cadfef909 100644 --- a/builtin/providers/openstack/resource_openstack_lb_member_v1.go +++ b/builtin/providers/openstack/resource_openstack_lb_member_v1.go @@ -5,8 +5,6 @@ import ( "log" "github.com/hashicorp/terraform/helper/schema" - "github.com/rackspace/gophercloud" - "github.com/rackspace/gophercloud/openstack" "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/lbaas/members" ) @@ -55,9 +53,7 @@ func resourceLBMemberV1() *schema.Resource { func resourceLBMemberV1Create(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - networkingClient, err := openstack.NewNetworkV2(config.osClient, gophercloud.EndpointOpts{ - Region: d.Get("region").(string), - }) + networkingClient, err := config.networkingV2Client(d.Get("region").(string)) if err != nil { return fmt.Errorf("Error creating OpenStack networking client: %s", err) } @@ -83,9 +79,7 @@ func resourceLBMemberV1Create(d *schema.ResourceData, meta interface{}) error { func resourceLBMemberV1Read(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - networkingClient, err := openstack.NewNetworkV2(config.osClient, gophercloud.EndpointOpts{ - Region: d.Get("region").(string), - }) + networkingClient, err := config.networkingV2Client(d.Get("region").(string)) if err != nil { return fmt.Errorf("Error creating OpenStack networking client: %s", err) } @@ -113,9 +107,7 @@ func resourceLBMemberV1Read(d *schema.ResourceData, meta interface{}) error { func resourceLBMemberV1Update(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - networkingClient, err := openstack.NewNetworkV2(config.osClient, gophercloud.EndpointOpts{ - Region: d.Get("region").(string), - }) + networkingClient, err := config.networkingV2Client(d.Get("region").(string)) if err != nil { return fmt.Errorf("Error creating OpenStack networking client: %s", err) } @@ -137,9 +129,7 @@ func resourceLBMemberV1Update(d *schema.ResourceData, meta interface{}) error { func resourceLBMemberV1Delete(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - networkingClient, err := openstack.NewNetworkV2(config.osClient, gophercloud.EndpointOpts{ - Region: d.Get("region").(string), - }) + networkingClient, err := config.networkingV2Client(d.Get("region").(string)) if err != nil { return fmt.Errorf("Error creating OpenStack networking client: %s", err) } diff --git a/builtin/providers/openstack/resource_openstack_lb_monitor_v1.go b/builtin/providers/openstack/resource_openstack_lb_monitor_v1.go index f6c097d23c..ca5ad76594 100644 --- a/builtin/providers/openstack/resource_openstack_lb_monitor_v1.go +++ b/builtin/providers/openstack/resource_openstack_lb_monitor_v1.go @@ -6,8 +6,6 @@ import ( "strconv" "github.com/hashicorp/terraform/helper/schema" - "github.com/rackspace/gophercloud" - "github.com/rackspace/gophercloud/openstack" "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/lbaas/monitors" ) @@ -76,9 +74,7 @@ func resourceLBMonitorV1() *schema.Resource { func resourceLBMonitorV1Create(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - networkingClient, err := openstack.NewNetworkV2(config.osClient, gophercloud.EndpointOpts{ - Region: d.Get("region").(string), - }) + networkingClient, err := config.networkingV2Client(d.Get("region").(string)) if err != nil { return fmt.Errorf("Error creating OpenStack networking client: %s", err) } @@ -117,9 +113,7 @@ func resourceLBMonitorV1Create(d *schema.ResourceData, meta interface{}) error { func resourceLBMonitorV1Read(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - networkingClient, err := openstack.NewNetworkV2(config.osClient, gophercloud.EndpointOpts{ - Region: d.Get("region").(string), - }) + networkingClient, err := config.networkingV2Client(d.Get("region").(string)) if err != nil { return fmt.Errorf("Error creating OpenStack networking client: %s", err) } @@ -172,9 +166,7 @@ func resourceLBMonitorV1Read(d *schema.ResourceData, meta interface{}) error { func resourceLBMonitorV1Update(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - networkingClient, err := openstack.NewNetworkV2(config.osClient, gophercloud.EndpointOpts{ - Region: d.Get("region").(string), - }) + networkingClient, err := config.networkingV2Client(d.Get("region").(string)) if err != nil { return fmt.Errorf("Error creating OpenStack networking client: %s", err) } @@ -221,9 +213,7 @@ func resourceLBMonitorV1Update(d *schema.ResourceData, meta interface{}) error { func resourceLBMonitorV1Delete(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - networkingClient, err := openstack.NewNetworkV2(config.osClient, gophercloud.EndpointOpts{ - Region: d.Get("region").(string), - }) + networkingClient, err := config.networkingV2Client(d.Get("region").(string)) if err != nil { return fmt.Errorf("Error creating OpenStack networking client: %s", err) } diff --git a/builtin/providers/openstack/resource_openstack_lb_pool_v1.go b/builtin/providers/openstack/resource_openstack_lb_pool_v1.go index 6ca79a802f..3cadc28587 100644 --- a/builtin/providers/openstack/resource_openstack_lb_pool_v1.go +++ b/builtin/providers/openstack/resource_openstack_lb_pool_v1.go @@ -6,8 +6,6 @@ import ( "github.com/hashicorp/terraform/helper/hashcode" "github.com/hashicorp/terraform/helper/schema" - "github.com/rackspace/gophercloud" - "github.com/rackspace/gophercloud/openstack" "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/lbaas/pools" ) @@ -66,9 +64,7 @@ func resourceLBPoolV1() *schema.Resource { func resourceLBPoolV1Create(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - networkingClient, err := openstack.NewNetworkV2(config.osClient, gophercloud.EndpointOpts{ - Region: d.Get("region").(string), - }) + networkingClient, err := config.networkingV2Client(d.Get("region").(string)) if err != nil { return fmt.Errorf("Error creating OpenStack networking client: %s", err) } @@ -104,9 +100,7 @@ func resourceLBPoolV1Create(d *schema.ResourceData, meta interface{}) error { func resourceLBPoolV1Read(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - networkingClient, err := openstack.NewNetworkV2(config.osClient, gophercloud.EndpointOpts{ - Region: d.Get("region").(string), - }) + networkingClient, err := config.networkingV2Client(d.Get("region").(string)) if err != nil { return fmt.Errorf("Error creating OpenStack networking client: %s", err) } @@ -137,9 +131,7 @@ func resourceLBPoolV1Read(d *schema.ResourceData, meta interface{}) error { func resourceLBPoolV1Update(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - networkingClient, err := openstack.NewNetworkV2(config.osClient, gophercloud.EndpointOpts{ - Region: d.Get("region").(string), - }) + networkingClient, err := config.networkingV2Client(d.Get("region").(string)) if err != nil { return fmt.Errorf("Error creating OpenStack networking client: %s", err) } @@ -191,9 +183,7 @@ func resourceLBPoolV1Update(d *schema.ResourceData, meta interface{}) error { func resourceLBPoolV1Delete(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - networkingClient, err := openstack.NewNetworkV2(config.osClient, gophercloud.EndpointOpts{ - Region: d.Get("region").(string), - }) + networkingClient, err := config.networkingV2Client(d.Get("region").(string)) if err != nil { return fmt.Errorf("Error creating OpenStack networking client: %s", err) } diff --git a/builtin/providers/openstack/resource_openstack_lb_vip_v1.go b/builtin/providers/openstack/resource_openstack_lb_vip_v1.go index eefe239be2..cef3977c8d 100644 --- a/builtin/providers/openstack/resource_openstack_lb_vip_v1.go +++ b/builtin/providers/openstack/resource_openstack_lb_vip_v1.go @@ -7,7 +7,6 @@ import ( "github.com/hashicorp/terraform/helper/schema" "github.com/rackspace/gophercloud" - "github.com/rackspace/gophercloud/openstack" "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/lbaas/vips" ) @@ -86,9 +85,7 @@ func resourceLBVipV1() *schema.Resource { func resourceLBVipV1Create(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - networkingClient, err := openstack.NewNetworkV2(config.osClient, gophercloud.EndpointOpts{ - Region: d.Get("region").(string), - }) + networkingClient, err := config.networkingV2Client(d.Get("region").(string)) if err != nil { return fmt.Errorf("Error creating OpenStack networking client: %s", err) } @@ -129,9 +126,7 @@ func resourceLBVipV1Create(d *schema.ResourceData, meta interface{}) error { func resourceLBVipV1Read(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - networkingClient, err := openstack.NewNetworkV2(config.osClient, gophercloud.EndpointOpts{ - Region: d.Get("region").(string), - }) + networkingClient, err := config.networkingV2Client(d.Get("region").(string)) if err != nil { return fmt.Errorf("Error creating OpenStack networking client: %s", err) } @@ -189,9 +184,7 @@ func resourceLBVipV1Read(d *schema.ResourceData, meta interface{}) error { func resourceLBVipV1Update(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - networkingClient, err := openstack.NewNetworkV2(config.osClient, gophercloud.EndpointOpts{ - Region: d.Get("region").(string), - }) + networkingClient, err := config.networkingV2Client(d.Get("region").(string)) if err != nil { return fmt.Errorf("Error creating OpenStack networking client: %s", err) } @@ -235,9 +228,7 @@ func resourceLBVipV1Update(d *schema.ResourceData, meta interface{}) error { func resourceLBVipV1Delete(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - networkingClient, err := openstack.NewNetworkV2(config.osClient, gophercloud.EndpointOpts{ - Region: d.Get("region").(string), - }) + networkingClient, err := config.networkingV2Client(d.Get("region").(string)) if err != nil { return fmt.Errorf("Error creating OpenStack networking client: %s", err) } diff --git a/builtin/providers/openstack/resource_openstack_networking_network_v2.go b/builtin/providers/openstack/resource_openstack_networking_network_v2.go index e32db9697c..fc420b2e9a 100644 --- a/builtin/providers/openstack/resource_openstack_networking_network_v2.go +++ b/builtin/providers/openstack/resource_openstack_networking_network_v2.go @@ -6,8 +6,6 @@ import ( "strconv" "github.com/hashicorp/terraform/helper/schema" - "github.com/rackspace/gophercloud" - "github.com/rackspace/gophercloud/openstack" "github.com/rackspace/gophercloud/openstack/networking/v2/networks" ) @@ -51,9 +49,7 @@ func resourceNetworkingNetworkV2() *schema.Resource { func resourceNetworkingNetworkV2Create(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - networkingClient, err := openstack.NewNetworkV2(config.osClient, gophercloud.EndpointOpts{ - Region: d.Get("region").(string), - }) + networkingClient, err := config.networkingV2Client(d.Get("region").(string)) if err != nil { return fmt.Errorf("Error creating OpenStack networking client: %s", err) } @@ -95,9 +91,7 @@ func resourceNetworkingNetworkV2Create(d *schema.ResourceData, meta interface{}) func resourceNetworkingNetworkV2Read(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - networkingClient, err := openstack.NewNetworkV2(config.osClient, gophercloud.EndpointOpts{ - Region: d.Get("region").(string), - }) + networkingClient, err := config.networkingV2Client(d.Get("region").(string)) if err != nil { return fmt.Errorf("Error creating OpenStack networking client: %s", err) } @@ -140,9 +134,7 @@ func resourceNetworkingNetworkV2Read(d *schema.ResourceData, meta interface{}) e func resourceNetworkingNetworkV2Update(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - networkingClient, err := openstack.NewNetworkV2(config.osClient, gophercloud.EndpointOpts{ - Region: d.Get("region").(string), - }) + networkingClient, err := config.networkingV2Client(d.Get("region").(string)) if err != nil { return fmt.Errorf("Error creating OpenStack networking client: %s", err) } @@ -184,9 +176,7 @@ func resourceNetworkingNetworkV2Update(d *schema.ResourceData, meta interface{}) func resourceNetworkingNetworkV2Delete(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - networkingClient, err := openstack.NewNetworkV2(config.osClient, gophercloud.EndpointOpts{ - Region: d.Get("region").(string), - }) + networkingClient, err := config.networkingV2Client(d.Get("region").(string)) if err != nil { return fmt.Errorf("Error creating OpenStack networking client: %s", err) } diff --git a/builtin/providers/openstack/resource_openstack_networking_subnet_v2.go b/builtin/providers/openstack/resource_openstack_networking_subnet_v2.go index 0e72ce98d1..74a43e27c7 100644 --- a/builtin/providers/openstack/resource_openstack_networking_subnet_v2.go +++ b/builtin/providers/openstack/resource_openstack_networking_subnet_v2.go @@ -7,8 +7,6 @@ import ( "github.com/hashicorp/terraform/helper/hashcode" "github.com/hashicorp/terraform/helper/schema" - "github.com/rackspace/gophercloud" - "github.com/rackspace/gophercloud/openstack" "github.com/rackspace/gophercloud/openstack/networking/v2/subnets" ) @@ -110,9 +108,7 @@ func resourceNetworkingSubnetV2() *schema.Resource { func resourceNetworkingSubnetV2Create(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - networkingClient, err := openstack.NewNetworkV2(config.osClient, gophercloud.EndpointOpts{ - Region: d.Get("region").(string), - }) + networkingClient, err := config.networkingV2Client(d.Get("region").(string)) if err != nil { return fmt.Errorf("Error creating OpenStack networking client: %s", err) } @@ -152,9 +148,7 @@ func resourceNetworkingSubnetV2Create(d *schema.ResourceData, meta interface{}) func resourceNetworkingSubnetV2Read(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - networkingClient, err := openstack.NewNetworkV2(config.osClient, gophercloud.EndpointOpts{ - Region: d.Get("region").(string), - }) + networkingClient, err := config.networkingV2Client(d.Get("region").(string)) if err != nil { return fmt.Errorf("Error creating OpenStack networking client: %s", err) } @@ -212,9 +206,7 @@ func resourceNetworkingSubnetV2Read(d *schema.ResourceData, meta interface{}) er func resourceNetworkingSubnetV2Update(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - networkingClient, err := openstack.NewNetworkV2(config.osClient, gophercloud.EndpointOpts{ - Region: d.Get("region").(string), - }) + networkingClient, err := config.networkingV2Client(d.Get("region").(string)) if err != nil { return fmt.Errorf("Error creating OpenStack networking client: %s", err) } @@ -260,9 +252,7 @@ func resourceNetworkingSubnetV2Update(d *schema.ResourceData, meta interface{}) func resourceNetworkingSubnetV2Delete(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - networkingClient, err := openstack.NewNetworkV2(config.osClient, gophercloud.EndpointOpts{ - Region: d.Get("region").(string), - }) + networkingClient, err := config.networkingV2Client(d.Get("region").(string)) if err != nil { return fmt.Errorf("Error creating OpenStack networking client: %s", err) } From 777c34cf7c4f6d791e5bd65ae013058d66c93246 Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Sat, 31 Jan 2015 17:19:42 -0700 Subject: [PATCH 055/132] move lb member ops into lb pool file --- builtin/providers/openstack/provider.go | 1 - .../resource_openstack_lb_member_v1.go | 144 ------------------ .../resource_openstack_lb_pool_v1.go | 127 +++++++++++++++ 3 files changed, 127 insertions(+), 145 deletions(-) delete mode 100644 builtin/providers/openstack/resource_openstack_lb_member_v1.go diff --git a/builtin/providers/openstack/provider.go b/builtin/providers/openstack/provider.go index 65496d5346..a53882f848 100644 --- a/builtin/providers/openstack/provider.go +++ b/builtin/providers/openstack/provider.go @@ -62,7 +62,6 @@ func Provider() terraform.ResourceProvider { "openstack_compute_instance_v2": resourceComputeInstanceV2(), "openstack_compute_keypair_v2": resourceComputeKeypairV2(), "openstack_compute_secgroup_v2": resourceComputeSecGroupV2(), - "openstack_lb_member_v1": resourceLBMemberV1(), "openstack_lb_monitor_v1": resourceLBMonitorV1(), "openstack_lb_pool_v1": resourceLBPoolV1(), "openstack_lb_vip_v1": resourceLBVipV1(), diff --git a/builtin/providers/openstack/resource_openstack_lb_member_v1.go b/builtin/providers/openstack/resource_openstack_lb_member_v1.go deleted file mode 100644 index 9cadfef909..0000000000 --- a/builtin/providers/openstack/resource_openstack_lb_member_v1.go +++ /dev/null @@ -1,144 +0,0 @@ -package openstack - -import ( - "fmt" - "log" - - "github.com/hashicorp/terraform/helper/schema" - "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/lbaas/members" -) - -func resourceLBMemberV1() *schema.Resource { - return &schema.Resource{ - Create: resourceLBMemberV1Create, - Read: resourceLBMemberV1Read, - Update: resourceLBMemberV1Update, - Delete: resourceLBMemberV1Delete, - - Schema: map[string]*schema.Schema{ - "region": &schema.Schema{ - Type: schema.TypeString, - Required: true, - ForceNew: true, - DefaultFunc: envDefaultFunc("OS_REGION_NAME"), - }, - "tenant_id": &schema.Schema{ - Type: schema.TypeString, - Optional: true, - ForceNew: true, - }, - "address": &schema.Schema{ - Type: schema.TypeString, - Required: true, - ForceNew: true, - }, - "port": &schema.Schema{ - Type: schema.TypeInt, - Required: true, - ForceNew: true, - }, - "pool_id": &schema.Schema{ - Type: schema.TypeString, - Required: true, - ForceNew: true, - }, - "admin_state_up": &schema.Schema{ - Type: schema.TypeBool, - Required: true, - ForceNew: false, - }, - }, - } -} - -func resourceLBMemberV1Create(d *schema.ResourceData, meta interface{}) error { - config := meta.(*Config) - networkingClient, err := config.networkingV2Client(d.Get("region").(string)) - if err != nil { - return fmt.Errorf("Error creating OpenStack networking client: %s", err) - } - - createOpts := members.CreateOpts{ - //TenantID: d.Get("tenant_id").(string), - Address: d.Get("address").(string), - ProtocolPort: d.Get("port").(int), - PoolID: d.Get("pool_id").(string), - } - - log.Printf("[INFO] Requesting lb member creation") - p, err := members.Create(networkingClient, createOpts).Extract() - if err != nil { - return fmt.Errorf("Error creating OpenStack LB member: %s", err) - } - log.Printf("[INFO] LB Member ID: %s", p.ID) - - d.SetId(p.ID) - - return resourceLBMemberV1Read(d, meta) -} - -func resourceLBMemberV1Read(d *schema.ResourceData, meta interface{}) error { - config := meta.(*Config) - networkingClient, err := config.networkingV2Client(d.Get("region").(string)) - if err != nil { - return fmt.Errorf("Error creating OpenStack networking client: %s", err) - } - - p, err := members.Get(networkingClient, d.Id()).Extract() - if err != nil { - return fmt.Errorf("Error retrieving OpenStack LB Member: %s", err) - } - - log.Printf("[DEBUG] Retreived OpenStack LB Member %s: %+v", d.Id(), p) - - d.Set("region", d.Get("region").(string)) - d.Set("address", p.Address) - d.Set("port", p.ProtocolPort) - d.Set("pool_id", p.PoolID) - - if t, exists := d.GetOk("tenant_id"); exists && t != "" { - d.Set("tenant_id", p.TenantID) - } else { - d.Set("tenant_id", "") - } - - return nil -} - -func resourceLBMemberV1Update(d *schema.ResourceData, meta interface{}) error { - config := meta.(*Config) - networkingClient, err := config.networkingV2Client(d.Get("region").(string)) - if err != nil { - return fmt.Errorf("Error creating OpenStack networking client: %s", err) - } - - var updateOpts members.UpdateOpts - if d.HasChange("admin_state_up") { - updateOpts.AdminStateUp = d.Get("admin_state_up").(bool) - } - - log.Printf("[DEBUG] Updating OpenStack LB Member %s with options: %+v", d.Id(), updateOpts) - - _, err = members.Update(networkingClient, d.Id(), updateOpts).Extract() - if err != nil { - return fmt.Errorf("Error updating OpenStack LB Member: %s", err) - } - - return resourceLBMemberV1Read(d, meta) -} - -func resourceLBMemberV1Delete(d *schema.ResourceData, meta interface{}) error { - config := meta.(*Config) - networkingClient, err := config.networkingV2Client(d.Get("region").(string)) - if err != nil { - return fmt.Errorf("Error creating OpenStack networking client: %s", err) - } - - err = members.Delete(networkingClient, d.Id()).ExtractErr() - if err != nil { - return fmt.Errorf("Error deleting OpenStack LB Member: %s", err) - } - - d.SetId("") - return nil -} diff --git a/builtin/providers/openstack/resource_openstack_lb_pool_v1.go b/builtin/providers/openstack/resource_openstack_lb_pool_v1.go index 3cadc28587..a7b5abbafb 100644 --- a/builtin/providers/openstack/resource_openstack_lb_pool_v1.go +++ b/builtin/providers/openstack/resource_openstack_lb_pool_v1.go @@ -1,12 +1,15 @@ package openstack import ( + "bytes" "fmt" "log" "github.com/hashicorp/terraform/helper/hashcode" "github.com/hashicorp/terraform/helper/schema" + "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/lbaas/members" "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/lbaas/pools" + "github.com/rackspace/gophercloud/pagination" ) func resourceLBPoolV1() *schema.Resource { @@ -49,6 +52,41 @@ func resourceLBPoolV1() *schema.Resource { Optional: true, ForceNew: true, }, + "member": &schema.Schema{ + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "region": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + DefaultFunc: envDefaultFunc("OS_REGION_NAME"), + }, + "tenant_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "address": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "port": &schema.Schema{ + Type: schema.TypeInt, + Required: true, + ForceNew: true, + }, + "admin_state_up": &schema.Schema{ + Type: schema.TypeBool, + Required: true, + ForceNew: false, + }, + }, + }, + Set: resourceLBMemberV1Hash, + }, "monitor_ids": &schema.Schema{ Type: schema.TypeSet, Optional: true, @@ -95,6 +133,15 @@ func resourceLBPoolV1Create(d *schema.ResourceData, meta interface{}) error { } } + if memberOpts := resourcePoolMembersV1(d); memberOpts != nil { + for _, memberOpt := range memberOpts { + _, err := members.Create(networkingClient, memberOpt).Extract() + if err != nil { + return fmt.Errorf("Error creating OpenStack LB member: %s", err) + } + } + } + return resourceLBPoolV1Read(d, meta) } @@ -125,6 +172,7 @@ func resourceLBPoolV1Read(d *schema.ResourceData, meta interface{}) error { } d.Set("monitor_ids", p.MonitorIDs) + d.Set("member_ids", p.MemberIDs) return nil } @@ -178,6 +226,49 @@ func resourceLBPoolV1Update(d *schema.ResourceData, meta interface{}) error { } } + if d.HasChange("member") { + oldMembersRaw, newMembersRaw := d.GetChange("member") + oldMembersSet, newMembersSet := oldMembersRaw.(*schema.Set), newMembersRaw.(*schema.Set) + membersToAdd := newMembersSet.Difference(oldMembersSet) + membersToRemove := oldMembersSet.Difference(newMembersSet) + + log.Printf("[DEBUG] Members to add: %v", membersToAdd) + + log.Printf("[DEBUG] Members to remove: %v", membersToRemove) + + for _, m := range membersToRemove.List() { + oldMember := resourcePoolMemberV1(d, m) + listOpts := members.ListOpts{ + PoolID: d.Id(), + Address: oldMember.Address, + ProtocolPort: oldMember.ProtocolPort, + } + err = members.List(networkingClient, listOpts).EachPage(func(page pagination.Page) (bool, error) { + extractedMembers, err := members.ExtractMembers(page) + if err != nil { + return false, err + } + for _, member := range extractedMembers { + err := members.Delete(networkingClient, member.ID).ExtractErr() + if err != nil { + return false, fmt.Errorf("Error deleting member (%s) from OpenStack LB pool (%s): %s", member.ID, d.Id(), err) + } + log.Printf("[DEBUG] Deleted member (%s) from pool (%s)", member.ID, d.Id()) + } + return true, nil + }) + } + + for _, m := range membersToAdd.List() { + createOpts := resourcePoolMemberV1(d, m) + newMember, err := members.Create(networkingClient, createOpts).Extract() + if err != nil { + return fmt.Errorf("Error creating LB member: %s", err) + } + log.Printf("[DEBUG] Created member (%s) in OpenStack LB pool (%s)", newMember.ID, d.Id()) + } + } + return resourceLBPoolV1Read(d, meta) } @@ -205,3 +296,39 @@ func resourcePoolMonitorIDsV1(d *schema.ResourceData) []string { } return mIDs } + +func resourcePoolMembersV1(d *schema.ResourceData) []members.CreateOpts { + memberOptsRaw := (d.Get("member")).(*schema.Set) + memberOpts := make([]members.CreateOpts, memberOptsRaw.Len()) + for i, raw := range memberOptsRaw.List() { + rawMap := raw.(map[string]interface{}) + memberOpts[i] = members.CreateOpts{ + TenantID: rawMap["tenant_id"].(string), + Address: rawMap["address"].(string), + ProtocolPort: rawMap["port"].(int), + PoolID: d.Id(), + } + } + return memberOpts +} + +func resourcePoolMemberV1(d *schema.ResourceData, raw interface{}) members.CreateOpts { + rawMap := raw.(map[string]interface{}) + return members.CreateOpts{ + TenantID: rawMap["tenant_id"].(string), + Address: rawMap["address"].(string), + ProtocolPort: rawMap["port"].(int), + PoolID: d.Id(), + } +} + +func resourceLBMemberV1Hash(v interface{}) int { + var buf bytes.Buffer + m := v.(map[string]interface{}) + buf.WriteString(fmt.Sprintf("%s-", m["region"].(string))) + buf.WriteString(fmt.Sprintf("%s-", m["tenant_id"].(string))) + buf.WriteString(fmt.Sprintf("%s-", m["address"].(string))) + buf.WriteString(fmt.Sprintf("%d-", m["port"].(int))) + + return hashcode.String(buf.String()) +} From 33d62bbdbffd41db611288e7bdf2ee2ff89bd746 Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Sat, 31 Jan 2015 17:21:57 -0700 Subject: [PATCH 056/132] 'networks' -> 'network' --- .../openstack/resource_openstack_compute_instance_v2.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/builtin/providers/openstack/resource_openstack_compute_instance_v2.go b/builtin/providers/openstack/resource_openstack_compute_instance_v2.go index a2e66ca2e5..8059dec1b1 100644 --- a/builtin/providers/openstack/resource_openstack_compute_instance_v2.go +++ b/builtin/providers/openstack/resource_openstack_compute_instance_v2.go @@ -60,7 +60,7 @@ func resourceComputeInstanceV2() *schema.Resource { Optional: true, ForceNew: true, }, - "networks": &schema.Schema{ + "network": &schema.Schema{ Type: schema.TypeList, Optional: true, ForceNew: true, @@ -430,7 +430,7 @@ func resourceInstanceSecGroupsV2(d *schema.ResourceData) []string { } func resourceInstanceNetworksV2(d *schema.ResourceData) []servers.Network { - rawNetworks := d.Get("networks").([]interface{}) + rawNetworks := d.Get("network").([]interface{}) networks := make([]servers.Network, len(rawNetworks)) for i, raw := range rawNetworks { rawMap := raw.(map[string]interface{}) From 6b2f2df04289b8ff87ae022c54e87b58bc9dccf2 Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Sat, 31 Jan 2015 17:22:19 -0700 Subject: [PATCH 057/132] 'rules' -> 'rule' --- .../resource_openstack_compute_secgroup_v2.go | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/builtin/providers/openstack/resource_openstack_compute_secgroup_v2.go b/builtin/providers/openstack/resource_openstack_compute_secgroup_v2.go index f83ce84c7e..f1d9ae7141 100644 --- a/builtin/providers/openstack/resource_openstack_compute_secgroup_v2.go +++ b/builtin/providers/openstack/resource_openstack_compute_secgroup_v2.go @@ -34,7 +34,7 @@ func resourceComputeSecGroupV2() *schema.Resource { Required: true, ForceNew: false, }, - "rules": &schema.Schema{ + "rule": &schema.Schema{ Type: schema.TypeSet, Optional: true, Elem: &schema.Resource{ @@ -66,7 +66,7 @@ func resourceComputeSecGroupV2() *schema.Resource { }, }, }, - Set: resourceSecGroupRuleHash, + Set: resourceSecGroupRuleV2Hash, }, }, } @@ -117,7 +117,7 @@ func resourceComputeSecGroupV2Read(d *schema.ResourceData, meta interface{}) err d.Set("region", d.Get("region").(string)) d.Set("name", sg.Name) d.Set("description", sg.Description) - d.Set("rules", sg.Rules) + d.Set("rule", sg.Rules) return nil } @@ -141,8 +141,8 @@ func resourceComputeSecGroupV2Update(d *schema.ResourceData, meta interface{}) e return fmt.Errorf("Error updating OpenStack security group (%s): %s", d.Id(), err) } - if d.HasChange("rules") { - oldSGRaw, newSGRaw := d.GetChange("rules") + if d.HasChange("rule") { + oldSGRaw, newSGRaw := d.GetChange("rule") oldSGRSet, newSGRSet := oldSGRaw.(*schema.Set), newSGRaw.(*schema.Set) secgrouprulesToAdd := newSGRSet.Difference(oldSGRSet) secgrouprulesToRemove := oldSGRSet.Difference(newSGRSet) @@ -188,7 +188,7 @@ func resourceComputeSecGroupV2Delete(d *schema.ResourceData, meta interface{}) e return nil } -func resourceSecGroupRuleHash(v interface{}) int { +func resourceSecGroupRuleV2Hash(v interface{}) int { var buf bytes.Buffer m := v.(map[string]interface{}) buf.WriteString(fmt.Sprintf("%d-", m["from_port"].(int))) @@ -201,7 +201,7 @@ func resourceSecGroupRuleHash(v interface{}) int { } func resourceSecGroupRulesV2(d *schema.ResourceData) []secgroups.CreateRuleOpts { - rawRules := (d.Get("rules")).(*schema.Set) + rawRules := (d.Get("rule")).(*schema.Set) createRuleOptsList := make([]secgroups.CreateRuleOpts, rawRules.Len()) for i, raw := range rawRules.List() { rawMap := raw.(map[string]interface{}) @@ -219,7 +219,7 @@ func resourceSecGroupRulesV2(d *schema.ResourceData) []secgroups.CreateRuleOpts func resourceSecGroupRuleV2(d *schema.ResourceData, raw interface{}) secgroups.CreateRuleOpts { rawMap := raw.(map[string]interface{}) - createRuleOpts := secgroups.CreateRuleOpts{ + return secgroups.CreateRuleOpts{ ParentGroupID: d.Id(), FromPort: rawMap["from_port"].(int), ToPort: rawMap["to_port"].(int), @@ -227,6 +227,4 @@ func resourceSecGroupRuleV2(d *schema.ResourceData, raw interface{}) secgroups.C CIDR: rawMap["cidr"].(string), FromGroupID: rawMap["from_group_id"].(string), } - - return createRuleOpts } From b9395b36d28b7267d3968f43495f48ca75a4757f Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Sat, 31 Jan 2015 17:22:37 -0700 Subject: [PATCH 058/132] update client methods --- .../resource_openstack_compute_instance_v2_test.go | 12 +++--------- .../resource_openstack_compute_keypair_v2_test.go | 12 +++--------- 2 files changed, 6 insertions(+), 18 deletions(-) diff --git a/builtin/providers/openstack/resource_openstack_compute_instance_v2_test.go b/builtin/providers/openstack/resource_openstack_compute_instance_v2_test.go index ff2457d095..77559fa3a9 100644 --- a/builtin/providers/openstack/resource_openstack_compute_instance_v2_test.go +++ b/builtin/providers/openstack/resource_openstack_compute_instance_v2_test.go @@ -7,8 +7,6 @@ import ( "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/terraform" - "github.com/rackspace/gophercloud" - "github.com/rackspace/gophercloud/openstack" "github.com/rackspace/gophercloud/openstack/compute/v2/servers" ) @@ -33,9 +31,7 @@ func TestAccComputeV2Instance_basic(t *testing.T) { func testAccCheckComputeV2InstanceDestroy(s *terraform.State) error { config := testAccProvider.Meta().(*Config) - computeClient, err := openstack.NewComputeV2(config.osClient, gophercloud.EndpointOpts{ - Region: OS_REGION_NAME, - }) + computeClient, err := config.computeV2Client(OS_REGION_NAME) if err != nil { return fmt.Errorf("(testAccCheckComputeV2InstanceDestroy) Error creating OpenStack compute client: %s", err) } @@ -65,10 +61,8 @@ func testAccCheckComputeV2InstanceExists(t *testing.T, n string, instance *serve return fmt.Errorf("No ID is set") } - osClient := testAccProvider.Meta().(*Config).osClient - computeClient, err := openstack.NewComputeV2(osClient, gophercloud.EndpointOpts{ - Region: OS_REGION_NAME, - }) + config := testAccProvider.Meta().(*Config) + computeClient, err := config.computeV2Client(OS_REGION_NAME) if err != nil { return fmt.Errorf("(testAccCheckComputeV2InstanceExists) Error creating OpenStack compute client: %s", err) } diff --git a/builtin/providers/openstack/resource_openstack_compute_keypair_v2_test.go b/builtin/providers/openstack/resource_openstack_compute_keypair_v2_test.go index 0456341df8..da090bcd83 100644 --- a/builtin/providers/openstack/resource_openstack_compute_keypair_v2_test.go +++ b/builtin/providers/openstack/resource_openstack_compute_keypair_v2_test.go @@ -7,8 +7,6 @@ import ( "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/terraform" - "github.com/rackspace/gophercloud" - "github.com/rackspace/gophercloud/openstack" "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/keypairs" ) @@ -32,9 +30,7 @@ func TestAccComputeV2Keypair_basic(t *testing.T) { func testAccCheckComputeV2KeypairDestroy(s *terraform.State) error { config := testAccProvider.Meta().(*Config) - computeClient, err := openstack.NewComputeV2(config.osClient, gophercloud.EndpointOpts{ - Region: OS_REGION_NAME, - }) + computeClient, err := config.computeV2Client(OS_REGION_NAME) if err != nil { return fmt.Errorf("(testAccCheckComputeV2KeypairDestroy) Error creating OpenStack compute client: %s", err) } @@ -64,10 +60,8 @@ func testAccCheckComputeV2KeypairExists(t *testing.T, n string, kp *keypairs.Key return fmt.Errorf("No ID is set") } - osClient := testAccProvider.Meta().(*Config).osClient - computeClient, err := openstack.NewComputeV2(osClient, gophercloud.EndpointOpts{ - Region: OS_REGION_NAME, - }) + config := testAccProvider.Meta().(*Config) + computeClient, err := config.computeV2Client(OS_REGION_NAME) if err != nil { return fmt.Errorf("(testAccCheckComputeV2KeypairExists) Error creating OpenStack compute client: %s", err) } From 7cdb790ece6009594beccec787f26b94108b1bb2 Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Sat, 31 Jan 2015 17:35:42 -0700 Subject: [PATCH 059/132] update compute intance docs: 'networks -> 'network' --- .../providers/openstack/r/compute_instance_v2.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/source/docs/providers/openstack/r/compute_instance_v2.html.markdown b/website/source/docs/providers/openstack/r/compute_instance_v2.html.markdown index 4429174fb4..6a9a5ac95c 100644 --- a/website/source/docs/providers/openstack/r/compute_instance_v2.html.markdown +++ b/website/source/docs/providers/openstack/r/compute_instance_v2.html.markdown @@ -48,7 +48,7 @@ The following arguments are supported: * `availability_zone` - (Optional) The availability zone in which to create the server. Changing this creates a new server. -* `networks` - (Optional) An array of one or more networks to attach to the +* `network` - (Optional) An array of one or more networks to attach to the instance. The network object structure is documented below. Changing this creates a new server. From 3427597bd0d9204201a4d7cb25ba8b79a3ae9384 Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Sat, 31 Jan 2015 17:37:11 -0700 Subject: [PATCH 060/132] update docs to remove security group rule and lb member files --- .../r/compute_secgroup_v2.html.markdown | 30 ++++++++ .../r/compute_secgrouprule_v2.html.markdown | 69 ------------------- .../openstack/r/lb_member_v1.html.markdown | 58 ---------------- .../openstack/r/lb_pool_v1.html.markdown | 28 +++++++- website/source/layouts/openstack.erb | 6 -- 5 files changed, 57 insertions(+), 134 deletions(-) delete mode 100644 website/source/docs/providers/openstack/r/compute_secgrouprule_v2.html.markdown delete mode 100644 website/source/docs/providers/openstack/r/lb_member_v1.html.markdown diff --git a/website/source/docs/providers/openstack/r/compute_secgroup_v2.html.markdown b/website/source/docs/providers/openstack/r/compute_secgroup_v2.html.markdown index 86f546ed25..50f3285021 100644 --- a/website/source/docs/providers/openstack/r/compute_secgroup_v2.html.markdown +++ b/website/source/docs/providers/openstack/r/compute_secgroup_v2.html.markdown @@ -16,6 +16,12 @@ Manages a V2 security group resource within OpenStack. resource "openstack_compute_secgroup_v2" "secgroup_1" { name = "my_secgroup" description = "my security group" + rule { + from_port = 22 + to_port = 22 + ip_protocol = "tcp" + cidr = "0.0.0.0/0" + } } ``` @@ -34,6 +40,29 @@ The following arguments are supported: * `description` - (Required) A description for the security group. Changing this updates the `description` of an existing security group. +* `rule` - (Optional) A rule describing how the security group operates. The + rule object structure is documented below. Changing this updates the + security group rules. + +The `rule` block supports: + +* `from_port` - (Required) An integer representing the lower bound of the port +range to open. Changing this creates a new security group rule. + +* `to_port` - (Required) An integer representing the upper bound of the port +range to open. Changing this creates a new security group rule. + +* `ip_protocol` - (Required) The protocol type that will be allowed. Changing +this creates a new security group rule. + +* `cidr` - (Optional) Required if `from_group_id` is empty. The IP range that +will be the source of network traffic to the security group. Use 0.0.0.0./0 +to allow all IP addresses. Changing this creates a new security group rule. + +* `from_group_id - (Optional) Required if `cidr` is empty. The ID of a group +from which to forward traffic to the parent group. Changing +this creates a new security group rule. + ## Attributes Reference The following attributes are exported: @@ -41,3 +70,4 @@ The following attributes are exported: * `region` - See Argument Reference above. * `name` - See Argument Reference above. * `description` - See Argument Reference above. +* `rule` - See Argument Reference above. diff --git a/website/source/docs/providers/openstack/r/compute_secgrouprule_v2.html.markdown b/website/source/docs/providers/openstack/r/compute_secgrouprule_v2.html.markdown deleted file mode 100644 index 06385a6c87..0000000000 --- a/website/source/docs/providers/openstack/r/compute_secgrouprule_v2.html.markdown +++ /dev/null @@ -1,69 +0,0 @@ ---- -layout: "openstack" -page_title: "OpenStack: openstack_compute_secgrouprule_v2" -sidebar_current: "docs-openstack-resource-compute-secgrouprule-v2" -description: |- - Manages a V2 security group rule resource within OpenStack. ---- - -# openstack\_compute\_secgrouprule_v2 - -Manages a V2 security group rule resource within OpenStack. - -## Example Usage - -``` -resource "openstack_compute_secgroup_v2" "secgroup_1" { - name = "my_secgroup" - description = "my security group" -} - -resource "openstack_compute_secgrouprule_v2" "secgrouprule_1" { - group_id = "${openstack_compute_secgroup_v2.secgroup_1.id}" - from_port = 22 - to_port = 22 - ip_protocol = "TCP" - cidr = "0.0.0.0/0" -} -``` - -## Argument Reference - -The following arguments are supported: - -* `region` - (Required) The region in which to obtain the V2 Compute client. - A Compute client is needed to create a security group rule. If omitted, the - `OS_REGION_NAME` environment variable is used. Changing this creates a new - security group rule. - -* `group_id` - (Required) The ID of the group to which this rule will be added. - Changing this creates a new security group rule. - -* `from_port` - (Required) An integer representing the lower bound of the port - range to open. Changing this creates a new security group rule. - -* `to_port` - (Required) An integer representing the upper bound of the port - range to open. Changing this creates a new security group rule. - -* `ip_protocol` - (Required) The protocol type that will be allowed. Changing - this creates a new security group rule. - -* `cidr` - (Optional) Required if `from_group_id` is empty. The IP range that - will be the source of network traffic to the security group. Use 0.0.0.0./0 - to allow all IP addresses. Changing this creates a new security group rule. - -* `from_group_id - (Optional) Required if `cidr` is empty. The ID of a group - from which to forward traffic to the parent group. Changing - this creates a new security group rule. - -## Attributes Reference - -The following attributes are exported: - -* `region` - See Argument Reference above. -* `group_id` - See Argument Reference above. -* `from_port` - See Argument Reference above. -* `to_port` - See Argument Reference above. -* `ip_protocol` - See Argument Reference above. -* `cidr` - See Argument Reference above. -* `from_group_id` - See Argument Reference above. diff --git a/website/source/docs/providers/openstack/r/lb_member_v1.html.markdown b/website/source/docs/providers/openstack/r/lb_member_v1.html.markdown deleted file mode 100644 index 2d1be74dc2..0000000000 --- a/website/source/docs/providers/openstack/r/lb_member_v1.html.markdown +++ /dev/null @@ -1,58 +0,0 @@ ---- -layout: "openstack" -page_title: "OpenStack: openstack_lb_member_v1" -sidebar_current: "docs-openstack-resource-lb-member-v1" -description: |- - Manages a V1 load balancer member resource within OpenStack. ---- - -# openstack\_lb\_member_v1 - -Manages a V1 load balancer member resource within OpenStack. - -## Example Usage - -``` -resource "openstack_lb_member_v1" "node_1" { - address = "196.172.0.1" - port = 80 - pool_id = "12345" - admin_state_up = true -} -``` - -## Argument Reference - -The following arguments are supported: - -* `region` - (Required) The region in which to obtain the V2 Networking client. - A Networking client is needed to create an LB member. If omitted, the - `OS_REGION_NAME` environment variable is used. Changing this creates a new - LB member. - -* `address` - (Required) The IP address of the member. Changing this creates a - new member. - -* `port` - (Required) An integer representing the port on which the member is - hosted. Changing this creates a new member. - -* `pool_id` - (Required) The pool to which this member will belong. Changing - this creates a new member. - -* `admin_state_up` - (Optional) The administrative state of the member. - Acceptable values are 'true' and 'false'. Changing this value updates the - state of the existing member. - -* `tenant_id` - (Optional) The owner of the member. Required if admin wants to - create a pool member for another tenant. Changing this creates a new member. - -## Attributes Reference - -The following attributes are exported: - -* `region` - See Argument Reference above. -* `address` - See Argument Reference above. -* `port` - See Argument Reference above. -* `pool_id` - See Argument Reference above. -* `admin_state_up` - See Argument Reference above. -* `tenant_id` - See Argument Reference above. diff --git a/website/source/docs/providers/openstack/r/lb_pool_v1.html.markdown b/website/source/docs/providers/openstack/r/lb_pool_v1.html.markdown index f0de6917a2..5ddbdf1af8 100644 --- a/website/source/docs/providers/openstack/r/lb_pool_v1.html.markdown +++ b/website/source/docs/providers/openstack/r/lb_pool_v1.html.markdown @@ -18,7 +18,12 @@ resource "openstack_lb_pool_v1" "pool_1" { protocol = "HTTP" subnet_id = "12345" lb_method = "ROUND_ROBIN" - monitor_id = "67890" + monitor_ids = ["67890"] + member { + address = "192.168.0.1" + port = 80 + admin_state_up = "true" + } } ``` @@ -51,6 +56,26 @@ The following arguments are supported: * `monitor_ids` - (Optional) A list of IDs of monitors to associate with the pool. +* `member` - (Optional) An existing node to add to the pool. Changing this + updates the members of the pool. The member object structure is documented + below. + +The `member` block supports: + +* `address` - (Required) The IP address of the member. Changing this creates a +new member. + +* `port` - (Required) An integer representing the port on which the member is +hosted. Changing this creates a new member. + +* `admin_state_up` - (Optional) The administrative state of the member. +Acceptable values are 'true' and 'false'. Changing this value updates the +state of the existing member. + +* `tenant_id` - (Optional) The owner of the member. Required if admin wants to +create a pool member for another tenant. Changing this creates a new member. + + ## Attributes Reference The following attributes are exported: @@ -62,3 +87,4 @@ The following attributes are exported: * `lb_method` - See Argument Reference above. * `tenant_id` - See Argument Reference above. * `monitor_id` - See Argument Reference above. +* `member` - See Argument Reference above. diff --git a/website/source/layouts/openstack.erb b/website/source/layouts/openstack.erb index 37b0c2a7c5..71cc9eb9ea 100644 --- a/website/source/layouts/openstack.erb +++ b/website/source/layouts/openstack.erb @@ -22,12 +22,6 @@ > openstack_compute_secgroup_v2 - > - openstack_compute_secgrouprule_v2 - - > - openstack_lb_member_v1 - > openstack_lb_monitor_v1 From fa15d41d45cd9a10615194c498b899a1b36ccf85 Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Sat, 31 Jan 2015 17:55:42 -0700 Subject: [PATCH 061/132] UpdateOpts not optional --- .../resource_openstack_lb_monitor_v1.go | 26 ++++++------------- 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/builtin/providers/openstack/resource_openstack_lb_monitor_v1.go b/builtin/providers/openstack/resource_openstack_lb_monitor_v1.go index ca5ad76594..7483b17e49 100644 --- a/builtin/providers/openstack/resource_openstack_lb_monitor_v1.go +++ b/builtin/providers/openstack/resource_openstack_lb_monitor_v1.go @@ -171,25 +171,15 @@ func resourceLBMonitorV1Update(d *schema.ResourceData, meta interface{}) error { return fmt.Errorf("Error creating OpenStack networking client: %s", err) } - var updateOpts monitors.UpdateOpts - if d.HasChange("delay") { - updateOpts.Delay = d.Get("delay").(int) - } - if d.HasChange("timeout") { - updateOpts.Timeout = d.Get("timeout").(int) - } - if d.HasChange("max_retries") { - updateOpts.MaxRetries = d.Get("max_retries").(int) - } - if d.HasChange("url_path") { - updateOpts.URLPath = d.Get("url_path").(string) - } - if d.HasChange("http_method") { - updateOpts.HTTPMethod = d.Get("http_method").(string) - } - if d.HasChange("expected_codes") { - updateOpts.ExpectedCodes = d.Get("expected_codes").(string) + updateOpts := monitors.UpdateOpts{ + Delay: d.Get("delay").(int), + Timeout: d.Get("timeout").(int), + MaxRetries: d.Get("max_retries").(int), + URLPath: d.Get("url_path").(string), + HTTPMethod: d.Get("http_method").(string), + ExpectedCodes: d.Get("expected_codes").(string), } + if d.HasChange("admin_state_up") { asuRaw := d.Get("admin_state_up").(string) if asuRaw != "" { From 66129632b358a44949443590b89d5aed1a72e061 Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Sat, 31 Jan 2015 17:56:11 -0700 Subject: [PATCH 062/132] security groups acceptance tests --- ...urce_openstack_compute_secgroup_v2_test.go | 90 +++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 builtin/providers/openstack/resource_openstack_compute_secgroup_v2_test.go diff --git a/builtin/providers/openstack/resource_openstack_compute_secgroup_v2_test.go b/builtin/providers/openstack/resource_openstack_compute_secgroup_v2_test.go new file mode 100644 index 0000000000..e78865b8a5 --- /dev/null +++ b/builtin/providers/openstack/resource_openstack_compute_secgroup_v2_test.go @@ -0,0 +1,90 @@ +package openstack + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" + + "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/secgroups" +) + +func TestAccComputeV2SecGroup_basic(t *testing.T) { + var secgroup secgroups.SecurityGroup + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckComputeV2SecGroupDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccComputeV2SecGroup_basic, + Check: resource.ComposeTestCheckFunc( + testAccCheckComputeV2SecGroupExists(t, "openstack_compute_secgroup_v2.foo", &secgroup), + ), + }, + }, + }) +} + +func testAccCheckComputeV2SecGroupDestroy(s *terraform.State) error { + config := testAccProvider.Meta().(*Config) + computeClient, err := config.computeV2Client(OS_REGION_NAME) + if err != nil { + return fmt.Errorf("(testAccCheckComputeV2SecGroupDestroy) Error creating OpenStack compute client: %s", err) + } + + for _, rs := range s.RootModule().Resources { + if rs.Type != "openstack_compute_secgroup_v2" { + continue + } + + _, err := secgroups.Get(computeClient, rs.Primary.ID).Extract() + if err == nil { + return fmt.Errorf("Security group still exists") + } + } + + return nil +} + +func testAccCheckComputeV2SecGroupExists(t *testing.T, n string, secgroup *secgroups.SecurityGroup) 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 ID is set") + } + + config := testAccProvider.Meta().(*Config) + computeClient, err := config.computeV2Client(OS_REGION_NAME) + if err != nil { + return fmt.Errorf("(testAccCheckComputeV2SecGroupExists) Error creating OpenStack compute client: %s", err) + } + + found, err := secgroups.Get(computeClient, rs.Primary.ID).Extract() + if err != nil { + return err + } + + if found.ID != rs.Primary.ID { + return fmt.Errorf("Security group not found") + } + + *secgroup = *found + + return nil + } +} + +var testAccComputeV2SecGroup_basic = fmt.Sprintf(` + resource "openstack_compute_secgroup_v2" "foo" { + region = "%s" + name = "test_group_1" + description = "first test security group" + }`, + OS_REGION_NAME) From e08e97304f91d9d674e874ac4acb505bb0be6d73 Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Sat, 31 Jan 2015 17:56:27 -0700 Subject: [PATCH 063/132] lb monitors acceptance tests --- .../resource_openstack_lb_monitor_v1_test.go | 110 ++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 builtin/providers/openstack/resource_openstack_lb_monitor_v1_test.go diff --git a/builtin/providers/openstack/resource_openstack_lb_monitor_v1_test.go b/builtin/providers/openstack/resource_openstack_lb_monitor_v1_test.go new file mode 100644 index 0000000000..5aaf61d2c6 --- /dev/null +++ b/builtin/providers/openstack/resource_openstack_lb_monitor_v1_test.go @@ -0,0 +1,110 @@ +package openstack + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" + + "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/lbaas/monitors" +) + +func TestAccLBV1Monitor_basic(t *testing.T) { + var monitor monitors.Monitor + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckLBV1MonitorDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccLBV1Monitor_basic, + Check: resource.ComposeTestCheckFunc( + testAccCheckLBV1MonitorExists(t, "openstack_lb_monitor_v1.monitor_1", &monitor), + ), + }, + resource.TestStep{ + Config: testAccLBV1Monitor_update, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("openstack_lb_monitor_v1.monitor_1", "delay", "20"), + ), + }, + }, + }) +} + +func testAccCheckLBV1MonitorDestroy(s *terraform.State) error { + config := testAccProvider.Meta().(*Config) + networkingClient, err := config.networkingV2Client(OS_REGION_NAME) + if err != nil { + return fmt.Errorf("(testAccCheckLBV1MonitorDestroy) Error creating OpenStack networking client: %s", err) + } + + for _, rs := range s.RootModule().Resources { + if rs.Type != "openstack_lb_monitor_v1" { + continue + } + + _, err := monitors.Get(networkingClient, rs.Primary.ID).Extract() + if err == nil { + return fmt.Errorf("LB monitor still exists") + } + } + + return nil +} + +func testAccCheckLBV1MonitorExists(t *testing.T, n string, monitor *monitors.Monitor) 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 ID is set") + } + + config := testAccProvider.Meta().(*Config) + networkingClient, err := config.networkingV2Client(OS_REGION_NAME) + if err != nil { + return fmt.Errorf("(testAccCheckLBV1MonitorExists) Error creating OpenStack networking client: %s", err) + } + + found, err := monitors.Get(networkingClient, rs.Primary.ID).Extract() + if err != nil { + return err + } + + if found.ID != rs.Primary.ID { + return fmt.Errorf("Monitor not found") + } + + *monitor = *found + + return nil + } +} + +var testAccLBV1Monitor_basic = fmt.Sprintf(` + resource "openstack_lb_monitor_v1" "monitor_1" { + region = "%s" + type = "PING" + delay = 30 + timeout = 5 + max_retries = 3 + admin_state_up = "true" + }`, + OS_REGION_NAME) + +var testAccLBV1Monitor_update = fmt.Sprintf(` + resource "openstack_lb_monitor_v1" "monitor_1" { + region = "%s" + type = "PING" + delay = 20 + timeout = 5 + max_retries = 3 + admin_state_up = "true" + }`, + OS_REGION_NAME) From e7a69d0a6c59450459bfe9aedc1065591ad24771 Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Sat, 31 Jan 2015 17:56:40 -0700 Subject: [PATCH 064/132] lb pools acceptance tests --- .../resource_openstack_lb_pool_v1_test.go | 134 ++++++++++++++++++ 1 file changed, 134 insertions(+) create mode 100644 builtin/providers/openstack/resource_openstack_lb_pool_v1_test.go diff --git a/builtin/providers/openstack/resource_openstack_lb_pool_v1_test.go b/builtin/providers/openstack/resource_openstack_lb_pool_v1_test.go new file mode 100644 index 0000000000..1889c23845 --- /dev/null +++ b/builtin/providers/openstack/resource_openstack_lb_pool_v1_test.go @@ -0,0 +1,134 @@ +package openstack + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" + + "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/lbaas/pools" +) + +func TestAccLBV1Pool_basic(t *testing.T) { + var pool pools.Pool + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckLBV1PoolDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccLBV1Pool_basic, + Check: resource.ComposeTestCheckFunc( + testAccCheckLBV1PoolExists(t, "openstack_lb_pool_v1.pool_1", &pool), + ), + }, + resource.TestStep{ + Config: testAccLBV1Pool_update, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("openstack_lb_pool_v1.pool_1", "name", "tf_test_lb_pool_updated"), + ), + }, + }, + }) +} + +func testAccCheckLBV1PoolDestroy(s *terraform.State) error { + config := testAccProvider.Meta().(*Config) + networkingClient, err := config.networkingV2Client(OS_REGION_NAME) + if err != nil { + return fmt.Errorf("(testAccCheckLBV1PoolDestroy) Error creating OpenStack networking client: %s", err) + } + + for _, rs := range s.RootModule().Resources { + if rs.Type != "openstack_lb_pool_v1" { + continue + } + + _, err := pools.Get(networkingClient, rs.Primary.ID).Extract() + if err == nil { + return fmt.Errorf("LB Pool still exists") + } + } + + return nil +} + +func testAccCheckLBV1PoolExists(t *testing.T, n string, pool *pools.Pool) 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 ID is set") + } + + config := testAccProvider.Meta().(*Config) + networkingClient, err := config.networkingV2Client(OS_REGION_NAME) + if err != nil { + return fmt.Errorf("(testAccCheckLBV1PoolExists) Error creating OpenStack networking client: %s", err) + } + + found, err := pools.Get(networkingClient, rs.Primary.ID).Extract() + if err != nil { + return err + } + + if found.ID != rs.Primary.ID { + return fmt.Errorf("Pool not found") + } + + *pool = *found + + return nil + } +} + +var testAccLBV1Pool_basic = fmt.Sprintf(` + resource "openstack_networking_network_v2" "network_1" { + region = "%s" + name = "network_1" + admin_state_up = "true" + } + + resource "openstack_networking_subnet_v2" "subnet_1" { + region = "%s" + network_id = "${openstack_networking_network_v2.network_1.id}" + cidr = "192.168.199.0/24" + ip_version = 4 + } + + resource "openstack_lb_pool_v1" "pool_1" { + region = "%s" + name = "tf_test_lb_pool" + protocol = "HTTP" + subnet_id = "${openstack_networking_subnet_v2.subnet_1.id}" + lb_method = "ROUND_ROBIN" + }`, + OS_REGION_NAME, OS_REGION_NAME, OS_REGION_NAME) + +var testAccLBV1Pool_update = fmt.Sprintf(` + resource "openstack_networking_network_v2" "network_1" { + region = "%s" + name = "network_1" + admin_state_up = "true" + } + + resource "openstack_networking_subnet_v2" "subnet_1" { + region = "%s" + network_id = "${openstack_networking_network_v2.network_1.id}" + cidr = "192.168.199.0/24" + ip_version = 4 + } + + resource "openstack_lb_pool_v1" "pool_1" { + region = "%s" + name = "tf_test_lb_pool_updated" + protocol = "HTTP" + subnet_id = "${openstack_networking_subnet_v2.subnet_1.id}" + lb_method = "ROUND_ROBIN" + }`, + OS_REGION_NAME, OS_REGION_NAME, OS_REGION_NAME) From d46d9a6540fd2375db3c494d5f70ac7eaa8f0d84 Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Sat, 31 Jan 2015 17:56:54 -0700 Subject: [PATCH 065/132] lb vips acceptance tests --- .../resource_openstack_lb_vip_v1_test.go | 152 ++++++++++++++++++ 1 file changed, 152 insertions(+) create mode 100644 builtin/providers/openstack/resource_openstack_lb_vip_v1_test.go diff --git a/builtin/providers/openstack/resource_openstack_lb_vip_v1_test.go b/builtin/providers/openstack/resource_openstack_lb_vip_v1_test.go new file mode 100644 index 0000000000..f30cd9d56d --- /dev/null +++ b/builtin/providers/openstack/resource_openstack_lb_vip_v1_test.go @@ -0,0 +1,152 @@ +package openstack + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" + + "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/lbaas/vips" +) + +func TestAccLBV1VIP_basic(t *testing.T) { + var vip vips.VirtualIP + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckLBV1VIPDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccLBV1VIP_basic, + Check: resource.ComposeTestCheckFunc( + testAccCheckLBV1VIPExists(t, "openstack_lb_vip_v1.vip_1", &vip), + ), + }, + resource.TestStep{ + Config: testAccLBV1VIP_update, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("openstack_lb_vip_v1.vip_1", "name", "tf_test_lb_vip_updated"), + ), + }, + }, + }) +} + +func testAccCheckLBV1VIPDestroy(s *terraform.State) error { + config := testAccProvider.Meta().(*Config) + networkingClient, err := config.networkingV2Client(OS_REGION_NAME) + if err != nil { + return fmt.Errorf("(testAccCheckLBV1VIPDestroy) Error creating OpenStack networking client: %s", err) + } + + for _, rs := range s.RootModule().Resources { + if rs.Type != "openstack_lb_vip_v1" { + continue + } + + _, err := vips.Get(networkingClient, rs.Primary.ID).Extract() + if err == nil { + return fmt.Errorf("LB VIP still exists") + } + } + + return nil +} + +func testAccCheckLBV1VIPExists(t *testing.T, n string, vip *vips.VirtualIP) 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 ID is set") + } + + config := testAccProvider.Meta().(*Config) + networkingClient, err := config.networkingV2Client(OS_REGION_NAME) + if err != nil { + return fmt.Errorf("(testAccCheckLBV1VIPExists) Error creating OpenStack networking client: %s", err) + } + + found, err := vips.Get(networkingClient, rs.Primary.ID).Extract() + if err != nil { + return err + } + + if found.ID != rs.Primary.ID { + return fmt.Errorf("VIP not found") + } + + *vip = *found + + return nil + } +} + +var testAccLBV1VIP_basic = fmt.Sprintf(` + resource "openstack_networking_network_v2" "network_1" { + region = "%s" + name = "network_1" + admin_state_up = "true" + } + + resource "openstack_networking_subnet_v2" "subnet_1" { + region = "%s" + network_id = "${openstack_networking_network_v2.network_1.id}" + cidr = "192.168.199.0/24" + ip_version = 4 + } + + resource "openstack_lb_pool_v1" "pool_1" { + region = "%s" + name = "tf_test_lb_pool" + protocol = "HTTP" + subnet_id = "${openstack_networking_subnet_v2.subnet_1.id}" + lb_method = "ROUND_ROBIN" + } + + resource "openstack_lb_vip_v1" "vip_1" { + region = "RegionOne" + name = "tf_test_lb_vip" + subnet_id = "${openstack_networking_subnet_v2.subnet_1.id}" + protocol = "HTTP" + port = 80 + pool_id = "${openstack_lb_pool_v1.pool_1.id}" + }`, + OS_REGION_NAME, OS_REGION_NAME, OS_REGION_NAME) + +var testAccLBV1VIP_update = fmt.Sprintf(` + resource "openstack_networking_network_v2" "network_1" { + region = "%s" + name = "network_1" + admin_state_up = "true" + } + + resource "openstack_networking_subnet_v2" "subnet_1" { + region = "%s" + network_id = "${openstack_networking_network_v2.network_1.id}" + cidr = "192.168.199.0/24" + ip_version = 4 + } + + resource "openstack_lb_pool_v1" "pool_1" { + region = "%s" + name = "tf_test_lb_pool" + protocol = "HTTP" + subnet_id = "${openstack_networking_subnet_v2.subnet_1.id}" + lb_method = "ROUND_ROBIN" + } + + resource "openstack_lb_vip_v1" "vip_1" { + region = "RegionOne" + name = "tf_test_lb_vip_updated" + subnet_id = "${openstack_networking_subnet_v2.subnet_1.id}" + protocol = "HTTP" + port = 80 + pool_id = "${openstack_lb_pool_v1.pool_1.id}" + }`, + OS_REGION_NAME, OS_REGION_NAME, OS_REGION_NAME) From e0409340776a65abc7ada949f1c92bb34e8cabb1 Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Sat, 31 Jan 2015 17:57:10 -0700 Subject: [PATCH 066/132] networking networks acceptance tests --- ...ce_openstack_networking_network_v2_test.go | 104 ++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 builtin/providers/openstack/resource_openstack_networking_network_v2_test.go diff --git a/builtin/providers/openstack/resource_openstack_networking_network_v2_test.go b/builtin/providers/openstack/resource_openstack_networking_network_v2_test.go new file mode 100644 index 0000000000..5bff605320 --- /dev/null +++ b/builtin/providers/openstack/resource_openstack_networking_network_v2_test.go @@ -0,0 +1,104 @@ +package openstack + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" + + "github.com/rackspace/gophercloud/openstack/networking/v2/networks" +) + +func TestAccNetworkingV2Network_basic(t *testing.T) { + var network networks.Network + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckNetworkingV2NetworkDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccNetworkingV2Network_basic, + Check: resource.ComposeTestCheckFunc( + testAccCheckNetworkingV2NetworkExists(t, "openstack_networking_network_v2.foo", &network), + ), + }, + resource.TestStep{ + Config: testAccNetworkingV2Network_update, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("openstack_networking_network_v2.foo", "name", "network_2"), + ), + }, + }, + }) +} + +func testAccCheckNetworkingV2NetworkDestroy(s *terraform.State) error { + config := testAccProvider.Meta().(*Config) + networkingClient, err := config.networkingV2Client(OS_REGION_NAME) + if err != nil { + return fmt.Errorf("(testAccCheckNetworkingV2NetworkDestroy) Error creating OpenStack networking client: %s", err) + } + + for _, rs := range s.RootModule().Resources { + if rs.Type != "openstack_networking_network_v2" { + continue + } + + _, err := networks.Get(networkingClient, rs.Primary.ID).Extract() + if err == nil { + return fmt.Errorf("Network still exists") + } + } + + return nil +} + +func testAccCheckNetworkingV2NetworkExists(t *testing.T, n string, network *networks.Network) 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 ID is set") + } + + config := testAccProvider.Meta().(*Config) + networkingClient, err := config.networkingV2Client(OS_REGION_NAME) + if err != nil { + return fmt.Errorf("(testAccCheckNetworkingV2NetworkExists) Error creating OpenStack networking client: %s", err) + } + + found, err := networks.Get(networkingClient, rs.Primary.ID).Extract() + if err != nil { + return err + } + + if found.ID != rs.Primary.ID { + return fmt.Errorf("Network not found") + } + + *network = *found + + return nil + } +} + +var testAccNetworkingV2Network_basic = fmt.Sprintf(` + resource "openstack_networking_network_v2" "foo" { + region = "%s" + name = "network_1" + admin_state_up = "true" + }`, + OS_REGION_NAME) + +var testAccNetworkingV2Network_update = fmt.Sprintf(` + resource "openstack_networking_network_v2" "foo" { + region = "%s" + name = "network_2" + admin_state_up = "true" + }`, + OS_REGION_NAME) From 08672e697ebe92849f387241c6d36f202da8d63c Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Sat, 31 Jan 2015 17:57:25 -0700 Subject: [PATCH 067/132] networking subnets acceptance tests --- ...rce_openstack_networking_subnet_v2_test.go | 119 ++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 builtin/providers/openstack/resource_openstack_networking_subnet_v2_test.go diff --git a/builtin/providers/openstack/resource_openstack_networking_subnet_v2_test.go b/builtin/providers/openstack/resource_openstack_networking_subnet_v2_test.go new file mode 100644 index 0000000000..d7f6116e9f --- /dev/null +++ b/builtin/providers/openstack/resource_openstack_networking_subnet_v2_test.go @@ -0,0 +1,119 @@ +package openstack + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" + + "github.com/rackspace/gophercloud/openstack/networking/v2/subnets" +) + +func TestAccNetworkingV2Subnet_basic(t *testing.T) { + var subnet subnets.Subnet + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckNetworkingV2SubnetDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccNetworkingV2Subnet_basic, + Check: resource.ComposeTestCheckFunc( + testAccCheckNetworkingV2SubnetExists(t, "openstack_networking_subnet_v2.subnet_1", &subnet), + ), + }, + resource.TestStep{ + Config: testAccNetworkingV2Subnet_update, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("openstack_networking_subnet_v2.subnet_1", "name", "tf-test-subnet"), + resource.TestCheckResourceAttr("openstack_networking_subnet_v2.subnet_1", "gateway_ip", "192.68.0.1"), + ), + }, + }, + }) +} + +func testAccCheckNetworkingV2SubnetDestroy(s *terraform.State) error { + config := testAccProvider.Meta().(*Config) + networkingClient, err := config.networkingV2Client(OS_REGION_NAME) + if err != nil { + return fmt.Errorf("(testAccCheckNetworkingV2SubnetDestroy) Error creating OpenStack networking client: %s", err) + } + + for _, rs := range s.RootModule().Resources { + if rs.Type != "openstack_networking_subnet_v2" { + continue + } + + _, err := subnets.Get(networkingClient, rs.Primary.ID).Extract() + if err == nil { + return fmt.Errorf("Subnet still exists") + } + } + + return nil +} + +func testAccCheckNetworkingV2SubnetExists(t *testing.T, n string, subnet *subnets.Subnet) 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 ID is set") + } + + config := testAccProvider.Meta().(*Config) + networkingClient, err := config.networkingV2Client(OS_REGION_NAME) + if err != nil { + return fmt.Errorf("(testAccCheckNetworkingV2SubnetExists) Error creating OpenStack networking client: %s", err) + } + + found, err := subnets.Get(networkingClient, rs.Primary.ID).Extract() + if err != nil { + return err + } + + if found.ID != rs.Primary.ID { + return fmt.Errorf("Subnet not found") + } + + *subnet = *found + + return nil + } +} + +var testAccNetworkingV2Subnet_basic = fmt.Sprintf(` + resource "openstack_networking_network_v2" "network_1" { + region = "%s" + name = "network_1" + admin_state_up = "true" + } + + resource "openstack_networking_subnet_v2" "subnet_1" { + region = "%s" + network_id = "${openstack_networking_network_v2.network_1.id}" + cidr = "192.168.199.0/24" + ip_version = 4 + }`, OS_REGION_NAME, OS_REGION_NAME) + +var testAccNetworkingV2Subnet_update = fmt.Sprintf(` + resource "openstack_networking_network_v2" "network_1" { + region = "%s" + name = "network_1" + admin_state_up = "true" + } + + resource "openstack_networking_subnet_v2" "subnet_1" { + region = "%s" + name = "tf-test-subnet" + network_id = "${openstack_networking_network_v2.network_1.id}" + cidr = "192.168.199.0/24" + ip_version = 4 + gateway_ip = "192.68.0.1" + }`, OS_REGION_NAME, OS_REGION_NAME) From 43564d1c5cf3f7533615699574bbceec9f1390c0 Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Sat, 31 Jan 2015 20:51:50 -0700 Subject: [PATCH 068/132] object storage container v1 ops --- builtin/providers/openstack/config.go | 6 + builtin/providers/openstack/provider.go | 17 +- ...ce_openstack_objectstorage_container_v1.go | 148 ++++++++++++++++++ 3 files changed, 163 insertions(+), 8 deletions(-) create mode 100644 builtin/providers/openstack/resource_openstack_objectstorage_container_v1.go diff --git a/builtin/providers/openstack/config.go b/builtin/providers/openstack/config.go index 2e37c4fd0f..864dc9ab7b 100644 --- a/builtin/providers/openstack/config.go +++ b/builtin/providers/openstack/config.go @@ -53,3 +53,9 @@ func (c *Config) networkingV2Client(region string) (*gophercloud.ServiceClient, Region: region, }) } + +func (c *Config) objectStorageV1Client(region string) (*gophercloud.ServiceClient, error) { + return openstack.NewObjectStorageV1(c.osClient, gophercloud.EndpointOpts{ + Region: region, + }) +} diff --git a/builtin/providers/openstack/provider.go b/builtin/providers/openstack/provider.go index a53882f848..019c7b386e 100644 --- a/builtin/providers/openstack/provider.go +++ b/builtin/providers/openstack/provider.go @@ -59,14 +59,15 @@ func Provider() terraform.ResourceProvider { }, ResourcesMap: map[string]*schema.Resource{ - "openstack_compute_instance_v2": resourceComputeInstanceV2(), - "openstack_compute_keypair_v2": resourceComputeKeypairV2(), - "openstack_compute_secgroup_v2": resourceComputeSecGroupV2(), - "openstack_lb_monitor_v1": resourceLBMonitorV1(), - "openstack_lb_pool_v1": resourceLBPoolV1(), - "openstack_lb_vip_v1": resourceLBVipV1(), - "openstack_networking_network_v2": resourceNetworkingNetworkV2(), - "openstack_networking_subnet_v2": resourceNetworkingSubnetV2(), + "openstack_compute_instance_v2": resourceComputeInstanceV2(), + "openstack_compute_keypair_v2": resourceComputeKeypairV2(), + "openstack_compute_secgroup_v2": resourceComputeSecGroupV2(), + "openstack_lb_monitor_v1": resourceLBMonitorV1(), + "openstack_lb_pool_v1": resourceLBPoolV1(), + "openstack_lb_vip_v1": resourceLBVipV1(), + "openstack_networking_network_v2": resourceNetworkingNetworkV2(), + "openstack_networking_subnet_v2": resourceNetworkingSubnetV2(), + "openstack_objectstorage_container_v1": resourceObjectStorageContainerV1(), }, ConfigureFunc: configureProvider, diff --git a/builtin/providers/openstack/resource_openstack_objectstorage_container_v1.go b/builtin/providers/openstack/resource_openstack_objectstorage_container_v1.go new file mode 100644 index 0000000000..f9b5d5250f --- /dev/null +++ b/builtin/providers/openstack/resource_openstack_objectstorage_container_v1.go @@ -0,0 +1,148 @@ +package openstack + +import ( + "fmt" + "log" + + "github.com/hashicorp/terraform/helper/schema" + "github.com/rackspace/gophercloud/openstack/objectstorage/v1/containers" +) + +func resourceObjectStorageContainerV1() *schema.Resource { + return &schema.Resource{ + Create: resourceObjectStorageContainerV1Create, + Read: resourceObjectStorageContainerV1Read, + Update: resourceObjectStorageContainerV1Update, + Delete: resourceObjectStorageContainerV1Delete, + + Schema: map[string]*schema.Schema{ + "region": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + DefaultFunc: envDefaultFunc("OS_REGION_NAME"), + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: false, + }, + "container_read": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: false, + }, + "container_sync_to": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: false, + }, + "container_sync_key": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: false, + }, + "container_write": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: false, + }, + "content_type": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: false, + }, + "metadata": &schema.Schema{ + Type: schema.TypeMap, + Optional: true, + ForceNew: false, + }, + }, + } +} + +func resourceObjectStorageContainerV1Create(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + objectStorgeClient, err := config.objectStorageV1Client(d.Get("region").(string)) + if err != nil { + return fmt.Errorf("Error creating OpenStack object storage client: %s", err) + } + + cn := d.Get("name").(string) + + createOpts := &containers.CreateOpts{ + ContainerRead: d.Get("container_read").(string), + ContainerSyncTo: d.Get("container_sync_to").(string), + ContainerSyncKey: d.Get("container_sync_key").(string), + ContainerWrite: d.Get("container_write").(string), + ContentType: d.Get("content_type").(string), + Metadata: resourceContainerMetadataV2(d), + } + + log.Printf("[INFO] Requesting container creation") + _, err = containers.Create(objectStorgeClient, cn, createOpts).Extract() + if err != nil { + return fmt.Errorf("Error creating OpenStack container: %s", err) + } + log.Printf("[INFO] Container ID: %s", cn) + + // Store the ID now + d.SetId(cn) + + return resourceObjectStorageContainerV1Read(d, meta) +} + +func resourceObjectStorageContainerV1Read(d *schema.ResourceData, meta interface{}) error { + return nil +} + +func resourceObjectStorageContainerV1Update(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + objectStorgeClient, err := config.objectStorageV1Client(d.Get("region").(string)) + if err != nil { + return fmt.Errorf("Error creating OpenStack object storage client: %s", err) + } + + updateOpts := containers.UpdateOpts{ + ContainerRead: d.Get("container_read").(string), + ContainerSyncTo: d.Get("container_sync_to").(string), + ContainerSyncKey: d.Get("container_sync_key").(string), + ContainerWrite: d.Get("container_write").(string), + ContentType: d.Get("content_type").(string), + } + + _, err = containers.Update(objectStorgeClient, d.Id(), updateOpts).Extract() + if err != nil { + return fmt.Errorf("Error updating OpenStack container: %s", err) + } + + if d.HasChange("metadata") { + updateOpts.Metadata = resourceContainerMetadataV2(d) + } + + return resourceObjectStorageContainerV1Read(d, meta) +} + +func resourceObjectStorageContainerV1Delete(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + objectStorgeClient, err := config.objectStorageV1Client(d.Get("region").(string)) + if err != nil { + return fmt.Errorf("Error creating OpenStack object storage client: %s", err) + } + + _, err = containers.Delete(objectStorgeClient, d.Id()).Extract() + if err != nil { + return fmt.Errorf("Error deleting OpenStack container: %s", err) + } + + d.SetId("") + return nil +} + +func resourceContainerMetadataV2(d *schema.ResourceData) map[string]string { + m := make(map[string]string) + for key, val := range d.Get("metadata").(map[string]interface{}) { + m[key] = val.(string) + } + return m +} From a5147f472bfcd3b5c02785ebd69e4ed5a788899b Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Sun, 1 Feb 2015 00:14:43 -0700 Subject: [PATCH 069/132] update metadata before actual Update op --- .../resource_openstack_objectstorage_container_v1.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/builtin/providers/openstack/resource_openstack_objectstorage_container_v1.go b/builtin/providers/openstack/resource_openstack_objectstorage_container_v1.go index f9b5d5250f..687e65b57e 100644 --- a/builtin/providers/openstack/resource_openstack_objectstorage_container_v1.go +++ b/builtin/providers/openstack/resource_openstack_objectstorage_container_v1.go @@ -111,15 +111,15 @@ func resourceObjectStorageContainerV1Update(d *schema.ResourceData, meta interfa ContentType: d.Get("content_type").(string), } + if d.HasChange("metadata") { + updateOpts.Metadata = resourceContainerMetadataV2(d) + } + _, err = containers.Update(objectStorgeClient, d.Id(), updateOpts).Extract() if err != nil { return fmt.Errorf("Error updating OpenStack container: %s", err) } - if d.HasChange("metadata") { - updateOpts.Metadata = resourceContainerMetadataV2(d) - } - return resourceObjectStorageContainerV1Read(d, meta) } From f1ac6dbfec477132673a683c4cdd0ea9ede244ce Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Sun, 1 Feb 2015 00:15:19 -0700 Subject: [PATCH 070/132] block storage volume v1 ops --- ...source_openstack_blockstorage_volume_v1.go | 226 ++++++++++++++++++ 1 file changed, 226 insertions(+) create mode 100644 builtin/providers/openstack/resource_openstack_blockstorage_volume_v1.go diff --git a/builtin/providers/openstack/resource_openstack_blockstorage_volume_v1.go b/builtin/providers/openstack/resource_openstack_blockstorage_volume_v1.go new file mode 100644 index 0000000000..ee86b51d4b --- /dev/null +++ b/builtin/providers/openstack/resource_openstack_blockstorage_volume_v1.go @@ -0,0 +1,226 @@ +package openstack + +import ( + "fmt" + "log" + "time" + + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/helper/schema" + "github.com/rackspace/gophercloud" + "github.com/rackspace/gophercloud/openstack/blockstorage/v1/volumes" +) + +func resourceBlockStorageVolumeV1() *schema.Resource { + return &schema.Resource{ + Create: resourceBlockStorageVolumeV1Create, + Read: resourceBlockStorageVolumeV1Read, + Update: resourceBlockStorageVolumeV1Update, + Delete: resourceBlockStorageVolumeV1Delete, + + Schema: map[string]*schema.Schema{ + "region": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + DefaultFunc: envDefaultFunc("OS_REGION_NAME"), + }, + "size": &schema.Schema{ + Type: schema.TypeInt, + Required: true, + ForceNew: true, + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: false, + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: false, + }, + "metadata": &schema.Schema{ + Type: schema.TypeMap, + Optional: true, + ForceNew: false, + }, + "snapshot_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "source_vol_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "image_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "volume_type": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + }, + } +} + +func resourceBlockStorageVolumeV1Create(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + blockStorageClient, err := config.blockStorageV1Client(d.Get("region").(string)) + if err != nil { + return fmt.Errorf("Error creating OpenStack block storage client: %s", err) + } + + createOpts := &volumes.CreateOpts{ + Description: d.Get("description").(string), + Name: d.Get("name").(string), + Size: d.Get("size").(int), + SnapshotID: d.Get("snapshot_id").(string), + SourceVolID: d.Get("source_vol_id").(string), + ImageID: d.Get("image_id").(string), + VolumeType: d.Get("volume_type").(string), + Metadata: resourceContainerMetadataV2(d), + } + + log.Printf("[INFO] Requesting volume creation") + v, err := volumes.Create(blockStorageClient, createOpts).Extract() + if err != nil { + return fmt.Errorf("Error creating OpenStack volume: %s", err) + } + log.Printf("[INFO] Volume ID: %s", v.ID) + + // Store the ID now + d.SetId(v.ID) + + // Wait for the volume to become running. + log.Printf( + "[DEBUG] Waiting for volume (%s) to become running", + v.ID) + + stateConf := &resource.StateChangeConf{ + Target: "available", + Refresh: VolumeV1StateRefreshFunc(blockStorageClient, v.ID), + Timeout: 10 * time.Minute, + Delay: 10 * time.Second, + MinTimeout: 3 * time.Second, + } + + _, err = stateConf.WaitForState() + if err != nil { + return fmt.Errorf( + "Error waiting for volume (%s) to become ready: %s", + v.ID, err) + } + + return resourceBlockStorageVolumeV1Read(d, meta) +} + +func resourceBlockStorageVolumeV1Read(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + blockStorageClient, err := config.blockStorageV1Client(d.Get("region").(string)) + if err != nil { + return fmt.Errorf("Error creating OpenStack block storage client: %s", err) + } + + v, err := volumes.Get(blockStorageClient, d.Id()).Extract() + if err != nil { + return fmt.Errorf("Error retrieving OpenStack volume: %s", err) + } + + log.Printf("[DEBUG] Retreived volume %s: %+v", d.Id(), v) + + d.Set("region", d.Get("region").(string)) + d.Set("description", v.Description) + d.Set("name", v.Name) + d.Set("size", v.Size) + d.Set("snapshot_id", v.SnapshotID) + d.Set("source_vol_id", v.SourceVolID) + d.Set("volume_type", v.VolumeType) + d.Set("metadata", v.Metadata) + + return nil +} + +func resourceBlockStorageVolumeV1Update(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + blockStorageClient, err := config.blockStorageV1Client(d.Get("region").(string)) + if err != nil { + return fmt.Errorf("Error creating OpenStack block storage client: %s", err) + } + + updateOpts := volumes.UpdateOpts{ + Name: d.Get("name").(string), + Description: d.Get("description").(string), + } + + if d.HasChange("metadata") { + updateOpts.Metadata = resourceVolumeMetadataV1(d) + } + + _, err = volumes.Update(blockStorageClient, d.Id(), updateOpts).Extract() + if err != nil { + return fmt.Errorf("Error updating OpenStack volume: %s", err) + } + + return resourceBlockStorageVolumeV1Read(d, meta) +} + +func resourceBlockStorageVolumeV1Delete(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + blockStorageClient, err := config.blockStorageV1Client(d.Get("region").(string)) + if err != nil { + return fmt.Errorf("Error creating OpenStack block storage client: %s", err) + } + + err = volumes.Delete(blockStorageClient, d.Id()).ExtractErr() + if err != nil { + return fmt.Errorf("Error deleting OpenStack volume: %s", err) + } + + // Wait for the volume to delete before moving on. + log.Printf("[DEBUG] Waiting for volume (%s) to delete", d.Id()) + + stateConf := &resource.StateChangeConf{ + Pending: []string{"deleting"}, + Target: "", + Refresh: VolumeV1StateRefreshFunc(blockStorageClient, d.Id()), + Timeout: 10 * time.Minute, + Delay: 10 * time.Second, + MinTimeout: 3 * time.Second, + } + + _, err = stateConf.WaitForState() + if err != nil { + return fmt.Errorf( + "Error waiting for volume (%s) to delete: %s", + d.Id(), err) + } + + d.SetId("") + return nil +} + +func resourceVolumeMetadataV1(d *schema.ResourceData) map[string]string { + m := make(map[string]string) + for key, val := range d.Get("metadata").(map[string]interface{}) { + m[key] = val.(string) + } + return m +} + +// VolumeV1StateRefreshFunc returns a resource.StateRefreshFunc that is used to watch +// an OpenStack volume. +func VolumeV1StateRefreshFunc(client *gophercloud.ServiceClient, volumeID string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + v, _ := volumes.Get(client, volumeID).Extract() + if v != nil { + return v, v.Status, nil + } + return nil, "", nil + } +} From acd5a033f0614cd2fd03b75c0bde32bfde46e8f0 Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Sun, 1 Feb 2015 00:23:53 -0700 Subject: [PATCH 071/132] fix typo in client variable name --- .../resource_openstack_objectstorage_container_v1.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/builtin/providers/openstack/resource_openstack_objectstorage_container_v1.go b/builtin/providers/openstack/resource_openstack_objectstorage_container_v1.go index 687e65b57e..692ed2e46e 100644 --- a/builtin/providers/openstack/resource_openstack_objectstorage_container_v1.go +++ b/builtin/providers/openstack/resource_openstack_objectstorage_container_v1.go @@ -63,7 +63,7 @@ func resourceObjectStorageContainerV1() *schema.Resource { func resourceObjectStorageContainerV1Create(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - objectStorgeClient, err := config.objectStorageV1Client(d.Get("region").(string)) + objectStorageClient, err := config.objectStorageV1Client(d.Get("region").(string)) if err != nil { return fmt.Errorf("Error creating OpenStack object storage client: %s", err) } @@ -80,7 +80,7 @@ func resourceObjectStorageContainerV1Create(d *schema.ResourceData, meta interfa } log.Printf("[INFO] Requesting container creation") - _, err = containers.Create(objectStorgeClient, cn, createOpts).Extract() + _, err = containers.Create(objectStorageClient, cn, createOpts).Extract() if err != nil { return fmt.Errorf("Error creating OpenStack container: %s", err) } @@ -98,7 +98,7 @@ func resourceObjectStorageContainerV1Read(d *schema.ResourceData, meta interface func resourceObjectStorageContainerV1Update(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - objectStorgeClient, err := config.objectStorageV1Client(d.Get("region").(string)) + objectStorageClient, err := config.objectStorageV1Client(d.Get("region").(string)) if err != nil { return fmt.Errorf("Error creating OpenStack object storage client: %s", err) } @@ -115,7 +115,7 @@ func resourceObjectStorageContainerV1Update(d *schema.ResourceData, meta interfa updateOpts.Metadata = resourceContainerMetadataV2(d) } - _, err = containers.Update(objectStorgeClient, d.Id(), updateOpts).Extract() + _, err = containers.Update(objectStorageClient, d.Id(), updateOpts).Extract() if err != nil { return fmt.Errorf("Error updating OpenStack container: %s", err) } @@ -125,12 +125,12 @@ func resourceObjectStorageContainerV1Update(d *schema.ResourceData, meta interfa func resourceObjectStorageContainerV1Delete(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - objectStorgeClient, err := config.objectStorageV1Client(d.Get("region").(string)) + objectStorageClient, err := config.objectStorageV1Client(d.Get("region").(string)) if err != nil { return fmt.Errorf("Error creating OpenStack object storage client: %s", err) } - _, err = containers.Delete(objectStorgeClient, d.Id()).Extract() + _, err = containers.Delete(objectStorageClient, d.Id()).Extract() if err != nil { return fmt.Errorf("Error deleting OpenStack container: %s", err) } From d2169e0e96c30210d5d2e8753c2927b5d31b2446 Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Sun, 1 Feb 2015 00:33:53 -0700 Subject: [PATCH 072/132] block storage v1 acceptance tests --- ...e_openstack_blockstorage_volume_v1_test.go | 138 ++++++++++++++++++ 1 file changed, 138 insertions(+) create mode 100644 builtin/providers/openstack/resource_openstack_blockstorage_volume_v1_test.go diff --git a/builtin/providers/openstack/resource_openstack_blockstorage_volume_v1_test.go b/builtin/providers/openstack/resource_openstack_blockstorage_volume_v1_test.go new file mode 100644 index 0000000000..5404fd3912 --- /dev/null +++ b/builtin/providers/openstack/resource_openstack_blockstorage_volume_v1_test.go @@ -0,0 +1,138 @@ +package openstack + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" + + "github.com/rackspace/gophercloud/openstack/blockstorage/v1/volumes" +) + +func TestAccBlockStorageV1Volume_basic(t *testing.T) { + var volume volumes.Volume + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckBlockStorageV1VolumeDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccBlockStorageV1Volume_basic, + Check: resource.ComposeTestCheckFunc( + testAccCheckBlockStorageV1VolumeExists(t, "openstack_blockstorage_volume_v1.volume_1", &volume), + resource.TestCheckResourceAttr("openstack_blockstorage_volume_v1.volume_1", "name", "tf-test-volume"), + testAccCheckBlockStorageV1VolumeMetadata(&volume, "foo", "bar"), + ), + }, + resource.TestStep{ + Config: testAccBlockStorageV1Volume_update, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("openstack_blockstorage_volume_v1.volume_1", "name", "tf-test-volume-updated"), + testAccCheckBlockStorageV1VolumeMetadata(&volume, "foo", "bar"), + ), + }, + }, + }) +} + +func testAccCheckBlockStorageV1VolumeDestroy(s *terraform.State) error { + config := testAccProvider.Meta().(*Config) + blockStorageClient, err := config.blockStorageV1Client(OS_REGION_NAME) + if err != nil { + return fmt.Errorf("Error creating OpenStack block storage client: %s", err) + } + + for _, rs := range s.RootModule().Resources { + if rs.Type != "openstack_blockstorage_volume_v1" { + continue + } + + _, err := volumes.Get(blockStorageClient, rs.Primary.ID).Extract() + if err == nil { + return fmt.Errorf("Volume still exists") + } + } + + return nil +} + +func testAccCheckBlockStorageV1VolumeExists(t *testing.T, n string, volume *volumes.Volume) 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 ID is set") + } + + config := testAccProvider.Meta().(*Config) + blockStorageClient, err := config.blockStorageV1Client(OS_REGION_NAME) + if err != nil { + return fmt.Errorf("Error creating OpenStack block storage client: %s", err) + } + + found, err := volumes.Get(blockStorageClient, rs.Primary.ID).Extract() + if err != nil { + return err + } + + if found.ID != rs.Primary.ID { + return fmt.Errorf("Volume not found") + } + + *volume = *found + + return nil + } +} + +func testAccCheckBlockStorageV1VolumeMetadata( + volume *volumes.Volume, k string, v string) resource.TestCheckFunc { + return func(s *terraform.State) error { + if volume.Metadata == nil { + return fmt.Errorf("No metadata") + } + + for key, value := range volume.Metadata { + if k != key { + continue + } + + if v == value { + return nil + } + + return fmt.Errorf("Bad value for %s: %s", k, value) + } + + return fmt.Errorf("Metadata not found: %s", k) + } +} + +var testAccBlockStorageV1Volume_basic = fmt.Sprintf(` + resource "openstack_blockstorage_volume_v1" "volume_1" { + region = "%s" + name = "tf-test-volume" + description = "first test volume" + metadata{ + foo = "bar" + } + size = 1 + }`, + OS_REGION_NAME) + +var testAccBlockStorageV1Volume_update = fmt.Sprintf(` + resource "openstack_blockstorage_volume_v1" "volume_1" { + region = "%s" + name = "tf-test-volume-updated" + description = "first test volume" + metadata{ + foo = "bar" + } + size = 1 + }`, + OS_REGION_NAME) From a85067062d911f1370a54741a90515f9f3f3b7b5 Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Sun, 1 Feb 2015 00:34:08 -0700 Subject: [PATCH 073/132] object storage v1 acceptance tests --- ...enstack_objectstorage_container_v1_test.go | 77 +++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 builtin/providers/openstack/resource_openstack_objectstorage_container_v1_test.go diff --git a/builtin/providers/openstack/resource_openstack_objectstorage_container_v1_test.go b/builtin/providers/openstack/resource_openstack_objectstorage_container_v1_test.go new file mode 100644 index 0000000000..9377ad2fb0 --- /dev/null +++ b/builtin/providers/openstack/resource_openstack_objectstorage_container_v1_test.go @@ -0,0 +1,77 @@ +package openstack + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" + "github.com/rackspace/gophercloud/openstack/objectstorage/v1/containers" +) + +func TestAccObjectStorageV1Container_basic(t *testing.T) { + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckObjectStorageV1ContainerDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccObjectStorageV1Container_basic, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("openstack_objectstorage_container_v1.container_1", "name", "tf-test-container"), + resource.TestCheckResourceAttr("openstack_objectstorage_container_v1.container_1", "content_type", "application/json"), + ), + }, + resource.TestStep{ + Config: testAccObjectStorageV1Container_update, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("openstack_objectstorage_container_v1.container_1", "content_type", "text/plain"), + ), + }, + }, + }) +} + +func testAccCheckObjectStorageV1ContainerDestroy(s *terraform.State) error { + config := testAccProvider.Meta().(*Config) + objectStorageClient, err := config.objectStorageV1Client(OS_REGION_NAME) + if err != nil { + return fmt.Errorf("Error creating OpenStack object storage client: %s", err) + } + + for _, rs := range s.RootModule().Resources { + if rs.Type != "openstack_objectstorage_container_v1" { + continue + } + + _, err := containers.Get(objectStorageClient, rs.Primary.ID).Extract() + if err == nil { + return fmt.Errorf("Container still exists") + } + } + + return nil +} + +var testAccObjectStorageV1Container_basic = fmt.Sprintf(` + resource "openstack_objectstorage_container_v1" "container_1" { + region = "%s" + name = "tf-test-container" + metadata { + test = "true" + } + content_type = "application/json" + }`, + OS_REGION_NAME) + +var testAccObjectStorageV1Container_update = fmt.Sprintf(` + resource "openstack_objectstorage_container_v1" "container_1" { + region = "%s" + name = "tf-test-container" + metadata { + test = "true" + } + content_type = "text/plain" + }`, + OS_REGION_NAME) From 761d58df2f3cc4f2507b3950a53ec982d3884ac2 Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Sun, 1 Feb 2015 00:34:37 -0700 Subject: [PATCH 074/132] add container and volume resources --- builtin/providers/openstack/config.go | 6 ++++++ builtin/providers/openstack/provider.go | 1 + 2 files changed, 7 insertions(+) diff --git a/builtin/providers/openstack/config.go b/builtin/providers/openstack/config.go index 864dc9ab7b..d05662017c 100644 --- a/builtin/providers/openstack/config.go +++ b/builtin/providers/openstack/config.go @@ -42,6 +42,12 @@ func (c *Config) loadAndValidate() error { return nil } +func (c *Config) blockStorageV1Client(region string) (*gophercloud.ServiceClient, error) { + return openstack.NewBlockStorageV1(c.osClient, gophercloud.EndpointOpts{ + Region: region, + }) +} + func (c *Config) computeV2Client(region string) (*gophercloud.ServiceClient, error) { return openstack.NewComputeV2(c.osClient, gophercloud.EndpointOpts{ Region: region, diff --git a/builtin/providers/openstack/provider.go b/builtin/providers/openstack/provider.go index 019c7b386e..180b5c3a7a 100644 --- a/builtin/providers/openstack/provider.go +++ b/builtin/providers/openstack/provider.go @@ -59,6 +59,7 @@ func Provider() terraform.ResourceProvider { }, ResourcesMap: map[string]*schema.Resource{ + "openstack_blockstorage_volume_v1": resourceBlockStorageVolumeV1(), "openstack_compute_instance_v2": resourceComputeInstanceV2(), "openstack_compute_keypair_v2": resourceComputeKeypairV2(), "openstack_compute_secgroup_v2": resourceComputeSecGroupV2(), From 9c128b7c9964727fe9d25aa3601fa930585d8c83 Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Sun, 1 Feb 2015 01:11:01 -0700 Subject: [PATCH 075/132] docs for volume and container resources --- .../r/blockstorage_volume_v1.html.markdown | 68 +++++++++++++++++++ .../objectstorage_container_v1.html.markdown | 68 +++++++++++++++++++ website/source/layouts/openstack.erb | 6 ++ 3 files changed, 142 insertions(+) create mode 100644 website/source/docs/providers/openstack/r/blockstorage_volume_v1.html.markdown create mode 100644 website/source/docs/providers/openstack/r/objectstorage_container_v1.html.markdown diff --git a/website/source/docs/providers/openstack/r/blockstorage_volume_v1.html.markdown b/website/source/docs/providers/openstack/r/blockstorage_volume_v1.html.markdown new file mode 100644 index 0000000000..0b91eb11c6 --- /dev/null +++ b/website/source/docs/providers/openstack/r/blockstorage_volume_v1.html.markdown @@ -0,0 +1,68 @@ +--- +layout: "openstack" +page_title: "OpenStack: openstack_blockstorage_volume_v1" +sidebar_current: "docs-openstack-resource-blockstorage-volume-v1" +description: |- +Manages a V1 volume resource within OpenStack. +--- + +# openstack\_blockstorage\_volume_v1 + +Manages a V1 volume resource within OpenStack. + +## Example Usage + +``` +resource "openstack_blockstorage_volume_v1" "volume_1" { + region = "RegionOne" + name = "tf-test-volume" + description = "first test volume" + size = 3 +} +``` + +## Argument Reference + +The following arguments are supported: + +* `region` - (Required) The region in which to create the volume. If + omitted, the `OS_REGION_NAME` environment variable is used. Changing this + creates a new volume. + +* `size` - (Required) The size of the volume to create (in gigabytes). Changing + this creates a new volume. + +* `name` - (Optional) A unique name for the volume. Changing this updates the + volume's name. + +* `description` - (Optional) A description of the volume. Changing this updates + the volume's description. + +* `image_id` - (Optional) The image ID from which to create the volume. + Changing this creates a new volume. + +* `snapshot_id` - (Optional) The snapshot ID from which to create the volume. + Changing this creates a new volume. + +* `source_vol_id` - (Optional) The volume ID from which to create the volume. + Changing this creates a new volume. + +* `metadata` - (Optional) Metadata key/value pairs to associate with the volume. + Changing this updates the existing volume metadata. + +* `volume_type` - (Optional) The type of volume to create (either SATA or SSD). + Changing this creates a new volume. + +## Attributes Reference + +The following attributes are exported: + +* `region` - See Argument Reference above. +* `size` - See Argument Reference above. +* `name` - See Argument Reference above. +* `description` - See Argument Reference above. +* `image_id` - See Argument Reference above. +* `source_vol_id` - See Argument Reference above. +* `snapshot_id` - See Argument Reference above. +* `metadata` - See Argument Reference above. +* `volume_type` - See Argument Reference above. diff --git a/website/source/docs/providers/openstack/r/objectstorage_container_v1.html.markdown b/website/source/docs/providers/openstack/r/objectstorage_container_v1.html.markdown new file mode 100644 index 0000000000..8101d1ca21 --- /dev/null +++ b/website/source/docs/providers/openstack/r/objectstorage_container_v1.html.markdown @@ -0,0 +1,68 @@ +--- +layout: "openstack" +page_title: "OpenStack: openstack_objectstorage_container_v1" +sidebar_current: "docs-openstack-resource-objectstorage-container-v1" +description: |- +Manages a V1 container resource within OpenStack. +--- + +# openstack\_objectstorage\_container_v1 + +Manages a V1 container resource within OpenStack. + +## Example Usage + +``` +resource "openstack_objectstorage_container_v1" "container_1" { + region = "RegionOne" + name = "tf-test-container-1" + metadata { + test = "true" + } + content_type = "application/json" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `region` - (Required) The region in which to create the container. If + omitted, the `OS_REGION_NAME` environment variable is used. Changing this + creates a new container. + +* `name` - (Required) A unique name for the container. Changing this creates a + new container. + +* `container_read` - (Optional) Sets an access control list (ACL) that grants + read access. This header can contain a comma-delimited list of users that + can read the container (allows the GET method for all objects in the + container). Changing this updates the access control list read access. + +* `container_sync_to` - (Optional) The destination for container synchronization. + Changing this updates container synchronization. + +* `container_sync_key` - (Optional) The secret key for container synchronization. + Changing this updates container synchronization. + +* `container_write` - (Optional) Sets an ACL that grants write access. + Changing this updates the access control list write access. + +* `metadata` - (Optional) Custom key/value pairs to associate with the container. + Changing this updates the existing container metadata. + +* `content_type` - (Optional) The MIME type for the container. Changing this + updates the MIME type. + +## Attributes Reference + +The following attributes are exported: + +* `region` - See Argument Reference above. +* `name` - See Argument Reference above. +* `container_read` - See Argument Reference above. +* `container_sync_to` - See Argument Reference above. +* `container_sync_key` - See Argument Reference above. +* `container_write` - See Argument Reference above. +* `metadata` - See Argument Reference above. +* `content_type` - See Argument Reference above. diff --git a/website/source/layouts/openstack.erb b/website/source/layouts/openstack.erb index 71cc9eb9ea..22afb4aeb2 100644 --- a/website/source/layouts/openstack.erb +++ b/website/source/layouts/openstack.erb @@ -13,6 +13,9 @@ > Resources From 436ef9e53ba74b975ae8d29106c0efc35f17a3d6 Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Sun, 1 Feb 2015 02:10:42 -0700 Subject: [PATCH 076/132] boot from volume ops and docs --- .../resource_openstack_compute_instance_v2.go | 41 +++++++++++++++++-- .../r/compute_instance_v2.html.markdown | 17 ++++++++ 2 files changed, 55 insertions(+), 3 deletions(-) diff --git a/builtin/providers/openstack/resource_openstack_compute_instance_v2.go b/builtin/providers/openstack/resource_openstack_compute_instance_v2.go index 8059dec1b1..766c5dea80 100644 --- a/builtin/providers/openstack/resource_openstack_compute_instance_v2.go +++ b/builtin/providers/openstack/resource_openstack_compute_instance_v2.go @@ -9,6 +9,7 @@ import ( "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/schema" "github.com/rackspace/gophercloud" + "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/bootfromvolume" "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/keypairs" "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/secgroups" "github.com/rackspace/gophercloud/openstack/compute/v2/servers" @@ -36,13 +37,13 @@ func resourceComputeInstanceV2() *schema.Resource { }, "image_ref": &schema.Schema{ Type: schema.TypeString, - Required: true, + Optional: true, ForceNew: false, DefaultFunc: envDefaultFunc("OS_IMAGE_ID"), }, "flavor_ref": &schema.Schema{ Type: schema.TypeString, - Required: true, + Optional: true, ForceNew: false, DefaultFunc: envDefaultFunc("OS_FLAVOR_ID"), }, @@ -113,6 +114,11 @@ func resourceComputeInstanceV2() *schema.Resource { Optional: true, ForceNew: true, }, + "block_device": &schema.Schema{ + Type: schema.TypeMap, + Optional: true, + ForceNew: true, + }, }, } } @@ -145,6 +151,14 @@ func resourceComputeInstanceV2Create(d *schema.ResourceData, meta interface{}) e } } + if blockDeviceRaw, ok := d.Get("block_device").(map[string]interface{}); ok && blockDeviceRaw != nil { + blockDevice := resourceInstanceBlockDeviceV2(d, blockDeviceRaw) + createOpts = &bootfromvolume.CreateOptsExt{ + createOpts, + blockDevice, + } + } + log.Printf("[INFO] Requesting instance creation") server, err := servers.Create(computeClient, createOpts).Extract() if err != nil { @@ -407,7 +421,7 @@ func resourceComputeInstanceV2Delete(d *schema.ResourceData, meta interface{}) e return nil } -// ServerStateRefreshFunc returns a resource.StateRefreshFunc that is used to watch +// ServerV2StateRefreshFunc returns a resource.StateRefreshFunc that is used to watch // an OpenStack instance. func ServerV2StateRefreshFunc(client *gophercloud.ServiceClient, instanceID string) resource.StateRefreshFunc { return func() (interface{}, string, error) { @@ -450,3 +464,24 @@ func resourceInstanceMetadataV2(d *schema.ResourceData) map[string]string { } return m } + +func resourceInstanceBlockDeviceV2(d *schema.ResourceData, bd map[string]interface{}) []bootfromvolume.BlockDevice { + sourceType := bootfromvolume.SourceType(bd["source_type"].(string)) + bfvOpts := []bootfromvolume.BlockDevice{ + bootfromvolume.BlockDevice{ + UUID: bd["uuid"].(string), + SourceType: sourceType, + }, + } + if vs, ok := bd["volume_size"].(int); ok { + bfvOpts[0].VolumeSize = vs + } + if dt, ok := bd["destination_type"].(string); ok { + bfvOpts[0].DestinationType = dt + } + if bi, ok := bd["boot_index"].(int); ok { + bfvOpts[0].BootIndex = bi + } + + return bfvOpts +} diff --git a/website/source/docs/providers/openstack/r/compute_instance_v2.html.markdown b/website/source/docs/providers/openstack/r/compute_instance_v2.html.markdown index 6a9a5ac95c..9095cb15aa 100644 --- a/website/source/docs/providers/openstack/r/compute_instance_v2.html.markdown +++ b/website/source/docs/providers/openstack/r/compute_instance_v2.html.markdown @@ -62,6 +62,9 @@ The following arguments are supported: pair must already be created and associated with the tenant's account. Changing this creates a new server. +* `block_device` - (Optional) The object for booting by volume. The block_device + object structure is documented below. Changing this creates a new server. + The `network` block supports: * `uuid` - (Required unless `port` is provided) The network UUID to attach to @@ -73,6 +76,20 @@ The `network` block supports: * `fixed_ip` - (Optional) Specifies a fixed IP address to be used on this network. +The `block_device` block supports: + +* `uuid` - (Required) The UUID of the image, volume, or snapshot. + +* `source_type` - (Required) The source type of the device. Must be one of + "image", "volume", or "snapshot". + +* `volume_size` - (Optional) The size of the volume to create (in gigabytes). + +* `boot_index` - (Optional) The boot index of the volume. It defaults to 0. + +* `destination_type` - (Optional) The type that gets created. Possible values + are "volume" and "local". + ## Attributes Reference The following attributes are exported: From e2634562a4fd6288d5e81615d2da851cf0effbeb Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Sun, 1 Feb 2015 02:36:58 -0700 Subject: [PATCH 077/132] define block_device schema --- .../resource_openstack_compute_instance_v2.go | 42 +++++++++++++------ 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/builtin/providers/openstack/resource_openstack_compute_instance_v2.go b/builtin/providers/openstack/resource_openstack_compute_instance_v2.go index 766c5dea80..17775ef3a7 100644 --- a/builtin/providers/openstack/resource_openstack_compute_instance_v2.go +++ b/builtin/providers/openstack/resource_openstack_compute_instance_v2.go @@ -115,9 +115,33 @@ func resourceComputeInstanceV2() *schema.Resource { ForceNew: true, }, "block_device": &schema.Schema{ - Type: schema.TypeMap, + Type: schema.TypeList, Optional: true, ForceNew: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "uuid": &schema.Schema{ + Type: schema.TypeString, + Required: true, + }, + "source_type": &schema.Schema{ + Type: schema.TypeString, + Required: true, + }, + "volume_size": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + }, + "destination_type": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + }, + "boot_index": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + }, + }, + }, }, }, } @@ -469,19 +493,13 @@ func resourceInstanceBlockDeviceV2(d *schema.ResourceData, bd map[string]interfa sourceType := bootfromvolume.SourceType(bd["source_type"].(string)) bfvOpts := []bootfromvolume.BlockDevice{ bootfromvolume.BlockDevice{ - UUID: bd["uuid"].(string), - SourceType: sourceType, + UUID: bd["uuid"].(string), + SourceType: sourceType, + VolumeSize: bd["volume_size"].(int), + DestinationType: bd["destination_type"].(string), + BootIndex: bd["boot_index"].(int), }, } - if vs, ok := bd["volume_size"].(int); ok { - bfvOpts[0].VolumeSize = vs - } - if dt, ok := bd["destination_type"].(string); ok { - bfvOpts[0].DestinationType = dt - } - if bi, ok := bd["boot_index"].(int); ok { - bfvOpts[0].BootIndex = bi - } return bfvOpts } From ccd51ae3ab796e86558b74b17901c217e0291c8e Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Tue, 3 Feb 2015 20:30:10 -0700 Subject: [PATCH 078/132] added ok codes to gophercloud -> update ServerV2StateRefreshFunc --- ...source_openstack_blockstorage_volume_v1.go | 67 +++++++++++++++---- .../resource_openstack_compute_instance_v2.go | 10 ++- 2 files changed, 63 insertions(+), 14 deletions(-) diff --git a/builtin/providers/openstack/resource_openstack_blockstorage_volume_v1.go b/builtin/providers/openstack/resource_openstack_blockstorage_volume_v1.go index ee86b51d4b..ea2d99a653 100644 --- a/builtin/providers/openstack/resource_openstack_blockstorage_volume_v1.go +++ b/builtin/providers/openstack/resource_openstack_blockstorage_volume_v1.go @@ -7,6 +7,7 @@ import ( "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/schema" + "github.com/racker/perigee" "github.com/rackspace/gophercloud" "github.com/rackspace/gophercloud/openstack/blockstorage/v1/volumes" ) @@ -97,9 +98,9 @@ func resourceBlockStorageVolumeV1Create(d *schema.ResourceData, meta interface{} // Store the ID now d.SetId(v.ID) - // Wait for the volume to become running. + // Wait for the volume to become available. log.Printf( - "[DEBUG] Waiting for volume (%s) to become running", + "[DEBUG] Waiting for volume (%s) to become available", v.ID) stateConf := &resource.StateChangeConf{ @@ -132,16 +133,48 @@ func resourceBlockStorageVolumeV1Read(d *schema.ResourceData, meta interface{}) return fmt.Errorf("Error retrieving OpenStack volume: %s", err) } + log.Printf("\n\ngot volume: %+v\n\n", v) + log.Printf("[DEBUG] Retreived volume %s: %+v", d.Id(), v) d.Set("region", d.Get("region").(string)) - d.Set("description", v.Description) - d.Set("name", v.Name) d.Set("size", v.Size) - d.Set("snapshot_id", v.SnapshotID) - d.Set("source_vol_id", v.SourceVolID) - d.Set("volume_type", v.VolumeType) - d.Set("metadata", v.Metadata) + + if t, exists := d.GetOk("description"); exists && t != "" { + d.Set("description", v.Description) + } else { + d.Set("description", "") + } + + if t, exists := d.GetOk("name"); exists && t != "" { + d.Set("name", v.Name) + } else { + d.Set("name", "") + } + + if t, exists := d.GetOk("snapshot_id"); exists && t != "" { + d.Set("snapshot_id", v.SnapshotID) + } else { + d.Set("snapshot_id", "") + } + + if t, exists := d.GetOk("source_vol_id"); exists && t != "" { + d.Set("source_vol_id", v.SourceVolID) + } else { + d.Set("source_vol_id", "") + } + + if t, exists := d.GetOk("volume_type"); exists && t != "" { + d.Set("volume_type", v.VolumeType) + } else { + d.Set("volume_type", "") + } + + if t, exists := d.GetOk("metadata"); exists && t != "" { + d.Set("metadata", v.Metadata) + } else { + d.Set("metadata", "") + } return nil } @@ -187,7 +220,7 @@ func resourceBlockStorageVolumeV1Delete(d *schema.ResourceData, meta interface{} stateConf := &resource.StateChangeConf{ Pending: []string{"deleting"}, - Target: "", + Target: "deleted", Refresh: VolumeV1StateRefreshFunc(blockStorageClient, d.Id()), Timeout: 10 * time.Minute, Delay: 10 * time.Second, @@ -217,10 +250,18 @@ func resourceVolumeMetadataV1(d *schema.ResourceData) map[string]string { // an OpenStack volume. func VolumeV1StateRefreshFunc(client *gophercloud.ServiceClient, volumeID string) resource.StateRefreshFunc { return func() (interface{}, string, error) { - v, _ := volumes.Get(client, volumeID).Extract() - if v != nil { - return v, v.Status, nil + v, err := volumes.Get(client, volumeID).Extract() + if err != nil { + errCode, ok := err.(*perigee.UnexpectedResponseCodeError) + if !ok { + return nil, "", err + } + if errCode.Actual == 404 { + return v, "deleted", nil + } + return nil, "", err } - return nil, "", nil + + return v, v.Status, nil } } diff --git a/builtin/providers/openstack/resource_openstack_compute_instance_v2.go b/builtin/providers/openstack/resource_openstack_compute_instance_v2.go index 17775ef3a7..7b3db0c6c0 100644 --- a/builtin/providers/openstack/resource_openstack_compute_instance_v2.go +++ b/builtin/providers/openstack/resource_openstack_compute_instance_v2.go @@ -8,6 +8,7 @@ import ( "github.com/hashicorp/terraform/helper/hashcode" "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/schema" + "github.com/racker/perigee" "github.com/rackspace/gophercloud" "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/bootfromvolume" "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/keypairs" @@ -427,7 +428,7 @@ func resourceComputeInstanceV2Delete(d *schema.ResourceData, meta interface{}) e log.Printf("[DEBUG] Waiting for instance (%s) to delete", d.Id()) stateConf := &resource.StateChangeConf{ - Target: "", + Target: "DELETED", Refresh: ServerV2StateRefreshFunc(computeClient, d.Id()), Timeout: 10 * time.Minute, Delay: 10 * time.Second, @@ -451,6 +452,13 @@ func ServerV2StateRefreshFunc(client *gophercloud.ServiceClient, instanceID stri return func() (interface{}, string, error) { s, err := servers.Get(client, instanceID).Extract() if err != nil { + errCode, ok := err.(*perigee.UnexpectedResponseCodeError) + if !ok { + return nil, "", err + } + if errCode.Actual == 404 { + return s, "DELETED", nil + } return nil, "", err } From 8e9c6787dd048e422541342b9108c5c64ee2c5c8 Mon Sep 17 00:00:00 2001 From: Julien Vey Date: Wed, 4 Feb 2015 22:14:36 +0100 Subject: [PATCH 079/132] Just try the first IP available if none found before Some cloud don't implement correctly IP addresses. Instead of failing during the provisionning, we just take the first IP available and try with this one. --- .../resource_openstack_compute_instance_v2.go | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/builtin/providers/openstack/resource_openstack_compute_instance_v2.go b/builtin/providers/openstack/resource_openstack_compute_instance_v2.go index 7b3db0c6c0..2d9a0cdb84 100644 --- a/builtin/providers/openstack/resource_openstack_compute_instance_v2.go +++ b/builtin/providers/openstack/resource_openstack_compute_instance_v2.go @@ -246,11 +246,25 @@ func resourceComputeInstanceV2Read(d *schema.ResourceData, meta interface{}) err pa := paRaw.(map[string]interface{}) if pa["version"].(float64) == 4 { host = pa["addr"].(string) - d.Set("access_ip_v4", host) + break } } } } + + // If no host found, just get the first IP we find + if host == "" { + for _, networkAddresses := range server.Addresses { + for _, element := range networkAddresses.([]interface{}) { + address := element.(map[string]interface{}) + if address["version"].(float64) == 4 { + host = address["addr"].(string) + break + } + } + } + } + d.Set("access_ip_v4", host) d.Set("host", host) log.Printf("host: %s", host) From aae87816f672e43aa41b5e3b77855feb817610e8 Mon Sep 17 00:00:00 2001 From: Julien Vey Date: Wed, 4 Feb 2015 22:15:11 +0100 Subject: [PATCH 080/132] add ACTIVE as pending state when deleting instance --- .../openstack/resource_openstack_compute_instance_v2.go | 1 + 1 file changed, 1 insertion(+) diff --git a/builtin/providers/openstack/resource_openstack_compute_instance_v2.go b/builtin/providers/openstack/resource_openstack_compute_instance_v2.go index 2d9a0cdb84..65c2b45da7 100644 --- a/builtin/providers/openstack/resource_openstack_compute_instance_v2.go +++ b/builtin/providers/openstack/resource_openstack_compute_instance_v2.go @@ -442,6 +442,7 @@ func resourceComputeInstanceV2Delete(d *schema.ResourceData, meta interface{}) e log.Printf("[DEBUG] Waiting for instance (%s) to delete", d.Id()) stateConf := &resource.StateChangeConf{ + Pending: []string{"ACTIVE"}, Target: "DELETED", Refresh: ServerV2StateRefreshFunc(computeClient, d.Id()), Timeout: 10 * time.Minute, From 9aa9c902482c3fd3131334737cd07d75bfc1b38b Mon Sep 17 00:00:00 2001 From: Julien Vey Date: Thu, 5 Feb 2015 08:23:46 +0100 Subject: [PATCH 081/132] Add floating IP resource --- builtin/providers/openstack/provider.go | 1 + ...urce_openstack_networking_floatingip_v2.go | 160 ++++++++++++++++++ ...openstack_networking_floatingip_v2_test.go | 89 ++++++++++ 3 files changed, 250 insertions(+) create mode 100644 builtin/providers/openstack/resource_openstack_networking_floatingip_v2.go create mode 100644 builtin/providers/openstack/resource_openstack_networking_floatingip_v2_test.go diff --git a/builtin/providers/openstack/provider.go b/builtin/providers/openstack/provider.go index 180b5c3a7a..955101a441 100644 --- a/builtin/providers/openstack/provider.go +++ b/builtin/providers/openstack/provider.go @@ -68,6 +68,7 @@ func Provider() terraform.ResourceProvider { "openstack_lb_vip_v1": resourceLBVipV1(), "openstack_networking_network_v2": resourceNetworkingNetworkV2(), "openstack_networking_subnet_v2": resourceNetworkingSubnetV2(), + "openstack_networking_floatingip_v2": resourceNetworkingFloatingIPV2(), "openstack_objectstorage_container_v1": resourceObjectStorageContainerV1(), }, diff --git a/builtin/providers/openstack/resource_openstack_networking_floatingip_v2.go b/builtin/providers/openstack/resource_openstack_networking_floatingip_v2.go new file mode 100644 index 0000000000..410fb0e397 --- /dev/null +++ b/builtin/providers/openstack/resource_openstack_networking_floatingip_v2.go @@ -0,0 +1,160 @@ +package openstack + +import ( + "fmt" + + "github.com/hashicorp/terraform/helper/schema" + "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/layer3/floatingips" + "github.com/rackspace/gophercloud/openstack/networking/v2/networks" + "github.com/rackspace/gophercloud/pagination" +) + +func resourceNetworkingFloatingIPV2() *schema.Resource { + return &schema.Resource{ + Create: resourceNetworkFloatingIPV2Create, + Read: resourceNetworkFloatingIPV2Read, + Delete: resourceNetworkFloatingIPV2Delete, + + Schema: map[string]*schema.Schema{ + "region": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + DefaultFunc: envDefaultFunc("OS_REGION_NAME"), + }, + "address": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + "pool": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + }, + } +} + +func resourceNetworkFloatingIPV2Create(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + networkClient, err := config.networkingV2Client(d.Get("region").(string)) + if err != nil { + return fmt.Errorf("Error creating OpenStack network client: %s", err) + } + + poolID, err := getNetworkID(d, meta, d.Get("pool").(string)) + if err != nil { + return fmt.Errorf("Error retrieving floating IP pool name: %s", err) + } + if len(poolID) == 0 { + return fmt.Errorf("No network found with name: %s", d.Get("pool").(string)) + } + floatingIP, err := floatingips.Create(networkClient, floatingips.CreateOpts{ + FloatingNetworkID: poolID, + }).Extract() + if err != nil { + return fmt.Errorf("Error allocating floating IP: %s", err) + } + + d.SetId(floatingIP.ID) + + return resourceNetworkFloatingIPV2Read(d, meta) +} + +func resourceNetworkFloatingIPV2Read(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + networkClient, err := config.networkingV2Client(d.Get("region").(string)) + if err != nil { + return fmt.Errorf("Error creating OpenStack network client: %s", err) + } + + floatingIP, err := floatingips.Get(networkClient, d.Id()).Extract() + if err != nil { + return fmt.Errorf("Error retrieving floatingIP: %s", err) + } + + d.Set("region", d.Get("region").(string)) + d.Set("address", floatingIP.FloatingIP) + poolName, err := getNetworkName(d, meta, floatingIP.FloatingNetworkID) + if err != nil { + return fmt.Errorf("Error retrieving floating IP pool name: %s", err) + } + d.Set("pool", poolName) + + return nil +} + +func resourceNetworkFloatingIPV2Delete(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + networkClient, err := config.networkingV2Client(d.Get("region").(string)) + if err != nil { + return fmt.Errorf("Error creating OpenStack network client: %s", err) + } + + err = floatingips.Delete(networkClient, d.Id()).ExtractErr() + if err != nil { + return fmt.Errorf("Error deleting floating IP: %s", err) + } + d.SetId("") + return nil +} + +func getNetworkID(d *schema.ResourceData, meta interface{}, networkName string) (string, error) { + config := meta.(*Config) + networkClient, err := config.networkingV2Client(d.Get("region").(string)) + if err != nil { + return "", fmt.Errorf("Error creating OpenStack network client: %s", err) + } + + opts := networks.ListOpts{Name: networkName} + pager := networks.List(networkClient, opts) + networkID := "" + + err = pager.EachPage(func(page pagination.Page) (bool, error) { + networkList, err := networks.ExtractNetworks(page) + if err != nil { + return false, err + } + + for _, n := range networkList { + if n.Name == networkName { + networkID = n.ID + return false, nil + } + } + + return true, nil + }) + + return networkID, err +} + +func getNetworkName(d *schema.ResourceData, meta interface{}, networkID string) (string, error) { + config := meta.(*Config) + networkClient, err := config.networkingV2Client(d.Get("region").(string)) + if err != nil { + return "", fmt.Errorf("Error creating OpenStack network client: %s", err) + } + + opts := networks.ListOpts{ID: networkID} + pager := networks.List(networkClient, opts) + networkName := "" + + err = pager.EachPage(func(page pagination.Page) (bool, error) { + networkList, err := networks.ExtractNetworks(page) + if err != nil { + return false, err + } + + for _, n := range networkList { + if n.ID == networkID { + networkName = n.Name + return false, nil + } + } + + return true, nil + }) + + return networkName, err +} diff --git a/builtin/providers/openstack/resource_openstack_networking_floatingip_v2_test.go b/builtin/providers/openstack/resource_openstack_networking_floatingip_v2_test.go new file mode 100644 index 0000000000..3902759284 --- /dev/null +++ b/builtin/providers/openstack/resource_openstack_networking_floatingip_v2_test.go @@ -0,0 +1,89 @@ +package openstack + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" + + "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/layer3/floatingips" +) + +func TestAccNetworkingV2FloatingIP_basic(t *testing.T) { + var floatingIP floatingips.FloatingIP + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckNetworkingV2FloatingIPDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccNetworkingV2FloatingIP_basic, + Check: resource.ComposeTestCheckFunc( + testAccCheckNetworkingV2FloatingIPExists(t, "openstack_networking_floatingip_v2.foo", &floatingIP), + ), + }, + }, + }) +} + +func testAccCheckNetworkingV2FloatingIPDestroy(s *terraform.State) error { + config := testAccProvider.Meta().(*Config) + networkClient, err := config.networkingV2Client(OS_REGION_NAME) + if err != nil { + return fmt.Errorf("(testAccCheckNetworkingV2FloatingIPDestroy) Error creating OpenStack floating IP: %s", err) + } + + for _, rs := range s.RootModule().Resources { + if rs.Type != "openstack_networking_floatingip_v2" { + continue + } + + _, err := floatingips.Get(networkClient, rs.Primary.ID).Extract() + if err == nil { + return fmt.Errorf("FloatingIP still exists") + } + } + + return nil +} + +func testAccCheckNetworkingV2FloatingIPExists(t *testing.T, n string, kp *floatingips.FloatingIP) 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 ID is set") + } + + config := testAccProvider.Meta().(*Config) + networkClient, err := config.networkingV2Client(OS_REGION_NAME) + if err != nil { + return fmt.Errorf("(testAccCheckNetworkingV2FloatingIPExists) Error creating OpenStack networking client: %s", err) + } + + found, err := floatingips.Get(networkClient, rs.Primary.ID).Extract() + if err != nil { + return err + } + + if found.ID != rs.Primary.ID { + return fmt.Errorf("FloatingIP not found") + } + + *kp = *found + + return nil + } +} + +var testAccNetworkingV2FloatingIP_basic = fmt.Sprintf(` + resource "openstack_networking_floatingip_v2" "foo" { + region = "%s" + pool = "PublicNetwork-01" + }`, + OS_REGION_NAME) From 760e03856e536f296ce4449aa1789148d96d8cba Mon Sep 17 00:00:00 2001 From: Julien Vey Date: Fri, 6 Feb 2015 14:34:11 +0100 Subject: [PATCH 082/132] Manage floating IP in compute instances --- .../resource_openstack_compute_instance_v2.go | 133 ++++++++++++++++++ 1 file changed, 133 insertions(+) diff --git a/builtin/providers/openstack/resource_openstack_compute_instance_v2.go b/builtin/providers/openstack/resource_openstack_compute_instance_v2.go index 65c2b45da7..a5807100f2 100644 --- a/builtin/providers/openstack/resource_openstack_compute_instance_v2.go +++ b/builtin/providers/openstack/resource_openstack_compute_instance_v2.go @@ -14,6 +14,9 @@ import ( "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/keypairs" "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/secgroups" "github.com/rackspace/gophercloud/openstack/compute/v2/servers" + "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/layer3/floatingips" + "github.com/rackspace/gophercloud/openstack/networking/v2/networks" + "github.com/rackspace/gophercloud/openstack/networking/v2/ports" "github.com/rackspace/gophercloud/pagination" ) @@ -48,6 +51,11 @@ func resourceComputeInstanceV2() *schema.Resource { ForceNew: false, DefaultFunc: envDefaultFunc("OS_FLAVOR_ID"), }, + "floating_ip": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: false, + }, "security_groups": &schema.Schema{ Type: schema.TypeSet, Optional: true, @@ -215,6 +223,22 @@ func resourceComputeInstanceV2Create(d *schema.ResourceData, meta interface{}) e "Error waiting for instance (%s) to become ready: %s", server.ID, err) } + floatingIP := d.Get("floating_ip").(string) + if len(floatingIP) > 0 { + networkingClient, err := config.networkingV2Client(d.Get("region").(string)) + if err != nil { + return fmt.Errorf("Error creating OpenStack compute client: %s", err) + } + + allFloatingIPs, err := getFloatingIPs(networkingClient) + if err != nil { + return fmt.Errorf("Error listing OpenStack floating IPs: %s", err) + } + err = assignFloatingIP(networkingClient, extractFloatingIPFromIP(allFloatingIPs, floatingIP), server.ID) + if err != nil { + fmt.Errorf("Error assigning floating IP to OpenStack compute instance: %s", err) + } + } return resourceComputeInstanceV2Read(d, meta) } @@ -375,6 +399,25 @@ func resourceComputeInstanceV2Update(d *schema.ResourceData, meta interface{}) e } } + if d.HasChange("floating_ip") { + floatingIP := d.Get("floating_ip").(string) + if len(floatingIP) > 0 { + networkingClient, err := config.networkingV2Client(d.Get("region").(string)) + if err != nil { + return fmt.Errorf("Error creating OpenStack compute client: %s", err) + } + + allFloatingIPs, err := getFloatingIPs(networkingClient) + if err != nil { + return fmt.Errorf("Error listing OpenStack floating IPs: %s", err) + } + err = assignFloatingIP(networkingClient, extractFloatingIPFromIP(allFloatingIPs, floatingIP), d.Id()) + if err != nil { + fmt.Errorf("Error assigning floating IP to OpenStack compute instance: %s", err) + } + } + } + if d.HasChange("flavor_ref") { resizeOpts := &servers.ResizeOpts{ FlavorRef: d.Get("flavor_ref").(string), @@ -526,3 +569,93 @@ func resourceInstanceBlockDeviceV2(d *schema.ResourceData, bd map[string]interfa return bfvOpts } + +func extractFloatingIPFromIP(ips []floatingips.FloatingIP, IP string) *floatingips.FloatingIP { + for _, floatingIP := range ips { + if floatingIP.FloatingIP == IP { + return &floatingIP + } + } + return nil +} + +func assignFloatingIP(networkingClient *gophercloud.ServiceClient, floatingIP *floatingips.FloatingIP, instanceID string) error { + networkID, err := getFirstNetworkID(networkingClient, instanceID) + if err != nil { + return err + } + portID, err := getInstancePortID(networkingClient, instanceID, networkID) + _, err = floatingips.Update(networkingClient, floatingIP.ID, floatingips.UpdateOpts{ + PortID: portID, + }).Extract() + return err +} + +func getFirstNetworkID(networkingClient *gophercloud.ServiceClient, instanceID string) (string, error) { + pager := networks.List(networkingClient, networks.ListOpts{}) + + var networkdID string + err := pager.EachPage(func(page pagination.Page) (bool, error) { + networkList, err := networks.ExtractNetworks(page) + if err != nil { + return false, err + } + + if len(networkList) > 0 { + networkdID = networkList[0].ID + return false, nil + } + return false, fmt.Errorf("No network found for the instance %s", instanceID) + }) + if err != nil { + return "", err + } + return networkdID, nil + +} + +func getInstancePortID(networkingClient *gophercloud.ServiceClient, instanceID, networkID string) (string, error) { + pager := ports.List(networkingClient, ports.ListOpts{ + DeviceID: instanceID, + NetworkID: networkID, + }) + + var portID string + err := pager.EachPage(func(page pagination.Page) (bool, error) { + portList, err := ports.ExtractPorts(page) + if err != nil { + return false, err + } + for _, port := range portList { + portID = port.ID + return false, nil + } + return true, nil + }) + + if err != nil { + return "", err + } + return portID, nil +} + +func getFloatingIPs(networkingClient *gophercloud.ServiceClient) ([]floatingips.FloatingIP, error) { + pager := floatingips.List(networkingClient, floatingips.ListOpts{}) + + ips := []floatingips.FloatingIP{} + err := pager.EachPage(func(page pagination.Page) (bool, error) { + floatingipList, err := floatingips.ExtractFloatingIPs(page) + if err != nil { + return false, err + } + for _, f := range floatingipList { + ips = append(ips, f) + } + return true, nil + }) + + if err != nil { + return nil, err + } + return ips, nil +} From 132d5acb33a1a637d065cd2f35e12d53ba589361 Mon Sep 17 00:00:00 2001 From: Julien Vey Date: Mon, 9 Feb 2015 13:27:30 +0100 Subject: [PATCH 083/132] Make pool name configurable in tests --- builtin/providers/openstack/provider_test.go | 7 +++++++ .../openstack/resource_openstack_compute_instance_v2.go | 4 ++-- .../resource_openstack_networking_floatingip_v2_test.go | 4 ++-- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/builtin/providers/openstack/provider_test.go b/builtin/providers/openstack/provider_test.go index 9e90bb4ea7..d98ec1820a 100644 --- a/builtin/providers/openstack/provider_test.go +++ b/builtin/providers/openstack/provider_test.go @@ -10,6 +10,7 @@ import ( var ( OS_REGION_NAME = "" + OS_POOL_NAME = "" ) var testAccProviders map[string]terraform.ResourceProvider @@ -49,6 +50,12 @@ func testAccPreCheck(t *testing.T) { t.Fatal("OS_IMAGE_ID must be set for acceptance tests") } + v = os.Getenv("OS_POOL_NAME") + if v == "" { + t.Fatal("OS_POOL_NAME must be set for acceptance tests") + } + OS_POOL_NAME = v + v = os.Getenv("OS_FLAVOR_ID") if v == "" { t.Fatal("OS_FLAVOR_ID must be set for acceptance tests") diff --git a/builtin/providers/openstack/resource_openstack_compute_instance_v2.go b/builtin/providers/openstack/resource_openstack_compute_instance_v2.go index a5807100f2..bcf30a6ee7 100644 --- a/builtin/providers/openstack/resource_openstack_compute_instance_v2.go +++ b/builtin/providers/openstack/resource_openstack_compute_instance_v2.go @@ -224,7 +224,7 @@ func resourceComputeInstanceV2Create(d *schema.ResourceData, meta interface{}) e server.ID, err) } floatingIP := d.Get("floating_ip").(string) - if len(floatingIP) > 0 { + if floatingIP != "" { networkingClient, err := config.networkingV2Client(d.Get("region").(string)) if err != nil { return fmt.Errorf("Error creating OpenStack compute client: %s", err) @@ -401,7 +401,7 @@ func resourceComputeInstanceV2Update(d *schema.ResourceData, meta interface{}) e if d.HasChange("floating_ip") { floatingIP := d.Get("floating_ip").(string) - if len(floatingIP) > 0 { + if floatingIP != "" { networkingClient, err := config.networkingV2Client(d.Get("region").(string)) if err != nil { return fmt.Errorf("Error creating OpenStack compute client: %s", err) diff --git a/builtin/providers/openstack/resource_openstack_networking_floatingip_v2_test.go b/builtin/providers/openstack/resource_openstack_networking_floatingip_v2_test.go index 3902759284..cd08ea5121 100644 --- a/builtin/providers/openstack/resource_openstack_networking_floatingip_v2_test.go +++ b/builtin/providers/openstack/resource_openstack_networking_floatingip_v2_test.go @@ -84,6 +84,6 @@ func testAccCheckNetworkingV2FloatingIPExists(t *testing.T, n string, kp *floati var testAccNetworkingV2FloatingIP_basic = fmt.Sprintf(` resource "openstack_networking_floatingip_v2" "foo" { region = "%s" - pool = "PublicNetwork-01" + pool = "%s" }`, - OS_REGION_NAME) + OS_REGION_NAME, OS_POOL_NAME) From 32d0e36709b75844f697239c607245017013b385 Mon Sep 17 00:00:00 2001 From: Eric Bellemon Date: Mon, 9 Feb 2015 23:37:39 +0100 Subject: [PATCH 084/132] Add router resource --- builtin/providers/openstack/provider.go | 1 + ...resource_openstack_networking_router_v2.go | 190 ++++++++++++++++++ ...rce_openstack_networking_router_v2_test.go | 104 ++++++++++ 3 files changed, 295 insertions(+) create mode 100644 builtin/providers/openstack/resource_openstack_networking_router_v2.go create mode 100644 builtin/providers/openstack/resource_openstack_networking_router_v2_test.go diff --git a/builtin/providers/openstack/provider.go b/builtin/providers/openstack/provider.go index 955101a441..64e87cbb4c 100644 --- a/builtin/providers/openstack/provider.go +++ b/builtin/providers/openstack/provider.go @@ -69,6 +69,7 @@ func Provider() terraform.ResourceProvider { "openstack_networking_network_v2": resourceNetworkingNetworkV2(), "openstack_networking_subnet_v2": resourceNetworkingSubnetV2(), "openstack_networking_floatingip_v2": resourceNetworkingFloatingIPV2(), + "openstack_networking_router_v2": resourceNetworkingRouterV2(), "openstack_objectstorage_container_v1": resourceObjectStorageContainerV1(), }, diff --git a/builtin/providers/openstack/resource_openstack_networking_router_v2.go b/builtin/providers/openstack/resource_openstack_networking_router_v2.go new file mode 100644 index 0000000000..c4fe8e90ad --- /dev/null +++ b/builtin/providers/openstack/resource_openstack_networking_router_v2.go @@ -0,0 +1,190 @@ +package openstack + +import ( + "fmt" + "log" + "strconv" + + "github.com/hashicorp/terraform/helper/schema" + "github.com/racker/perigee" + "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/layer3/routers" +) + +func resourceNetworkingRouterV2() *schema.Resource { + return &schema.Resource{ + Create: resourceNetworkingRouterV2Create, + Read: resourceNetworkingRouterV2Read, + Update: resourceNetworkingRouterV2Update, + Delete: resourceNetworkingRouterV2Delete, + + Schema: map[string]*schema.Schema{ + "region": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + DefaultFunc: envDefaultFunc("OS_REGION_NAME"), + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: false, + }, + "admin_state_up": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: false, + }, + "external_gateway": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: false, + }, + "tenant_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + }, + } +} + +func resourceNetworkingRouterV2Create(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + networkingClient, err := config.networkingV2Client(d.Get("region").(string)) + if err != nil { + return fmt.Errorf("Error creating OpenStack networking client: %s", err) + } + + createOpts := routers.CreateOpts{ + Name: d.Get("name").(string), + TenantID: d.Get("tenant_id").(string), + } + + asuRaw := d.Get("admin_state_up").(string) + if asuRaw != "" { + asu, err := strconv.ParseBool(asuRaw) + if err != nil { + return fmt.Errorf("admin_state_up, if provided, must be either 'true' or 'false'") + } + createOpts.AdminStateUp = &asu + } + + externalGateway := d.Get("external_gateway").(string) + if externalGateway != "" { + gatewayInfo := routers.GatewayInfo{ + NetworkID: externalGateway, + } + createOpts.GatewayInfo = &gatewayInfo + } + + log.Printf("[INFO] Requesting router creation") + n, err := routers.Create(networkingClient, createOpts).Extract() + if err != nil { + return fmt.Errorf("Error creating OpenStack Neutron router: %s", err) + } + log.Printf("[INFO] Router ID: %s", n.ID) + + d.SetId(n.ID) + + return resourceNetworkingRouterV2Read(d, meta) +} + +func resourceNetworkingRouterV2Read(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + networkingClient, err := config.networkingV2Client(d.Get("region").(string)) + if err != nil { + return fmt.Errorf("Error creating OpenStack networking client: %s", err) + } + + n, err := routers.Get(networkingClient, d.Id()).Extract() + if err != nil { + httpError, ok := err.(*perigee.UnexpectedResponseCodeError) + if !ok { + return fmt.Errorf("Error retrieving OpenStack Neutron Router: %s", err) + } + + if httpError.Actual == 404 { + d.SetId("") + return nil + } + return fmt.Errorf("Error retrieving OpenStack Neutron Router: %s", err) + } + + log.Printf("[DEBUG] Retreived Router %s: %+v", d.Id(), n) + + d.Set("region", d.Get("region").(string)) + + if t, exists := d.GetOk("name"); exists && t != "" { + d.Set("name", n.Name) + } else { + d.Set("name", "") + } + + if t, exists := d.GetOk("admin_state_up"); exists && t != "" { + d.Set("admin_state_up", strconv.FormatBool(n.AdminStateUp)) + } else { + d.Set("admin_state_up", "") + } + + if t, exists := d.GetOk("tenant_id"); exists && t != "" { + d.Set("tenant_id", n.TenantID) + } else { + d.Set("tenant_id", "") + } + + if t, exists := d.GetOk("external_gateway"); exists && t != "" { + d.Set("external_gateway", n.GatewayInfo.NetworkID) + } else { + d.Set("external_gateway", "") + } + + return nil +} + +func resourceNetworkingRouterV2Update(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + networkingClient, err := config.networkingV2Client(d.Get("region").(string)) + if err != nil { + return fmt.Errorf("Error creating OpenStack networking client: %s", err) + } + + var updateOpts routers.UpdateOpts + if d.HasChange("name") { + updateOpts.Name = d.Get("name").(string) + } + if d.HasChange("admin_state_up") { + asuRaw := d.Get("admin_state_up").(string) + if asuRaw != "" { + asu, err := strconv.ParseBool(asuRaw) + if err != nil { + return fmt.Errorf("admin_state_up, if provided, must be either 'true' or 'false'") + } + updateOpts.AdminStateUp = &asu + } + } + + log.Printf("[DEBUG] Updating Router %s with options: %+v", d.Id(), updateOpts) + + _, err = routers.Update(networkingClient, d.Id(), updateOpts).Extract() + if err != nil { + return fmt.Errorf("Error updating OpenStack Neutron Router: %s", err) + } + + return resourceNetworkingRouterV2Read(d, meta) +} + +func resourceNetworkingRouterV2Delete(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + networkingClient, err := config.networkingV2Client(d.Get("region").(string)) + if err != nil { + return fmt.Errorf("Error creating OpenStack networking client: %s", err) + } + + err = routers.Delete(networkingClient, d.Id()).ExtractErr() + if err != nil { + return fmt.Errorf("Error deleting OpenStack Neutron Router: %s", err) + } + + d.SetId("") + return nil +} diff --git a/builtin/providers/openstack/resource_openstack_networking_router_v2_test.go b/builtin/providers/openstack/resource_openstack_networking_router_v2_test.go new file mode 100644 index 0000000000..57356cb74e --- /dev/null +++ b/builtin/providers/openstack/resource_openstack_networking_router_v2_test.go @@ -0,0 +1,104 @@ +package openstack + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" + + "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/layer3/routers" +) + +func TestAccNetworkingV2Router_basic(t *testing.T) { + var router routers.Router + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckNetworkingV2RouterDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccNetworkingV2Router_basic, + Check: resource.ComposeTestCheckFunc( + testAccCheckNetworkingV2RouterExists(t, "openstack_networking_router_v2.foo", &router), + ), + }, + resource.TestStep{ + Config: testAccNetworkingV2Router_update, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("openstack_networking_router_v2.foo", "name", "router_2"), + ), + }, + }, + }) +} + +func testAccCheckNetworkingV2RouterDestroy(s *terraform.State) error { + config := testAccProvider.Meta().(*Config) + networkingClient, err := config.networkingV2Client(OS_REGION_NAME) + if err != nil { + return fmt.Errorf("(testAccCheckNetworkingV2RouterDestroy) Error creating OpenStack networking client: %s", err) + } + + for _, rs := range s.RootModule().Resources { + if rs.Type != "openstack_networking_router_v2" { + continue + } + + _, err := routers.Get(networkingClient, rs.Primary.ID).Extract() + if err == nil { + return fmt.Errorf("Router still exists") + } + } + + return nil +} + +func testAccCheckNetworkingV2RouterExists(t *testing.T, n string, router *routers.Router) 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 ID is set") + } + + config := testAccProvider.Meta().(*Config) + networkingClient, err := config.networkingV2Client(OS_REGION_NAME) + if err != nil { + return fmt.Errorf("(testAccCheckNetworkingV2RouterExists) Error creating OpenStack networking client: %s", err) + } + + found, err := routers.Get(networkingClient, rs.Primary.ID).Extract() + if err != nil { + return err + } + + if found.ID != rs.Primary.ID { + return fmt.Errorf("Router not found") + } + + *router = *found + + return nil + } +} + +var testAccNetworkingV2Router_basic = fmt.Sprintf(` + resource "openstack_networking_router_v2" "foo" { + name = "router" + region = "%s" + admin_state_up = "true" + }`, + OS_REGION_NAME) + +var testAccNetworkingV2Router_update = fmt.Sprintf(` + resource "openstack_networking_router_v2" "foo" { + region = "%s" + name = "router_2" + admin_state_up = "true" + }`, + OS_REGION_NAME) From e9abf04e4b750a6d078be187e50918bb1435b290 Mon Sep 17 00:00:00 2001 From: Eric Bellemon Date: Mon, 9 Feb 2015 23:37:58 +0100 Subject: [PATCH 085/132] Add router interface resource --- builtin/providers/openstack/provider.go | 25 ++-- ...penstack_networking_router_interface_v2.go | 109 ++++++++++++++++++ ...ack_networking_router_interface_v2_test.go | 104 +++++++++++++++++ 3 files changed, 226 insertions(+), 12 deletions(-) create mode 100644 builtin/providers/openstack/resource_openstack_networking_router_interface_v2.go create mode 100644 builtin/providers/openstack/resource_openstack_networking_router_interface_v2_test.go diff --git a/builtin/providers/openstack/provider.go b/builtin/providers/openstack/provider.go index 64e87cbb4c..450e1c7055 100644 --- a/builtin/providers/openstack/provider.go +++ b/builtin/providers/openstack/provider.go @@ -59,18 +59,19 @@ func Provider() terraform.ResourceProvider { }, ResourcesMap: map[string]*schema.Resource{ - "openstack_blockstorage_volume_v1": resourceBlockStorageVolumeV1(), - "openstack_compute_instance_v2": resourceComputeInstanceV2(), - "openstack_compute_keypair_v2": resourceComputeKeypairV2(), - "openstack_compute_secgroup_v2": resourceComputeSecGroupV2(), - "openstack_lb_monitor_v1": resourceLBMonitorV1(), - "openstack_lb_pool_v1": resourceLBPoolV1(), - "openstack_lb_vip_v1": resourceLBVipV1(), - "openstack_networking_network_v2": resourceNetworkingNetworkV2(), - "openstack_networking_subnet_v2": resourceNetworkingSubnetV2(), - "openstack_networking_floatingip_v2": resourceNetworkingFloatingIPV2(), - "openstack_networking_router_v2": resourceNetworkingRouterV2(), - "openstack_objectstorage_container_v1": resourceObjectStorageContainerV1(), + "openstack_blockstorage_volume_v1": resourceBlockStorageVolumeV1(), + "openstack_compute_instance_v2": resourceComputeInstanceV2(), + "openstack_compute_keypair_v2": resourceComputeKeypairV2(), + "openstack_compute_secgroup_v2": resourceComputeSecGroupV2(), + "openstack_lb_monitor_v1": resourceLBMonitorV1(), + "openstack_lb_pool_v1": resourceLBPoolV1(), + "openstack_lb_vip_v1": resourceLBVipV1(), + "openstack_networking_network_v2": resourceNetworkingNetworkV2(), + "openstack_networking_subnet_v2": resourceNetworkingSubnetV2(), + "openstack_networking_floatingip_v2": resourceNetworkingFloatingIPV2(), + "openstack_networking_router_v2": resourceNetworkingRouterV2(), + "openstack_networking_router_interface_v2": resourceNetworkingRouterInterfaceV2(), + "openstack_objectstorage_container_v1": resourceObjectStorageContainerV1(), }, ConfigureFunc: configureProvider, diff --git a/builtin/providers/openstack/resource_openstack_networking_router_interface_v2.go b/builtin/providers/openstack/resource_openstack_networking_router_interface_v2.go new file mode 100644 index 0000000000..2daaf787de --- /dev/null +++ b/builtin/providers/openstack/resource_openstack_networking_router_interface_v2.go @@ -0,0 +1,109 @@ +package openstack + +import ( + "fmt" + "log" + + "github.com/hashicorp/terraform/helper/schema" + "github.com/racker/perigee" + "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/layer3/routers" + "github.com/rackspace/gophercloud/openstack/networking/v2/ports" +) + +func resourceNetworkingRouterInterfaceV2() *schema.Resource { + return &schema.Resource{ + Create: resourceNetworkingRouterInterfaceV2Create, + Read: resourceNetworkingRouterInterfaceV2Read, + Delete: resourceNetworkingRouterInterfaceV2Delete, + + Schema: map[string]*schema.Schema{ + "region": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + DefaultFunc: envDefaultFunc("OS_REGION_NAME"), + }, + "router_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "subnet_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + }, + } +} + +func resourceNetworkingRouterInterfaceV2Create(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + networkingClient, err := config.networkingV2Client(d.Get("region").(string)) + if err != nil { + return fmt.Errorf("Error creating OpenStack networking client: %s", err) + } + + createOpts := routers.InterfaceOpts{ + SubnetID: d.Get("subnet_id").(string), + } + + log.Printf("[INFO] Requesting router interface creation") + n, err := routers.AddInterface(networkingClient, d.Get("router_id").(string), createOpts).Extract() + if err != nil { + return fmt.Errorf("Error creating OpenStack Neutron router interface: %s", err) + } + log.Printf("[INFO] Router interface Port ID: %s", n.PortID) + + d.SetId(n.PortID) + + return resourceNetworkingRouterInterfaceV2Read(d, meta) +} + +func resourceNetworkingRouterInterfaceV2Read(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + networkingClient, err := config.networkingV2Client(d.Get("region").(string)) + if err != nil { + return fmt.Errorf("Error creating OpenStack networking client: %s", err) + } + + n, err := ports.Get(networkingClient, d.Id()).Extract() + if err != nil { + httpError, ok := err.(*perigee.UnexpectedResponseCodeError) + if !ok { + return fmt.Errorf("Error retrieving OpenStack Neutron Router Interface: %s", err) + } + + if httpError.Actual == 404 { + d.SetId("") + return nil + } + return fmt.Errorf("Error retrieving OpenStack Neutron Router Interface: %s", err) + } + + log.Printf("[DEBUG] Retreived Router Interface %s: %+v", d.Id(), n) + + d.Set("region", d.Get("region").(string)) + + return nil +} + +func resourceNetworkingRouterInterfaceV2Delete(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + networkingClient, err := config.networkingV2Client(d.Get("region").(string)) + if err != nil { + return fmt.Errorf("Error creating OpenStack networking client: %s", err) + } + + removeOpts := routers.InterfaceOpts{ + SubnetID: d.Get("subnet_id").(string), + } + + _, err = routers.RemoveInterface(networkingClient, d.Get("router_id").(string), removeOpts).Extract() + if err != nil { + return fmt.Errorf("Error deleting OpenStack Neutron Router Interface: %s", err) + } + + d.SetId("") + return nil +} diff --git a/builtin/providers/openstack/resource_openstack_networking_router_interface_v2_test.go b/builtin/providers/openstack/resource_openstack_networking_router_interface_v2_test.go new file mode 100644 index 0000000000..a74dbc30b4 --- /dev/null +++ b/builtin/providers/openstack/resource_openstack_networking_router_interface_v2_test.go @@ -0,0 +1,104 @@ +package openstack + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" + + "github.com/rackspace/gophercloud/openstack/networking/v2/ports" +) + +func TestAccNetworkingV2RouterInterface_basic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckNetworkingV2RouterInterfaceDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccNetworkingV2RouterInterface_basic, + Check: resource.ComposeTestCheckFunc( + testAccCheckNetworkingV2RouterInterfaceExists(t, "openstack_networking_router_interface_v2.int_1"), + ), + }, + }, + }) +} + +func testAccCheckNetworkingV2RouterInterfaceDestroy(s *terraform.State) error { + config := testAccProvider.Meta().(*Config) + networkingClient, err := config.networkingV2Client(OS_REGION_NAME) + if err != nil { + return fmt.Errorf("(testAccCheckNetworkingV2RouterInterfaceDestroy) Error creating OpenStack networking client: %s", err) + } + + for _, rs := range s.RootModule().Resources { + if rs.Type != "openstack_networking_router_interface_v2" { + continue + } + + _, err := ports.Get(networkingClient, rs.Primary.ID).Extract() + if err == nil { + return fmt.Errorf("Router interface still exists") + } + } + + return nil +} + +func testAccCheckNetworkingV2RouterInterfaceExists(t *testing.T, n string) 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 ID is set") + } + + config := testAccProvider.Meta().(*Config) + networkingClient, err := config.networkingV2Client(OS_REGION_NAME) + if err != nil { + return fmt.Errorf("(testAccCheckNetworkingV2RouterInterfaceExists) Error creating OpenStack networking client: %s", err) + } + + found, err := ports.Get(networkingClient, rs.Primary.ID).Extract() + if err != nil { + return err + } + + if found.ID != rs.Primary.ID { + return fmt.Errorf("Router interface not found") + } + + return nil + } +} + +var testAccNetworkingV2RouterInterface_basic = fmt.Sprintf(` + resource "openstack_networking_router_v2" "router_1" { + name = "router_1" + region = "%s" + admin_state_up = "true" + } + + resource "openstack_networking_router_interface_v2" "int_1" { + subnet_id = "${openstack_networking_subnet_v2.subnet_1.id}" + router_id = "${openstack_networking_router_v2.router_1.id}" + region = "%s" + } + + resource "openstack_networking_network_v2" "network_1" { + region = "%s" + name = "network_1" + admin_state_up = "true" + } + + resource "openstack_networking_subnet_v2" "subnet_1" { + region = "%s" + network_id = "${openstack_networking_network_v2.network_1.id}" + cidr = "192.168.199.0/24" + ip_version = 4 + }`, OS_REGION_NAME, OS_REGION_NAME, OS_REGION_NAME, OS_REGION_NAME) From 9b30ef4eb2c8284364b5ed18869cdba572f0b2fd Mon Sep 17 00:00:00 2001 From: Eric Bellemon Date: Mon, 9 Feb 2015 23:55:21 +0100 Subject: [PATCH 086/132] Remove region properties on acceptance tests --- ...ack_networking_router_interface_v2_test.go | 38 +++++++++---------- ...rce_openstack_networking_router_v2_test.go | 20 ++++------ 2 files changed, 25 insertions(+), 33 deletions(-) diff --git a/builtin/providers/openstack/resource_openstack_networking_router_interface_v2_test.go b/builtin/providers/openstack/resource_openstack_networking_router_interface_v2_test.go index a74dbc30b4..be3b12c0b5 100644 --- a/builtin/providers/openstack/resource_openstack_networking_router_interface_v2_test.go +++ b/builtin/providers/openstack/resource_openstack_networking_router_interface_v2_test.go @@ -78,27 +78,23 @@ func testAccCheckNetworkingV2RouterInterfaceExists(t *testing.T, n string) resou } var testAccNetworkingV2RouterInterface_basic = fmt.Sprintf(` - resource "openstack_networking_router_v2" "router_1" { - name = "router_1" - region = "%s" - admin_state_up = "true" - } +resource "openstack_networking_router_v2" "router_1" { + name = "router_1" + admin_state_up = "true" +} - resource "openstack_networking_router_interface_v2" "int_1" { - subnet_id = "${openstack_networking_subnet_v2.subnet_1.id}" - router_id = "${openstack_networking_router_v2.router_1.id}" - region = "%s" - } +resource "openstack_networking_router_interface_v2" "int_1" { + subnet_id = "${openstack_networking_subnet_v2.subnet_1.id}" + router_id = "${openstack_networking_router_v2.router_1.id}" +} - resource "openstack_networking_network_v2" "network_1" { - region = "%s" - name = "network_1" - admin_state_up = "true" - } +resource "openstack_networking_network_v2" "network_1" { + name = "network_1" + admin_state_up = "true" +} - resource "openstack_networking_subnet_v2" "subnet_1" { - region = "%s" - network_id = "${openstack_networking_network_v2.network_1.id}" - cidr = "192.168.199.0/24" - ip_version = 4 - }`, OS_REGION_NAME, OS_REGION_NAME, OS_REGION_NAME, OS_REGION_NAME) +resource "openstack_networking_subnet_v2" "subnet_1" { + network_id = "${openstack_networking_network_v2.network_1.id}" + cidr = "192.168.199.0/24" + ip_version = 4 +}`) diff --git a/builtin/providers/openstack/resource_openstack_networking_router_v2_test.go b/builtin/providers/openstack/resource_openstack_networking_router_v2_test.go index 57356cb74e..248f4e721f 100644 --- a/builtin/providers/openstack/resource_openstack_networking_router_v2_test.go +++ b/builtin/providers/openstack/resource_openstack_networking_router_v2_test.go @@ -88,17 +88,13 @@ func testAccCheckNetworkingV2RouterExists(t *testing.T, n string, router *router } var testAccNetworkingV2Router_basic = fmt.Sprintf(` - resource "openstack_networking_router_v2" "foo" { - name = "router" - region = "%s" - admin_state_up = "true" - }`, - OS_REGION_NAME) + resource "openstack_networking_router_v2" "foo" { + name = "router" + admin_state_up = "true" + }`) var testAccNetworkingV2Router_update = fmt.Sprintf(` - resource "openstack_networking_router_v2" "foo" { - region = "%s" - name = "router_2" - admin_state_up = "true" - }`, - OS_REGION_NAME) + resource "openstack_networking_router_v2" "foo" { + name = "router_2" + admin_state_up = "true" + }`) From fafa9468711f9ce1c851afdce06a80c9f17fd9bb Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Mon, 9 Feb 2015 20:27:39 -0700 Subject: [PATCH 087/132] handle 404 (Not Found) in Get operations --- ...source_openstack_blockstorage_volume_v1.go | 2 +- .../resource_openstack_compute_instance_v2.go | 2 +- .../resource_openstack_compute_keypair_v2.go | 2 +- .../resource_openstack_compute_secgroup_v2.go | 2 +- .../resource_openstack_lb_monitor_v1.go | 2 +- .../resource_openstack_lb_pool_v1.go | 2 +- .../openstack/resource_openstack_lb_vip_v1.go | 2 +- ...urce_openstack_networking_floatingip_v2.go | 2 +- ...esource_openstack_networking_network_v2.go | 2 +- ...resource_openstack_networking_subnet_v2.go | 2 +- builtin/providers/openstack/util.go | 22 +++++++++++++++++++ 11 files changed, 32 insertions(+), 10 deletions(-) create mode 100644 builtin/providers/openstack/util.go diff --git a/builtin/providers/openstack/resource_openstack_blockstorage_volume_v1.go b/builtin/providers/openstack/resource_openstack_blockstorage_volume_v1.go index ea2d99a653..ab85317bb0 100644 --- a/builtin/providers/openstack/resource_openstack_blockstorage_volume_v1.go +++ b/builtin/providers/openstack/resource_openstack_blockstorage_volume_v1.go @@ -130,7 +130,7 @@ func resourceBlockStorageVolumeV1Read(d *schema.ResourceData, meta interface{}) v, err := volumes.Get(blockStorageClient, d.Id()).Extract() if err != nil { - return fmt.Errorf("Error retrieving OpenStack volume: %s", err) + return CheckDeleted(d, err, "volume") } log.Printf("\n\ngot volume: %+v\n\n", v) diff --git a/builtin/providers/openstack/resource_openstack_compute_instance_v2.go b/builtin/providers/openstack/resource_openstack_compute_instance_v2.go index bcf30a6ee7..a60279c3d6 100644 --- a/builtin/providers/openstack/resource_openstack_compute_instance_v2.go +++ b/builtin/providers/openstack/resource_openstack_compute_instance_v2.go @@ -252,7 +252,7 @@ func resourceComputeInstanceV2Read(d *schema.ResourceData, meta interface{}) err server, err := servers.Get(computeClient, d.Id()).Extract() if err != nil { - return fmt.Errorf("Error retrieving OpenStack server: %s", err) + return CheckDeleted(d, err, "server") } log.Printf("[DEBUG] Retreived Server %s: %+v", d.Id(), server) diff --git a/builtin/providers/openstack/resource_openstack_compute_keypair_v2.go b/builtin/providers/openstack/resource_openstack_compute_keypair_v2.go index 8cdc849139..9c1417412e 100644 --- a/builtin/providers/openstack/resource_openstack_compute_keypair_v2.go +++ b/builtin/providers/openstack/resource_openstack_compute_keypair_v2.go @@ -65,7 +65,7 @@ func resourceComputeKeypairV2Read(d *schema.ResourceData, meta interface{}) erro kp, err := keypairs.Get(computeClient, d.Id()).Extract() if err != nil { - return fmt.Errorf("Error retrieving OpenStack keypair: %s", err) + return CheckDeleted(d, err, "keypair") } d.Set("region", d.Get("region").(string)) diff --git a/builtin/providers/openstack/resource_openstack_compute_secgroup_v2.go b/builtin/providers/openstack/resource_openstack_compute_secgroup_v2.go index f1d9ae7141..cb61e7458c 100644 --- a/builtin/providers/openstack/resource_openstack_compute_secgroup_v2.go +++ b/builtin/providers/openstack/resource_openstack_compute_secgroup_v2.go @@ -111,7 +111,7 @@ func resourceComputeSecGroupV2Read(d *schema.ResourceData, meta interface{}) err sg, err := secgroups.Get(computeClient, d.Id()).Extract() if err != nil { - return fmt.Errorf("Error retrieving OpenStack security group: %s", err) + return CheckDeleted(d, err, "security group") } d.Set("region", d.Get("region").(string)) diff --git a/builtin/providers/openstack/resource_openstack_lb_monitor_v1.go b/builtin/providers/openstack/resource_openstack_lb_monitor_v1.go index 7483b17e49..0761ec1f42 100644 --- a/builtin/providers/openstack/resource_openstack_lb_monitor_v1.go +++ b/builtin/providers/openstack/resource_openstack_lb_monitor_v1.go @@ -120,7 +120,7 @@ func resourceLBMonitorV1Read(d *schema.ResourceData, meta interface{}) error { m, err := monitors.Get(networkingClient, d.Id()).Extract() if err != nil { - return fmt.Errorf("Error retrieving OpenStack LB Monitor: %s", err) + return CheckDeleted(d, err, "LB monitor") } log.Printf("[DEBUG] Retreived OpenStack LB Monitor %s: %+v", d.Id(), m) diff --git a/builtin/providers/openstack/resource_openstack_lb_pool_v1.go b/builtin/providers/openstack/resource_openstack_lb_pool_v1.go index a7b5abbafb..7e3abdbf7e 100644 --- a/builtin/providers/openstack/resource_openstack_lb_pool_v1.go +++ b/builtin/providers/openstack/resource_openstack_lb_pool_v1.go @@ -154,7 +154,7 @@ func resourceLBPoolV1Read(d *schema.ResourceData, meta interface{}) error { p, err := pools.Get(networkingClient, d.Id()).Extract() if err != nil { - return fmt.Errorf("Error retrieving OpenStack LB Pool: %s", err) + return CheckDeleted(d, err, "LB pool") } log.Printf("[DEBUG] Retreived OpenStack LB Pool %s: %+v", d.Id(), p) diff --git a/builtin/providers/openstack/resource_openstack_lb_vip_v1.go b/builtin/providers/openstack/resource_openstack_lb_vip_v1.go index cef3977c8d..6181bc8a5e 100644 --- a/builtin/providers/openstack/resource_openstack_lb_vip_v1.go +++ b/builtin/providers/openstack/resource_openstack_lb_vip_v1.go @@ -133,7 +133,7 @@ func resourceLBVipV1Read(d *schema.ResourceData, meta interface{}) error { p, err := vips.Get(networkingClient, d.Id()).Extract() if err != nil { - return fmt.Errorf("Error retrieving OpenStack LB VIP: %s", err) + return CheckDeleted(d, err, "LB VIP") } log.Printf("[DEBUG] Retreived OpenStack LB VIP %s: %+v", d.Id(), p) diff --git a/builtin/providers/openstack/resource_openstack_networking_floatingip_v2.go b/builtin/providers/openstack/resource_openstack_networking_floatingip_v2.go index 410fb0e397..fb49657687 100644 --- a/builtin/providers/openstack/resource_openstack_networking_floatingip_v2.go +++ b/builtin/providers/openstack/resource_openstack_networking_floatingip_v2.go @@ -70,7 +70,7 @@ func resourceNetworkFloatingIPV2Read(d *schema.ResourceData, meta interface{}) e floatingIP, err := floatingips.Get(networkClient, d.Id()).Extract() if err != nil { - return fmt.Errorf("Error retrieving floatingIP: %s", err) + return CheckDeleted(d, err, "floating IP") } d.Set("region", d.Get("region").(string)) diff --git a/builtin/providers/openstack/resource_openstack_networking_network_v2.go b/builtin/providers/openstack/resource_openstack_networking_network_v2.go index fc420b2e9a..bf556f4185 100644 --- a/builtin/providers/openstack/resource_openstack_networking_network_v2.go +++ b/builtin/providers/openstack/resource_openstack_networking_network_v2.go @@ -98,7 +98,7 @@ func resourceNetworkingNetworkV2Read(d *schema.ResourceData, meta interface{}) e n, err := networks.Get(networkingClient, d.Id()).Extract() if err != nil { - return fmt.Errorf("Error retrieving OpenStack Neutron Network: %s", err) + return CheckDeleted(d, err, "network") } log.Printf("[DEBUG] Retreived Network %s: %+v", d.Id(), n) diff --git a/builtin/providers/openstack/resource_openstack_networking_subnet_v2.go b/builtin/providers/openstack/resource_openstack_networking_subnet_v2.go index 74a43e27c7..8462611df7 100644 --- a/builtin/providers/openstack/resource_openstack_networking_subnet_v2.go +++ b/builtin/providers/openstack/resource_openstack_networking_subnet_v2.go @@ -155,7 +155,7 @@ func resourceNetworkingSubnetV2Read(d *schema.ResourceData, meta interface{}) er s, err := subnets.Get(networkingClient, d.Id()).Extract() if err != nil { - return fmt.Errorf("Error retrieving OpenStack Neutron Subnet: %s", err) + return CheckDeleted(d, err, "subnet") } log.Printf("[DEBUG] Retreived Subnet %s: %+v", d.Id(), s) diff --git a/builtin/providers/openstack/util.go b/builtin/providers/openstack/util.go new file mode 100644 index 0000000000..7ed9f8f5f3 --- /dev/null +++ b/builtin/providers/openstack/util.go @@ -0,0 +1,22 @@ +package openstack + +import ( + "fmt" + + "github.com/hashicorp/terraform/helper/schema" + "github.com/racker/perigee" +) + +// CheckDeleted checks the error to see if it's a 404 (Not Found) and, if so, +// sets the resource ID to the empty string instead of throwing an error. +func CheckDeleted(d *schema.ResourceData, err error, resource string) error { + errCode, ok := err.(*perigee.UnexpectedResponseCodeError) + if !ok { + return fmt.Errorf("Error retrieving OpenStack %s: %s", resource, err) + } + if errCode.Actual == 404 { + d.SetId("") + return nil + } + return fmt.Errorf("Error retrieving OpenStack %s: %s", resource, err) +} From f51a53000f54ef180a1f3a3e4cd30628b72c769c Mon Sep 17 00:00:00 2001 From: Joe Topjian Date: Tue, 10 Feb 2015 05:20:23 +0000 Subject: [PATCH 088/132] Support for image_name This commit renames image_ref to image_id and adds the image_name parameter. Users can now specify either an image UUID or image name when launching instances. image_name is preferrable as deployers/sysadmins generally regularly deprecate/remove outdated and insecure images. Using a consistent naming scheme allows end-users to always retrieve a working image. --- builtin/providers/openstack/provider_test.go | 8 +-- .../resource_openstack_compute_instance_v2.go | 51 +++++++++++++++++-- 2 files changed, 53 insertions(+), 6 deletions(-) diff --git a/builtin/providers/openstack/provider_test.go b/builtin/providers/openstack/provider_test.go index d98ec1820a..cafda7ef86 100644 --- a/builtin/providers/openstack/provider_test.go +++ b/builtin/providers/openstack/provider_test.go @@ -45,9 +45,11 @@ func testAccPreCheck(t *testing.T) { } OS_REGION_NAME = v - v = os.Getenv("OS_IMAGE_ID") - if v == "" { - t.Fatal("OS_IMAGE_ID must be set for acceptance tests") + v1 := os.Getenv("OS_IMAGE_ID") + v2 := os.Getenv("OS_IMAGE_NAME") + + if v1 == "" && v2 == "" { + t.Fatal("OS_IMAGE_ID or OS_IMAGE_NAME must be set for acceptance tests") } v = os.Getenv("OS_POOL_NAME") diff --git a/builtin/providers/openstack/resource_openstack_compute_instance_v2.go b/builtin/providers/openstack/resource_openstack_compute_instance_v2.go index a60279c3d6..c56f867926 100644 --- a/builtin/providers/openstack/resource_openstack_compute_instance_v2.go +++ b/builtin/providers/openstack/resource_openstack_compute_instance_v2.go @@ -13,6 +13,7 @@ import ( "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/bootfromvolume" "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/keypairs" "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/secgroups" + "github.com/rackspace/gophercloud/openstack/compute/v2/images" "github.com/rackspace/gophercloud/openstack/compute/v2/servers" "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/layer3/floatingips" "github.com/rackspace/gophercloud/openstack/networking/v2/networks" @@ -39,12 +40,18 @@ func resourceComputeInstanceV2() *schema.Resource { Required: true, ForceNew: false, }, - "image_ref": &schema.Schema{ + "image_id": &schema.Schema{ Type: schema.TypeString, Optional: true, - ForceNew: false, + ForceNew: true, DefaultFunc: envDefaultFunc("OS_IMAGE_ID"), }, + "image_name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + DefaultFunc: envDefaultFunc("OS_IMAGE_NAME"), + }, "flavor_ref": &schema.Schema{ Type: schema.TypeString, Optional: true, @@ -165,9 +172,14 @@ func resourceComputeInstanceV2Create(d *schema.ResourceData, meta interface{}) e var createOpts servers.CreateOptsBuilder + imageId, err := getImageID(computeClient, d) + if err != nil { + return err + } + createOpts = &servers.CreateOpts{ Name: d.Get("name").(string), - ImageRef: d.Get("image_ref").(string), + ImageRef: imageId, FlavorRef: d.Get("flavor_ref").(string), SecurityGroups: resourceInstanceSecGroupsV2(d), AvailabilityZone: d.Get("availability_zone").(string), @@ -659,3 +671,36 @@ func getFloatingIPs(networkingClient *gophercloud.ServiceClient) ([]floatingips. } return ips, nil } + +func getImageID(client *gophercloud.ServiceClient, d *schema.ResourceData) (string, error) { + imageID := d.Get("image_id").(string) + imageName := d.Get("image_name").(string) + if imageID == "" { + pager := images.ListDetail(client, nil) + + pager.EachPage(func(page pagination.Page) (bool, error) { + imageList, err := images.ExtractImages(page) + + if err != nil { + return false, err + } + + for _, i := range imageList { + if i.Name == imageName { + imageID = i.ID + } + } + return true, nil + }) + + if imageID == "" { + return "", fmt.Errorf("Unable to find image: %v", imageName) + } + } + + if imageID == "" && imageName == "" { + return "", fmt.Errorf("Neither an image ID nor an image name were able to be determined.") + } + + return imageID, nil +} From bad2c9f18d5038c9b6377c916dec2f46cc500479 Mon Sep 17 00:00:00 2001 From: Joe Topjian Date: Tue, 10 Feb 2015 16:58:27 +0000 Subject: [PATCH 089/132] Accounting for multiple results of an image name If multiple results are found, an error will be returned to the user. --- .../resource_openstack_compute_instance_v2.go | 27 ++++++++++++------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/builtin/providers/openstack/resource_openstack_compute_instance_v2.go b/builtin/providers/openstack/resource_openstack_compute_instance_v2.go index c56f867926..b4f51cc1d7 100644 --- a/builtin/providers/openstack/resource_openstack_compute_instance_v2.go +++ b/builtin/providers/openstack/resource_openstack_compute_instance_v2.go @@ -673,34 +673,43 @@ func getFloatingIPs(networkingClient *gophercloud.ServiceClient) ([]floatingips. } func getImageID(client *gophercloud.ServiceClient, d *schema.ResourceData) (string, error) { - imageID := d.Get("image_id").(string) + imageId := d.Get("image_id").(string) imageName := d.Get("image_name").(string) - if imageID == "" { - pager := images.ListDetail(client, nil) + imageCount := 0 + if imageId == "" && imageName != "" { + pager := images.ListDetail(client, &images.ListOpts{ + Name: imageName, + }) pager.EachPage(func(page pagination.Page) (bool, error) { imageList, err := images.ExtractImages(page) - if err != nil { return false, err } for _, i := range imageList { if i.Name == imageName { - imageID = i.ID + imageCount++ + imageId = i.ID } } return true, nil }) - if imageID == "" { - return "", fmt.Errorf("Unable to find image: %v", imageName) + switch imageCount { + case 0: + return "", fmt.Errorf("Unable to find image: %s", imageName) + case 1: + return imageId, nil + default: + return "", fmt.Errorf("Found %d images matching %s", imageCount, imageName) } } - if imageID == "" && imageName == "" { + if imageId == "" && imageName == "" { return "", fmt.Errorf("Neither an image ID nor an image name were able to be determined.") } - return imageID, nil + return imageId, nil + } From 74482abc5bf300c6d909ffd9ffd17be6ba04ba72 Mon Sep 17 00:00:00 2001 From: Joe Topjian Date: Wed, 11 Feb 2015 04:11:04 +0000 Subject: [PATCH 090/132] Refactoring multiple results --- .../resource_openstack_compute_instance_v2.go | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/builtin/providers/openstack/resource_openstack_compute_instance_v2.go b/builtin/providers/openstack/resource_openstack_compute_instance_v2.go index b4f51cc1d7..5b03577f4f 100644 --- a/builtin/providers/openstack/resource_openstack_compute_instance_v2.go +++ b/builtin/providers/openstack/resource_openstack_compute_instance_v2.go @@ -674,10 +674,14 @@ func getFloatingIPs(networkingClient *gophercloud.ServiceClient) ([]floatingips. func getImageID(client *gophercloud.ServiceClient, d *schema.ResourceData) (string, error) { imageId := d.Get("image_id").(string) - imageName := d.Get("image_name").(string) - imageCount := 0 - if imageId == "" && imageName != "" { + if imageId != "" { + return imageId, nil + } + + imageCount := 0 + imageName := d.Get("image_name").(string) + if imageName != "" { pager := images.ListDetail(client, &images.ListOpts{ Name: imageName, }) @@ -705,11 +709,5 @@ func getImageID(client *gophercloud.ServiceClient, d *schema.ResourceData) (stri return "", fmt.Errorf("Found %d images matching %s", imageCount, imageName) } } - - if imageId == "" && imageName == "" { - return "", fmt.Errorf("Neither an image ID nor an image name were able to be determined.") - } - - return imageId, nil - + return "", fmt.Errorf("Neither an image ID nor an image name were able to be determined.") } From 2b5c7c6e2c9c72c12b349552e3e405e9a456a38c Mon Sep 17 00:00:00 2001 From: Joe Topjian Date: Wed, 11 Feb 2015 04:14:45 +0000 Subject: [PATCH 091/132] Updated documentation to reflect the image_ref / image_id change. --- .../openstack/r/compute_instance_v2.html.markdown | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/website/source/docs/providers/openstack/r/compute_instance_v2.html.markdown b/website/source/docs/providers/openstack/r/compute_instance_v2.html.markdown index 9095cb15aa..f6cf6401ce 100644 --- a/website/source/docs/providers/openstack/r/compute_instance_v2.html.markdown +++ b/website/source/docs/providers/openstack/r/compute_instance_v2.html.markdown @@ -15,7 +15,7 @@ Manages a V2 VM instance resource within OpenStack. ``` resource "openstack_compute_instance_v2" "test-server" { name = "tf-test" - image_ref = "ad091b52-742f-469e-8f3c-fd81cadf0743" + image_id = "ad091b52-742f-469e-8f3c-fd81cadf0743" flavor_ref = "3" metadata { this = "that" @@ -35,8 +35,13 @@ The following arguments are supported: * `name` - (Required) A unique name for the resource. -* `image_ref` - (Required) The image reference (ID) for the desired image for - the server. Changing this creates a new server. +* `image_id` - (Required) The image reference (ID) for the desired image for + the server. Changing this creates a new server. Note that `image_id` and + `image_name` are mutually exclusive. + +* `image_name` - (Required) The image name for the server. Changing this + creates a new server. Note that `image_id` and `image_name` are mutually + exclusive. * `flavor_ref` - (Required) The flavor reference (ID) for the desired flavor for the server. Changing this resizes the existing server. From 6f8df3d34ef8f1ef3e1a5d0260d58f60d68d5fcc Mon Sep 17 00:00:00 2001 From: Joe Topjian Date: Wed, 11 Feb 2015 04:22:25 +0000 Subject: [PATCH 092/132] Doc touchup --- .../providers/openstack/r/compute_instance_v2.html.markdown | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/website/source/docs/providers/openstack/r/compute_instance_v2.html.markdown b/website/source/docs/providers/openstack/r/compute_instance_v2.html.markdown index f6cf6401ce..542210dc6c 100644 --- a/website/source/docs/providers/openstack/r/compute_instance_v2.html.markdown +++ b/website/source/docs/providers/openstack/r/compute_instance_v2.html.markdown @@ -35,9 +35,9 @@ The following arguments are supported: * `name` - (Required) A unique name for the resource. -* `image_id` - (Required) The image reference (ID) for the desired image for - the server. Changing this creates a new server. Note that `image_id` and - `image_name` are mutually exclusive. +* `image_id` - (Required) The image ID of the desired image for the server. + Changing this creates a new server. Note that `image_id` and `image_name` + are mutually exclusive. * `image_name` - (Required) The image name for the server. Changing this creates a new server. Note that `image_id` and `image_name` are mutually From 52102624c68acc946aeb5c5c559c4c51febb74b3 Mon Sep 17 00:00:00 2001 From: Joe Topjian Date: Wed, 11 Feb 2015 04:27:03 +0000 Subject: [PATCH 093/132] More doc touchups --- .../openstack/r/compute_instance_v2.html.markdown | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/website/source/docs/providers/openstack/r/compute_instance_v2.html.markdown b/website/source/docs/providers/openstack/r/compute_instance_v2.html.markdown index 542210dc6c..03091df0f9 100644 --- a/website/source/docs/providers/openstack/r/compute_instance_v2.html.markdown +++ b/website/source/docs/providers/openstack/r/compute_instance_v2.html.markdown @@ -35,13 +35,11 @@ The following arguments are supported: * `name` - (Required) A unique name for the resource. -* `image_id` - (Required) The image ID of the desired image for the server. - Changing this creates a new server. Note that `image_id` and `image_name` - are mutually exclusive. +* `image_id` - (Optional; Required if `image_name` is empty) The image ID of + the desired image for the server. Changing this creates a new server. -* `image_name` - (Required) The image name for the server. Changing this - creates a new server. Note that `image_id` and `image_name` are mutually - exclusive. +* `image_name` - (Optional; Required if `image_id` is empty) The name of the + desired image for the server. Changing this creates a new server. * `flavor_ref` - (Required) The flavor reference (ID) for the desired flavor for the server. Changing this resizes the existing server. From 768292c069c246a6b87455a576ee9755b597171f Mon Sep 17 00:00:00 2001 From: Joe Topjian Date: Wed, 11 Feb 2015 05:24:38 +0000 Subject: [PATCH 094/132] Support for flavor_name This commit renames flavor_ref to flavor_id and adds the flavor_name parameter. Users can now specify either a flavor ID or name when launching instances. --- builtin/providers/openstack/provider_test.go | 7 +- .../resource_openstack_compute_instance_v2.go | 66 +++++++++++++++++-- .../r/compute_instance_v2.html.markdown | 9 ++- 3 files changed, 72 insertions(+), 10 deletions(-) diff --git a/builtin/providers/openstack/provider_test.go b/builtin/providers/openstack/provider_test.go index cafda7ef86..7b3e65dd43 100644 --- a/builtin/providers/openstack/provider_test.go +++ b/builtin/providers/openstack/provider_test.go @@ -58,8 +58,9 @@ func testAccPreCheck(t *testing.T) { } OS_POOL_NAME = v - v = os.Getenv("OS_FLAVOR_ID") - if v == "" { - t.Fatal("OS_FLAVOR_ID must be set for acceptance tests") + v1 = os.Getenv("OS_FLAVOR_ID") + v2 = os.Getenv("OS_FLAVOR_NAME") + if v1 == "" && v2 == "" { + t.Fatal("OS_FLAVOR_ID or OS_FLAVOR_NAME must be set for acceptance tests") } } diff --git a/builtin/providers/openstack/resource_openstack_compute_instance_v2.go b/builtin/providers/openstack/resource_openstack_compute_instance_v2.go index 5b03577f4f..0a7b1b6247 100644 --- a/builtin/providers/openstack/resource_openstack_compute_instance_v2.go +++ b/builtin/providers/openstack/resource_openstack_compute_instance_v2.go @@ -13,6 +13,7 @@ import ( "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/bootfromvolume" "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/keypairs" "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/secgroups" + "github.com/rackspace/gophercloud/openstack/compute/v2/flavors" "github.com/rackspace/gophercloud/openstack/compute/v2/images" "github.com/rackspace/gophercloud/openstack/compute/v2/servers" "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/layer3/floatingips" @@ -52,12 +53,20 @@ func resourceComputeInstanceV2() *schema.Resource { ForceNew: true, DefaultFunc: envDefaultFunc("OS_IMAGE_NAME"), }, - "flavor_ref": &schema.Schema{ + "flavor_id": &schema.Schema{ Type: schema.TypeString, Optional: true, ForceNew: false, + Computed: true, DefaultFunc: envDefaultFunc("OS_FLAVOR_ID"), }, + "flavor_name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: false, + Computed: true, + DefaultFunc: envDefaultFunc("OS_FLAVOR_NAME"), + }, "floating_ip": &schema.Schema{ Type: schema.TypeString, Optional: true, @@ -177,10 +186,15 @@ func resourceComputeInstanceV2Create(d *schema.ResourceData, meta interface{}) e return err } + flavorId, err := getFlavorID(computeClient, d) + if err != nil { + return err + } + createOpts = &servers.CreateOpts{ Name: d.Get("name").(string), ImageRef: imageId, - FlavorRef: d.Get("flavor_ref").(string), + FlavorRef: flavorId, SecurityGroups: resourceInstanceSecGroupsV2(d), AvailabilityZone: d.Get("availability_zone").(string), Networks: resourceInstanceNetworksV2(d), @@ -327,11 +341,17 @@ func resourceComputeInstanceV2Read(d *schema.ResourceData, meta interface{}) err }) d.Set("security_groups.#", secGrpNum) - newFlavor, ok := server.Flavor["id"].(string) + flavorId, ok := server.Flavor["id"].(string) if !ok { return fmt.Errorf("Error setting OpenStack server's flavor: %v", server.Flavor) } - d.Set("flavor_ref", newFlavor) + d.Set("flavor_id", flavorId) + + flavor, err := flavors.Get(computeClient, flavorId).Extract() + if err != nil { + return err + } + d.Set("flavor_name", flavor.Name) return nil } @@ -711,3 +731,41 @@ func getImageID(client *gophercloud.ServiceClient, d *schema.ResourceData) (stri } return "", fmt.Errorf("Neither an image ID nor an image name were able to be determined.") } + +func getFlavorID(client *gophercloud.ServiceClient, d *schema.ResourceData) (string, error) { + flavorId := d.Get("flavor_id").(string) + + if flavorId != "" { + return flavorId, nil + } + + flavorCount := 0 + flavorName := d.Get("flavor_name").(string) + if flavorName != "" { + pager := flavors.ListDetail(client, nil) + pager.EachPage(func(page pagination.Page) (bool, error) { + flavorList, err := flavors.ExtractFlavors(page) + if err != nil { + return false, err + } + + for _, f := range flavorList { + if f.Name == flavorName { + flavorCount++ + flavorId = f.ID + } + } + return true, nil + }) + + switch flavorCount { + case 0: + return "", fmt.Errorf("Unable to find flavor: %s", flavorName) + case 1: + return flavorId, nil + default: + return "", fmt.Errorf("Found %d flavors matching %s", flavorCount, flavorName) + } + } + return "", fmt.Errorf("Neither an flavor ID nor an flavor name were able to be determined.") +} diff --git a/website/source/docs/providers/openstack/r/compute_instance_v2.html.markdown b/website/source/docs/providers/openstack/r/compute_instance_v2.html.markdown index 03091df0f9..ba03ee01c6 100644 --- a/website/source/docs/providers/openstack/r/compute_instance_v2.html.markdown +++ b/website/source/docs/providers/openstack/r/compute_instance_v2.html.markdown @@ -16,7 +16,7 @@ Manages a V2 VM instance resource within OpenStack. resource "openstack_compute_instance_v2" "test-server" { name = "tf-test" image_id = "ad091b52-742f-469e-8f3c-fd81cadf0743" - flavor_ref = "3" + flavor_id = "3" metadata { this = "that" } @@ -41,8 +41,11 @@ The following arguments are supported: * `image_name` - (Optional; Required if `image_id` is empty) The name of the desired image for the server. Changing this creates a new server. -* `flavor_ref` - (Required) The flavor reference (ID) for the desired flavor - for the server. Changing this resizes the existing server. +* `flavor_id` - (Optional; Required if `flavor_name` is empty) The flavor ID of + the desired flavor for the server. Changing this resizes the existing server. + +* `flavor_name` - (Optional; Required if `flavor_id` is empty) The name of the + desired flavor for the server. Changing this resizes the existing server. * `security_groups` - (Optional) An array of one or more security group names to associate with the server. Changing this results in adding/removing From b3438d07d69fd3d92ad865a07d8e116ae5a0da60 Mon Sep 17 00:00:00 2001 From: Joe Topjian Date: Wed, 11 Feb 2015 05:33:04 +0000 Subject: [PATCH 095/132] This commit enables both the image_id and the image_name to be computed, so that specifying one will populate the other. --- .../resource_openstack_compute_instance_v2.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/builtin/providers/openstack/resource_openstack_compute_instance_v2.go b/builtin/providers/openstack/resource_openstack_compute_instance_v2.go index 0a7b1b6247..fbc7a7dd79 100644 --- a/builtin/providers/openstack/resource_openstack_compute_instance_v2.go +++ b/builtin/providers/openstack/resource_openstack_compute_instance_v2.go @@ -45,12 +45,14 @@ func resourceComputeInstanceV2() *schema.Resource { Type: schema.TypeString, Optional: true, ForceNew: true, + Computed: true, DefaultFunc: envDefaultFunc("OS_IMAGE_ID"), }, "image_name": &schema.Schema{ Type: schema.TypeString, Optional: true, ForceNew: true, + Computed: true, DefaultFunc: envDefaultFunc("OS_IMAGE_NAME"), }, "flavor_id": &schema.Schema{ @@ -353,6 +355,18 @@ func resourceComputeInstanceV2Read(d *schema.ResourceData, meta interface{}) err } d.Set("flavor_name", flavor.Name) + imageId, ok := server.Image["id"].(string) + if !ok { + return fmt.Errorf("Error setting OpenStack server's image: %v", server.Image) + } + d.Set("image_id", imageId) + + image, err := images.Get(computeClient, imageId).Extract() + if err != nil { + return err + } + d.Set("image_name", image.Name) + return nil } From 16ea14e8c914f15340d947f34658f40b023f1896 Mon Sep 17 00:00:00 2001 From: Joe Topjian Date: Wed, 11 Feb 2015 17:08:23 +0000 Subject: [PATCH 096/132] Grammar fix --- .../openstack/resource_openstack_compute_instance_v2.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builtin/providers/openstack/resource_openstack_compute_instance_v2.go b/builtin/providers/openstack/resource_openstack_compute_instance_v2.go index fbc7a7dd79..0025e7f8a4 100644 --- a/builtin/providers/openstack/resource_openstack_compute_instance_v2.go +++ b/builtin/providers/openstack/resource_openstack_compute_instance_v2.go @@ -781,5 +781,5 @@ func getFlavorID(client *gophercloud.ServiceClient, d *schema.ResourceData) (str return "", fmt.Errorf("Found %d flavors matching %s", flavorCount, flavorName) } } - return "", fmt.Errorf("Neither an flavor ID nor an flavor name were able to be determined.") + return "", fmt.Errorf("Neither a flavor ID nor a flavor name were able to be determined.") } From e5f2315bfeaab93680e96e824932cd9c346eb558 Mon Sep 17 00:00:00 2001 From: Joe Topjian Date: Tue, 10 Feb 2015 16:01:08 +0000 Subject: [PATCH 097/132] Instance volume attach This commit adds the ability for instances to attach volumes from within their resource. --- .../resource_openstack_compute_instance_v2.go | 186 ++++++++++++++++++ ...urce_openstack_compute_instance_v2_test.go | 69 +++++++ 2 files changed, 255 insertions(+) diff --git a/builtin/providers/openstack/resource_openstack_compute_instance_v2.go b/builtin/providers/openstack/resource_openstack_compute_instance_v2.go index 0025e7f8a4..1dc0a16160 100644 --- a/builtin/providers/openstack/resource_openstack_compute_instance_v2.go +++ b/builtin/providers/openstack/resource_openstack_compute_instance_v2.go @@ -1,6 +1,7 @@ package openstack import ( + "bytes" "fmt" "log" "time" @@ -13,6 +14,7 @@ import ( "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/bootfromvolume" "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/keypairs" "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/secgroups" + "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/volumeattach" "github.com/rackspace/gophercloud/openstack/compute/v2/flavors" "github.com/rackspace/gophercloud/openstack/compute/v2/images" "github.com/rackspace/gophercloud/openstack/compute/v2/servers" @@ -170,6 +172,30 @@ func resourceComputeInstanceV2() *schema.Resource { }, }, }, + "volume": &schema.Schema{ + Type: schema.TypeSet, + Optional: true, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "volume_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + }, + "device": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + }, + }, + Set: resourceComputeVolumeAttachmentHash, + }, }, } } @@ -268,6 +294,20 @@ func resourceComputeInstanceV2Create(d *schema.ResourceData, meta interface{}) e } } + // were volume attachments specified? + if v := d.Get("volume"); v != nil { + vols := v.(*schema.Set).List() + if len(vols) > 0 { + if blockClient, err := config.blockStorageV1Client(d.Get("region").(string)); err != nil { + return fmt.Errorf("Error creating OpenStack block storage client: %s", err) + } else { + if err := attachVolumesToInstance(computeClient, blockClient, d.Id(), vols); err != nil { + return err + } + } + } + } + return resourceComputeInstanceV2Read(d, meta) } @@ -367,6 +407,23 @@ func resourceComputeInstanceV2Read(d *schema.ResourceData, meta interface{}) err } d.Set("image_name", image.Name) + // volume attachments + vas, err := getVolumeAttachments(computeClient, d.Id()) + if err != nil { + return err + } + if len(vas) > 0 { + attachments := make([]map[string]interface{}, len(vas)) + for i, attachment := range vas { + attachments[i] = make(map[string]interface{}) + attachments[i]["id"] = attachment.ID + attachments[i]["volume_id"] = attachment.VolumeID + attachments[i]["device"] = attachment.Device + } + log.Printf("[INFO] Volume attachments: %v", attachments) + d.Set("volume", attachments) + } + return nil } @@ -464,6 +521,37 @@ func resourceComputeInstanceV2Update(d *schema.ResourceData, meta interface{}) e } } + if d.HasChange("volume") { + // old attachments and new attachments + oldAttachments, newAttachments := d.GetChange("volume") + + // for each old attachment, detach the volume + oldAttachmentSet := oldAttachments.(*schema.Set).List() + if len(oldAttachmentSet) > 0 { + if blockClient, err := config.blockStorageV1Client(d.Get("region").(string)); err != nil { + return err + } else { + if err := detachVolumesFromInstance(computeClient, blockClient, d.Id(), oldAttachmentSet); err != nil { + return err + } + } + } + + // for each new attachment, attach the volume + newAttachmentSet := newAttachments.(*schema.Set).List() + if len(newAttachmentSet) > 0 { + if blockClient, err := config.blockStorageV1Client(d.Get("region").(string)); err != nil { + return err + } else { + if err := attachVolumesToInstance(computeClient, blockClient, d.Id(), newAttachmentSet); err != nil { + return err + } + } + } + + d.SetPartial("volume") + } + if d.HasChange("flavor_ref") { resizeOpts := &servers.ResizeOpts{ FlavorRef: d.Get("flavor_ref").(string), @@ -783,3 +871,101 @@ func getFlavorID(client *gophercloud.ServiceClient, d *schema.ResourceData) (str } return "", fmt.Errorf("Neither a flavor ID nor a flavor name were able to be determined.") } + +func resourceComputeVolumeAttachmentHash(v interface{}) int { + var buf bytes.Buffer + m := v.(map[string]interface{}) + buf.WriteString(fmt.Sprintf("%s-", m["volume_id"].(string))) + buf.WriteString(fmt.Sprintf("%s-", m["device"].(string))) + return hashcode.String(buf.String()) +} + +func attachVolumesToInstance(computeClient *gophercloud.ServiceClient, blockClient *gophercloud.ServiceClient, serverId string, vols []interface{}) error { + if len(vols) > 0 { + for _, v := range vols { + va := v.(map[string]interface{}) + volumeId := va["volume_id"].(string) + device := va["device"].(string) + + s := "" + if serverId != "" { + s = serverId + } else if va["server_id"] != "" { + s = va["server_id"].(string) + } else { + return fmt.Errorf("Unable to determine server ID to attach volume.") + } + + vaOpts := &volumeattach.CreateOpts{ + Device: device, + VolumeID: volumeId, + } + + if _, err := volumeattach.Create(computeClient, s, vaOpts).Extract(); err != nil { + return err + } + + stateConf := &resource.StateChangeConf{ + Target: "in-use", + Refresh: VolumeV1StateRefreshFunc(blockClient, va["volume_id"].(string)), + Timeout: 30 * time.Minute, + Delay: 5 * time.Second, + MinTimeout: 2 * time.Second, + } + + if _, err := stateConf.WaitForState(); err != nil { + return err + } + + log.Printf("[INFO] Attached volume %s to instance %s", volumeId, serverId) + } + } + return nil +} + +func detachVolumesFromInstance(computeClient *gophercloud.ServiceClient, blockClient *gophercloud.ServiceClient, serverId string, vols []interface{}) error { + if len(vols) > 0 { + for _, v := range vols { + va := v.(map[string]interface{}) + aId := va["id"].(string) + + if err := volumeattach.Delete(computeClient, serverId, aId).ExtractErr(); err != nil { + return err + } + + stateConf := &resource.StateChangeConf{ + Target: "available", + Refresh: VolumeV1StateRefreshFunc(blockClient, va["volume_id"].(string)), + Timeout: 30 * time.Minute, + Delay: 5 * time.Second, + MinTimeout: 2 * time.Second, + } + + if _, err := stateConf.WaitForState(); err != nil { + return err + } + log.Printf("[INFO] Detached volume %s from instance %s", va["volume_id"], serverId) + } + } + + return nil +} + +func getVolumeAttachments(computeClient *gophercloud.ServiceClient, serverId string) ([]volumeattach.VolumeAttachment, error) { + var attachments []volumeattach.VolumeAttachment + err := volumeattach.List(computeClient, serverId).EachPage(func(page pagination.Page) (bool, error) { + actual, err := volumeattach.ExtractVolumeAttachments(page) + if err != nil { + return false, err + } + + attachments = actual + return true, nil + }) + + if err != nil { + return nil, err + } + + return attachments, nil +} diff --git a/builtin/providers/openstack/resource_openstack_compute_instance_v2_test.go b/builtin/providers/openstack/resource_openstack_compute_instance_v2_test.go index 77559fa3a9..f4c6c8557d 100644 --- a/builtin/providers/openstack/resource_openstack_compute_instance_v2_test.go +++ b/builtin/providers/openstack/resource_openstack_compute_instance_v2_test.go @@ -7,7 +7,10 @@ import ( "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/terraform" + "github.com/rackspace/gophercloud/openstack/blockstorage/v1/volumes" + "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/volumeattach" "github.com/rackspace/gophercloud/openstack/compute/v2/servers" + "github.com/rackspace/gophercloud/pagination" ) func TestAccComputeV2Instance_basic(t *testing.T) { @@ -29,6 +32,27 @@ func TestAccComputeV2Instance_basic(t *testing.T) { }) } +func TestAccComputeV2Instance_volumeAttach(t *testing.T) { + var instance servers.Server + var volume volumes.Volume + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckComputeV2InstanceDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccComputeV2Instance_volumeAttach, + Check: resource.ComposeTestCheckFunc( + testAccCheckBlockStorageV1VolumeExists(t, "openstack_blockstorage_volume_v1.myvol", &volume), + testAccCheckComputeV2InstanceExists(t, "openstack_compute_instance_v2.foo", &instance), + testAccCheckComputeV2InstanceVolumeAttachment(&instance, &volume), + ), + }, + }, + }) +} + func testAccCheckComputeV2InstanceDestroy(s *terraform.State) error { config := testAccProvider.Meta().(*Config) computeClient, err := config.computeV2Client(OS_REGION_NAME) @@ -105,6 +129,36 @@ func testAccCheckComputeV2InstanceMetadata( } } +func testAccCheckComputeV2InstanceVolumeAttachment( + instance *servers.Server, volume *volumes.Volume) resource.TestCheckFunc { + return func(s *terraform.State) error { + var attachments []volumeattach.VolumeAttachment + + config := testAccProvider.Meta().(*Config) + computeClient, err := config.computeV2Client(OS_REGION_NAME) + if err != nil { + return err + } + err = volumeattach.List(computeClient, instance.ID).EachPage(func(page pagination.Page) (bool, error) { + actual, err := volumeattach.ExtractVolumeAttachments(page) + if err != nil { + return false, fmt.Errorf("Unable to lookup attachment: %s", err) + } + + attachments = actual + return true, nil + }) + + for _, attachment := range attachments { + if attachment.VolumeID == volume.ID { + return nil + } + } + + return fmt.Errorf("Volume not found: %s", volume.ID) + } +} + var testAccComputeV2Instance_basic = fmt.Sprintf(` resource "openstack_compute_instance_v2" "foo" { region = "%s" @@ -114,3 +168,18 @@ var testAccComputeV2Instance_basic = fmt.Sprintf(` } }`, OS_REGION_NAME) + +var testAccComputeV2Instance_volumeAttach = fmt.Sprintf(` + resource "openstack_blockstorage_volume_v1" "myvol" { + name = "myvol" + size = 1 + } + + resource "openstack_compute_instance_v2" "foo" { + region = "%s" + name = "terraform-test" + volume { + volume_id = "${openstack_blockstorage_volume_v1.myvol.id}" + } + }`, + OS_REGION_NAME) From 2b152f38b2f72434e499306ce4c659e879f7a950 Mon Sep 17 00:00:00 2001 From: Joe Topjian Date: Thu, 12 Feb 2015 03:26:22 +0000 Subject: [PATCH 098/132] Doc update for instance volume attachment. --- .../openstack/r/compute_instance_v2.html.markdown | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/website/source/docs/providers/openstack/r/compute_instance_v2.html.markdown b/website/source/docs/providers/openstack/r/compute_instance_v2.html.markdown index ba03ee01c6..36805ed0d2 100644 --- a/website/source/docs/providers/openstack/r/compute_instance_v2.html.markdown +++ b/website/source/docs/providers/openstack/r/compute_instance_v2.html.markdown @@ -71,6 +71,9 @@ The following arguments are supported: * `block_device` - (Optional) The object for booting by volume. The block_device object structure is documented below. Changing this creates a new server. +* `volume` - (Optional) Attach an existing volume to the instance. The volume + structure is described below. + The `network` block supports: * `uuid` - (Required unless `port` is provided) The network UUID to attach to @@ -96,6 +99,14 @@ The `block_device` block supports: * `destination_type` - (Optional) The type that gets created. Possible values are "volume" and "local". +The `volume` block supports: + +* `volume_id` - (Required) The UUID of the volume to attach. + +* `device` - (Optional) The device that the volume will be attached as. For + example: `/dev/vdc`. Omit this option to allow the volume to be + auto-assigned a device. + ## Attributes Reference The following attributes are exported: From 49b01a4f0a219fab6109e77446cc7a2d29fb4960 Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Wed, 11 Feb 2015 21:56:26 -0700 Subject: [PATCH 099/132] update compute instance security group Read operation --- .../openstack/resource_openstack_compute_instance_v2.go | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/builtin/providers/openstack/resource_openstack_compute_instance_v2.go b/builtin/providers/openstack/resource_openstack_compute_instance_v2.go index 1dc0a16160..6406600ae6 100644 --- a/builtin/providers/openstack/resource_openstack_compute_instance_v2.go +++ b/builtin/providers/openstack/resource_openstack_compute_instance_v2.go @@ -175,7 +175,6 @@ func resourceComputeInstanceV2() *schema.Resource { "volume": &schema.Schema{ Type: schema.TypeSet, Optional: true, - Computed: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "id": &schema.Schema{ @@ -369,19 +368,18 @@ func resourceComputeInstanceV2Read(d *schema.ResourceData, meta interface{}) err d.Set("metadata", server.Metadata) - secGrpNum := 0 + secGrpNames := []string{} err = secgroups.ListByServer(computeClient, d.Id()).EachPage(func(page pagination.Page) (bool, error) { secGrpList, err := secgroups.ExtractSecurityGroups(page) if err != nil { return false, fmt.Errorf("Error getting security groups for OpenStack server: %s", err) } for _, sg := range secGrpList { - d.Set(fmt.Sprintf("security_groups.%d", secGrpNum), sg.Name) - secGrpNum++ + secGrpNames = append(secGrpNames, sg.Name) } return true, nil }) - d.Set("security_groups.#", secGrpNum) + d.Set("security_groups", secGrpNames) flavorId, ok := server.Flavor["id"].(string) if !ok { From bb6969a4c537bd5443ba71b245590d91549c2526 Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Wed, 11 Feb 2015 22:05:38 -0700 Subject: [PATCH 100/132] resize server on flavor_id or flavor_name change --- .../resource_openstack_compute_instance_v2.go | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/builtin/providers/openstack/resource_openstack_compute_instance_v2.go b/builtin/providers/openstack/resource_openstack_compute_instance_v2.go index 6406600ae6..6da455ad12 100644 --- a/builtin/providers/openstack/resource_openstack_compute_instance_v2.go +++ b/builtin/providers/openstack/resource_openstack_compute_instance_v2.go @@ -550,11 +550,15 @@ func resourceComputeInstanceV2Update(d *schema.ResourceData, meta interface{}) e d.SetPartial("volume") } - if d.HasChange("flavor_ref") { - resizeOpts := &servers.ResizeOpts{ - FlavorRef: d.Get("flavor_ref").(string), + if d.HasChange("flavor_id") || d.HasChange("flavor_name") { + flavorId, err := getFlavorID(computeClient, d) + if err != nil { + return err } - err := servers.Resize(computeClient, d.Id(), resizeOpts).ExtractErr() + resizeOpts := &servers.ResizeOpts{ + FlavorRef: flavorId, + } + err = servers.Resize(computeClient, d.Id(), resizeOpts).ExtractErr() if err != nil { return fmt.Errorf("Error resizing OpenStack server: %s", err) } From 64d53009a05af30a0a62123811e15686b7fbaddf Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Wed, 11 Feb 2015 22:29:31 -0700 Subject: [PATCH 101/132] typeset->typelist --- .../resource_openstack_compute_instance_v2.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/builtin/providers/openstack/resource_openstack_compute_instance_v2.go b/builtin/providers/openstack/resource_openstack_compute_instance_v2.go index 6da455ad12..ce6d7772fc 100644 --- a/builtin/providers/openstack/resource_openstack_compute_instance_v2.go +++ b/builtin/providers/openstack/resource_openstack_compute_instance_v2.go @@ -77,13 +77,10 @@ func resourceComputeInstanceV2() *schema.Resource { ForceNew: false, }, "security_groups": &schema.Schema{ - Type: schema.TypeSet, + Type: schema.TypeList, Optional: true, ForceNew: false, Elem: &schema.Schema{Type: schema.TypeString}, - Set: func(v interface{}) int { - return hashcode.String(v.(string)) - }, }, "availability_zone": &schema.Schema{ Type: schema.TypeString, @@ -374,6 +371,7 @@ func resourceComputeInstanceV2Read(d *schema.ResourceData, meta interface{}) err if err != nil { return false, fmt.Errorf("Error getting security groups for OpenStack server: %s", err) } + log.Printf("[DEBUG] secGrpList: %+v\n\n", secGrpList) for _, sg := range secGrpList { secGrpNames = append(secGrpNames, sg.Name) } @@ -466,7 +464,9 @@ func resourceComputeInstanceV2Update(d *schema.ResourceData, meta interface{}) e if d.HasChange("security_groups") { oldSGRaw, newSGRaw := d.GetChange("security_groups") - oldSGSet, newSGSet := oldSGRaw.(*schema.Set), newSGRaw.(*schema.Set) + oldSGSlice, newSGSlice := oldSGRaw.([]interface{}), newSGRaw.([]interface{}) + oldSGSet := schema.NewSet(func(v interface{}) int { return hashcode.String(v.(string)) }, oldSGSlice) + newSGSet := schema.NewSet(func(v interface{}) int { return hashcode.String(v.(string)) }, newSGSlice) secgroupsToAdd := newSGSet.Difference(oldSGSet) secgroupsToRemove := oldSGSet.Difference(newSGSet) @@ -661,9 +661,9 @@ func ServerV2StateRefreshFunc(client *gophercloud.ServiceClient, instanceID stri } func resourceInstanceSecGroupsV2(d *schema.ResourceData) []string { - rawSecGroups := d.Get("security_groups").(*schema.Set) - secgroups := make([]string, rawSecGroups.Len()) - for i, raw := range rawSecGroups.List() { + rawSecGroups := d.Get("security_groups").([]interface{}) + secgroups := make([]string, len(rawSecGroups)) + for i, raw := range rawSecGroups { secgroups[i] = raw.(string) } return secgroups From 4df32aebed07d3d222d90a5fdf6f9a12efe641ab Mon Sep 17 00:00:00 2001 From: Joe Topjian Date: Thu, 12 Feb 2015 20:58:12 +0000 Subject: [PATCH 102/132] Changing how security groups are read for compute instances --- .../resource_openstack_compute_instance_v2.go | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/builtin/providers/openstack/resource_openstack_compute_instance_v2.go b/builtin/providers/openstack/resource_openstack_compute_instance_v2.go index ce6d7772fc..9693fb8904 100644 --- a/builtin/providers/openstack/resource_openstack_compute_instance_v2.go +++ b/builtin/providers/openstack/resource_openstack_compute_instance_v2.go @@ -366,17 +366,9 @@ func resourceComputeInstanceV2Read(d *schema.ResourceData, meta interface{}) err d.Set("metadata", server.Metadata) secGrpNames := []string{} - err = secgroups.ListByServer(computeClient, d.Id()).EachPage(func(page pagination.Page) (bool, error) { - secGrpList, err := secgroups.ExtractSecurityGroups(page) - if err != nil { - return false, fmt.Errorf("Error getting security groups for OpenStack server: %s", err) - } - log.Printf("[DEBUG] secGrpList: %+v\n\n", secGrpList) - for _, sg := range secGrpList { - secGrpNames = append(secGrpNames, sg.Name) - } - return true, nil - }) + for _, sg := range server.SecurityGroups { + secGrpNames = append(secGrpNames, sg["name"].(string)) + } d.Set("security_groups", secGrpNames) flavorId, ok := server.Flavor["id"].(string) From 633e98dffe249a93e9592f46a1ca0b8a5f8a69ae Mon Sep 17 00:00:00 2001 From: Jon Perritt Date: Thu, 12 Feb 2015 17:25:45 -0700 Subject: [PATCH 103/132] security group rule fix; still not exporting rule ID --- .../resource_openstack_compute_instance_v2.go | 13 ++- .../resource_openstack_compute_secgroup_v2.go | 104 ++++++++++++------ builtin/providers/openstack/util.go | 6 +- 3 files changed, 87 insertions(+), 36 deletions(-) diff --git a/builtin/providers/openstack/resource_openstack_compute_instance_v2.go b/builtin/providers/openstack/resource_openstack_compute_instance_v2.go index 9693fb8904..5462d566bf 100644 --- a/builtin/providers/openstack/resource_openstack_compute_instance_v2.go +++ b/builtin/providers/openstack/resource_openstack_compute_instance_v2.go @@ -477,9 +477,18 @@ func resourceComputeInstanceV2Update(d *schema.ResourceData, meta interface{}) e for _, g := range secgroupsToRemove.List() { err := secgroups.RemoveServerFromGroup(computeClient, d.Id(), g.(string)).ExtractErr() if err != nil { - return fmt.Errorf("Error removing security group from OpenStack server (%s): %s", d.Id(), err) + errCode, ok := err.(*perigee.UnexpectedResponseCodeError) + if !ok { + return fmt.Errorf("Error removing security group from OpenStack server (%s): %s", d.Id(), err) + } + if errCode.Actual == 404 { + continue + } else { + return fmt.Errorf("Error removing security group from OpenStack server (%s): %s", d.Id(), err) + } + } else { + log.Printf("[DEBUG] Removed security group (%s) from instance (%s)", g.(string), d.Id()) } - log.Printf("[DEBUG] Removed security group (%s) from instance (%s)", g.(string), d.Id()) } } diff --git a/builtin/providers/openstack/resource_openstack_compute_secgroup_v2.go b/builtin/providers/openstack/resource_openstack_compute_secgroup_v2.go index cb61e7458c..948bfa80b2 100644 --- a/builtin/providers/openstack/resource_openstack_compute_secgroup_v2.go +++ b/builtin/providers/openstack/resource_openstack_compute_secgroup_v2.go @@ -7,6 +7,7 @@ import ( "github.com/hashicorp/terraform/helper/hashcode" "github.com/hashicorp/terraform/helper/schema" + "github.com/racker/perigee" "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/secgroups" ) @@ -35,38 +36,41 @@ func resourceComputeSecGroupV2() *schema.Resource { ForceNew: false, }, "rule": &schema.Schema{ - Type: schema.TypeSet, + Type: schema.TypeList, Optional: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, "from_port": &schema.Schema{ Type: schema.TypeInt, Required: true, - ForceNew: true, + ForceNew: false, }, "to_port": &schema.Schema{ Type: schema.TypeInt, Required: true, - ForceNew: true, + ForceNew: false, }, "ip_protocol": &schema.Schema{ Type: schema.TypeString, Required: true, - ForceNew: true, + ForceNew: false, }, "cidr": &schema.Schema{ Type: schema.TypeString, Optional: true, - ForceNew: true, + ForceNew: false, }, "from_group_id": &schema.Schema{ Type: schema.TypeString, Optional: true, - ForceNew: true, + ForceNew: false, }, }, }, - Set: resourceSecGroupRuleV2Hash, }, }, } @@ -117,7 +121,8 @@ func resourceComputeSecGroupV2Read(d *schema.ResourceData, meta interface{}) err d.Set("region", d.Get("region").(string)) d.Set("name", sg.Name) d.Set("description", sg.Description) - d.Set("rule", sg.Rules) + log.Printf("[DEBUG] rulesToMap(sg.Rules): %+v", rulesToMap(sg.Rules)) + d.Set("rules", rulesToMap(sg.Rules)) return nil } @@ -143,16 +148,18 @@ func resourceComputeSecGroupV2Update(d *schema.ResourceData, meta interface{}) e if d.HasChange("rule") { oldSGRaw, newSGRaw := d.GetChange("rule") - oldSGRSet, newSGRSet := oldSGRaw.(*schema.Set), newSGRaw.(*schema.Set) + oldSGRSlice, newSGRSlice := oldSGRaw.([]interface{}), newSGRaw.([]interface{}) + oldSGRSet := schema.NewSet(secgroupRuleV2Hash, oldSGRSlice) + newSGRSet := schema.NewSet(secgroupRuleV2Hash, newSGRSlice) secgrouprulesToAdd := newSGRSet.Difference(oldSGRSet) secgrouprulesToRemove := oldSGRSet.Difference(newSGRSet) log.Printf("[DEBUG] Security group rules to add: %v", secgrouprulesToAdd) - log.Printf("[DEBUG] Security groups to remove: %v", secgrouprulesToRemove) + log.Printf("[DEBUG] Security groups rules to remove: %v", secgrouprulesToRemove) for _, rawRule := range secgrouprulesToAdd.List() { - createRuleOpts := resourceSecGroupRuleV2(d, rawRule) + createRuleOpts := resourceSecGroupRuleCreateOptsV2(d, rawRule) rule, err := secgroups.CreateRule(computeClient, createRuleOpts).Extract() if err != nil { return fmt.Errorf("Error adding rule to OpenStack security group (%s): %s", d.Id(), err) @@ -161,12 +168,21 @@ func resourceComputeSecGroupV2Update(d *schema.ResourceData, meta interface{}) e } for _, r := range secgrouprulesToRemove.List() { - rule := r.(secgroups.Rule) - err := secgroups.DeleteRule(computeClient, "").ExtractErr() + rule := resourceSecGroupRuleV2(d, r) + err := secgroups.DeleteRule(computeClient, rule.ID).ExtractErr() if err != nil { - return fmt.Errorf("Error removing rule (%s) from OpenStack security group (%s): %s", rule.ID, d.Id(), err) + errCode, ok := err.(*perigee.UnexpectedResponseCodeError) + if !ok { + return fmt.Errorf("Error removing rule (%s) from OpenStack security group (%s): %s", rule.ID, d.Id(), err) + } + if errCode.Actual == 404 { + continue + } else { + return fmt.Errorf("Error removing rule (%s) from OpenStack security group (%s)", rule.ID, d.Id()) + } + } else { + log.Printf("[DEBUG] Removed rule (%s) from OpenStack security group (%s): %s", rule.ID, d.Id(), err) } - log.Printf("[DEBUG] Removed rule (%s) from OpenStack security group (%s)", rule.ID, d.Id()) } } @@ -188,22 +204,10 @@ func resourceComputeSecGroupV2Delete(d *schema.ResourceData, meta interface{}) e return nil } -func resourceSecGroupRuleV2Hash(v interface{}) int { - var buf bytes.Buffer - m := v.(map[string]interface{}) - buf.WriteString(fmt.Sprintf("%d-", m["from_port"].(int))) - buf.WriteString(fmt.Sprintf("%d-", m["to_port"].(int))) - buf.WriteString(fmt.Sprintf("%s-", m["ip_protocol"].(string))) - buf.WriteString(fmt.Sprintf("%s-", m["cidr"].(string))) - buf.WriteString(fmt.Sprintf("%s-", m["from_group_id"].(string))) - - return hashcode.String(buf.String()) -} - func resourceSecGroupRulesV2(d *schema.ResourceData) []secgroups.CreateRuleOpts { - rawRules := (d.Get("rule")).(*schema.Set) - createRuleOptsList := make([]secgroups.CreateRuleOpts, rawRules.Len()) - for i, raw := range rawRules.List() { + rawRules := (d.Get("rule")).([]interface{}) + createRuleOptsList := make([]secgroups.CreateRuleOpts, len(rawRules)) + for i, raw := range rawRules { rawMap := raw.(map[string]interface{}) createRuleOptsList[i] = secgroups.CreateRuleOpts{ ParentGroupID: d.Id(), @@ -217,7 +221,7 @@ func resourceSecGroupRulesV2(d *schema.ResourceData) []secgroups.CreateRuleOpts return createRuleOptsList } -func resourceSecGroupRuleV2(d *schema.ResourceData, raw interface{}) secgroups.CreateRuleOpts { +func resourceSecGroupRuleCreateOptsV2(d *schema.ResourceData, raw interface{}) secgroups.CreateRuleOpts { rawMap := raw.(map[string]interface{}) return secgroups.CreateRuleOpts{ ParentGroupID: d.Id(), @@ -228,3 +232,41 @@ func resourceSecGroupRuleV2(d *schema.ResourceData, raw interface{}) secgroups.C FromGroupID: rawMap["from_group_id"].(string), } } + +func resourceSecGroupRuleV2(d *schema.ResourceData, raw interface{}) secgroups.Rule { + rawMap := raw.(map[string]interface{}) + return secgroups.Rule{ + ID: rawMap["id"].(string), + ParentGroupID: d.Id(), + FromPort: rawMap["from_port"].(int), + ToPort: rawMap["to_port"].(int), + IPProtocol: rawMap["ip_protocol"].(string), + IPRange: secgroups.IPRange{CIDR: rawMap["cidr"].(string)}, + } +} + +func rulesToMap(sgrs []secgroups.Rule) []map[string]interface{} { + sgrMap := make([]map[string]interface{}, len(sgrs)) + for i, sgr := range sgrs { + sgrMap[i] = map[string]interface{}{ + "to_port": sgr.ToPort, + "from_port": sgr.FromPort, + "id": sgr.ID, + "ruleID": sgr.ID, + "cidr": sgr.IPRange.CIDR, + "ip_protocol": sgr.IPProtocol, + } + } + return sgrMap +} + +func secgroupRuleV2Hash(v interface{}) int { + var buf bytes.Buffer + m := v.(map[string]interface{}) + buf.WriteString(fmt.Sprintf("%d-", m["from_port"].(int))) + buf.WriteString(fmt.Sprintf("%d-", m["to_port"].(int))) + buf.WriteString(fmt.Sprintf("%s-", m["ip_protocol"].(string))) + buf.WriteString(fmt.Sprintf("%s-", m["cidr"].(string))) + + return hashcode.String(buf.String()) +} diff --git a/builtin/providers/openstack/util.go b/builtin/providers/openstack/util.go index 7ed9f8f5f3..c2a3851563 100644 --- a/builtin/providers/openstack/util.go +++ b/builtin/providers/openstack/util.go @@ -9,14 +9,14 @@ import ( // CheckDeleted checks the error to see if it's a 404 (Not Found) and, if so, // sets the resource ID to the empty string instead of throwing an error. -func CheckDeleted(d *schema.ResourceData, err error, resource string) error { +func CheckDeleted(d *schema.ResourceData, err error, msg string) error { errCode, ok := err.(*perigee.UnexpectedResponseCodeError) if !ok { - return fmt.Errorf("Error retrieving OpenStack %s: %s", resource, err) + return fmt.Errorf("%s: %s", msg, err) } if errCode.Actual == 404 { d.SetId("") return nil } - return fmt.Errorf("Error retrieving OpenStack %s: %s", resource, err) + return fmt.Errorf("%s: %s", msg, err) } From 4c9a44b69f292381a0b231828358d5c4ea7364a7 Mon Sep 17 00:00:00 2001 From: Joe Topjian Date: Tue, 10 Feb 2015 05:47:35 +0000 Subject: [PATCH 104/132] Added access_ip_v6 support This commit populates access_ip_v6 by either the AccessIPv6 attribute or by finding the first available IPv6 address. This commit retains the original feature of setting the default ssh connection to the IPv4 address unless one is not found. IPv6 access can still be enabled by explicitly setting it in the resource paramters. This commit also removes d.Set("host") in favor of SetConnInfo --- .../resource_openstack_compute_instance_v2.go | 64 +++++++++++++++---- 1 file changed, 50 insertions(+), 14 deletions(-) diff --git a/builtin/providers/openstack/resource_openstack_compute_instance_v2.go b/builtin/providers/openstack/resource_openstack_compute_instance_v2.go index 5462d566bf..f7d92b14fd 100644 --- a/builtin/providers/openstack/resource_openstack_compute_instance_v2.go +++ b/builtin/providers/openstack/resource_openstack_compute_instance_v2.go @@ -326,42 +326,78 @@ func resourceComputeInstanceV2Read(d *schema.ResourceData, meta interface{}) err d.Set("access_ip_v4", server.AccessIPv4) d.Set("access_ip_v6", server.AccessIPv6) - host := server.AccessIPv4 - if host == "" { + hostv4 := server.AccessIPv4 + if hostv4 == "" { if publicAddressesRaw, ok := server.Addresses["public"]; ok { publicAddresses := publicAddressesRaw.([]interface{}) for _, paRaw := range publicAddresses { pa := paRaw.(map[string]interface{}) if pa["version"].(float64) == 4 { - host = pa["addr"].(string) + hostv4 = pa["addr"].(string) break } } } } - // If no host found, just get the first IP we find - if host == "" { + // If no host found, just get the first IPv4 we find + if hostv4 == "" { for _, networkAddresses := range server.Addresses { for _, element := range networkAddresses.([]interface{}) { address := element.(map[string]interface{}) if address["version"].(float64) == 4 { - host = address["addr"].(string) + hostv4 = address["addr"].(string) break } } } } - d.Set("access_ip_v4", host) - d.Set("host", host) + d.Set("access_ip_v4", hostv4) + log.Printf("hostv4: %s", hostv4) - log.Printf("host: %s", host) + hostv6 := server.AccessIPv6 + if hostv6 == "" { + if publicAddressesRaw, ok := server.Addresses["public"]; ok { + publicAddresses := publicAddressesRaw.([]interface{}) + for _, paRaw := range publicAddresses { + pa := paRaw.(map[string]interface{}) + if pa["version"].(float64) == 4 { + hostv6 = fmt.Sprintf("[%s]", pa["addr"].(string)) + break + } + } + } + } - // Initialize the connection info - d.SetConnInfo(map[string]string{ - "type": "ssh", - "host": host, - }) + // If no hostv6 found, just get the first IPv6 we find + if hostv6 == "" { + for _, networkAddresses := range server.Addresses { + for _, element := range networkAddresses.([]interface{}) { + address := element.(map[string]interface{}) + if address["version"].(float64) == 6 { + hostv6 = fmt.Sprintf("[%s]", address["addr"].(string)) + break + } + } + } + } + d.Set("access_ip_v6", hostv6) + log.Printf("hostv6: %s", hostv6) + + preferredv := "" + if hostv4 != "" { + preferredv = hostv4 + } else if hostv6 != "" { + preferredv = hostv6 + } + + if preferredv != "" { + // Initialize the connection info + d.SetConnInfo(map[string]string{ + "type": "ssh", + "host": preferredv, + }) + } d.Set("metadata", server.Metadata) From 79e5c419c3b9ffac4b328966741afb9ce5af4195 Mon Sep 17 00:00:00 2001 From: Joe Topjian Date: Fri, 13 Feb 2015 05:26:35 +0000 Subject: [PATCH 105/132] Fixing rule/rules and re-arranged order for schema consistency --- .../openstack/resource_openstack_compute_secgroup_v2.go | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/builtin/providers/openstack/resource_openstack_compute_secgroup_v2.go b/builtin/providers/openstack/resource_openstack_compute_secgroup_v2.go index 948bfa80b2..f1ee715a29 100644 --- a/builtin/providers/openstack/resource_openstack_compute_secgroup_v2.go +++ b/builtin/providers/openstack/resource_openstack_compute_secgroup_v2.go @@ -122,7 +122,7 @@ func resourceComputeSecGroupV2Read(d *schema.ResourceData, meta interface{}) err d.Set("name", sg.Name) d.Set("description", sg.Description) log.Printf("[DEBUG] rulesToMap(sg.Rules): %+v", rulesToMap(sg.Rules)) - d.Set("rules", rulesToMap(sg.Rules)) + d.Set("rule", rulesToMap(sg.Rules)) return nil } @@ -249,12 +249,11 @@ func rulesToMap(sgrs []secgroups.Rule) []map[string]interface{} { sgrMap := make([]map[string]interface{}, len(sgrs)) for i, sgr := range sgrs { sgrMap[i] = map[string]interface{}{ - "to_port": sgr.ToPort, - "from_port": sgr.FromPort, "id": sgr.ID, - "ruleID": sgr.ID, - "cidr": sgr.IPRange.CIDR, + "from_port": sgr.FromPort, + "to_port": sgr.ToPort, "ip_protocol": sgr.IPProtocol, + "cidr": sgr.IPRange.CIDR, } } return sgrMap From 42fb14f19a85cc0a6b340498ccb889d52672306f Mon Sep 17 00:00:00 2001 From: Long Nguyen Date: Mon, 16 Feb 2015 16:04:08 -0500 Subject: [PATCH 106/132] Added self option to security groups --- .../resource_openstack_compute_secgroup_v2.go | 17 +++++++++++++++-- .../r/compute_secgroup_v2.html.markdown | 5 ++++- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/builtin/providers/openstack/resource_openstack_compute_secgroup_v2.go b/builtin/providers/openstack/resource_openstack_compute_secgroup_v2.go index f1ee715a29..013040db85 100644 --- a/builtin/providers/openstack/resource_openstack_compute_secgroup_v2.go +++ b/builtin/providers/openstack/resource_openstack_compute_secgroup_v2.go @@ -69,6 +69,11 @@ func resourceComputeSecGroupV2() *schema.Resource { Optional: true, ForceNew: false, }, + "self": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + ForceNew: false, + }, }, }, }, @@ -209,13 +214,17 @@ func resourceSecGroupRulesV2(d *schema.ResourceData) []secgroups.CreateRuleOpts createRuleOptsList := make([]secgroups.CreateRuleOpts, len(rawRules)) for i, raw := range rawRules { rawMap := raw.(map[string]interface{}) + groupId := rawMap["from_group_id"].(string) + if rawMap["self"].(bool) { + groupId = d.Id() + } createRuleOptsList[i] = secgroups.CreateRuleOpts{ ParentGroupID: d.Id(), FromPort: rawMap["from_port"].(int), ToPort: rawMap["to_port"].(int), IPProtocol: rawMap["ip_protocol"].(string), CIDR: rawMap["cidr"].(string), - FromGroupID: rawMap["from_group_id"].(string), + FromGroupID: groupId, } } return createRuleOptsList @@ -223,13 +232,17 @@ func resourceSecGroupRulesV2(d *schema.ResourceData) []secgroups.CreateRuleOpts func resourceSecGroupRuleCreateOptsV2(d *schema.ResourceData, raw interface{}) secgroups.CreateRuleOpts { rawMap := raw.(map[string]interface{}) + groupId := rawMap["from_group_id"].(string) + if rawMap["self"].(bool) { + groupId = d.Id() + } return secgroups.CreateRuleOpts{ ParentGroupID: d.Id(), FromPort: rawMap["from_port"].(int), ToPort: rawMap["to_port"].(int), IPProtocol: rawMap["ip_protocol"].(string), CIDR: rawMap["cidr"].(string), - FromGroupID: rawMap["from_group_id"].(string), + FromGroupID: groupId, } } diff --git a/website/source/docs/providers/openstack/r/compute_secgroup_v2.html.markdown b/website/source/docs/providers/openstack/r/compute_secgroup_v2.html.markdown index 50f3285021..5b9538793d 100644 --- a/website/source/docs/providers/openstack/r/compute_secgroup_v2.html.markdown +++ b/website/source/docs/providers/openstack/r/compute_secgroup_v2.html.markdown @@ -59,10 +59,13 @@ this creates a new security group rule. will be the source of network traffic to the security group. Use 0.0.0.0./0 to allow all IP addresses. Changing this creates a new security group rule. -* `from_group_id - (Optional) Required if `cidr` is empty. The ID of a group +* `from_group_id` - (Optional) Required if `cidr` is empty. The ID of a group from which to forward traffic to the parent group. Changing this creates a new security group rule. +* `self` - (Optional) Required if `cidr` and `from_group_id` is empty. If true, +the security group itself will be added as a source to this ingress rule. + ## Attributes Reference The following attributes are exported: From d03b420e623c4a9c4e8992c3f3d3ba5d573d2e9f Mon Sep 17 00:00:00 2001 From: Eric Bellemon Date: Tue, 17 Feb 2015 18:48:23 +0100 Subject: [PATCH 107/132] Replace perigee.UnexpectedResponseCodeError with gophercloud.UnexpectedResponseCodeError --- .../openstack/resource_openstack_blockstorage_volume_v1.go | 3 +-- .../openstack/resource_openstack_compute_instance_v2.go | 5 ++--- .../openstack/resource_openstack_compute_secgroup_v2.go | 4 ++-- .../resource_openstack_networking_router_interface_v2.go | 4 ++-- .../openstack/resource_openstack_networking_router_v2.go | 4 ++-- builtin/providers/openstack/util.go | 4 ++-- 6 files changed, 11 insertions(+), 13 deletions(-) diff --git a/builtin/providers/openstack/resource_openstack_blockstorage_volume_v1.go b/builtin/providers/openstack/resource_openstack_blockstorage_volume_v1.go index ab85317bb0..f38fea5fb7 100644 --- a/builtin/providers/openstack/resource_openstack_blockstorage_volume_v1.go +++ b/builtin/providers/openstack/resource_openstack_blockstorage_volume_v1.go @@ -7,7 +7,6 @@ import ( "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/schema" - "github.com/racker/perigee" "github.com/rackspace/gophercloud" "github.com/rackspace/gophercloud/openstack/blockstorage/v1/volumes" ) @@ -252,7 +251,7 @@ func VolumeV1StateRefreshFunc(client *gophercloud.ServiceClient, volumeID string return func() (interface{}, string, error) { v, err := volumes.Get(client, volumeID).Extract() if err != nil { - errCode, ok := err.(*perigee.UnexpectedResponseCodeError) + errCode, ok := err.(*gophercloud.UnexpectedResponseCodeError) if !ok { return nil, "", err } diff --git a/builtin/providers/openstack/resource_openstack_compute_instance_v2.go b/builtin/providers/openstack/resource_openstack_compute_instance_v2.go index f7d92b14fd..3488069312 100644 --- a/builtin/providers/openstack/resource_openstack_compute_instance_v2.go +++ b/builtin/providers/openstack/resource_openstack_compute_instance_v2.go @@ -9,7 +9,6 @@ import ( "github.com/hashicorp/terraform/helper/hashcode" "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/schema" - "github.com/racker/perigee" "github.com/rackspace/gophercloud" "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/bootfromvolume" "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/keypairs" @@ -513,7 +512,7 @@ func resourceComputeInstanceV2Update(d *schema.ResourceData, meta interface{}) e for _, g := range secgroupsToRemove.List() { err := secgroups.RemoveServerFromGroup(computeClient, d.Id(), g.(string)).ExtractErr() if err != nil { - errCode, ok := err.(*perigee.UnexpectedResponseCodeError) + errCode, ok := err.(*gophercloud.UnexpectedResponseCodeError) if !ok { return fmt.Errorf("Error removing security group from OpenStack server (%s): %s", d.Id(), err) } @@ -683,7 +682,7 @@ func ServerV2StateRefreshFunc(client *gophercloud.ServiceClient, instanceID stri return func() (interface{}, string, error) { s, err := servers.Get(client, instanceID).Extract() if err != nil { - errCode, ok := err.(*perigee.UnexpectedResponseCodeError) + errCode, ok := err.(*gophercloud.UnexpectedResponseCodeError) if !ok { return nil, "", err } diff --git a/builtin/providers/openstack/resource_openstack_compute_secgroup_v2.go b/builtin/providers/openstack/resource_openstack_compute_secgroup_v2.go index 013040db85..cf00f7f1b8 100644 --- a/builtin/providers/openstack/resource_openstack_compute_secgroup_v2.go +++ b/builtin/providers/openstack/resource_openstack_compute_secgroup_v2.go @@ -7,7 +7,7 @@ import ( "github.com/hashicorp/terraform/helper/hashcode" "github.com/hashicorp/terraform/helper/schema" - "github.com/racker/perigee" + "github.com/rackspace/gophercloud" "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/secgroups" ) @@ -176,7 +176,7 @@ func resourceComputeSecGroupV2Update(d *schema.ResourceData, meta interface{}) e rule := resourceSecGroupRuleV2(d, r) err := secgroups.DeleteRule(computeClient, rule.ID).ExtractErr() if err != nil { - errCode, ok := err.(*perigee.UnexpectedResponseCodeError) + errCode, ok := err.(*gophercloud.UnexpectedResponseCodeError) if !ok { return fmt.Errorf("Error removing rule (%s) from OpenStack security group (%s): %s", rule.ID, d.Id(), err) } diff --git a/builtin/providers/openstack/resource_openstack_networking_router_interface_v2.go b/builtin/providers/openstack/resource_openstack_networking_router_interface_v2.go index 2daaf787de..492c14d300 100644 --- a/builtin/providers/openstack/resource_openstack_networking_router_interface_v2.go +++ b/builtin/providers/openstack/resource_openstack_networking_router_interface_v2.go @@ -5,7 +5,7 @@ import ( "log" "github.com/hashicorp/terraform/helper/schema" - "github.com/racker/perigee" + "github.com/rackspace/gophercloud" "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/layer3/routers" "github.com/rackspace/gophercloud/openstack/networking/v2/ports" ) @@ -69,7 +69,7 @@ func resourceNetworkingRouterInterfaceV2Read(d *schema.ResourceData, meta interf n, err := ports.Get(networkingClient, d.Id()).Extract() if err != nil { - httpError, ok := err.(*perigee.UnexpectedResponseCodeError) + httpError, ok := err.(*gophercloud.UnexpectedResponseCodeError) if !ok { return fmt.Errorf("Error retrieving OpenStack Neutron Router Interface: %s", err) } diff --git a/builtin/providers/openstack/resource_openstack_networking_router_v2.go b/builtin/providers/openstack/resource_openstack_networking_router_v2.go index c4fe8e90ad..cb235a88be 100644 --- a/builtin/providers/openstack/resource_openstack_networking_router_v2.go +++ b/builtin/providers/openstack/resource_openstack_networking_router_v2.go @@ -6,7 +6,7 @@ import ( "strconv" "github.com/hashicorp/terraform/helper/schema" - "github.com/racker/perigee" + "github.com/rackspace/gophercloud" "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/layer3/routers" ) @@ -98,7 +98,7 @@ func resourceNetworkingRouterV2Read(d *schema.ResourceData, meta interface{}) er n, err := routers.Get(networkingClient, d.Id()).Extract() if err != nil { - httpError, ok := err.(*perigee.UnexpectedResponseCodeError) + httpError, ok := err.(*gophercloud.UnexpectedResponseCodeError) if !ok { return fmt.Errorf("Error retrieving OpenStack Neutron Router: %s", err) } diff --git a/builtin/providers/openstack/util.go b/builtin/providers/openstack/util.go index c2a3851563..93a8bfbc52 100644 --- a/builtin/providers/openstack/util.go +++ b/builtin/providers/openstack/util.go @@ -4,13 +4,13 @@ import ( "fmt" "github.com/hashicorp/terraform/helper/schema" - "github.com/racker/perigee" + "github.com/rackspace/gophercloud" ) // CheckDeleted checks the error to see if it's a 404 (Not Found) and, if so, // sets the resource ID to the empty string instead of throwing an error. func CheckDeleted(d *schema.ResourceData, err error, msg string) error { - errCode, ok := err.(*perigee.UnexpectedResponseCodeError) + errCode, ok := err.(*gophercloud.UnexpectedResponseCodeError) if !ok { return fmt.Errorf("%s: %s", msg, err) } From c3c4840bafc735a75d343ffaa87f5bb5d96eba40 Mon Sep 17 00:00:00 2001 From: Joe Topjian Date: Fri, 13 Feb 2015 20:59:41 +0000 Subject: [PATCH 108/132] openstack_compute_floatingip_v2 This commit adds a resource that allows the user to allocate, deallocate, associate, and disassociate floating IPs through the nova api. --- builtin/providers/openstack/provider.go | 1 + ...esource_openstack_compute_floatingip_v2.go | 121 ++++++++++++++++++ ...ce_openstack_compute_floatingip_v2_test.go | 86 +++++++++++++ 3 files changed, 208 insertions(+) create mode 100644 builtin/providers/openstack/resource_openstack_compute_floatingip_v2.go create mode 100644 builtin/providers/openstack/resource_openstack_compute_floatingip_v2_test.go diff --git a/builtin/providers/openstack/provider.go b/builtin/providers/openstack/provider.go index 450e1c7055..6a708a28ff 100644 --- a/builtin/providers/openstack/provider.go +++ b/builtin/providers/openstack/provider.go @@ -63,6 +63,7 @@ func Provider() terraform.ResourceProvider { "openstack_compute_instance_v2": resourceComputeInstanceV2(), "openstack_compute_keypair_v2": resourceComputeKeypairV2(), "openstack_compute_secgroup_v2": resourceComputeSecGroupV2(), + "openstack_compute_floatingip_v2": resourceComputeFloatingIPV2(), "openstack_lb_monitor_v1": resourceLBMonitorV1(), "openstack_lb_pool_v1": resourceLBPoolV1(), "openstack_lb_vip_v1": resourceLBVipV1(), diff --git a/builtin/providers/openstack/resource_openstack_compute_floatingip_v2.go b/builtin/providers/openstack/resource_openstack_compute_floatingip_v2.go new file mode 100644 index 0000000000..5a78483de9 --- /dev/null +++ b/builtin/providers/openstack/resource_openstack_compute_floatingip_v2.go @@ -0,0 +1,121 @@ +package openstack + +import ( + "fmt" + "log" + + "github.com/hashicorp/terraform/helper/schema" + "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/floatingip" +) + +func resourceComputeFloatingIPV2() *schema.Resource { + return &schema.Resource{ + Create: resourceComputeFloatingIPV2Create, + Read: resourceComputeFloatingIPV2Read, + Update: nil, + Delete: resourceComputeFloatingIPV2Delete, + + Schema: map[string]*schema.Schema{ + "region": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + DefaultFunc: envDefaultFunc("OS_REGION_NAME"), + }, + + "pool": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + DefaultFunc: envDefaultFunc("OS_POOL_NAME"), + }, + + // exported + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + + "address": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + + "fixed_ip": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + + "instance_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func resourceComputeFloatingIPV2Create(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + computeClient, err := config.computeV2Client(d.Get("region").(string)) + if err != nil { + return fmt.Errorf("Error creating OpenStack compute client: %s", err) + } + + createOpts := &floatingip.CreateOpts{ + Pool: d.Get("pool").(string), + } + newFip, err := floatingip.Create(computeClient, createOpts).Extract() + if err != nil { + return fmt.Errorf("Error creating Floating IP: %s", err) + } + + d.SetId(newFip.ID) + + return resourceComputeFloatingIPV2Read(d, meta) +} + +func resourceComputeFloatingIPV2Read(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + computeClient, err := config.computeV2Client(d.Get("region").(string)) + if err != nil { + return fmt.Errorf("Error creating OpenStack compute client: %s", err) + } + + fip, err := floatingip.Get(computeClient, d.Id()).Extract() + if err != nil { + return fmt.Errorf("Error getting Floating IP: %s", err) + } + + log.Printf("[DEBUG] Retrieved Floating IP %s: %+v", d.Id(), fip) + + d.Set("id", d.Id()) + d.Set("region", d.Get("region").(string)) + d.Set("pool", fip.Pool) + d.Set("instance_id", fip.InstanceID) + d.Set("address", fip.IP) + d.Set("fixed_ip", fip.FixedIP) + + return nil +} + +func resourceComputeFloatingIPV2Delete(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + computeClient, err := config.computeV2Client(d.Get("region").(string)) + if err != nil { + return fmt.Errorf("Error creating OpenStack compute client: %s", err) + } + + fip, err := floatingip.Get(computeClient, d.Id()).Extract() + if err != nil { + return fmt.Errorf("Error getting Floating IP for update: %s", err) + } + + log.Printf("[DEBUG] Deleting Floating IP %s", fip.IP) + + // Now do the actual deletion + if err := floatingip.Delete(computeClient, fip.ID).ExtractErr(); err != nil { + return fmt.Errorf("Error deleting Floating IP: %s", err) + } + + return nil +} diff --git a/builtin/providers/openstack/resource_openstack_compute_floatingip_v2_test.go b/builtin/providers/openstack/resource_openstack_compute_floatingip_v2_test.go new file mode 100644 index 0000000000..c246d1a510 --- /dev/null +++ b/builtin/providers/openstack/resource_openstack_compute_floatingip_v2_test.go @@ -0,0 +1,86 @@ +package openstack + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" + + "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/floatingip" +) + +func TestAccComputeV2FloatingIP_basic(t *testing.T) { + var floatingIP floatingip.FloatingIP + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckComputeV2FloatingIPDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccComputeV2FloatingIP_basic, + Check: resource.ComposeTestCheckFunc( + testAccCheckComputeV2FloatingIPExists(t, "openstack_compute_floatingip_v2.foo", &floatingIP), + ), + }, + }, + }) +} + +func testAccCheckComputeV2FloatingIPDestroy(s *terraform.State) error { + config := testAccProvider.Meta().(*Config) + computeClient, err := config.computeV2Client(OS_REGION_NAME) + if err != nil { + return fmt.Errorf("(testAccCheckComputeV2FloatingIPDestroy) Error creating OpenStack compute client: %s", err) + } + + for _, rs := range s.RootModule().Resources { + if rs.Type != "openstack_compute_floatingip_v2" { + continue + } + + _, err := floatingip.Get(computeClient, rs.Primary.ID).Extract() + if err == nil { + return fmt.Errorf("FloatingIP still exists") + } + } + + return nil +} + +func testAccCheckComputeV2FloatingIPExists(t *testing.T, n string, kp *floatingip.FloatingIP) 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 ID is set") + } + + config := testAccProvider.Meta().(*Config) + computeClient, err := config.computeV2Client(OS_REGION_NAME) + if err != nil { + return fmt.Errorf("(testAccCheckComputeV2FloatingIPExists) Error creating OpenStack compute client: %s", err) + } + + found, err := floatingip.Get(computeClient, rs.Primary.ID).Extract() + if err != nil { + return err + } + + if found.ID != rs.Primary.ID { + return fmt.Errorf("FloatingIP not found") + } + + *kp = *found + + return nil + } +} + +var testAccComputeV2FloatingIP_basic = fmt.Sprintf(` + resource "openstack_compute_floatingip_v2" "foo" { + }`) From b7091414fe7edf4cbfb725c14474bc5b96e4161b Mon Sep 17 00:00:00 2001 From: Joe Topjian Date: Thu, 19 Feb 2015 22:22:37 +0000 Subject: [PATCH 109/132] Volume Safe Delete This commit ensures that a volume is detached from all instances before it is deleted. It also adds in an `attachment` exported parameter that shows details of the volume's attachment(s). --- ...source_openstack_blockstorage_volume_v1.go | 81 +++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/builtin/providers/openstack/resource_openstack_blockstorage_volume_v1.go b/builtin/providers/openstack/resource_openstack_blockstorage_volume_v1.go index f38fea5fb7..eefd75f7ec 100644 --- a/builtin/providers/openstack/resource_openstack_blockstorage_volume_v1.go +++ b/builtin/providers/openstack/resource_openstack_blockstorage_volume_v1.go @@ -1,14 +1,17 @@ package openstack import ( + "bytes" "fmt" "log" "time" + "github.com/hashicorp/terraform/helper/hashcode" "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/schema" "github.com/rackspace/gophercloud" "github.com/rackspace/gophercloud/openstack/blockstorage/v1/volumes" + "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/volumeattach" ) func resourceBlockStorageVolumeV1() *schema.Resource { @@ -65,6 +68,27 @@ func resourceBlockStorageVolumeV1() *schema.Resource { Optional: true, ForceNew: true, }, + "attachment": &schema.Schema{ + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + "instance_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + "device": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + }, + }, + Set: resourceVolumeAttachmentHash, + }, }, } } @@ -175,6 +199,18 @@ func resourceBlockStorageVolumeV1Read(d *schema.ResourceData, meta interface{}) d.Set("metadata", "") } + if len(v.Attachments) > 0 { + attachments := make([]map[string]interface{}, len(v.Attachments)) + for i, attachment := range v.Attachments { + attachments[i] = make(map[string]interface{}) + attachments[i]["id"] = attachment["id"] + attachments[i]["instance_id"] = attachment["server_id"] + attachments[i]["device"] = attachment["device"] + log.Printf("[DEBUG] attachment: %v", attachment) + } + d.Set("attachment", attachments) + } + return nil } @@ -209,6 +245,42 @@ func resourceBlockStorageVolumeV1Delete(d *schema.ResourceData, meta interface{} return fmt.Errorf("Error creating OpenStack block storage client: %s", err) } + v, err := volumes.Get(blockStorageClient, d.Id()).Extract() + if err != nil { + return CheckDeleted(d, err, "volume") + } + + // make sure this volume is detached from all instances before deleting + if len(v.Attachments) > 0 { + log.Printf("[DEBUG] detaching volumes") + if computeClient, err := config.computeV2Client(d.Get("region").(string)); err != nil { + return err + } else { + for _, volumeAttachment := range v.Attachments { + log.Printf("[DEBUG] Attachment: %v", volumeAttachment) + if err := volumeattach.Delete(computeClient, volumeAttachment["server_id"].(string), volumeAttachment["id"].(string)).ExtractErr(); err != nil { + return err + } + } + + stateConf := &resource.StateChangeConf{ + Pending: []string{"in-use"}, + Target: "available", + Refresh: VolumeV1StateRefreshFunc(blockStorageClient, d.Id()), + Timeout: 10 * time.Minute, + Delay: 10 * time.Second, + MinTimeout: 3 * time.Second, + } + + _, err = stateConf.WaitForState() + if err != nil { + return fmt.Errorf( + "Error waiting for volume (%s) to become available: %s", + d.Id(), err) + } + } + } + err = volumes.Delete(blockStorageClient, d.Id()).ExtractErr() if err != nil { return fmt.Errorf("Error deleting OpenStack volume: %s", err) @@ -264,3 +336,12 @@ func VolumeV1StateRefreshFunc(client *gophercloud.ServiceClient, volumeID string return v, v.Status, nil } } + +func resourceVolumeAttachmentHash(v interface{}) int { + var buf bytes.Buffer + m := v.(map[string]interface{}) + if m["instance_id"] != nil { + buf.WriteString(fmt.Sprintf("%s-", m["instance_id"].(string))) + } + return hashcode.String(buf.String()) +} From 102848525f4e2a1b31200994b67c4ce409cc8b28 Mon Sep 17 00:00:00 2001 From: Joe Topjian Date: Fri, 20 Feb 2015 05:08:09 +0000 Subject: [PATCH 110/132] Added CheckDelete to handle bad Gets. Also removed unneeded Get from Delete. --- .../resource_openstack_compute_floatingip_v2.go | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/builtin/providers/openstack/resource_openstack_compute_floatingip_v2.go b/builtin/providers/openstack/resource_openstack_compute_floatingip_v2.go index 5a78483de9..3501fe2822 100644 --- a/builtin/providers/openstack/resource_openstack_compute_floatingip_v2.go +++ b/builtin/providers/openstack/resource_openstack_compute_floatingip_v2.go @@ -83,7 +83,7 @@ func resourceComputeFloatingIPV2Read(d *schema.ResourceData, meta interface{}) e fip, err := floatingip.Get(computeClient, d.Id()).Extract() if err != nil { - return fmt.Errorf("Error getting Floating IP: %s", err) + return CheckDeleted(d, err, "floating ip") } log.Printf("[DEBUG] Retrieved Floating IP %s: %+v", d.Id(), fip) @@ -105,15 +105,8 @@ func resourceComputeFloatingIPV2Delete(d *schema.ResourceData, meta interface{}) return fmt.Errorf("Error creating OpenStack compute client: %s", err) } - fip, err := floatingip.Get(computeClient, d.Id()).Extract() - if err != nil { - return fmt.Errorf("Error getting Floating IP for update: %s", err) - } - - log.Printf("[DEBUG] Deleting Floating IP %s", fip.IP) - - // Now do the actual deletion - if err := floatingip.Delete(computeClient, fip.ID).ExtractErr(); err != nil { + log.Printf("[DEBUG] Deleting Floating IP %s", d.Id()) + if err := floatingip.Delete(computeClient, d.Id()).ExtractErr(); err != nil { return fmt.Errorf("Error deleting Floating IP: %s", err) } From 552b0af2016e893919cfa572b20c12496dbea60a Mon Sep 17 00:00:00 2001 From: Guillaume Giamarchi Date: Mon, 2 Feb 2015 21:36:21 +0100 Subject: [PATCH 111/132] Add FWaaS rule resource --- .../resource_openstack_fw_rule_v2.go | 219 ++++++++++++++++++ 1 file changed, 219 insertions(+) create mode 100644 builtin/providers/openstack/resource_openstack_fw_rule_v2.go diff --git a/builtin/providers/openstack/resource_openstack_fw_rule_v2.go b/builtin/providers/openstack/resource_openstack_fw_rule_v2.go new file mode 100644 index 0000000000..97d8da5684 --- /dev/null +++ b/builtin/providers/openstack/resource_openstack_fw_rule_v2.go @@ -0,0 +1,219 @@ +package openstack + +import ( + "fmt" + "log" + + "github.com/hashicorp/terraform/helper/schema" + "github.com/racker/perigee" + "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/fwaas/rules" +) + +func resourceFWRuleV2() *schema.Resource { + return &schema.Resource{ + Create: resourceFirewallRuleCreate, + Read: resourceFirewallRuleRead, + Update: resourceFirewallRuleUpdate, + Delete: resourceFirewallRuleDelete, + + Schema: map[string]*schema.Schema{ + "region": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + DefaultFunc: envDefaultFunc("OS_REGION_NAME"), + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + }, + "protocol": &schema.Schema{ + Type: schema.TypeString, + Required: true, + }, + "action": &schema.Schema{ + Type: schema.TypeString, + Required: true, + }, + "ip_version": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + Default: 4, + }, + "source_ip_address": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + }, + "destination_ip_address": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + }, + "source_port": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + }, + "destination_port": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + }, + "enabled": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Default: true, + }, + }, + } +} + +func resourceFirewallRuleCreate(d *schema.ResourceData, meta interface{}) error { + + config := meta.(*Config) + networkingClient, err := config.networkingV2Client(d.Get("region").(string)) + if err != nil { + return fmt.Errorf("Error creating OpenStack networking client: %s", err) + } + + enabled := d.Get("enabled").(bool) + + ruleConfiguration := rules.CreateOpts{ + Name: d.Get("name").(string), + Description: d.Get("description").(string), + Protocol: d.Get("protocol").(string), + Action: d.Get("action").(string), + IPVersion: d.Get("ip_version").(int), + SourceIPAddress: d.Get("source_ip_address").(string), + DestinationIPAddress: d.Get("destination_ip_address").(string), + SourcePort: d.Get("source_port").(string), + DestinationPort: d.Get("destination_port").(string), + Enabled: &enabled, + } + + log.Printf("[DEBUG] Create firewall rule: %#v", ruleConfiguration) + + rule, err := rules.Create(networkingClient, ruleConfiguration).Extract() + + if err != nil { + return err + } + + log.Printf("[DEBUG] Firewall rule with id %s : %#v", rule.ID, rule) + + d.SetId(rule.ID) + + d.Set("name", rule.Name) + d.Set("description", rule.Description) + d.Set("protocol", rule.Protocol) + d.Set("action", rule.Action) + d.Set("ip_version", rule.IPVersion) + d.Set("source_ip_address", rule.SourceIPAddress) + d.Set("destination_ip_address", rule.DestinationIPAddress) + d.Set("source_port", rule.SourcePort) + d.Set("destination_port", rule.DestinationPort) + d.Set("enabled", rule.Enabled) + + return nil +} + +func resourceFirewallRuleRead(d *schema.ResourceData, meta interface{}) error { + log.Printf("[DEBUG] Retrieve information about firewall rule: %s", d.Id()) + + config := meta.(*Config) + networkingClient, err := config.networkingV2Client(d.Get("region").(string)) + if err != nil { + return fmt.Errorf("Error creating OpenStack networking client: %s", err) + } + + rule, err := rules.Get(networkingClient, d.Id()).Extract() + + if err != nil { + httpError, ok := err.(*perigee.UnexpectedResponseCodeError) + if !ok { + return err + } + if httpError.Actual == 404 { + d.SetId("") + return nil + } + return err + } + + d.Set("name", rule.Name) + d.Set("description", rule.Description) + d.Set("protocol", rule.Protocol) + d.Set("action", rule.Action) + d.Set("ip_version", rule.IPVersion) + d.Set("source_ip_address", rule.SourceIPAddress) + d.Set("destination_ip_address", rule.DestinationIPAddress) + d.Set("source_port", rule.SourcePort) + d.Set("destination_port", rule.DestinationPort) + d.Set("enabled", rule.Enabled) + + return nil +} + +func resourceFirewallRuleUpdate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + networkingClient, err := config.networkingV2Client(d.Get("region").(string)) + if err != nil { + return fmt.Errorf("Error creating OpenStack networking client: %s", err) + } + + opts := rules.UpdateOpts{} + + if d.HasChange("name") { + name := d.Get("name").(string) + opts.Name = &name + } + if d.HasChange("description") { + description := d.Get("description").(string) + opts.Description = &description + } + if d.HasChange("protocol") { + opts.Protocol = d.Get("protocol").(string) + } + if d.HasChange("action") { + opts.Action = d.Get("action").(string) + } + if d.HasChange("ip_version") { + opts.IPVersion = d.Get("ip_version").(int) + } + if d.HasChange("source_ip_address") { + sourceIPAddress := d.Get("source_ip_address").(string) + opts.SourceIPAddress = &sourceIPAddress + } + if d.HasChange("destination_ip_address") { + destinationIPAddress := d.Get("destination_ip_address").(string) + opts.DestinationIPAddress = &destinationIPAddress + } + if d.HasChange("source_port") { + sourcePort := d.Get("source_port").(string) + opts.SourcePort = &sourcePort + } + if d.HasChange("destination_port") { + destinationPort := d.Get("destination_port").(string) + opts.DestinationPort = &destinationPort + } + if d.HasChange("enabled") { + enabled := d.Get("enabled").(bool) + opts.Enabled = &enabled + } + + log.Printf("[DEBUG] Updating firewall rules: %#v", opts) + + return rules.Update(networkingClient, d.Id(), opts).Err +} + +func resourceFirewallRuleDelete(d *schema.ResourceData, meta interface{}) error { + log.Printf("[DEBUG] Destroy firewall rule: %s", d.Id()) + + config := meta.(*Config) + networkingClient, err := config.networkingV2Client(d.Get("region").(string)) + if err != nil { + return fmt.Errorf("Error creating OpenStack networking client: %s", err) + } + return rules.Delete(networkingClient, d.Id()).Err +} From f829427151c432acc5aebf66a03264d0b169044b Mon Sep 17 00:00:00 2001 From: Guillaume Giamarchi Date: Tue, 3 Feb 2015 20:56:13 +0100 Subject: [PATCH 112/132] Add FWaaS policy resource --- .../resource_openstack_fw_policy_v2.go | 196 ++++++++++++++++++ 1 file changed, 196 insertions(+) create mode 100644 builtin/providers/openstack/resource_openstack_fw_policy_v2.go diff --git a/builtin/providers/openstack/resource_openstack_fw_policy_v2.go b/builtin/providers/openstack/resource_openstack_fw_policy_v2.go new file mode 100644 index 0000000000..8f7b593d86 --- /dev/null +++ b/builtin/providers/openstack/resource_openstack_fw_policy_v2.go @@ -0,0 +1,196 @@ +package openstack + +import ( + "fmt" + "log" + "time" + + "github.com/hashicorp/terraform/helper/hashcode" + "github.com/hashicorp/terraform/helper/schema" + "github.com/racker/perigee" + "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/fwaas/policies" +) + +func resourceFWPolicyV2() *schema.Resource { + return &schema.Resource{ + Create: resourceFirewallPolicyCreate, + Read: resourceFirewallPolicyRead, + Update: resourceFirewallPolicyUpdate, + Delete: resourceFirewallPolicyDelete, + + Schema: map[string]*schema.Schema{ + "region": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + DefaultFunc: envDefaultFunc("OS_REGION_NAME"), + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + }, + "audited": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + "shared": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + "rules": &schema.Schema{ + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: func(v interface{}) int { + return hashcode.String(v.(string)) + }, + }, + }, + } +} + +func resourceFirewallPolicyCreate(d *schema.ResourceData, meta interface{}) error { + + // TODO To remove + time.Sleep(time.Second * 5) + + config := meta.(*Config) + networkingClient, err := config.networkingV2Client(d.Get("region").(string)) + if err != nil { + return fmt.Errorf("Error creating OpenStack networking client: %s", err) + } + + v := d.Get("rules").(*schema.Set) + + log.Printf("[DEBUG] Rules found : %#v", v) + log.Printf("[DEBUG] Rules count : %d", v.Len()) + + rules := make([]string, v.Len()) + for i, v := range v.List() { + rules[i] = v.(string) + } + + opts := policies.CreateOpts{ + Name: d.Get("name").(string), + Description: d.Get("description").(string), + // Audited: d.Get("audited").(bool), + // Shared: d.Get("shared").(bool), + Rules: rules, + } + + log.Printf("[DEBUG] Create firewall policy: %#v", opts) + + policy, err := policies.Create(networkingClient, opts).Extract() + if err != nil { + return err + } + + log.Printf("[DEBUG] Firewall policy craeted: %#v", policy) + + d.SetId(policy.ID) + + return nil +} + +func resourceFirewallPolicyRead(d *schema.ResourceData, meta interface{}) error { + log.Printf("[DEBUG] Retrieve information about firewall policy: %s", d.Id()) + + config := meta.(*Config) + networkingClient, err := config.networkingV2Client(d.Get("region").(string)) + if err != nil { + return fmt.Errorf("Error creating OpenStack networking client: %s", err) + } + + policy, err := policies.Get(networkingClient, d.Id()).Extract() + + if err != nil { + httpError, ok := err.(*perigee.UnexpectedResponseCodeError) + if !ok { + return err + } + if httpError.Actual == 404 { + d.SetId("") + return nil + } + return err + } + + d.Set("name", policy.Name) + + return nil +} + +func resourceFirewallPolicyUpdate(d *schema.ResourceData, meta interface{}) error { + + config := meta.(*Config) + networkingClient, err := config.networkingV2Client(d.Get("region").(string)) + if err != nil { + return fmt.Errorf("Error creating OpenStack networking client: %s", err) + } + + opts := policies.UpdateOpts{} + + if d.HasChange("name") { + name := d.Get("name").(string) + opts.Name = &name + } + + if d.HasChange("description") { + description := d.Get("description").(string) + opts.Description = &description + } + + if d.HasChange("rules") { + v := d.Get("rules").(*schema.Set) + + log.Printf("[DEBUG] Rules found : %#v", v) + log.Printf("[DEBUG] Rules count : %d", v.Len()) + + rules := make([]string, v.Len()) + for i, v := range v.List() { + rules[i] = v.(string) + } + opts.Rules = rules + } + + log.Printf("[DEBUG] Updating firewall policy with id %s: %#v", d.Id(), opts) + + return policies.Update(networkingClient, d.Id(), opts).Err +} + +func resourceFirewallPolicyDelete(d *schema.ResourceData, meta interface{}) error { + log.Printf("[DEBUG] Destroy firewall policy: %s", d.Id()) + + config := meta.(*Config) + networkingClient, err := config.networkingV2Client(d.Get("region").(string)) + if err != nil { + return fmt.Errorf("Error creating OpenStack networking client: %s", err) + } + + for i := 0; i < 15; i++ { + + err = policies.Delete(networkingClient, d.Id()).Err + if err == nil { + break + } + + httpError, ok := err.(*perigee.UnexpectedResponseCodeError) + if !ok || httpError.Actual != 409 { + return err + } + + // This error usualy means that the policy is attached + // to a firewall. At this point, the firewall is probably + // being delete. So, we retry a few times. + + time.Sleep(time.Second * 2) + } + + return err +} From 5d42242d4b541b9abd9b332e5a318abd23ec414c Mon Sep 17 00:00:00 2001 From: Guillaume Giamarchi Date: Tue, 3 Feb 2015 22:14:56 +0100 Subject: [PATCH 113/132] Add FWaaS firewall resource --- .../resource_openstack_fw_firewall_v2.go | 236 ++++++++++++++++++ 1 file changed, 236 insertions(+) create mode 100644 builtin/providers/openstack/resource_openstack_fw_firewall_v2.go diff --git a/builtin/providers/openstack/resource_openstack_fw_firewall_v2.go b/builtin/providers/openstack/resource_openstack_fw_firewall_v2.go new file mode 100644 index 0000000000..e2125e7fb0 --- /dev/null +++ b/builtin/providers/openstack/resource_openstack_fw_firewall_v2.go @@ -0,0 +1,236 @@ +package openstack + +import ( + "errors" + "fmt" + "log" + "time" + + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/helper/schema" + "github.com/racker/perigee" + "github.com/rackspace/gophercloud" + "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/fwaas/firewalls" +) + +func resourceFWFirewallV2() *schema.Resource { + return &schema.Resource{ + Create: resourceFirewallCreate, + Read: resourceFirewallRead, + Update: resourceFirewallUpdate, + Delete: resourceFirewallDelete, + + Schema: map[string]*schema.Schema{ + "region": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + DefaultFunc: envDefaultFunc("OS_REGION_NAME"), + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + }, + "description": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + }, + "policy_id": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "admin_state_up": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Default: true, + }, + }, + } +} + +func resourceFirewallCreate(d *schema.ResourceData, meta interface{}) error { + + config := meta.(*Config) + networkingClient, err := config.networkingV2Client(d.Get("region").(string)) + if err != nil { + return fmt.Errorf("Error creating OpenStack networking client: %s", err) + } + + adminStateUp := d.Get("admin_state_up").(bool) + + firewallConfiguration := firewalls.CreateOpts{ + Name: d.Get("name").(string), + Description: d.Get("description").(string), + PolicyID: d.Get("policy_id").(string), + AdminStateUp: &adminStateUp, + } + + log.Printf("[DEBUG] Create firewall: %#v", firewallConfiguration) + + firewall, err := firewalls.Create(networkingClient, firewallConfiguration).Extract() + if err != nil { + return err + } + + log.Printf("[DEBUG] Firewall created: %#v", firewall) + + stateConf := &resource.StateChangeConf{ + Pending: []string{"PENDING_CREATE"}, + Target: "ACTIVE", + Refresh: WaitForFirewallActive(networkingClient, firewall.ID), + Timeout: 30 * time.Second, + Delay: 0, + MinTimeout: 2 * time.Second, + } + + d.SetId(firewall.ID) + + d.Set("name", firewall.Name) + d.Set("description", firewall.Description) + d.Set("policy_id", firewall.PolicyID) + d.Set("admin_state_up", firewall.AdminStateUp) + + _, err = stateConf.WaitForState() + + return nil +} + +func resourceFirewallRead(d *schema.ResourceData, meta interface{}) error { + log.Printf("[DEBUG] Retrieve information about firewall: %s", d.Id()) + + config := meta.(*Config) + networkingClient, err := config.networkingV2Client(d.Get("region").(string)) + if err != nil { + return fmt.Errorf("Error creating OpenStack networking client: %s", err) + } + + firewall, err := firewalls.Get(networkingClient, d.Id()).Extract() + if err != nil { + httpError, ok := err.(*perigee.UnexpectedResponseCodeError) + if !ok { + return err + } + + if httpError.Actual == 404 { + d.SetId("") + return nil + } + return err + } + + d.Set("name", firewall.Name) + d.Set("description", firewall.Description) + d.Set("policy_id", firewall.PolicyID) + d.Set("admin_state_up", firewall.AdminStateUp) + + return nil +} + +func resourceFirewallUpdate(d *schema.ResourceData, meta interface{}) error { + + config := meta.(*Config) + networkingClient, err := config.networkingV2Client(d.Get("region").(string)) + if err != nil { + return fmt.Errorf("Error creating OpenStack networking client: %s", err) + } + + opts := firewalls.UpdateOpts{} + + if d.HasChange("name") { + name := d.Get("name").(string) + opts.Name = &name + } + + if d.HasChange("description") { + description := d.Get("description").(string) + opts.Description = &description + } + + if d.HasChange("policy_id") { + opts.PolicyID = d.Get("policy_id").(string) + } + + log.Printf("[DEBUG] Updating firewall with id %s: %#v", d.Id(), opts) + + if err := firewalls.Update(networkingClient, d.Id(), opts).Err; err != nil { + return err + } + + stateConf := &resource.StateChangeConf{ + Pending: []string{"PENDING_CREATE"}, + Target: "ACTIVE", + Refresh: WaitForFirewallActive(networkingClient, d.Id()), + Timeout: 30 * time.Second, + Delay: 0, + MinTimeout: 2 * time.Second, + } + + _, err = stateConf.WaitForState() + + return err +} + +func resourceFirewallDelete(d *schema.ResourceData, meta interface{}) error { + log.Printf("[DEBUG] Destroy firewall: %s", d.Id()) + + config := meta.(*Config) + networkingClient, err := config.networkingV2Client(d.Get("region").(string)) + if err != nil { + return fmt.Errorf("Error creating OpenStack networking client: %s", err) + } + + err = firewalls.Delete(networkingClient, d.Id()).Err + + if err != nil { + return err + } + + stateConf := &resource.StateChangeConf{ + Pending: []string{"DELETING"}, + Target: "DELETED", + Refresh: WaitForFirewallDeletion(networkingClient, d.Id()), + Timeout: 2 * time.Minute, + Delay: 0, + MinTimeout: 2 * time.Second, + } + + _, err = stateConf.WaitForState() + + return err +} + +func WaitForFirewallActive(networkingClient *gophercloud.ServiceClient, id string) resource.StateRefreshFunc { + + return func() (interface{}, string, error) { + fw, err := firewalls.Get(networkingClient, id).Extract() + log.Printf("[DEBUG] Get firewall %s => %#v", id, fw) + + if err != nil { + return nil, "", err + } + return fw, fw.Status, nil + } +} + +func WaitForFirewallDeletion(networkingClient *gophercloud.ServiceClient, id string) resource.StateRefreshFunc { + + return func() (interface{}, string, error) { + fw, err := firewalls.Get(networkingClient, id).Extract() + log.Printf("[DEBUG] Get firewall %s => %#v", id, fw) + + if err != nil { + httpStatus := err.(*perigee.UnexpectedResponseCodeError) + log.Printf("[DEBUG] Get firewall %s status is %d", id, httpStatus.Actual) + + if httpStatus.Actual == 404 { + log.Printf("[DEBUG] Firewall %s is actually deleted", id) + return "", "DELETED", nil + } + return nil, "", errors.New(fmt.Sprintf("Unexpected status code %d", httpStatus.Actual)) + } + + log.Printf("[DEBUG] Firewall %s deletion is pending", id) + return fw, "DELETING", nil + } +} From 3d1001d8fe8864c2b79b83447c2a05fcf4b87e03 Mon Sep 17 00:00:00 2001 From: Guillaume Giamarchi Date: Thu, 5 Feb 2015 13:49:23 +0100 Subject: [PATCH 114/132] Add FWaaS rule acceptance test --- .../resource_openstack_fw_rule_v2_test.go | 182 ++++++++++++++++++ 1 file changed, 182 insertions(+) create mode 100644 builtin/providers/openstack/resource_openstack_fw_rule_v2_test.go diff --git a/builtin/providers/openstack/resource_openstack_fw_rule_v2_test.go b/builtin/providers/openstack/resource_openstack_fw_rule_v2_test.go new file mode 100644 index 0000000000..86e731b447 --- /dev/null +++ b/builtin/providers/openstack/resource_openstack_fw_rule_v2_test.go @@ -0,0 +1,182 @@ +package openstack + +import ( + "fmt" + "reflect" + "testing" + "time" + + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" + "github.com/racker/perigee" + "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/fwaas/rules" +) + +func TestAccOpenstackFirewallRule(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckOpenstackFirewallRuleDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testFirewallRuleMinimalConfig, + Check: resource.ComposeTestCheckFunc( + testAccCheckFirewallRuleExists( + "openstack_fw_rule_v2.accept_test_minimal", + &rules.Rule{ + Protocol: "udp", + Action: "deny", + IPVersion: 4, + Enabled: true, + }), + ), + }, + resource.TestStep{ + Config: testFirewallRuleConfig, + Check: resource.ComposeTestCheckFunc( + testAccCheckFirewallRuleExists( + "openstack_fw_rule_v2.accept_test", + &rules.Rule{ + Name: "accept_test", + Protocol: "udp", + Action: "deny", + Description: "Terraform accept test", + IPVersion: 4, + SourceIPAddress: "1.2.3.4", + DestinationIPAddress: "4.3.2.0/24", + SourcePort: "444", + DestinationPort: "555", + Enabled: true, + }), + ), + }, + resource.TestStep{ + Config: testFirewallRuleUpdateAllFieldsConfig, + Check: resource.ComposeTestCheckFunc( + testAccCheckFirewallRuleExists( + "openstack_fw_rule_v2.accept_test", + &rules.Rule{ + Name: "accept_test_updated_2", + Protocol: "tcp", + Action: "allow", + Description: "Terraform accept test updated", + IPVersion: 4, + SourceIPAddress: "1.2.3.0/24", + DestinationIPAddress: "4.3.2.8", + SourcePort: "666", + DestinationPort: "777", + Enabled: false, + }), + ), + }, + }, + }) +} + +func testAccCheckOpenstackFirewallRuleDestroy(s *terraform.State) error { + + config := testAccProvider.Meta().(*Config) + networkingClient, err := config.networkingV2Client(OS_REGION_NAME) + if err != nil { + return fmt.Errorf("(testAccCheckOpenstackFirewallRuleDestroy) Error creating OpenStack networking client: %s", err) + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "openstack_firewall_rule" { + continue + } + _, err = rules.Get(networkingClient, rs.Primary.ID).Extract() + if err == nil { + return fmt.Errorf("Firewall rule (%s) still exists.", rs.Primary.ID) + } + httpError, ok := err.(*perigee.UnexpectedResponseCodeError) + if !ok || httpError.Actual != 404 { + return httpError + } + } + return nil +} + +func testAccCheckFirewallRuleExists(n string, expected *rules.Rule) 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 ID is set") + } + + config := testAccProvider.Meta().(*Config) + networkingClient, err := config.networkingV2Client(OS_REGION_NAME) + if err != nil { + return fmt.Errorf("(testAccCheckFirewallRuleExists) Error creating OpenStack networking client: %s", err) + } + + var found *rules.Rule + for i := 0; i < 5; i++ { + // Firewall rule creation is asynchronous. Retry some times + // if we get a 404 error. Fail on any other error. + found, err = rules.Get(networkingClient, rs.Primary.ID).Extract() + if err != nil { + httpError, ok := err.(*perigee.UnexpectedResponseCodeError) + if !ok || httpError.Actual != 404 { + time.Sleep(time.Second) + continue + } + } + break + } + + if err != nil { + return err + } + + expected.ID = found.ID + + if !reflect.DeepEqual(expected, found) { + return fmt.Errorf("Expected:\n%#v\nFound:\n%#v", expected, found) + } + + return nil + } +} + +const testFirewallRuleMinimalConfig = ` +resource "openstack_fw_rule_v2" "accept_test_minimal" { + protocol = "udp" + action = "deny" +} +` + +const testFirewallRuleConfig = ` +resource "openstack_fw_rule_v2" "accept_test" { + name = "accept_test" + description = "Terraform accept test" + protocol = "udp" + action = "deny" + ip_version = 4 + source_ip_address = "1.2.3.4" + destination_ip_address = "4.3.2.0/24" + source_port = "444" + destination_port = "555" + enabled = true +} +` + +const testFirewallRuleUpdateAllFieldsConfig = ` +resource "openstack_fw_rule_v2" "accept_test" { + name = "accept_test_updated_2" + description = "Terraform accept test updated" + protocol = "tcp" + action = "allow" + ip_version = 4 + source_ip_address = "1.2.3.0/24" + destination_ip_address = "4.3.2.8" + source_port = "666" + destination_port = "777" + enabled = false +} +` From 88a55a5d58c2c6317d0e21de7c25ee481afe5102 Mon Sep 17 00:00:00 2001 From: Guillaume Giamarchi Date: Mon, 9 Feb 2015 22:44:27 +0100 Subject: [PATCH 115/132] Enable FWaaS resources --- builtin/providers/openstack/provider.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/builtin/providers/openstack/provider.go b/builtin/providers/openstack/provider.go index 6a708a28ff..7e0880007b 100644 --- a/builtin/providers/openstack/provider.go +++ b/builtin/providers/openstack/provider.go @@ -64,6 +64,9 @@ func Provider() terraform.ResourceProvider { "openstack_compute_keypair_v2": resourceComputeKeypairV2(), "openstack_compute_secgroup_v2": resourceComputeSecGroupV2(), "openstack_compute_floatingip_v2": resourceComputeFloatingIPV2(), + "openstack_fw_firewall_v2": resourceFWFirewallV2(), + "openstack_fw_policy_v2": resourceFWPolicyV2(), + "openstack_fw_rule_v2": resourceFWRuleV2(), "openstack_lb_monitor_v1": resourceLBMonitorV1(), "openstack_lb_pool_v1": resourceLBPoolV1(), "openstack_lb_vip_v1": resourceLBVipV1(), From 06826fb67742f2635cb9bdec15fbb4ec6763fbb5 Mon Sep 17 00:00:00 2001 From: Guillaume Giamarchi Date: Mon, 9 Feb 2015 22:53:09 +0100 Subject: [PATCH 116/132] Add FWaaS policy acceptance test --- .../resource_openstack_fw_policy_v2_test.go | 175 ++++++++++++++++++ 1 file changed, 175 insertions(+) create mode 100644 builtin/providers/openstack/resource_openstack_fw_policy_v2_test.go diff --git a/builtin/providers/openstack/resource_openstack_fw_policy_v2_test.go b/builtin/providers/openstack/resource_openstack_fw_policy_v2_test.go new file mode 100644 index 0000000000..8a3f19ef57 --- /dev/null +++ b/builtin/providers/openstack/resource_openstack_fw_policy_v2_test.go @@ -0,0 +1,175 @@ +package openstack + +import ( + "fmt" + "reflect" + "testing" + "time" + + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" + "github.com/racker/perigee" + "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/fwaas/policies" +) + +func TestAccOpenstackFirewallPolicy(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckOpenstackFirewallPolicyDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testFirewallPolicyConfig, + Check: resource.ComposeTestCheckFunc( + testAccCheckFirewallPolicyExists( + "openstack_fw_policy_v2.accept_test", + &policies.Policy{ + Rules: []string{}, + }), + ), + }, + resource.TestStep{ + Config: testFirewallPolicyConfigAddRules, + Check: resource.ComposeTestCheckFunc( + testAccCheckFirewallPolicyExists( + "openstack_fw_policy_v2.accept_test", + &policies.Policy{ + Name: "accept_test", + Description: "terraform acceptance test", + Rules: []string{ + "", + "", + }, + }), + ), + }, + resource.TestStep{ + Config: testFirewallPolicyUpdateDeleteRule, + Check: resource.ComposeTestCheckFunc( + testAccCheckFirewallPolicyExists( + "openstack_fw_policy_v2.accept_test", + &policies.Policy{}), + ), + }, + }, + }) +} + +func testAccCheckOpenstackFirewallPolicyDestroy(s *terraform.State) error { + + config := testAccProvider.Meta().(*Config) + networkingClient, err := config.networkingV2Client(OS_REGION_NAME) + if err != nil { + return fmt.Errorf("(testAccCheckOpenstackFirewallPolicyDestroy) Error creating OpenStack networking client: %s", err) + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "openstack_fw_policy_v2" { + continue + } + _, err = policies.Get(networkingClient, rs.Primary.ID).Extract() + if err == nil { + return fmt.Errorf("Firewall policy (%s) still exists.", rs.Primary.ID) + } + httpError, ok := err.(*perigee.UnexpectedResponseCodeError) + if !ok || httpError.Actual != 404 { + return httpError + } + } + return nil +} + +func testAccCheckFirewallPolicyExists(n string, expected *policies.Policy) 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 ID is set") + } + + config := testAccProvider.Meta().(*Config) + networkingClient, err := config.networkingV2Client(OS_REGION_NAME) + if err != nil { + return fmt.Errorf("(testAccCheckFirewallPolicyExists) Error creating OpenStack networking client: %s", err) + } + + var found *policies.Policy + for i := 0; i < 5; i++ { + // Firewall policy creation is asynchronous. Retry some times + // if we get a 404 error. Fail on any other error. + found, err = policies.Get(networkingClient, rs.Primary.ID).Extract() + if err != nil { + httpError, ok := err.(*perigee.UnexpectedResponseCodeError) + if !ok || httpError.Actual != 404 { + time.Sleep(time.Second) + continue + } + } + break + } + + if err != nil { + return err + } + + expected.ID = found.ID + + if !reflect.DeepEqual(expected, found) { + return fmt.Errorf("Expected:\n%#v\nFound:\n%#v", expected, found) + } + + return nil + } +} + +const testFirewallPolicyConfig = ` +resource "openstack_fw_policy_v2" "accept_test" { + +} +` + +const testFirewallPolicyConfigAddRules = ` +resource "openstack_fw_policy_v2" "accept_test" { + name = "accept_test" + description = "terraform acceptance test" + rules = [ + "${openstack_fw_rule_v2.accept_test_udp_deny.id}", + "${openstack_fw_rule_v2.accept_test_tcp_allow.id}", + "${openstack_fw_rule_v2.accept_test_icmp_allow.id}" + ] +} + +resource "openstack_fw_rule_v2" "accept_test_tcp_allow" { + protocol = "tcp" + action = "allow" +} + +resource "openstack_fw_rule_v2" "accept_test_udp_deny" { + protocol = "udp" + action = "deny" +} + +resource "openstack_fw_rule_v2" "accept_test_icmp_allow" { + protocol = "icmp" + action = "allow" +} +` + +const testFirewallPolicyUpdateDeleteRule = ` +resource "openstack_fw_policy_v2" "accept_test" { + name = "accept_test" + description = "terraform acceptance test" + rules = [ + "${openstack_fw_rule_v2.accept_test_udp_deny.id}" + ] +} + +resource "openstack_fw_rule_v2" "accept_test_udp_deny" { + protocol = "udp" + action = "deny" +} +` From 0ab06af410f9ebd211d1cbcdb082d84f1031b6e4 Mon Sep 17 00:00:00 2001 From: Guillaume Giamarchi Date: Mon, 9 Feb 2015 22:53:20 +0100 Subject: [PATCH 117/132] Add FWaaS firewall acceptance test --- .../resource_openstack_fw_firewall_v2_test.go | 151 ++++++++++++++++++ 1 file changed, 151 insertions(+) create mode 100644 builtin/providers/openstack/resource_openstack_fw_firewall_v2_test.go diff --git a/builtin/providers/openstack/resource_openstack_fw_firewall_v2_test.go b/builtin/providers/openstack/resource_openstack_fw_firewall_v2_test.go new file mode 100644 index 0000000000..e32ded4c9f --- /dev/null +++ b/builtin/providers/openstack/resource_openstack_fw_firewall_v2_test.go @@ -0,0 +1,151 @@ +package openstack + +import ( + "fmt" + "testing" + "time" + + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" + "github.com/racker/perigee" + "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/fwaas/firewalls" +) + +func TestAccOpenstackFirewall(t *testing.T) { + + var policyID *string + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckOpenstackFirewallDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testFirewallConfig, + Check: resource.ComposeTestCheckFunc( + testAccCheckFirewallExists("openstack_fw_firewall_v2.accept_test", "", "", policyID), + ), + }, + resource.TestStep{ + Config: testFirewallConfigUpdated, + Check: resource.ComposeTestCheckFunc( + testAccCheckFirewallExists("openstack_fw_firewall_v2.accept_test", "accept_test", "terraform acceptance test", policyID), + ), + }, + }, + }) +} + +func testAccCheckOpenstackFirewallDestroy(s *terraform.State) error { + + config := testAccProvider.Meta().(*Config) + networkingClient, err := config.networkingV2Client(OS_REGION_NAME) + if err != nil { + return fmt.Errorf("(testAccCheckOpenstackFirewallDestroy) Error creating OpenStack networking client: %s", err) + } + for _, rs := range s.RootModule().Resources { + if rs.Type != "openstack_firewall" { + continue + } + _, err = firewalls.Get(networkingClient, rs.Primary.ID).Extract() + if err == nil { + return fmt.Errorf("Firewall (%s) still exists.", rs.Primary.ID) + } + httpError, ok := err.(*perigee.UnexpectedResponseCodeError) + if !ok || httpError.Actual != 404 { + return httpError + } + } + return nil +} + +func testAccCheckFirewallExists(n, expectedName, expectedDescription string, policyID *string) 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 ID is set") + } + + config := testAccProvider.Meta().(*Config) + networkingClient, err := config.networkingV2Client(OS_REGION_NAME) + if err != nil { + return fmt.Errorf("(testAccCheckFirewallExists) Error creating OpenStack networking client: %s", err) + } + + var found *firewalls.Firewall + for i := 0; i < 5; i++ { + // Firewall creation is asynchronous. Retry some times + // if we get a 404 error. Fail on any other error. + found, err = firewalls.Get(networkingClient, rs.Primary.ID).Extract() + if err != nil { + httpError, ok := err.(*perigee.UnexpectedResponseCodeError) + if !ok || httpError.Actual != 404 { + time.Sleep(time.Second) + continue + } + } + break + } + + if err != nil { + return err + } + + if found.Name != expectedName { + return fmt.Errorf("Expected Name to be <%s> but found <%s>", expectedName, found.Name) + } + if found.Description != expectedDescription { + return fmt.Errorf("Expected Description to be <%s> but found <%s>", expectedDescription, found.Description) + } + if found.PolicyID == "" { + return fmt.Errorf("Policy should not be empty") + } + if policyID != nil && found.PolicyID == *policyID { + return fmt.Errorf("Policy had not been correctly updated. Went from <%s> to <%s>", expectedName, found.Name) + } + + policyID = &found.PolicyID + + return nil + } +} + +const testFirewallConfig = ` +resource "openstack_fw_firewall_v2" "accept_test" { + policy_id = "${openstack_fw_policy_v2.accept_test_policy_1.id}" +} + +resource "openstack_fw_policy_v2" "accept_test_policy_1" { + name = "policy-1" +} +` + +const testFirewallConfigUpdated = ` +resource "openstack_fw_firewall_v2" "accept_test" { + name = "accept_test" + description = "terraform acceptance test" + policy_id = "${openstack_fw_policy_v2.accept_test_policy_1.id}" +} + +resource "openstack_fw_policy_v2" "accept_test_policy_1" { + name = "policy-1" +} +` + +const testFirewallConfigForceNew = ` +resource "openstack_fw_firewall_v2" "accept_test" { + name = "accept_test" + description = "terraform acceptance test" + policy_id = "${openstack_fw_policy_v2.accept_test_policy_2.id}" +} + +resource "openstack_fw_policy_v2" "accept_test_policy_2" { + name = "policy-2" +} +` From cfd3329e00d8c69e3d27909ef81098dd9f3f1327 Mon Sep 17 00:00:00 2001 From: Guillaume Giamarchi Date: Tue, 10 Feb 2015 00:19:01 +0100 Subject: [PATCH 118/132] Add tenant_id attribute on FWaaS resources --- .../resource_openstack_fw_firewall_v2.go | 7 +++++++ .../resource_openstack_fw_policy_v2.go | 19 ++++++++++++++++--- .../resource_openstack_fw_policy_v2_test.go | 3 +++ .../resource_openstack_fw_rule_v2.go | 7 +++++++ .../resource_openstack_fw_rule_v2_test.go | 3 +++ 5 files changed, 36 insertions(+), 3 deletions(-) diff --git a/builtin/providers/openstack/resource_openstack_fw_firewall_v2.go b/builtin/providers/openstack/resource_openstack_fw_firewall_v2.go index e2125e7fb0..598907ed13 100644 --- a/builtin/providers/openstack/resource_openstack_fw_firewall_v2.go +++ b/builtin/providers/openstack/resource_openstack_fw_firewall_v2.go @@ -45,6 +45,11 @@ func resourceFWFirewallV2() *schema.Resource { Optional: true, Default: true, }, + "tenant_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, }, } } @@ -64,6 +69,7 @@ func resourceFirewallCreate(d *schema.ResourceData, meta interface{}) error { Description: d.Get("description").(string), PolicyID: d.Get("policy_id").(string), AdminStateUp: &adminStateUp, + TenantID: d.Get("tenant_id").(string), } log.Printf("[DEBUG] Create firewall: %#v", firewallConfiguration) @@ -90,6 +96,7 @@ func resourceFirewallCreate(d *schema.ResourceData, meta interface{}) error { d.Set("description", firewall.Description) d.Set("policy_id", firewall.PolicyID) d.Set("admin_state_up", firewall.AdminStateUp) + d.Set("tenant_id", firewall.TenantID) _, err = stateConf.WaitForState() diff --git a/builtin/providers/openstack/resource_openstack_fw_policy_v2.go b/builtin/providers/openstack/resource_openstack_fw_policy_v2.go index 8f7b593d86..04fa03c073 100644 --- a/builtin/providers/openstack/resource_openstack_fw_policy_v2.go +++ b/builtin/providers/openstack/resource_openstack_fw_policy_v2.go @@ -43,6 +43,11 @@ func resourceFWPolicyV2() *schema.Resource { Optional: true, Default: false, }, + "tenant_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, "rules": &schema.Schema{ Type: schema.TypeSet, Optional: true, @@ -76,12 +81,16 @@ func resourceFirewallPolicyCreate(d *schema.ResourceData, meta interface{}) erro rules[i] = v.(string) } + audited := d.Get("audited").(bool) + shared := d.Get("shared").(bool) + opts := policies.CreateOpts{ Name: d.Get("name").(string), Description: d.Get("description").(string), - // Audited: d.Get("audited").(bool), - // Shared: d.Get("shared").(bool), - Rules: rules, + Audited: &audited, + Shared: &shared, + TenantID: d.Get("tenant_id").(string), + Rules: rules, } log.Printf("[DEBUG] Create firewall policy: %#v", opts) @@ -122,6 +131,10 @@ func resourceFirewallPolicyRead(d *schema.ResourceData, meta interface{}) error } d.Set("name", policy.Name) + d.Set("description", policy.Description) + d.Set("shared", policy.Shared) + d.Set("audited", policy.Audited) + d.Set("tenant_id", policy.TenantID) return nil } diff --git a/builtin/providers/openstack/resource_openstack_fw_policy_v2_test.go b/builtin/providers/openstack/resource_openstack_fw_policy_v2_test.go index 8a3f19ef57..0f0d98e4d4 100644 --- a/builtin/providers/openstack/resource_openstack_fw_policy_v2_test.go +++ b/builtin/providers/openstack/resource_openstack_fw_policy_v2_test.go @@ -117,6 +117,9 @@ func testAccCheckFirewallPolicyExists(n string, expected *policies.Policy) resou } expected.ID = found.ID + // Erase the tenant id because we don't want to compare + // it as long it is not present in the expected + found.TenantID = "" if !reflect.DeepEqual(expected, found) { return fmt.Errorf("Expected:\n%#v\nFound:\n%#v", expected, found) diff --git a/builtin/providers/openstack/resource_openstack_fw_rule_v2.go b/builtin/providers/openstack/resource_openstack_fw_rule_v2.go index 97d8da5684..019ee54766 100644 --- a/builtin/providers/openstack/resource_openstack_fw_rule_v2.go +++ b/builtin/providers/openstack/resource_openstack_fw_rule_v2.go @@ -65,6 +65,11 @@ func resourceFWRuleV2() *schema.Resource { Optional: true, Default: true, }, + "tenant_id": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, }, } } @@ -90,6 +95,7 @@ func resourceFirewallRuleCreate(d *schema.ResourceData, meta interface{}) error SourcePort: d.Get("source_port").(string), DestinationPort: d.Get("destination_port").(string), Enabled: &enabled, + TenantID: d.Get("tenant_id").(string), } log.Printf("[DEBUG] Create firewall rule: %#v", ruleConfiguration) @@ -114,6 +120,7 @@ func resourceFirewallRuleCreate(d *schema.ResourceData, meta interface{}) error d.Set("source_port", rule.SourcePort) d.Set("destination_port", rule.DestinationPort) d.Set("enabled", rule.Enabled) + d.Set("tenant_id", rule.TenantID) return nil } diff --git a/builtin/providers/openstack/resource_openstack_fw_rule_v2_test.go b/builtin/providers/openstack/resource_openstack_fw_rule_v2_test.go index 86e731b447..5d9d07cb86 100644 --- a/builtin/providers/openstack/resource_openstack_fw_rule_v2_test.go +++ b/builtin/providers/openstack/resource_openstack_fw_rule_v2_test.go @@ -135,6 +135,9 @@ func testAccCheckFirewallRuleExists(n string, expected *rules.Rule) resource.Tes } expected.ID = found.ID + // Erase the tenant id because we don't want to compare + // it as long it is not present in the expected + found.TenantID = "" if !reflect.DeepEqual(expected, found) { return fmt.Errorf("Expected:\n%#v\nFound:\n%#v", expected, found) From d6733fb37903d98b73df365997ef9530297662c6 Mon Sep 17 00:00:00 2001 From: Guillaume Giamarchi Date: Tue, 17 Feb 2015 22:07:01 +0100 Subject: [PATCH 119/132] Fix code regarding to the latest gophercloud code --- .../resource_openstack_fw_firewall_v2.go | 11 ++++------ .../resource_openstack_fw_firewall_v2_test.go | 6 ++--- .../resource_openstack_fw_policy_v2.go | 12 +++++----- .../resource_openstack_fw_policy_v2_test.go | 6 ++--- .../resource_openstack_fw_rule_v2.go | 10 ++++----- .../resource_openstack_fw_rule_v2_test.go | 22 +++++++++---------- 6 files changed, 30 insertions(+), 37 deletions(-) diff --git a/builtin/providers/openstack/resource_openstack_fw_firewall_v2.go b/builtin/providers/openstack/resource_openstack_fw_firewall_v2.go index 598907ed13..cab83ce635 100644 --- a/builtin/providers/openstack/resource_openstack_fw_firewall_v2.go +++ b/builtin/providers/openstack/resource_openstack_fw_firewall_v2.go @@ -8,7 +8,6 @@ import ( "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/schema" - "github.com/racker/perigee" "github.com/rackspace/gophercloud" "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/fwaas/firewalls" ) @@ -114,7 +113,7 @@ func resourceFirewallRead(d *schema.ResourceData, meta interface{}) error { firewall, err := firewalls.Get(networkingClient, d.Id()).Extract() if err != nil { - httpError, ok := err.(*perigee.UnexpectedResponseCodeError) + httpError, ok := err.(*gophercloud.UnexpectedResponseCodeError) if !ok { return err } @@ -145,13 +144,11 @@ func resourceFirewallUpdate(d *schema.ResourceData, meta interface{}) error { opts := firewalls.UpdateOpts{} if d.HasChange("name") { - name := d.Get("name").(string) - opts.Name = &name + opts.Name = d.Get("name").(string) } if d.HasChange("description") { - description := d.Get("description").(string) - opts.Description = &description + opts.Description = d.Get("description").(string) } if d.HasChange("policy_id") { @@ -227,7 +224,7 @@ func WaitForFirewallDeletion(networkingClient *gophercloud.ServiceClient, id str log.Printf("[DEBUG] Get firewall %s => %#v", id, fw) if err != nil { - httpStatus := err.(*perigee.UnexpectedResponseCodeError) + httpStatus := err.(*gophercloud.UnexpectedResponseCodeError) log.Printf("[DEBUG] Get firewall %s status is %d", id, httpStatus.Actual) if httpStatus.Actual == 404 { diff --git a/builtin/providers/openstack/resource_openstack_fw_firewall_v2_test.go b/builtin/providers/openstack/resource_openstack_fw_firewall_v2_test.go index e32ded4c9f..a0adecdc45 100644 --- a/builtin/providers/openstack/resource_openstack_fw_firewall_v2_test.go +++ b/builtin/providers/openstack/resource_openstack_fw_firewall_v2_test.go @@ -7,7 +7,7 @@ import ( "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/terraform" - "github.com/racker/perigee" + "github.com/rackspace/gophercloud" "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/fwaas/firewalls" ) @@ -51,7 +51,7 @@ func testAccCheckOpenstackFirewallDestroy(s *terraform.State) error { if err == nil { return fmt.Errorf("Firewall (%s) still exists.", rs.Primary.ID) } - httpError, ok := err.(*perigee.UnexpectedResponseCodeError) + httpError, ok := err.(*gophercloud.UnexpectedResponseCodeError) if !ok || httpError.Actual != 404 { return httpError } @@ -84,7 +84,7 @@ func testAccCheckFirewallExists(n, expectedName, expectedDescription string, pol // if we get a 404 error. Fail on any other error. found, err = firewalls.Get(networkingClient, rs.Primary.ID).Extract() if err != nil { - httpError, ok := err.(*perigee.UnexpectedResponseCodeError) + httpError, ok := err.(*gophercloud.UnexpectedResponseCodeError) if !ok || httpError.Actual != 404 { time.Sleep(time.Second) continue diff --git a/builtin/providers/openstack/resource_openstack_fw_policy_v2.go b/builtin/providers/openstack/resource_openstack_fw_policy_v2.go index 04fa03c073..c4d05bb8e6 100644 --- a/builtin/providers/openstack/resource_openstack_fw_policy_v2.go +++ b/builtin/providers/openstack/resource_openstack_fw_policy_v2.go @@ -7,7 +7,7 @@ import ( "github.com/hashicorp/terraform/helper/hashcode" "github.com/hashicorp/terraform/helper/schema" - "github.com/racker/perigee" + "github.com/rackspace/gophercloud" "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/fwaas/policies" ) @@ -119,7 +119,7 @@ func resourceFirewallPolicyRead(d *schema.ResourceData, meta interface{}) error policy, err := policies.Get(networkingClient, d.Id()).Extract() if err != nil { - httpError, ok := err.(*perigee.UnexpectedResponseCodeError) + httpError, ok := err.(*gophercloud.UnexpectedResponseCodeError) if !ok { return err } @@ -150,13 +150,11 @@ func resourceFirewallPolicyUpdate(d *schema.ResourceData, meta interface{}) erro opts := policies.UpdateOpts{} if d.HasChange("name") { - name := d.Get("name").(string) - opts.Name = &name + opts.Name = d.Get("name").(string) } if d.HasChange("description") { - description := d.Get("description").(string) - opts.Description = &description + opts.Description = d.Get("description").(string) } if d.HasChange("rules") { @@ -193,7 +191,7 @@ func resourceFirewallPolicyDelete(d *schema.ResourceData, meta interface{}) erro break } - httpError, ok := err.(*perigee.UnexpectedResponseCodeError) + httpError, ok := err.(*gophercloud.UnexpectedResponseCodeError) if !ok || httpError.Actual != 409 { return err } diff --git a/builtin/providers/openstack/resource_openstack_fw_policy_v2_test.go b/builtin/providers/openstack/resource_openstack_fw_policy_v2_test.go index 0f0d98e4d4..58c1c1ac17 100644 --- a/builtin/providers/openstack/resource_openstack_fw_policy_v2_test.go +++ b/builtin/providers/openstack/resource_openstack_fw_policy_v2_test.go @@ -8,7 +8,7 @@ import ( "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/terraform" - "github.com/racker/perigee" + "github.com/rackspace/gophercloud" "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/fwaas/policies" ) @@ -70,7 +70,7 @@ func testAccCheckOpenstackFirewallPolicyDestroy(s *terraform.State) error { if err == nil { return fmt.Errorf("Firewall policy (%s) still exists.", rs.Primary.ID) } - httpError, ok := err.(*perigee.UnexpectedResponseCodeError) + httpError, ok := err.(*gophercloud.UnexpectedResponseCodeError) if !ok || httpError.Actual != 404 { return httpError } @@ -103,7 +103,7 @@ func testAccCheckFirewallPolicyExists(n string, expected *policies.Policy) resou // if we get a 404 error. Fail on any other error. found, err = policies.Get(networkingClient, rs.Primary.ID).Extract() if err != nil { - httpError, ok := err.(*perigee.UnexpectedResponseCodeError) + httpError, ok := err.(*gophercloud.UnexpectedResponseCodeError) if !ok || httpError.Actual != 404 { time.Sleep(time.Second) continue diff --git a/builtin/providers/openstack/resource_openstack_fw_rule_v2.go b/builtin/providers/openstack/resource_openstack_fw_rule_v2.go index 019ee54766..3d6b4a51b1 100644 --- a/builtin/providers/openstack/resource_openstack_fw_rule_v2.go +++ b/builtin/providers/openstack/resource_openstack_fw_rule_v2.go @@ -5,7 +5,7 @@ import ( "log" "github.com/hashicorp/terraform/helper/schema" - "github.com/racker/perigee" + "github.com/rackspace/gophercloud" "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/fwaas/rules" ) @@ -137,7 +137,7 @@ func resourceFirewallRuleRead(d *schema.ResourceData, meta interface{}) error { rule, err := rules.Get(networkingClient, d.Id()).Extract() if err != nil { - httpError, ok := err.(*perigee.UnexpectedResponseCodeError) + httpError, ok := err.(*gophercloud.UnexpectedResponseCodeError) if !ok { return err } @@ -172,12 +172,10 @@ func resourceFirewallRuleUpdate(d *schema.ResourceData, meta interface{}) error opts := rules.UpdateOpts{} if d.HasChange("name") { - name := d.Get("name").(string) - opts.Name = &name + opts.Name = d.Get("name").(string) } if d.HasChange("description") { - description := d.Get("description").(string) - opts.Description = &description + opts.Description = d.Get("description").(string) } if d.HasChange("protocol") { opts.Protocol = d.Get("protocol").(string) diff --git a/builtin/providers/openstack/resource_openstack_fw_rule_v2_test.go b/builtin/providers/openstack/resource_openstack_fw_rule_v2_test.go index 5d9d07cb86..748177375e 100644 --- a/builtin/providers/openstack/resource_openstack_fw_rule_v2_test.go +++ b/builtin/providers/openstack/resource_openstack_fw_rule_v2_test.go @@ -8,7 +8,7 @@ import ( "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/terraform" - "github.com/racker/perigee" + "github.com/rackspace/gophercloud" "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/fwaas/rules" ) @@ -88,7 +88,7 @@ func testAccCheckOpenstackFirewallRuleDestroy(s *terraform.State) error { if err == nil { return fmt.Errorf("Firewall rule (%s) still exists.", rs.Primary.ID) } - httpError, ok := err.(*perigee.UnexpectedResponseCodeError) + httpError, ok := err.(*gophercloud.UnexpectedResponseCodeError) if !ok || httpError.Actual != 404 { return httpError } @@ -121,7 +121,7 @@ func testAccCheckFirewallRuleExists(n string, expected *rules.Rule) resource.Tes // if we get a 404 error. Fail on any other error. found, err = rules.Get(networkingClient, rs.Primary.ID).Extract() if err != nil { - httpError, ok := err.(*perigee.UnexpectedResponseCodeError) + httpError, ok := err.(*gophercloud.UnexpectedResponseCodeError) if !ok || httpError.Actual != 404 { time.Sleep(time.Second) continue @@ -149,17 +149,17 @@ func testAccCheckFirewallRuleExists(n string, expected *rules.Rule) resource.Tes const testFirewallRuleMinimalConfig = ` resource "openstack_fw_rule_v2" "accept_test_minimal" { - protocol = "udp" - action = "deny" + protocol = "udp" + action = "deny" } ` const testFirewallRuleConfig = ` resource "openstack_fw_rule_v2" "accept_test" { - name = "accept_test" + name = "accept_test" description = "Terraform accept test" - protocol = "udp" - action = "deny" + protocol = "udp" + action = "deny" ip_version = 4 source_ip_address = "1.2.3.4" destination_ip_address = "4.3.2.0/24" @@ -171,10 +171,10 @@ resource "openstack_fw_rule_v2" "accept_test" { const testFirewallRuleUpdateAllFieldsConfig = ` resource "openstack_fw_rule_v2" "accept_test" { - name = "accept_test_updated_2" + name = "accept_test_updated_2" description = "Terraform accept test updated" - protocol = "tcp" - action = "allow" + protocol = "tcp" + action = "allow" ip_version = 4 source_ip_address = "1.2.3.0/24" destination_ip_address = "4.3.2.8" From 1c981d6f30fe1fb742cecbcb7fb6b58e93bb1f8e Mon Sep 17 00:00:00 2001 From: Guillaume Giamarchi Date: Wed, 18 Feb 2015 00:12:04 +0100 Subject: [PATCH 120/132] Fix race conditions on firewall state transition --- .../resource_openstack_fw_firewall_v2.go | 38 +++++++++++-------- .../resource_openstack_fw_firewall_v2_test.go | 12 ------ 2 files changed, 22 insertions(+), 28 deletions(-) diff --git a/builtin/providers/openstack/resource_openstack_fw_firewall_v2.go b/builtin/providers/openstack/resource_openstack_fw_firewall_v2.go index cab83ce635..a216b506b0 100644 --- a/builtin/providers/openstack/resource_openstack_fw_firewall_v2.go +++ b/builtin/providers/openstack/resource_openstack_fw_firewall_v2.go @@ -37,7 +37,6 @@ func resourceFWFirewallV2() *schema.Resource { "policy_id": &schema.Schema{ Type: schema.TypeString, Required: true, - ForceNew: true, }, "admin_state_up": &schema.Schema{ Type: schema.TypeBool, @@ -89,16 +88,10 @@ func resourceFirewallCreate(d *schema.ResourceData, meta interface{}) error { MinTimeout: 2 * time.Second, } - d.SetId(firewall.ID) - - d.Set("name", firewall.Name) - d.Set("description", firewall.Description) - d.Set("policy_id", firewall.PolicyID) - d.Set("admin_state_up", firewall.AdminStateUp) - d.Set("tenant_id", firewall.TenantID) - _, err = stateConf.WaitForState() + d.SetId(firewall.ID) + return nil } @@ -129,6 +122,7 @@ func resourceFirewallRead(d *schema.ResourceData, meta interface{}) error { d.Set("description", firewall.Description) d.Set("policy_id", firewall.PolicyID) d.Set("admin_state_up", firewall.AdminStateUp) + d.Set("tenant_id", firewall.TenantID) return nil } @@ -155,14 +149,15 @@ func resourceFirewallUpdate(d *schema.ResourceData, meta interface{}) error { opts.PolicyID = d.Get("policy_id").(string) } - log.Printf("[DEBUG] Updating firewall with id %s: %#v", d.Id(), opts) - - if err := firewalls.Update(networkingClient, d.Id(), opts).Err; err != nil { - return err + if d.HasChange("admin_state_up") { + adminStateUp := d.Get("admin_state_up").(bool) + opts.AdminStateUp = &adminStateUp } + log.Printf("[DEBUG] Updating firewall with id %s: %#v", d.Id(), opts) + stateConf := &resource.StateChangeConf{ - Pending: []string{"PENDING_CREATE"}, + Pending: []string{"PENDING_CREATE", "PENDING_UPDATE"}, Target: "ACTIVE", Refresh: WaitForFirewallActive(networkingClient, d.Id()), Timeout: 30 * time.Second, @@ -172,7 +167,7 @@ func resourceFirewallUpdate(d *schema.ResourceData, meta interface{}) error { _, err = stateConf.WaitForState() - return err + return firewalls.Update(networkingClient, d.Id(), opts).Err } func resourceFirewallDelete(d *schema.ResourceData, meta interface{}) error { @@ -184,13 +179,24 @@ func resourceFirewallDelete(d *schema.ResourceData, meta interface{}) error { return fmt.Errorf("Error creating OpenStack networking client: %s", err) } + stateConf := &resource.StateChangeConf{ + Pending: []string{"PENDING_CREATE", "PENDING_UPDATE"}, + Target: "ACTIVE", + Refresh: WaitForFirewallActive(networkingClient, d.Id()), + Timeout: 30 * time.Second, + Delay: 0, + MinTimeout: 2 * time.Second, + } + + _, err = stateConf.WaitForState() + err = firewalls.Delete(networkingClient, d.Id()).Err if err != nil { return err } - stateConf := &resource.StateChangeConf{ + stateConf = &resource.StateChangeConf{ Pending: []string{"DELETING"}, Target: "DELETED", Refresh: WaitForFirewallDeletion(networkingClient, d.Id()), diff --git a/builtin/providers/openstack/resource_openstack_fw_firewall_v2_test.go b/builtin/providers/openstack/resource_openstack_fw_firewall_v2_test.go index a0adecdc45..cc5343660a 100644 --- a/builtin/providers/openstack/resource_openstack_fw_firewall_v2_test.go +++ b/builtin/providers/openstack/resource_openstack_fw_firewall_v2_test.go @@ -127,18 +127,6 @@ resource "openstack_fw_policy_v2" "accept_test_policy_1" { ` const testFirewallConfigUpdated = ` -resource "openstack_fw_firewall_v2" "accept_test" { - name = "accept_test" - description = "terraform acceptance test" - policy_id = "${openstack_fw_policy_v2.accept_test_policy_1.id}" -} - -resource "openstack_fw_policy_v2" "accept_test_policy_1" { - name = "policy-1" -} -` - -const testFirewallConfigForceNew = ` resource "openstack_fw_firewall_v2" "accept_test" { name = "accept_test" description = "terraform acceptance test" From c5e861c0491dd03b3e701c0daf11164561a537a4 Mon Sep 17 00:00:00 2001 From: Guillaume Giamarchi Date: Wed, 18 Feb 2015 00:52:54 +0100 Subject: [PATCH 121/132] Remove useless code --- .../openstack/resource_openstack_fw_rule_v2.go | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/builtin/providers/openstack/resource_openstack_fw_rule_v2.go b/builtin/providers/openstack/resource_openstack_fw_rule_v2.go index 3d6b4a51b1..f3aacf5104 100644 --- a/builtin/providers/openstack/resource_openstack_fw_rule_v2.go +++ b/builtin/providers/openstack/resource_openstack_fw_rule_v2.go @@ -110,18 +110,6 @@ func resourceFirewallRuleCreate(d *schema.ResourceData, meta interface{}) error d.SetId(rule.ID) - d.Set("name", rule.Name) - d.Set("description", rule.Description) - d.Set("protocol", rule.Protocol) - d.Set("action", rule.Action) - d.Set("ip_version", rule.IPVersion) - d.Set("source_ip_address", rule.SourceIPAddress) - d.Set("destination_ip_address", rule.DestinationIPAddress) - d.Set("source_port", rule.SourcePort) - d.Set("destination_port", rule.DestinationPort) - d.Set("enabled", rule.Enabled) - d.Set("tenant_id", rule.TenantID) - return nil } From 54174dcc05efe3b560e105053eb3b90d0405af5c Mon Sep 17 00:00:00 2001 From: Guillaume Giamarchi Date: Wed, 18 Feb 2015 01:00:48 +0100 Subject: [PATCH 122/132] Fix firewall policies tests --- .../resource_openstack_fw_policy_v2_test.go | 41 +++++++------------ 1 file changed, 14 insertions(+), 27 deletions(-) diff --git a/builtin/providers/openstack/resource_openstack_fw_policy_v2_test.go b/builtin/providers/openstack/resource_openstack_fw_policy_v2_test.go index 58c1c1ac17..ed268b7c31 100644 --- a/builtin/providers/openstack/resource_openstack_fw_policy_v2_test.go +++ b/builtin/providers/openstack/resource_openstack_fw_policy_v2_test.go @@ -2,7 +2,6 @@ package openstack import ( "fmt" - "reflect" "testing" "time" @@ -23,9 +22,7 @@ func TestAccOpenstackFirewallPolicy(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckFirewallPolicyExists( "openstack_fw_policy_v2.accept_test", - &policies.Policy{ - Rules: []string{}, - }), + "", "", 0), ), }, resource.TestStep{ @@ -33,14 +30,7 @@ func TestAccOpenstackFirewallPolicy(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckFirewallPolicyExists( "openstack_fw_policy_v2.accept_test", - &policies.Policy{ - Name: "accept_test", - Description: "terraform acceptance test", - Rules: []string{ - "", - "", - }, - }), + "accept_test", "terraform acceptance test", 2), ), }, resource.TestStep{ @@ -48,7 +38,7 @@ func TestAccOpenstackFirewallPolicy(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckFirewallPolicyExists( "openstack_fw_policy_v2.accept_test", - &policies.Policy{}), + "accept_test", "terraform acceptance test", 1), ), }, }, @@ -78,7 +68,7 @@ func testAccCheckOpenstackFirewallPolicyDestroy(s *terraform.State) error { return nil } -func testAccCheckFirewallPolicyExists(n string, expected *policies.Policy) resource.TestCheckFunc { +func testAccCheckFirewallPolicyExists(n, name, description string, ruleCount int) resource.TestCheckFunc { return func(s *terraform.State) error { @@ -116,13 +106,16 @@ func testAccCheckFirewallPolicyExists(n string, expected *policies.Policy) resou return err } - expected.ID = found.ID - // Erase the tenant id because we don't want to compare - // it as long it is not present in the expected - found.TenantID = "" + if name != found.Name { + return fmt.Errorf("Expected name <%s>, but found <%s>", name, found.Name) + } - if !reflect.DeepEqual(expected, found) { - return fmt.Errorf("Expected:\n%#v\nFound:\n%#v", expected, found) + if description != found.Description { + return fmt.Errorf("Expected description <%s>, but found <%s>", description, found.Description) + } + + if ruleCount != len(found.Rules) { + return fmt.Errorf("Expected rule count <%d>, but found <%d>", ruleCount, len(found.Rules)) } return nil @@ -141,8 +134,7 @@ resource "openstack_fw_policy_v2" "accept_test" { description = "terraform acceptance test" rules = [ "${openstack_fw_rule_v2.accept_test_udp_deny.id}", - "${openstack_fw_rule_v2.accept_test_tcp_allow.id}", - "${openstack_fw_rule_v2.accept_test_icmp_allow.id}" + "${openstack_fw_rule_v2.accept_test_tcp_allow.id}" ] } @@ -155,11 +147,6 @@ resource "openstack_fw_rule_v2" "accept_test_udp_deny" { protocol = "udp" action = "deny" } - -resource "openstack_fw_rule_v2" "accept_test_icmp_allow" { - protocol = "icmp" - action = "allow" -} ` const testFirewallPolicyUpdateDeleteRule = ` From ed31588b8428f83f352a88f5d2e0f68d4a7ad20f Mon Sep 17 00:00:00 2001 From: Guillaume Giamarchi Date: Wed, 18 Feb 2015 01:01:46 +0100 Subject: [PATCH 123/132] Unassociate firewall rule from policy before delete --- .../openstack/resource_openstack_fw_rule_v2.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/builtin/providers/openstack/resource_openstack_fw_rule_v2.go b/builtin/providers/openstack/resource_openstack_fw_rule_v2.go index f3aacf5104..4a50303e10 100644 --- a/builtin/providers/openstack/resource_openstack_fw_rule_v2.go +++ b/builtin/providers/openstack/resource_openstack_fw_rule_v2.go @@ -6,6 +6,7 @@ import ( "github.com/hashicorp/terraform/helper/schema" "github.com/rackspace/gophercloud" + "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/fwaas/policies" "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/fwaas/rules" ) @@ -208,5 +209,18 @@ func resourceFirewallRuleDelete(d *schema.ResourceData, meta interface{}) error if err != nil { return fmt.Errorf("Error creating OpenStack networking client: %s", err) } + + rule, err := rules.Get(networkingClient, d.Id()).Extract() + if err != nil { + return err + } + + if rule.PolicyID != "" { + err := policies.RemoveRule(networkingClient, rule.PolicyID, rule.ID) + if err != nil { + return err + } + } + return rules.Delete(networkingClient, d.Id()).Err } From 1efaaeeca62738f3c35dd556a08c2db430353500 Mon Sep 17 00:00:00 2001 From: Guillaume Giamarchi Date: Wed, 18 Feb 2015 01:27:45 +0100 Subject: [PATCH 124/132] Use d.GetOk to populate data in read operations --- .../resource_openstack_fw_firewall_v2.go | 34 +++++++++-- .../resource_openstack_fw_policy_v2.go | 34 +++++++++-- .../resource_openstack_fw_rule_v2.go | 56 ++++++++++++++++--- 3 files changed, 106 insertions(+), 18 deletions(-) diff --git a/builtin/providers/openstack/resource_openstack_fw_firewall_v2.go b/builtin/providers/openstack/resource_openstack_fw_firewall_v2.go index a216b506b0..2d10fdc3cb 100644 --- a/builtin/providers/openstack/resource_openstack_fw_firewall_v2.go +++ b/builtin/providers/openstack/resource_openstack_fw_firewall_v2.go @@ -118,11 +118,35 @@ func resourceFirewallRead(d *schema.ResourceData, meta interface{}) error { return err } - d.Set("name", firewall.Name) - d.Set("description", firewall.Description) - d.Set("policy_id", firewall.PolicyID) - d.Set("admin_state_up", firewall.AdminStateUp) - d.Set("tenant_id", firewall.TenantID) + if t, exists := d.GetOk("name"); exists && t != "" { + d.Set("name", firewall.Name) + } else { + d.Set("name", "") + } + + if t, exists := d.GetOk("description"); exists && t != "" { + d.Set("description", firewall.Description) + } else { + d.Set("description", "") + } + + if t, exists := d.GetOk("policy_id"); exists && t != "" { + d.Set("policy_id", firewall.PolicyID) + } else { + d.Set("policy_id", "") + } + + if t, exists := d.GetOk("admin_state_up"); exists && t != "" { + d.Set("admin_state_up", firewall.AdminStateUp) + } else { + d.Set("admin_state_up", "") + } + + if t, exists := d.GetOk("tenant_id"); exists && t != "" { + d.Set("tenant_id", firewall.TenantID) + } else { + d.Set("tenant_id", "") + } return nil } diff --git a/builtin/providers/openstack/resource_openstack_fw_policy_v2.go b/builtin/providers/openstack/resource_openstack_fw_policy_v2.go index c4d05bb8e6..ad096397b8 100644 --- a/builtin/providers/openstack/resource_openstack_fw_policy_v2.go +++ b/builtin/providers/openstack/resource_openstack_fw_policy_v2.go @@ -130,11 +130,35 @@ func resourceFirewallPolicyRead(d *schema.ResourceData, meta interface{}) error return err } - d.Set("name", policy.Name) - d.Set("description", policy.Description) - d.Set("shared", policy.Shared) - d.Set("audited", policy.Audited) - d.Set("tenant_id", policy.TenantID) + if t, exists := d.GetOk("name"); exists && t != "" { + d.Set("name", policy.Name) + } else { + d.Set("name", "") + } + + if t, exists := d.GetOk("description"); exists && t != "" { + d.Set("description", policy.Description) + } else { + d.Set("description", "") + } + + if t, exists := d.GetOk("shared"); exists && t != "" { + d.Set("shared", policy.Shared) + } else { + d.Set("shared", "") + } + + if t, exists := d.GetOk("audited"); exists && t != "" { + d.Set("audited", policy.Audited) + } else { + d.Set("audited", "") + } + + if t, exists := d.GetOk("tenant_id"); exists && t != "" { + d.Set("tenant_id", policy.TenantID) + } else { + d.Set("tenant_id", "") + } return nil } diff --git a/builtin/providers/openstack/resource_openstack_fw_rule_v2.go b/builtin/providers/openstack/resource_openstack_fw_rule_v2.go index 4a50303e10..9aa110757b 100644 --- a/builtin/providers/openstack/resource_openstack_fw_rule_v2.go +++ b/builtin/providers/openstack/resource_openstack_fw_rule_v2.go @@ -137,16 +137,56 @@ func resourceFirewallRuleRead(d *schema.ResourceData, meta interface{}) error { return err } - d.Set("name", rule.Name) - d.Set("description", rule.Description) d.Set("protocol", rule.Protocol) d.Set("action", rule.Action) - d.Set("ip_version", rule.IPVersion) - d.Set("source_ip_address", rule.SourceIPAddress) - d.Set("destination_ip_address", rule.DestinationIPAddress) - d.Set("source_port", rule.SourcePort) - d.Set("destination_port", rule.DestinationPort) - d.Set("enabled", rule.Enabled) + + if t, exists := d.GetOk("name"); exists && t != "" { + d.Set("name", rule.Name) + } else { + d.Set("name", "") + } + + if t, exists := d.GetOk("description"); exists && t != "" { + d.Set("description", rule.Description) + } else { + d.Set("description", "") + } + + if t, exists := d.GetOk("ip_version"); exists && t != "" { + d.Set("ip_version", rule.IPVersion) + } else { + d.Set("ip_version", "") + } + + if t, exists := d.GetOk("source_ip_address"); exists && t != "" { + d.Set("source_ip_address", rule.SourceIPAddress) + } else { + d.Set("source_ip_address", "") + } + + if t, exists := d.GetOk("destination_ip_address"); exists && t != "" { + d.Set("destination_ip_address", rule.DestinationIPAddress) + } else { + d.Set("destination_ip_address", "") + } + + if t, exists := d.GetOk("source_port"); exists && t != "" { + d.Set("source_port", rule.SourcePort) + } else { + d.Set("source_port", "") + } + + if t, exists := d.GetOk("destination_port"); exists && t != "" { + d.Set("destination_port", rule.DestinationPort) + } else { + d.Set("destination_port", "") + } + + if t, exists := d.GetOk("enabled"); exists && t != "" { + d.Set("enabled", rule.Enabled) + } else { + d.Set("enabled", "") + } return nil } From 16a963313fe21196660ab83f2f061799668fe66a Mon Sep 17 00:00:00 2001 From: Guillaume Giamarchi Date: Thu, 19 Feb 2015 22:55:54 +0100 Subject: [PATCH 125/132] FWaaS version is actually v1 not v2 Rename files and methods. Confusion have been made between neutron version and FWaaS extension version. --- builtin/providers/openstack/provider.go | 6 +-- ...o => resource_openstack_fw_firewall_v1.go} | 30 +++++++------- ...resource_openstack_fw_firewall_v1_test.go} | 24 +++++------ ....go => resource_openstack_fw_policy_v1.go} | 18 ++++----- ...> resource_openstack_fw_policy_v1_test.go} | 40 +++++++++---------- ...v2.go => resource_openstack_fw_rule_v1.go} | 18 ++++----- ... => resource_openstack_fw_rule_v1_test.go} | 26 ++++++------ 7 files changed, 81 insertions(+), 81 deletions(-) rename builtin/providers/openstack/{resource_openstack_fw_firewall_v2.go => resource_openstack_fw_firewall_v1.go} (87%) rename builtin/providers/openstack/{resource_openstack_fw_firewall_v2_test.go => resource_openstack_fw_firewall_v1_test.go} (78%) rename builtin/providers/openstack/{resource_openstack_fw_policy_v2.go => resource_openstack_fw_policy_v1.go} (90%) rename builtin/providers/openstack/{resource_openstack_fw_policy_v2_test.go => resource_openstack_fw_policy_v1_test.go} (75%) rename builtin/providers/openstack/{resource_openstack_fw_rule_v2.go => resource_openstack_fw_rule_v1.go} (92%) rename builtin/providers/openstack/{resource_openstack_fw_rule_v2_test.go => resource_openstack_fw_rule_v1_test.go} (86%) diff --git a/builtin/providers/openstack/provider.go b/builtin/providers/openstack/provider.go index 7e0880007b..a43242333d 100644 --- a/builtin/providers/openstack/provider.go +++ b/builtin/providers/openstack/provider.go @@ -64,9 +64,9 @@ func Provider() terraform.ResourceProvider { "openstack_compute_keypair_v2": resourceComputeKeypairV2(), "openstack_compute_secgroup_v2": resourceComputeSecGroupV2(), "openstack_compute_floatingip_v2": resourceComputeFloatingIPV2(), - "openstack_fw_firewall_v2": resourceFWFirewallV2(), - "openstack_fw_policy_v2": resourceFWPolicyV2(), - "openstack_fw_rule_v2": resourceFWRuleV2(), + "openstack_fw_firewall_v1": resourceFWFirewallV1(), + "openstack_fw_policy_v1": resourceFWPolicyV1(), + "openstack_fw_rule_v1": resourceFWRuleV1(), "openstack_lb_monitor_v1": resourceLBMonitorV1(), "openstack_lb_pool_v1": resourceLBPoolV1(), "openstack_lb_vip_v1": resourceLBVipV1(), diff --git a/builtin/providers/openstack/resource_openstack_fw_firewall_v2.go b/builtin/providers/openstack/resource_openstack_fw_firewall_v1.go similarity index 87% rename from builtin/providers/openstack/resource_openstack_fw_firewall_v2.go rename to builtin/providers/openstack/resource_openstack_fw_firewall_v1.go index 2d10fdc3cb..21c93d33d2 100644 --- a/builtin/providers/openstack/resource_openstack_fw_firewall_v2.go +++ b/builtin/providers/openstack/resource_openstack_fw_firewall_v1.go @@ -12,12 +12,12 @@ import ( "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/fwaas/firewalls" ) -func resourceFWFirewallV2() *schema.Resource { +func resourceFWFirewallV1() *schema.Resource { return &schema.Resource{ - Create: resourceFirewallCreate, - Read: resourceFirewallRead, - Update: resourceFirewallUpdate, - Delete: resourceFirewallDelete, + Create: resourceFWFirewallV1Create, + Read: resourceFWFirewallV1Read, + Update: resourceFWFirewallV1Update, + Delete: resourceFWFirewallV1Delete, Schema: map[string]*schema.Schema{ "region": &schema.Schema{ @@ -52,7 +52,7 @@ func resourceFWFirewallV2() *schema.Resource { } } -func resourceFirewallCreate(d *schema.ResourceData, meta interface{}) error { +func resourceFWFirewallV1Create(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) networkingClient, err := config.networkingV2Client(d.Get("region").(string)) @@ -82,7 +82,7 @@ func resourceFirewallCreate(d *schema.ResourceData, meta interface{}) error { stateConf := &resource.StateChangeConf{ Pending: []string{"PENDING_CREATE"}, Target: "ACTIVE", - Refresh: WaitForFirewallActive(networkingClient, firewall.ID), + Refresh: waitForFirewallActive(networkingClient, firewall.ID), Timeout: 30 * time.Second, Delay: 0, MinTimeout: 2 * time.Second, @@ -95,7 +95,7 @@ func resourceFirewallCreate(d *schema.ResourceData, meta interface{}) error { return nil } -func resourceFirewallRead(d *schema.ResourceData, meta interface{}) error { +func resourceFWFirewallV1Read(d *schema.ResourceData, meta interface{}) error { log.Printf("[DEBUG] Retrieve information about firewall: %s", d.Id()) config := meta.(*Config) @@ -151,7 +151,7 @@ func resourceFirewallRead(d *schema.ResourceData, meta interface{}) error { return nil } -func resourceFirewallUpdate(d *schema.ResourceData, meta interface{}) error { +func resourceFWFirewallV1Update(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) networkingClient, err := config.networkingV2Client(d.Get("region").(string)) @@ -183,7 +183,7 @@ func resourceFirewallUpdate(d *schema.ResourceData, meta interface{}) error { stateConf := &resource.StateChangeConf{ Pending: []string{"PENDING_CREATE", "PENDING_UPDATE"}, Target: "ACTIVE", - Refresh: WaitForFirewallActive(networkingClient, d.Id()), + Refresh: waitForFirewallActive(networkingClient, d.Id()), Timeout: 30 * time.Second, Delay: 0, MinTimeout: 2 * time.Second, @@ -194,7 +194,7 @@ func resourceFirewallUpdate(d *schema.ResourceData, meta interface{}) error { return firewalls.Update(networkingClient, d.Id(), opts).Err } -func resourceFirewallDelete(d *schema.ResourceData, meta interface{}) error { +func resourceFWFirewallV1Delete(d *schema.ResourceData, meta interface{}) error { log.Printf("[DEBUG] Destroy firewall: %s", d.Id()) config := meta.(*Config) @@ -206,7 +206,7 @@ func resourceFirewallDelete(d *schema.ResourceData, meta interface{}) error { stateConf := &resource.StateChangeConf{ Pending: []string{"PENDING_CREATE", "PENDING_UPDATE"}, Target: "ACTIVE", - Refresh: WaitForFirewallActive(networkingClient, d.Id()), + Refresh: waitForFirewallActive(networkingClient, d.Id()), Timeout: 30 * time.Second, Delay: 0, MinTimeout: 2 * time.Second, @@ -223,7 +223,7 @@ func resourceFirewallDelete(d *schema.ResourceData, meta interface{}) error { stateConf = &resource.StateChangeConf{ Pending: []string{"DELETING"}, Target: "DELETED", - Refresh: WaitForFirewallDeletion(networkingClient, d.Id()), + Refresh: waitForFirewallDeletion(networkingClient, d.Id()), Timeout: 2 * time.Minute, Delay: 0, MinTimeout: 2 * time.Second, @@ -234,7 +234,7 @@ func resourceFirewallDelete(d *schema.ResourceData, meta interface{}) error { return err } -func WaitForFirewallActive(networkingClient *gophercloud.ServiceClient, id string) resource.StateRefreshFunc { +func waitForFirewallActive(networkingClient *gophercloud.ServiceClient, id string) resource.StateRefreshFunc { return func() (interface{}, string, error) { fw, err := firewalls.Get(networkingClient, id).Extract() @@ -247,7 +247,7 @@ func WaitForFirewallActive(networkingClient *gophercloud.ServiceClient, id strin } } -func WaitForFirewallDeletion(networkingClient *gophercloud.ServiceClient, id string) resource.StateRefreshFunc { +func waitForFirewallDeletion(networkingClient *gophercloud.ServiceClient, id string) resource.StateRefreshFunc { return func() (interface{}, string, error) { fw, err := firewalls.Get(networkingClient, id).Extract() diff --git a/builtin/providers/openstack/resource_openstack_fw_firewall_v2_test.go b/builtin/providers/openstack/resource_openstack_fw_firewall_v1_test.go similarity index 78% rename from builtin/providers/openstack/resource_openstack_fw_firewall_v2_test.go rename to builtin/providers/openstack/resource_openstack_fw_firewall_v1_test.go index cc5343660a..34112f778f 100644 --- a/builtin/providers/openstack/resource_openstack_fw_firewall_v2_test.go +++ b/builtin/providers/openstack/resource_openstack_fw_firewall_v1_test.go @@ -11,32 +11,32 @@ import ( "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/fwaas/firewalls" ) -func TestAccOpenstackFirewall(t *testing.T) { +func TestAccFWFirewallV1(t *testing.T) { var policyID *string resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, - CheckDestroy: testAccCheckOpenstackFirewallDestroy, + CheckDestroy: testAccCheckFWFirewallV1Destroy, Steps: []resource.TestStep{ resource.TestStep{ Config: testFirewallConfig, Check: resource.ComposeTestCheckFunc( - testAccCheckFirewallExists("openstack_fw_firewall_v2.accept_test", "", "", policyID), + testAccCheckFWFirewallV1Exists("openstack_fw_firewall_v1.accept_test", "", "", policyID), ), }, resource.TestStep{ Config: testFirewallConfigUpdated, Check: resource.ComposeTestCheckFunc( - testAccCheckFirewallExists("openstack_fw_firewall_v2.accept_test", "accept_test", "terraform acceptance test", policyID), + testAccCheckFWFirewallV1Exists("openstack_fw_firewall_v1.accept_test", "accept_test", "terraform acceptance test", policyID), ), }, }, }) } -func testAccCheckOpenstackFirewallDestroy(s *terraform.State) error { +func testAccCheckFWFirewallV1Destroy(s *terraform.State) error { config := testAccProvider.Meta().(*Config) networkingClient, err := config.networkingV2Client(OS_REGION_NAME) @@ -59,7 +59,7 @@ func testAccCheckOpenstackFirewallDestroy(s *terraform.State) error { return nil } -func testAccCheckFirewallExists(n, expectedName, expectedDescription string, policyID *string) resource.TestCheckFunc { +func testAccCheckFWFirewallV1Exists(n, expectedName, expectedDescription string, policyID *string) resource.TestCheckFunc { return func(s *terraform.State) error { @@ -117,23 +117,23 @@ func testAccCheckFirewallExists(n, expectedName, expectedDescription string, pol } const testFirewallConfig = ` -resource "openstack_fw_firewall_v2" "accept_test" { - policy_id = "${openstack_fw_policy_v2.accept_test_policy_1.id}" +resource "openstack_fw_firewall_v1" "accept_test" { + policy_id = "${openstack_fw_policy_v1.accept_test_policy_1.id}" } -resource "openstack_fw_policy_v2" "accept_test_policy_1" { +resource "openstack_fw_policy_v1" "accept_test_policy_1" { name = "policy-1" } ` const testFirewallConfigUpdated = ` -resource "openstack_fw_firewall_v2" "accept_test" { +resource "openstack_fw_firewall_v1" "accept_test" { name = "accept_test" description = "terraform acceptance test" - policy_id = "${openstack_fw_policy_v2.accept_test_policy_2.id}" + policy_id = "${openstack_fw_policy_v1.accept_test_policy_2.id}" } -resource "openstack_fw_policy_v2" "accept_test_policy_2" { +resource "openstack_fw_policy_v1" "accept_test_policy_2" { name = "policy-2" } ` diff --git a/builtin/providers/openstack/resource_openstack_fw_policy_v2.go b/builtin/providers/openstack/resource_openstack_fw_policy_v1.go similarity index 90% rename from builtin/providers/openstack/resource_openstack_fw_policy_v2.go rename to builtin/providers/openstack/resource_openstack_fw_policy_v1.go index ad096397b8..e9fc1645b1 100644 --- a/builtin/providers/openstack/resource_openstack_fw_policy_v2.go +++ b/builtin/providers/openstack/resource_openstack_fw_policy_v1.go @@ -11,12 +11,12 @@ import ( "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/fwaas/policies" ) -func resourceFWPolicyV2() *schema.Resource { +func resourceFWPolicyV1() *schema.Resource { return &schema.Resource{ - Create: resourceFirewallPolicyCreate, - Read: resourceFirewallPolicyRead, - Update: resourceFirewallPolicyUpdate, - Delete: resourceFirewallPolicyDelete, + Create: resourceFWPolicyV1Create, + Read: resourceFWPolicyV1Read, + Update: resourceFWPolicyV1Update, + Delete: resourceFWPolicyV1Delete, Schema: map[string]*schema.Schema{ "region": &schema.Schema{ @@ -60,7 +60,7 @@ func resourceFWPolicyV2() *schema.Resource { } } -func resourceFirewallPolicyCreate(d *schema.ResourceData, meta interface{}) error { +func resourceFWPolicyV1Create(d *schema.ResourceData, meta interface{}) error { // TODO To remove time.Sleep(time.Second * 5) @@ -107,7 +107,7 @@ func resourceFirewallPolicyCreate(d *schema.ResourceData, meta interface{}) erro return nil } -func resourceFirewallPolicyRead(d *schema.ResourceData, meta interface{}) error { +func resourceFWPolicyV1Read(d *schema.ResourceData, meta interface{}) error { log.Printf("[DEBUG] Retrieve information about firewall policy: %s", d.Id()) config := meta.(*Config) @@ -163,7 +163,7 @@ func resourceFirewallPolicyRead(d *schema.ResourceData, meta interface{}) error return nil } -func resourceFirewallPolicyUpdate(d *schema.ResourceData, meta interface{}) error { +func resourceFWPolicyV1Update(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) networkingClient, err := config.networkingV2Client(d.Get("region").(string)) @@ -199,7 +199,7 @@ func resourceFirewallPolicyUpdate(d *schema.ResourceData, meta interface{}) erro return policies.Update(networkingClient, d.Id(), opts).Err } -func resourceFirewallPolicyDelete(d *schema.ResourceData, meta interface{}) error { +func resourceFWPolicyV1Delete(d *schema.ResourceData, meta interface{}) error { log.Printf("[DEBUG] Destroy firewall policy: %s", d.Id()) config := meta.(*Config) diff --git a/builtin/providers/openstack/resource_openstack_fw_policy_v2_test.go b/builtin/providers/openstack/resource_openstack_fw_policy_v1_test.go similarity index 75% rename from builtin/providers/openstack/resource_openstack_fw_policy_v2_test.go rename to builtin/providers/openstack/resource_openstack_fw_policy_v1_test.go index ed268b7c31..1a37a383f7 100644 --- a/builtin/providers/openstack/resource_openstack_fw_policy_v2_test.go +++ b/builtin/providers/openstack/resource_openstack_fw_policy_v1_test.go @@ -11,33 +11,33 @@ import ( "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/fwaas/policies" ) -func TestAccOpenstackFirewallPolicy(t *testing.T) { +func TestAccFWPolicyV1(t *testing.T) { resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, - CheckDestroy: testAccCheckOpenstackFirewallPolicyDestroy, + CheckDestroy: testAccCheckFWPolicyV1Destroy, Steps: []resource.TestStep{ resource.TestStep{ Config: testFirewallPolicyConfig, Check: resource.ComposeTestCheckFunc( - testAccCheckFirewallPolicyExists( - "openstack_fw_policy_v2.accept_test", + testAccCheckFWPolicyV1Exists( + "openstack_fw_policy_v1.accept_test", "", "", 0), ), }, resource.TestStep{ Config: testFirewallPolicyConfigAddRules, Check: resource.ComposeTestCheckFunc( - testAccCheckFirewallPolicyExists( - "openstack_fw_policy_v2.accept_test", + testAccCheckFWPolicyV1Exists( + "openstack_fw_policy_v1.accept_test", "accept_test", "terraform acceptance test", 2), ), }, resource.TestStep{ Config: testFirewallPolicyUpdateDeleteRule, Check: resource.ComposeTestCheckFunc( - testAccCheckFirewallPolicyExists( - "openstack_fw_policy_v2.accept_test", + testAccCheckFWPolicyV1Exists( + "openstack_fw_policy_v1.accept_test", "accept_test", "terraform acceptance test", 1), ), }, @@ -45,7 +45,7 @@ func TestAccOpenstackFirewallPolicy(t *testing.T) { }) } -func testAccCheckOpenstackFirewallPolicyDestroy(s *terraform.State) error { +func testAccCheckFWPolicyV1Destroy(s *terraform.State) error { config := testAccProvider.Meta().(*Config) networkingClient, err := config.networkingV2Client(OS_REGION_NAME) @@ -53,7 +53,7 @@ func testAccCheckOpenstackFirewallPolicyDestroy(s *terraform.State) error { return fmt.Errorf("(testAccCheckOpenstackFirewallPolicyDestroy) Error creating OpenStack networking client: %s", err) } for _, rs := range s.RootModule().Resources { - if rs.Type != "openstack_fw_policy_v2" { + if rs.Type != "openstack_fw_policy_v1" { continue } _, err = policies.Get(networkingClient, rs.Primary.ID).Extract() @@ -68,7 +68,7 @@ func testAccCheckOpenstackFirewallPolicyDestroy(s *terraform.State) error { return nil } -func testAccCheckFirewallPolicyExists(n, name, description string, ruleCount int) resource.TestCheckFunc { +func testAccCheckFWPolicyV1Exists(n, name, description string, ruleCount int) resource.TestCheckFunc { return func(s *terraform.State) error { @@ -123,42 +123,42 @@ func testAccCheckFirewallPolicyExists(n, name, description string, ruleCount int } const testFirewallPolicyConfig = ` -resource "openstack_fw_policy_v2" "accept_test" { +resource "openstack_fw_policy_v1" "accept_test" { } ` const testFirewallPolicyConfigAddRules = ` -resource "openstack_fw_policy_v2" "accept_test" { +resource "openstack_fw_policy_v1" "accept_test" { name = "accept_test" description = "terraform acceptance test" rules = [ - "${openstack_fw_rule_v2.accept_test_udp_deny.id}", - "${openstack_fw_rule_v2.accept_test_tcp_allow.id}" + "${openstack_fw_rule_v1.accept_test_udp_deny.id}", + "${openstack_fw_rule_v1.accept_test_tcp_allow.id}" ] } -resource "openstack_fw_rule_v2" "accept_test_tcp_allow" { +resource "openstack_fw_rule_v1" "accept_test_tcp_allow" { protocol = "tcp" action = "allow" } -resource "openstack_fw_rule_v2" "accept_test_udp_deny" { +resource "openstack_fw_rule_v1" "accept_test_udp_deny" { protocol = "udp" action = "deny" } ` const testFirewallPolicyUpdateDeleteRule = ` -resource "openstack_fw_policy_v2" "accept_test" { +resource "openstack_fw_policy_v1" "accept_test" { name = "accept_test" description = "terraform acceptance test" rules = [ - "${openstack_fw_rule_v2.accept_test_udp_deny.id}" + "${openstack_fw_rule_v1.accept_test_udp_deny.id}" ] } -resource "openstack_fw_rule_v2" "accept_test_udp_deny" { +resource "openstack_fw_rule_v1" "accept_test_udp_deny" { protocol = "udp" action = "deny" } diff --git a/builtin/providers/openstack/resource_openstack_fw_rule_v2.go b/builtin/providers/openstack/resource_openstack_fw_rule_v1.go similarity index 92% rename from builtin/providers/openstack/resource_openstack_fw_rule_v2.go rename to builtin/providers/openstack/resource_openstack_fw_rule_v1.go index 9aa110757b..bd418e9b86 100644 --- a/builtin/providers/openstack/resource_openstack_fw_rule_v2.go +++ b/builtin/providers/openstack/resource_openstack_fw_rule_v1.go @@ -10,12 +10,12 @@ import ( "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/fwaas/rules" ) -func resourceFWRuleV2() *schema.Resource { +func resourceFWRuleV1() *schema.Resource { return &schema.Resource{ - Create: resourceFirewallRuleCreate, - Read: resourceFirewallRuleRead, - Update: resourceFirewallRuleUpdate, - Delete: resourceFirewallRuleDelete, + Create: resourceFWRuleV1Create, + Read: resourceFWRuleV1Read, + Update: resourceFWRuleV1Update, + Delete: resourceFWRuleV1Delete, Schema: map[string]*schema.Schema{ "region": &schema.Schema{ @@ -75,7 +75,7 @@ func resourceFWRuleV2() *schema.Resource { } } -func resourceFirewallRuleCreate(d *schema.ResourceData, meta interface{}) error { +func resourceFWRuleV1Create(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) networkingClient, err := config.networkingV2Client(d.Get("region").(string)) @@ -114,7 +114,7 @@ func resourceFirewallRuleCreate(d *schema.ResourceData, meta interface{}) error return nil } -func resourceFirewallRuleRead(d *schema.ResourceData, meta interface{}) error { +func resourceFWRuleV1Read(d *schema.ResourceData, meta interface{}) error { log.Printf("[DEBUG] Retrieve information about firewall rule: %s", d.Id()) config := meta.(*Config) @@ -191,7 +191,7 @@ func resourceFirewallRuleRead(d *schema.ResourceData, meta interface{}) error { return nil } -func resourceFirewallRuleUpdate(d *schema.ResourceData, meta interface{}) error { +func resourceFWRuleV1Update(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) networkingClient, err := config.networkingV2Client(d.Get("region").(string)) if err != nil { @@ -241,7 +241,7 @@ func resourceFirewallRuleUpdate(d *schema.ResourceData, meta interface{}) error return rules.Update(networkingClient, d.Id(), opts).Err } -func resourceFirewallRuleDelete(d *schema.ResourceData, meta interface{}) error { +func resourceFWRuleV1Delete(d *schema.ResourceData, meta interface{}) error { log.Printf("[DEBUG] Destroy firewall rule: %s", d.Id()) config := meta.(*Config) diff --git a/builtin/providers/openstack/resource_openstack_fw_rule_v2_test.go b/builtin/providers/openstack/resource_openstack_fw_rule_v1_test.go similarity index 86% rename from builtin/providers/openstack/resource_openstack_fw_rule_v2_test.go rename to builtin/providers/openstack/resource_openstack_fw_rule_v1_test.go index 748177375e..ba96bb8b19 100644 --- a/builtin/providers/openstack/resource_openstack_fw_rule_v2_test.go +++ b/builtin/providers/openstack/resource_openstack_fw_rule_v1_test.go @@ -12,17 +12,17 @@ import ( "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/fwaas/rules" ) -func TestAccOpenstackFirewallRule(t *testing.T) { +func TestAccFWRuleV1(t *testing.T) { resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, - CheckDestroy: testAccCheckOpenstackFirewallRuleDestroy, + CheckDestroy: testAccCheckFWRuleV1Destroy, Steps: []resource.TestStep{ resource.TestStep{ Config: testFirewallRuleMinimalConfig, Check: resource.ComposeTestCheckFunc( - testAccCheckFirewallRuleExists( - "openstack_fw_rule_v2.accept_test_minimal", + testAccCheckFWRuleV1Exists( + "openstack_fw_rule_v1.accept_test_minimal", &rules.Rule{ Protocol: "udp", Action: "deny", @@ -34,8 +34,8 @@ func TestAccOpenstackFirewallRule(t *testing.T) { resource.TestStep{ Config: testFirewallRuleConfig, Check: resource.ComposeTestCheckFunc( - testAccCheckFirewallRuleExists( - "openstack_fw_rule_v2.accept_test", + testAccCheckFWRuleV1Exists( + "openstack_fw_rule_v1.accept_test", &rules.Rule{ Name: "accept_test", Protocol: "udp", @@ -53,8 +53,8 @@ func TestAccOpenstackFirewallRule(t *testing.T) { resource.TestStep{ Config: testFirewallRuleUpdateAllFieldsConfig, Check: resource.ComposeTestCheckFunc( - testAccCheckFirewallRuleExists( - "openstack_fw_rule_v2.accept_test", + testAccCheckFWRuleV1Exists( + "openstack_fw_rule_v1.accept_test", &rules.Rule{ Name: "accept_test_updated_2", Protocol: "tcp", @@ -73,7 +73,7 @@ func TestAccOpenstackFirewallRule(t *testing.T) { }) } -func testAccCheckOpenstackFirewallRuleDestroy(s *terraform.State) error { +func testAccCheckFWRuleV1Destroy(s *terraform.State) error { config := testAccProvider.Meta().(*Config) networkingClient, err := config.networkingV2Client(OS_REGION_NAME) @@ -96,7 +96,7 @@ func testAccCheckOpenstackFirewallRuleDestroy(s *terraform.State) error { return nil } -func testAccCheckFirewallRuleExists(n string, expected *rules.Rule) resource.TestCheckFunc { +func testAccCheckFWRuleV1Exists(n string, expected *rules.Rule) resource.TestCheckFunc { return func(s *terraform.State) error { @@ -148,14 +148,14 @@ func testAccCheckFirewallRuleExists(n string, expected *rules.Rule) resource.Tes } const testFirewallRuleMinimalConfig = ` -resource "openstack_fw_rule_v2" "accept_test_minimal" { +resource "openstack_fw_rule_v1" "accept_test_minimal" { protocol = "udp" action = "deny" } ` const testFirewallRuleConfig = ` -resource "openstack_fw_rule_v2" "accept_test" { +resource "openstack_fw_rule_v1" "accept_test" { name = "accept_test" description = "Terraform accept test" protocol = "udp" @@ -170,7 +170,7 @@ resource "openstack_fw_rule_v2" "accept_test" { ` const testFirewallRuleUpdateAllFieldsConfig = ` -resource "openstack_fw_rule_v2" "accept_test" { +resource "openstack_fw_rule_v1" "accept_test" { name = "accept_test_updated_2" description = "Terraform accept test updated" protocol = "tcp" From bdeca31731ef0890c5cf162083185ae037d1b4dd Mon Sep 17 00:00:00 2001 From: Guillaume Giamarchi Date: Thu, 19 Feb 2015 23:31:19 +0100 Subject: [PATCH 126/132] remove boilerplate code using CheckDeleted --- .../openstack/resource_openstack_fw_firewall_v1.go | 12 ++---------- .../openstack/resource_openstack_fw_policy_v1.go | 10 +--------- .../openstack/resource_openstack_fw_rule_v1.go | 11 +---------- 3 files changed, 4 insertions(+), 29 deletions(-) diff --git a/builtin/providers/openstack/resource_openstack_fw_firewall_v1.go b/builtin/providers/openstack/resource_openstack_fw_firewall_v1.go index 21c93d33d2..732b416221 100644 --- a/builtin/providers/openstack/resource_openstack_fw_firewall_v1.go +++ b/builtin/providers/openstack/resource_openstack_fw_firewall_v1.go @@ -105,17 +105,9 @@ func resourceFWFirewallV1Read(d *schema.ResourceData, meta interface{}) error { } firewall, err := firewalls.Get(networkingClient, d.Id()).Extract() - if err != nil { - httpError, ok := err.(*gophercloud.UnexpectedResponseCodeError) - if !ok { - return err - } - if httpError.Actual == 404 { - d.SetId("") - return nil - } - return err + if err != nil { + return CheckDeleted(d, err, "LB pool") } if t, exists := d.GetOk("name"); exists && t != "" { diff --git a/builtin/providers/openstack/resource_openstack_fw_policy_v1.go b/builtin/providers/openstack/resource_openstack_fw_policy_v1.go index e9fc1645b1..7837e5a434 100644 --- a/builtin/providers/openstack/resource_openstack_fw_policy_v1.go +++ b/builtin/providers/openstack/resource_openstack_fw_policy_v1.go @@ -119,15 +119,7 @@ func resourceFWPolicyV1Read(d *schema.ResourceData, meta interface{}) error { policy, err := policies.Get(networkingClient, d.Id()).Extract() if err != nil { - httpError, ok := err.(*gophercloud.UnexpectedResponseCodeError) - if !ok { - return err - } - if httpError.Actual == 404 { - d.SetId("") - return nil - } - return err + return CheckDeleted(d, err, "LB pool") } if t, exists := d.GetOk("name"); exists && t != "" { diff --git a/builtin/providers/openstack/resource_openstack_fw_rule_v1.go b/builtin/providers/openstack/resource_openstack_fw_rule_v1.go index bd418e9b86..607d02b21e 100644 --- a/builtin/providers/openstack/resource_openstack_fw_rule_v1.go +++ b/builtin/providers/openstack/resource_openstack_fw_rule_v1.go @@ -5,7 +5,6 @@ import ( "log" "github.com/hashicorp/terraform/helper/schema" - "github.com/rackspace/gophercloud" "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/fwaas/policies" "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/fwaas/rules" ) @@ -126,15 +125,7 @@ func resourceFWRuleV1Read(d *schema.ResourceData, meta interface{}) error { rule, err := rules.Get(networkingClient, d.Id()).Extract() if err != nil { - httpError, ok := err.(*gophercloud.UnexpectedResponseCodeError) - if !ok { - return err - } - if httpError.Actual == 404 { - d.SetId("") - return nil - } - return err + return CheckDeleted(d, err, "LB pool") } d.Set("protocol", rule.Protocol) From 83160acf69c4752d86fd8fd15b34a1035a1fa5f9 Mon Sep 17 00:00:00 2001 From: Guillaume Giamarchi Date: Thu, 19 Feb 2015 23:44:49 +0100 Subject: [PATCH 127/132] Return Read call result in Create & Update --- .../openstack/resource_openstack_fw_firewall_v1.go | 9 +++++++-- .../openstack/resource_openstack_fw_policy_v1.go | 9 +++++++-- .../providers/openstack/resource_openstack_fw_rule_v1.go | 9 +++++++-- 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/builtin/providers/openstack/resource_openstack_fw_firewall_v1.go b/builtin/providers/openstack/resource_openstack_fw_firewall_v1.go index 732b416221..9d57643572 100644 --- a/builtin/providers/openstack/resource_openstack_fw_firewall_v1.go +++ b/builtin/providers/openstack/resource_openstack_fw_firewall_v1.go @@ -92,7 +92,7 @@ func resourceFWFirewallV1Create(d *schema.ResourceData, meta interface{}) error d.SetId(firewall.ID) - return nil + return resourceFWFirewallV1Read(d, meta) } func resourceFWFirewallV1Read(d *schema.ResourceData, meta interface{}) error { @@ -183,7 +183,12 @@ func resourceFWFirewallV1Update(d *schema.ResourceData, meta interface{}) error _, err = stateConf.WaitForState() - return firewalls.Update(networkingClient, d.Id(), opts).Err + err = firewalls.Update(networkingClient, d.Id(), opts).Err + if err != nil { + return err + } + + return resourceFWFirewallV1Read(d, meta) } func resourceFWFirewallV1Delete(d *schema.ResourceData, meta interface{}) error { diff --git a/builtin/providers/openstack/resource_openstack_fw_policy_v1.go b/builtin/providers/openstack/resource_openstack_fw_policy_v1.go index 7837e5a434..8150597523 100644 --- a/builtin/providers/openstack/resource_openstack_fw_policy_v1.go +++ b/builtin/providers/openstack/resource_openstack_fw_policy_v1.go @@ -104,7 +104,7 @@ func resourceFWPolicyV1Create(d *schema.ResourceData, meta interface{}) error { d.SetId(policy.ID) - return nil + return resourceFWPolicyV1Read(d, meta) } func resourceFWPolicyV1Read(d *schema.ResourceData, meta interface{}) error { @@ -188,7 +188,12 @@ func resourceFWPolicyV1Update(d *schema.ResourceData, meta interface{}) error { log.Printf("[DEBUG] Updating firewall policy with id %s: %#v", d.Id(), opts) - return policies.Update(networkingClient, d.Id(), opts).Err + err = policies.Update(networkingClient, d.Id(), opts).Err + if err != nil { + return err + } + + return resourceFWPolicyV1Read(d, meta) } func resourceFWPolicyV1Delete(d *schema.ResourceData, meta interface{}) error { diff --git a/builtin/providers/openstack/resource_openstack_fw_rule_v1.go b/builtin/providers/openstack/resource_openstack_fw_rule_v1.go index 607d02b21e..f4dbb2fc7e 100644 --- a/builtin/providers/openstack/resource_openstack_fw_rule_v1.go +++ b/builtin/providers/openstack/resource_openstack_fw_rule_v1.go @@ -110,7 +110,7 @@ func resourceFWRuleV1Create(d *schema.ResourceData, meta interface{}) error { d.SetId(rule.ID) - return nil + return resourceFWRuleV1Read(d, meta) } func resourceFWRuleV1Read(d *schema.ResourceData, meta interface{}) error { @@ -229,7 +229,12 @@ func resourceFWRuleV1Update(d *schema.ResourceData, meta interface{}) error { log.Printf("[DEBUG] Updating firewall rules: %#v", opts) - return rules.Update(networkingClient, d.Id(), opts).Err + err = rules.Update(networkingClient, d.Id(), opts).Err + if err != nil { + return err + } + + return resourceFWRuleV1Read(d, meta) } func resourceFWRuleV1Delete(d *schema.ResourceData, meta interface{}) error { From ba880b136bee77159ab98bde438ed61d76ec3949 Mon Sep 17 00:00:00 2001 From: Guillaume Giamarchi Date: Thu, 19 Feb 2015 23:53:30 +0100 Subject: [PATCH 128/132] Code clean-up --- .../providers/openstack/resource_openstack_fw_firewall_v1.go | 3 +-- builtin/providers/openstack/resource_openstack_fw_policy_v1.go | 3 --- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/builtin/providers/openstack/resource_openstack_fw_firewall_v1.go b/builtin/providers/openstack/resource_openstack_fw_firewall_v1.go index 9d57643572..16b2014a72 100644 --- a/builtin/providers/openstack/resource_openstack_fw_firewall_v1.go +++ b/builtin/providers/openstack/resource_openstack_fw_firewall_v1.go @@ -1,7 +1,6 @@ package openstack import ( - "errors" "fmt" "log" "time" @@ -258,7 +257,7 @@ func waitForFirewallDeletion(networkingClient *gophercloud.ServiceClient, id str log.Printf("[DEBUG] Firewall %s is actually deleted", id) return "", "DELETED", nil } - return nil, "", errors.New(fmt.Sprintf("Unexpected status code %d", httpStatus.Actual)) + return nil, "", fmt.Errorf("Unexpected status code %d", httpStatus.Actual) } log.Printf("[DEBUG] Firewall %s deletion is pending", id) diff --git a/builtin/providers/openstack/resource_openstack_fw_policy_v1.go b/builtin/providers/openstack/resource_openstack_fw_policy_v1.go index 8150597523..e58b994fc7 100644 --- a/builtin/providers/openstack/resource_openstack_fw_policy_v1.go +++ b/builtin/providers/openstack/resource_openstack_fw_policy_v1.go @@ -62,9 +62,6 @@ func resourceFWPolicyV1() *schema.Resource { func resourceFWPolicyV1Create(d *schema.ResourceData, meta interface{}) error { - // TODO To remove - time.Sleep(time.Second * 5) - config := meta.(*Config) networkingClient, err := config.networkingV2Client(d.Get("region").(string)) if err != nil { From f5feb7fbbb4f8db0b7ae88e17e8aad27d7c5dc8a Mon Sep 17 00:00:00 2001 From: Joe Topjian Date: Wed, 4 Mar 2015 04:41:15 +0000 Subject: [PATCH 129/132] Allows "self" to be discovered and recorded correctly. --- .../resource_openstack_compute_secgroup_v2.go | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/builtin/providers/openstack/resource_openstack_compute_secgroup_v2.go b/builtin/providers/openstack/resource_openstack_compute_secgroup_v2.go index cf00f7f1b8..3860dc69c0 100644 --- a/builtin/providers/openstack/resource_openstack_compute_secgroup_v2.go +++ b/builtin/providers/openstack/resource_openstack_compute_secgroup_v2.go @@ -72,6 +72,7 @@ func resourceComputeSecGroupV2() *schema.Resource { "self": &schema.Schema{ Type: schema.TypeBool, Optional: true, + Default: false, ForceNew: false, }, }, @@ -126,8 +127,16 @@ func resourceComputeSecGroupV2Read(d *schema.ResourceData, meta interface{}) err d.Set("region", d.Get("region").(string)) d.Set("name", sg.Name) d.Set("description", sg.Description) - log.Printf("[DEBUG] rulesToMap(sg.Rules): %+v", rulesToMap(sg.Rules)) - d.Set("rule", rulesToMap(sg.Rules)) + rtm := rulesToMap(sg.Rules) + for _, v := range rtm { + if v["group"] == d.Get("name") { + v["self"] = "1" + } else { + v["self"] = "0" + } + } + log.Printf("[DEBUG] rulesToMap(sg.Rules): %+v", rtm) + d.Set("rule", rtm) return nil } @@ -267,6 +276,7 @@ func rulesToMap(sgrs []secgroups.Rule) []map[string]interface{} { "to_port": sgr.ToPort, "ip_protocol": sgr.IPProtocol, "cidr": sgr.IPRange.CIDR, + "group": sgr.Group.Name, } } return sgrMap From f011462e30ff9be274cc54872701fba67e42e3e7 Mon Sep 17 00:00:00 2001 From: Joe Topjian Date: Fri, 13 Mar 2015 22:24:13 +0000 Subject: [PATCH 130/132] Volume Pending States This commit adds pending states for volume attachment, detachment, and deletion. --- .../openstack/resource_openstack_blockstorage_volume_v1.go | 4 ++-- .../openstack/resource_openstack_compute_instance_v2.go | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/builtin/providers/openstack/resource_openstack_blockstorage_volume_v1.go b/builtin/providers/openstack/resource_openstack_blockstorage_volume_v1.go index eefd75f7ec..598640b82f 100644 --- a/builtin/providers/openstack/resource_openstack_blockstorage_volume_v1.go +++ b/builtin/providers/openstack/resource_openstack_blockstorage_volume_v1.go @@ -264,7 +264,7 @@ func resourceBlockStorageVolumeV1Delete(d *schema.ResourceData, meta interface{} } stateConf := &resource.StateChangeConf{ - Pending: []string{"in-use"}, + Pending: []string{"in-use", "attaching"}, Target: "available", Refresh: VolumeV1StateRefreshFunc(blockStorageClient, d.Id()), Timeout: 10 * time.Minute, @@ -290,7 +290,7 @@ func resourceBlockStorageVolumeV1Delete(d *schema.ResourceData, meta interface{} log.Printf("[DEBUG] Waiting for volume (%s) to delete", d.Id()) stateConf := &resource.StateChangeConf{ - Pending: []string{"deleting"}, + Pending: []string{"deleting", "available"}, Target: "deleted", Refresh: VolumeV1StateRefreshFunc(blockStorageClient, d.Id()), Timeout: 10 * time.Minute, diff --git a/builtin/providers/openstack/resource_openstack_compute_instance_v2.go b/builtin/providers/openstack/resource_openstack_compute_instance_v2.go index 3488069312..90b64ed1d3 100644 --- a/builtin/providers/openstack/resource_openstack_compute_instance_v2.go +++ b/builtin/providers/openstack/resource_openstack_compute_instance_v2.go @@ -944,6 +944,7 @@ func attachVolumesToInstance(computeClient *gophercloud.ServiceClient, blockClie } stateConf := &resource.StateChangeConf{ + Pending: []string{"attaching", "available"}, Target: "in-use", Refresh: VolumeV1StateRefreshFunc(blockClient, va["volume_id"].(string)), Timeout: 30 * time.Minute, @@ -972,6 +973,7 @@ func detachVolumesFromInstance(computeClient *gophercloud.ServiceClient, blockCl } stateConf := &resource.StateChangeConf{ + Pending: []string{"detaching", "in-use"}, Target: "available", Refresh: VolumeV1StateRefreshFunc(blockClient, va["volume_id"].(string)), Timeout: 30 * time.Minute, From 2e37784065dac7b024618f887c7966835efe5b22 Mon Sep 17 00:00:00 2001 From: Julien Vey Date: Tue, 24 Mar 2015 13:59:55 +0100 Subject: [PATCH 131/132] Fix general comments by @phinze --- ...source_openstack_blockstorage_volume_v1.go | 47 +++------------- ...esource_openstack_compute_floatingip_v2.go | 9 +-- .../resource_openstack_compute_instance_v2.go | 6 +- .../resource_openstack_compute_keypair_v2.go | 3 +- .../resource_openstack_compute_secgroup_v2.go | 2 +- .../resource_openstack_fw_firewall_v1.go | 34 ++---------- .../resource_openstack_fw_policy_v1.go | 37 ++----------- .../resource_openstack_fw_rule_v1.go | 55 +++---------------- .../resource_openstack_lb_monitor_v1.go | 38 ++----------- .../resource_openstack_lb_pool_v1.go | 11 +--- .../openstack/resource_openstack_lb_vip_v1.go | 3 +- ...urce_openstack_networking_floatingip_v2.go | 8 ++- ...esource_openstack_networking_network_v2.go | 31 ++--------- ...penstack_networking_router_interface_v2.go | 4 +- ...resource_openstack_networking_router_v2.go | 31 ++--------- ...resource_openstack_networking_subnet_v2.go | 46 +++------------- ...ce_openstack_objectstorage_container_v1.go | 2 +- 17 files changed, 67 insertions(+), 300 deletions(-) diff --git a/builtin/providers/openstack/resource_openstack_blockstorage_volume_v1.go b/builtin/providers/openstack/resource_openstack_blockstorage_volume_v1.go index 598640b82f..dc26385908 100644 --- a/builtin/providers/openstack/resource_openstack_blockstorage_volume_v1.go +++ b/builtin/providers/openstack/resource_openstack_blockstorage_volume_v1.go @@ -111,7 +111,7 @@ func resourceBlockStorageVolumeV1Create(d *schema.ResourceData, meta interface{} Metadata: resourceContainerMetadataV2(d), } - log.Printf("[INFO] Requesting volume creation") + log.Printf("[DEBUG] Create Options: %#v", createOpts) v, err := volumes.Create(blockStorageClient, createOpts).Extract() if err != nil { return fmt.Errorf("Error creating OpenStack volume: %s", err) @@ -156,48 +156,15 @@ func resourceBlockStorageVolumeV1Read(d *schema.ResourceData, meta interface{}) return CheckDeleted(d, err, "volume") } - log.Printf("\n\ngot volume: %+v\n\n", v) - log.Printf("[DEBUG] Retreived volume %s: %+v", d.Id(), v) - d.Set("region", d.Get("region").(string)) d.Set("size", v.Size) - - if t, exists := d.GetOk("description"); exists && t != "" { - d.Set("description", v.Description) - } else { - d.Set("description", "") - } - - if t, exists := d.GetOk("name"); exists && t != "" { - d.Set("name", v.Name) - } else { - d.Set("name", "") - } - - if t, exists := d.GetOk("snapshot_id"); exists && t != "" { - d.Set("snapshot_id", v.SnapshotID) - } else { - d.Set("snapshot_id", "") - } - - if t, exists := d.GetOk("source_vol_id"); exists && t != "" { - d.Set("source_vol_id", v.SourceVolID) - } else { - d.Set("source_vol_id", "") - } - - if t, exists := d.GetOk("volume_type"); exists && t != "" { - d.Set("volume_type", v.VolumeType) - } else { - d.Set("volume_type", "") - } - - if t, exists := d.GetOk("metadata"); exists && t != "" { - d.Set("metadata", v.Metadata) - } else { - d.Set("metadata", "") - } + d.Set("description", v.Description) + d.Set("name", v.Name) + d.Set("snapshot_id", v.SnapshotID) + d.Set("source_vol_id", v.SourceVolID) + d.Set("volume_type", v.VolumeType) + d.Set("metadata", v.Metadata) if len(v.Attachments) > 0 { attachments := make([]map[string]interface{}, len(v.Attachments)) diff --git a/builtin/providers/openstack/resource_openstack_compute_floatingip_v2.go b/builtin/providers/openstack/resource_openstack_compute_floatingip_v2.go index 3501fe2822..bb2facc4ee 100644 --- a/builtin/providers/openstack/resource_openstack_compute_floatingip_v2.go +++ b/builtin/providers/openstack/resource_openstack_compute_floatingip_v2.go @@ -30,12 +30,6 @@ func resourceComputeFloatingIPV2() *schema.Resource { DefaultFunc: envDefaultFunc("OS_POOL_NAME"), }, - // exported - "id": &schema.Schema{ - Type: schema.TypeString, - Computed: true, - }, - "address": &schema.Schema{ Type: schema.TypeString, Computed: true, @@ -64,6 +58,7 @@ func resourceComputeFloatingIPV2Create(d *schema.ResourceData, meta interface{}) createOpts := &floatingip.CreateOpts{ Pool: d.Get("pool").(string), } + log.Printf("[DEBUG] Create Options: %#v", createOpts) newFip, err := floatingip.Create(computeClient, createOpts).Extract() if err != nil { return fmt.Errorf("Error creating Floating IP: %s", err) @@ -88,8 +83,6 @@ func resourceComputeFloatingIPV2Read(d *schema.ResourceData, meta interface{}) e log.Printf("[DEBUG] Retrieved Floating IP %s: %+v", d.Id(), fip) - d.Set("id", d.Id()) - d.Set("region", d.Get("region").(string)) d.Set("pool", fip.Pool) d.Set("instance_id", fip.InstanceID) d.Set("address", fip.IP) diff --git a/builtin/providers/openstack/resource_openstack_compute_instance_v2.go b/builtin/providers/openstack/resource_openstack_compute_instance_v2.go index 90b64ed1d3..63508ffa72 100644 --- a/builtin/providers/openstack/resource_openstack_compute_instance_v2.go +++ b/builtin/providers/openstack/resource_openstack_compute_instance_v2.go @@ -241,7 +241,7 @@ func resourceComputeInstanceV2Create(d *schema.ResourceData, meta interface{}) e } } - log.Printf("[INFO] Requesting instance creation") + log.Printf("[DEBUG] Create Options: %#v", createOpts) server, err := servers.Create(computeClient, createOpts).Extract() if err != nil { return fmt.Errorf("Error creating OpenStack server: %s", err) @@ -320,7 +320,6 @@ func resourceComputeInstanceV2Read(d *schema.ResourceData, meta interface{}) err log.Printf("[DEBUG] Retreived Server %s: %+v", d.Id(), server) - d.Set("region", d.Get("region").(string)) d.Set("name", server.Name) d.Set("access_ip_v4", server.AccessIPv4) d.Set("access_ip_v6", server.AccessIPv6) @@ -360,7 +359,7 @@ func resourceComputeInstanceV2Read(d *schema.ResourceData, meta interface{}) err publicAddresses := publicAddressesRaw.([]interface{}) for _, paRaw := range publicAddresses { pa := paRaw.(map[string]interface{}) - if pa["version"].(float64) == 4 { + if pa["version"].(float64) == 6 { hostv6 = fmt.Sprintf("[%s]", pa["addr"].(string)) break } @@ -594,6 +593,7 @@ func resourceComputeInstanceV2Update(d *schema.ResourceData, meta interface{}) e resizeOpts := &servers.ResizeOpts{ FlavorRef: flavorId, } + log.Printf("[DEBUG] Resize configuration: %#v", resizeOpts) err = servers.Resize(computeClient, d.Id(), resizeOpts).ExtractErr() if err != nil { return fmt.Errorf("Error resizing OpenStack server: %s", err) diff --git a/builtin/providers/openstack/resource_openstack_compute_keypair_v2.go b/builtin/providers/openstack/resource_openstack_compute_keypair_v2.go index 9c1417412e..db6bed5b2f 100644 --- a/builtin/providers/openstack/resource_openstack_compute_keypair_v2.go +++ b/builtin/providers/openstack/resource_openstack_compute_keypair_v2.go @@ -2,6 +2,7 @@ package openstack import ( "fmt" + "log" "github.com/hashicorp/terraform/helper/schema" "github.com/rackspace/gophercloud/openstack/compute/v2/extensions/keypairs" @@ -46,6 +47,7 @@ func resourceComputeKeypairV2Create(d *schema.ResourceData, meta interface{}) er PublicKey: d.Get("public_key").(string), } + log.Printf("[DEBUG] Create Options: %#v", createOpts) kp, err := keypairs.Create(computeClient, createOpts).Extract() if err != nil { return fmt.Errorf("Error creating OpenStack keypair: %s", err) @@ -68,7 +70,6 @@ func resourceComputeKeypairV2Read(d *schema.ResourceData, meta interface{}) erro return CheckDeleted(d, err, "keypair") } - d.Set("region", d.Get("region").(string)) d.Set("name", kp.Name) d.Set("public_key", kp.PublicKey) diff --git a/builtin/providers/openstack/resource_openstack_compute_secgroup_v2.go b/builtin/providers/openstack/resource_openstack_compute_secgroup_v2.go index 3860dc69c0..ca646d77d2 100644 --- a/builtin/providers/openstack/resource_openstack_compute_secgroup_v2.go +++ b/builtin/providers/openstack/resource_openstack_compute_secgroup_v2.go @@ -94,6 +94,7 @@ func resourceComputeSecGroupV2Create(d *schema.ResourceData, meta interface{}) e Description: d.Get("description").(string), } + log.Printf("[DEBUG] Create Options: %#v", createOpts) sg, err := secgroups.Create(computeClient, createOpts).Extract() if err != nil { return fmt.Errorf("Error creating OpenStack security group: %s", err) @@ -124,7 +125,6 @@ func resourceComputeSecGroupV2Read(d *schema.ResourceData, meta interface{}) err return CheckDeleted(d, err, "security group") } - d.Set("region", d.Get("region").(string)) d.Set("name", sg.Name) d.Set("description", sg.Description) rtm := rulesToMap(sg.Rules) diff --git a/builtin/providers/openstack/resource_openstack_fw_firewall_v1.go b/builtin/providers/openstack/resource_openstack_fw_firewall_v1.go index 16b2014a72..8505ac3b3a 100644 --- a/builtin/providers/openstack/resource_openstack_fw_firewall_v1.go +++ b/builtin/providers/openstack/resource_openstack_fw_firewall_v1.go @@ -109,35 +109,11 @@ func resourceFWFirewallV1Read(d *schema.ResourceData, meta interface{}) error { return CheckDeleted(d, err, "LB pool") } - if t, exists := d.GetOk("name"); exists && t != "" { - d.Set("name", firewall.Name) - } else { - d.Set("name", "") - } - - if t, exists := d.GetOk("description"); exists && t != "" { - d.Set("description", firewall.Description) - } else { - d.Set("description", "") - } - - if t, exists := d.GetOk("policy_id"); exists && t != "" { - d.Set("policy_id", firewall.PolicyID) - } else { - d.Set("policy_id", "") - } - - if t, exists := d.GetOk("admin_state_up"); exists && t != "" { - d.Set("admin_state_up", firewall.AdminStateUp) - } else { - d.Set("admin_state_up", "") - } - - if t, exists := d.GetOk("tenant_id"); exists && t != "" { - d.Set("tenant_id", firewall.TenantID) - } else { - d.Set("tenant_id", "") - } + d.Set("name", firewall.Name) + d.Set("description", firewall.Description) + d.Set("policy_id", firewall.PolicyID) + d.Set("admin_state_up", firewall.AdminStateUp) + d.Set("tenant_id", firewall.TenantID) return nil } diff --git a/builtin/providers/openstack/resource_openstack_fw_policy_v1.go b/builtin/providers/openstack/resource_openstack_fw_policy_v1.go index e58b994fc7..0560bfcef6 100644 --- a/builtin/providers/openstack/resource_openstack_fw_policy_v1.go +++ b/builtin/providers/openstack/resource_openstack_fw_policy_v1.go @@ -97,7 +97,7 @@ func resourceFWPolicyV1Create(d *schema.ResourceData, meta interface{}) error { return err } - log.Printf("[DEBUG] Firewall policy craeted: %#v", policy) + log.Printf("[DEBUG] Firewall policy created: %#v", policy) d.SetId(policy.ID) @@ -119,36 +119,11 @@ func resourceFWPolicyV1Read(d *schema.ResourceData, meta interface{}) error { return CheckDeleted(d, err, "LB pool") } - if t, exists := d.GetOk("name"); exists && t != "" { - d.Set("name", policy.Name) - } else { - d.Set("name", "") - } - - if t, exists := d.GetOk("description"); exists && t != "" { - d.Set("description", policy.Description) - } else { - d.Set("description", "") - } - - if t, exists := d.GetOk("shared"); exists && t != "" { - d.Set("shared", policy.Shared) - } else { - d.Set("shared", "") - } - - if t, exists := d.GetOk("audited"); exists && t != "" { - d.Set("audited", policy.Audited) - } else { - d.Set("audited", "") - } - - if t, exists := d.GetOk("tenant_id"); exists && t != "" { - d.Set("tenant_id", policy.TenantID) - } else { - d.Set("tenant_id", "") - } - + d.Set("name", policy.Name) + d.Set("description", policy.Description) + d.Set("shared", policy.Shared) + d.Set("audited", policy.Audited) + d.Set("tenant_id", policy.TenantID) return nil } diff --git a/builtin/providers/openstack/resource_openstack_fw_rule_v1.go b/builtin/providers/openstack/resource_openstack_fw_rule_v1.go index f4dbb2fc7e..f0f5affcc0 100644 --- a/builtin/providers/openstack/resource_openstack_fw_rule_v1.go +++ b/builtin/providers/openstack/resource_openstack_fw_rule_v1.go @@ -131,53 +131,14 @@ func resourceFWRuleV1Read(d *schema.ResourceData, meta interface{}) error { d.Set("protocol", rule.Protocol) d.Set("action", rule.Action) - if t, exists := d.GetOk("name"); exists && t != "" { - d.Set("name", rule.Name) - } else { - d.Set("name", "") - } - - if t, exists := d.GetOk("description"); exists && t != "" { - d.Set("description", rule.Description) - } else { - d.Set("description", "") - } - - if t, exists := d.GetOk("ip_version"); exists && t != "" { - d.Set("ip_version", rule.IPVersion) - } else { - d.Set("ip_version", "") - } - - if t, exists := d.GetOk("source_ip_address"); exists && t != "" { - d.Set("source_ip_address", rule.SourceIPAddress) - } else { - d.Set("source_ip_address", "") - } - - if t, exists := d.GetOk("destination_ip_address"); exists && t != "" { - d.Set("destination_ip_address", rule.DestinationIPAddress) - } else { - d.Set("destination_ip_address", "") - } - - if t, exists := d.GetOk("source_port"); exists && t != "" { - d.Set("source_port", rule.SourcePort) - } else { - d.Set("source_port", "") - } - - if t, exists := d.GetOk("destination_port"); exists && t != "" { - d.Set("destination_port", rule.DestinationPort) - } else { - d.Set("destination_port", "") - } - - if t, exists := d.GetOk("enabled"); exists && t != "" { - d.Set("enabled", rule.Enabled) - } else { - d.Set("enabled", "") - } + d.Set("name", rule.Name) + d.Set("description", rule.Description) + d.Set("ip_version", rule.IPVersion) + d.Set("source_ip_address", rule.SourceIPAddress) + d.Set("destination_ip_address", rule.DestinationIPAddress) + d.Set("source_port", rule.SourcePort) + d.Set("destination_port", rule.DestinationPort) + d.Set("enabled", rule.Enabled) return nil } diff --git a/builtin/providers/openstack/resource_openstack_lb_monitor_v1.go b/builtin/providers/openstack/resource_openstack_lb_monitor_v1.go index 0761ec1f42..cdfd54ccc1 100644 --- a/builtin/providers/openstack/resource_openstack_lb_monitor_v1.go +++ b/builtin/providers/openstack/resource_openstack_lb_monitor_v1.go @@ -99,7 +99,7 @@ func resourceLBMonitorV1Create(d *schema.ResourceData, meta interface{}) error { createOpts.AdminStateUp = &asu } - log.Printf("[INFO] Requesting lb monitor creation") + log.Printf("[DEBUG] Create Options: %#v", createOpts) m, err := monitors.Create(networkingClient, createOpts).Extract() if err != nil { return fmt.Errorf("Error creating OpenStack LB Monitor: %s", err) @@ -125,41 +125,15 @@ func resourceLBMonitorV1Read(d *schema.ResourceData, meta interface{}) error { log.Printf("[DEBUG] Retreived OpenStack LB Monitor %s: %+v", d.Id(), m) - d.Set("region", d.Get("region").(string)) d.Set("type", m.Type) d.Set("delay", m.Delay) d.Set("timeout", m.Timeout) d.Set("max_retries", m.MaxRetries) - - if t, exists := d.GetOk("tenant_id"); exists && t != "" { - d.Set("tenant_id", m.TenantID) - } else { - d.Set("tenant_id", "") - } - - if t, exists := d.GetOk("url_path"); exists && t != "" { - d.Set("url_path", m.URLPath) - } else { - d.Set("url_path", "") - } - - if t, exists := d.GetOk("http_method"); exists && t != "" { - d.Set("http_method", m.HTTPMethod) - } else { - d.Set("http_method", "") - } - - if t, exists := d.GetOk("expected_codes"); exists && t != "" { - d.Set("expected_codes", m.ExpectedCodes) - } else { - d.Set("expected_codes", "") - } - - if t, exists := d.GetOk("admin_state_up"); exists && t != "" { - d.Set("admin_state_up", strconv.FormatBool(m.AdminStateUp)) - } else { - d.Set("admin_state_up", "") - } + d.Set("tenant_id", m.TenantID) + d.Set("url_path", m.URLPath) + d.Set("http_method", m.HTTPMethod) + d.Set("expected_codes", m.ExpectedCodes) + d.Set("admin_state_up", strconv.FormatBool(m.AdminStateUp)) return nil } diff --git a/builtin/providers/openstack/resource_openstack_lb_pool_v1.go b/builtin/providers/openstack/resource_openstack_lb_pool_v1.go index 7e3abdbf7e..6b69f2fac1 100644 --- a/builtin/providers/openstack/resource_openstack_lb_pool_v1.go +++ b/builtin/providers/openstack/resource_openstack_lb_pool_v1.go @@ -115,7 +115,7 @@ func resourceLBPoolV1Create(d *schema.ResourceData, meta interface{}) error { TenantID: d.Get("tenant_id").(string), } - log.Printf("[INFO] Requesting lb pool creation") + log.Printf("[DEBUG] Create Options: %#v", createOpts) p, err := pools.Create(networkingClient, createOpts).Extract() if err != nil { return fmt.Errorf("Error creating OpenStack LB pool: %s", err) @@ -159,18 +159,11 @@ func resourceLBPoolV1Read(d *schema.ResourceData, meta interface{}) error { log.Printf("[DEBUG] Retreived OpenStack LB Pool %s: %+v", d.Id(), p) - d.Set("region", d.Get("region").(string)) d.Set("name", p.Name) d.Set("protocol", p.Protocol) d.Set("subnet_id", p.SubnetID) d.Set("lb_method", p.LBMethod) - - if t, exists := d.GetOk("tenant_id"); exists && t != "" { - d.Set("tenant_id", p.TenantID) - } else { - d.Set("tenant_id", "") - } - + d.Set("tenant_id", p.TenantID) d.Set("monitor_ids", p.MonitorIDs) d.Set("member_ids", p.MemberIDs) diff --git a/builtin/providers/openstack/resource_openstack_lb_vip_v1.go b/builtin/providers/openstack/resource_openstack_lb_vip_v1.go index 6181bc8a5e..bd2ae135e4 100644 --- a/builtin/providers/openstack/resource_openstack_lb_vip_v1.go +++ b/builtin/providers/openstack/resource_openstack_lb_vip_v1.go @@ -112,7 +112,7 @@ func resourceLBVipV1Create(d *schema.ResourceData, meta interface{}) error { createOpts.AdminStateUp = &asu } - log.Printf("[INFO] Requesting lb vip creation") + log.Printf("[DEBUG] Create Options: %#v", createOpts) p, err := vips.Create(networkingClient, createOpts).Extract() if err != nil { return fmt.Errorf("Error creating OpenStack LB VIP: %s", err) @@ -138,7 +138,6 @@ func resourceLBVipV1Read(d *schema.ResourceData, meta interface{}) error { log.Printf("[DEBUG] Retreived OpenStack LB VIP %s: %+v", d.Id(), p) - d.Set("region", d.Get("region").(string)) d.Set("name", p.Name) d.Set("subnet_id", p.SubnetID) d.Set("protocol", p.Protocol) diff --git a/builtin/providers/openstack/resource_openstack_networking_floatingip_v2.go b/builtin/providers/openstack/resource_openstack_networking_floatingip_v2.go index fb49657687..cbc4307648 100644 --- a/builtin/providers/openstack/resource_openstack_networking_floatingip_v2.go +++ b/builtin/providers/openstack/resource_openstack_networking_floatingip_v2.go @@ -2,6 +2,7 @@ package openstack import ( "fmt" + "log" "github.com/hashicorp/terraform/helper/schema" "github.com/rackspace/gophercloud/openstack/networking/v2/extensions/layer3/floatingips" @@ -49,9 +50,11 @@ func resourceNetworkFloatingIPV2Create(d *schema.ResourceData, meta interface{}) if len(poolID) == 0 { return fmt.Errorf("No network found with name: %s", d.Get("pool").(string)) } - floatingIP, err := floatingips.Create(networkClient, floatingips.CreateOpts{ + createOpts := floatingips.CreateOpts{ FloatingNetworkID: poolID, - }).Extract() + } + log.Printf("[DEBUG] Create Options: %#v", createOpts) + floatingIP, err := floatingips.Create(networkClient, createOpts).Extract() if err != nil { return fmt.Errorf("Error allocating floating IP: %s", err) } @@ -73,7 +76,6 @@ func resourceNetworkFloatingIPV2Read(d *schema.ResourceData, meta interface{}) e return CheckDeleted(d, err, "floating IP") } - d.Set("region", d.Get("region").(string)) d.Set("address", floatingIP.FloatingIP) poolName, err := getNetworkName(d, meta, floatingIP.FloatingNetworkID) if err != nil { diff --git a/builtin/providers/openstack/resource_openstack_networking_network_v2.go b/builtin/providers/openstack/resource_openstack_networking_network_v2.go index bf556f4185..2ac4ab94eb 100644 --- a/builtin/providers/openstack/resource_openstack_networking_network_v2.go +++ b/builtin/providers/openstack/resource_openstack_networking_network_v2.go @@ -77,7 +77,7 @@ func resourceNetworkingNetworkV2Create(d *schema.ResourceData, meta interface{}) createOpts.Shared = &shared } - log.Printf("[INFO] Requesting network creation") + log.Printf("[DEBUG] Create Options: %#v", createOpts) n, err := networks.Create(networkingClient, createOpts).Extract() if err != nil { return fmt.Errorf("Error creating OpenStack Neutron network: %s", err) @@ -103,31 +103,10 @@ func resourceNetworkingNetworkV2Read(d *schema.ResourceData, meta interface{}) e log.Printf("[DEBUG] Retreived Network %s: %+v", d.Id(), n) - d.Set("region", d.Get("region").(string)) - - if t, exists := d.GetOk("name"); exists && t != "" { - d.Set("name", n.Name) - } else { - d.Set("name", "") - } - - if t, exists := d.GetOk("admin_state_up"); exists && t != "" { - d.Set("admin_state_up", strconv.FormatBool(n.AdminStateUp)) - } else { - d.Set("admin_state_up", "") - } - - if t, exists := d.GetOk("shared"); exists && t != "" { - d.Set("shared", strconv.FormatBool(n.Shared)) - } else { - d.Set("shared", "") - } - - if t, exists := d.GetOk("tenant_id"); exists && t != "" { - d.Set("tenant_id", n.TenantID) - } else { - d.Set("tenant_id", "") - } + d.Set("name", n.Name) + d.Set("admin_state_up", strconv.FormatBool(n.AdminStateUp)) + d.Set("shared", strconv.FormatBool(n.Shared)) + d.Set("tenant_id", n.TenantID) return nil } diff --git a/builtin/providers/openstack/resource_openstack_networking_router_interface_v2.go b/builtin/providers/openstack/resource_openstack_networking_router_interface_v2.go index 492c14d300..e67ff6f58f 100644 --- a/builtin/providers/openstack/resource_openstack_networking_router_interface_v2.go +++ b/builtin/providers/openstack/resource_openstack_networking_router_interface_v2.go @@ -48,7 +48,7 @@ func resourceNetworkingRouterInterfaceV2Create(d *schema.ResourceData, meta inte SubnetID: d.Get("subnet_id").(string), } - log.Printf("[INFO] Requesting router interface creation") + log.Printf("[DEBUG] Create Options: %#v", createOpts) n, err := routers.AddInterface(networkingClient, d.Get("router_id").(string), createOpts).Extract() if err != nil { return fmt.Errorf("Error creating OpenStack Neutron router interface: %s", err) @@ -83,8 +83,6 @@ func resourceNetworkingRouterInterfaceV2Read(d *schema.ResourceData, meta interf log.Printf("[DEBUG] Retreived Router Interface %s: %+v", d.Id(), n) - d.Set("region", d.Get("region").(string)) - return nil } diff --git a/builtin/providers/openstack/resource_openstack_networking_router_v2.go b/builtin/providers/openstack/resource_openstack_networking_router_v2.go index cb235a88be..3b6df4816a 100644 --- a/builtin/providers/openstack/resource_openstack_networking_router_v2.go +++ b/builtin/providers/openstack/resource_openstack_networking_router_v2.go @@ -77,7 +77,7 @@ func resourceNetworkingRouterV2Create(d *schema.ResourceData, meta interface{}) createOpts.GatewayInfo = &gatewayInfo } - log.Printf("[INFO] Requesting router creation") + log.Printf("[DEBUG] Create Options: %#v", createOpts) n, err := routers.Create(networkingClient, createOpts).Extract() if err != nil { return fmt.Errorf("Error creating OpenStack Neutron router: %s", err) @@ -112,31 +112,10 @@ func resourceNetworkingRouterV2Read(d *schema.ResourceData, meta interface{}) er log.Printf("[DEBUG] Retreived Router %s: %+v", d.Id(), n) - d.Set("region", d.Get("region").(string)) - - if t, exists := d.GetOk("name"); exists && t != "" { - d.Set("name", n.Name) - } else { - d.Set("name", "") - } - - if t, exists := d.GetOk("admin_state_up"); exists && t != "" { - d.Set("admin_state_up", strconv.FormatBool(n.AdminStateUp)) - } else { - d.Set("admin_state_up", "") - } - - if t, exists := d.GetOk("tenant_id"); exists && t != "" { - d.Set("tenant_id", n.TenantID) - } else { - d.Set("tenant_id", "") - } - - if t, exists := d.GetOk("external_gateway"); exists && t != "" { - d.Set("external_gateway", n.GatewayInfo.NetworkID) - } else { - d.Set("external_gateway", "") - } + d.Set("name", n.Name) + d.Set("admin_state_up", strconv.FormatBool(n.AdminStateUp)) + d.Set("tenant_id", n.TenantID) + d.Set("external_gateway", n.GatewayInfo.NetworkID) return nil } diff --git a/builtin/providers/openstack/resource_openstack_networking_subnet_v2.go b/builtin/providers/openstack/resource_openstack_networking_subnet_v2.go index 8462611df7..2f898bb4c5 100644 --- a/builtin/providers/openstack/resource_openstack_networking_subnet_v2.go +++ b/builtin/providers/openstack/resource_openstack_networking_subnet_v2.go @@ -134,7 +134,7 @@ func resourceNetworkingSubnetV2Create(d *schema.ResourceData, meta interface{}) createOpts.EnableDHCP = &ed } - log.Printf("[INFO] Requesting subnet creation") + log.Printf("[DEBUG] Create Options: %#v", createOpts) s, err := subnets.Create(networkingClient, createOpts).Extract() if err != nil { return fmt.Errorf("Error creating OpenStack Neutron subnet: %s", err) @@ -160,46 +160,16 @@ func resourceNetworkingSubnetV2Read(d *schema.ResourceData, meta interface{}) er log.Printf("[DEBUG] Retreived Subnet %s: %+v", d.Id(), s) - d.Set("region", d.Get("region").(string)) d.Set("newtork_id", s.NetworkID) d.Set("cidr", s.CIDR) d.Set("ip_version", s.IPVersion) - - if t, exists := d.GetOk("name"); exists && t != "" { - d.Set("name", s.Name) - } else { - d.Set("name", "") - } - - if t, exists := d.GetOk("tenant_id"); exists && t != "" { - d.Set("tenant_id", s.TenantID) - } else { - d.Set("tenant_id", "") - } - - if _, exists := d.GetOk("allocation_pools"); exists { - d.Set("allocation_pools", s.AllocationPools) - } - - if t, exists := d.GetOk("gateway_ip"); exists && t != "" { - d.Set("gateway_ip", s.GatewayIP) - } else { - d.Set("gateway_ip", "") - } - - if t, exists := d.GetOk("enable_dhcp"); exists && t != "" { - d.Set("enable_dhcp", strconv.FormatBool(s.EnableDHCP)) - } else { - d.Set("enable_dhcp", "") - } - - if _, exists := d.GetOk("dns_nameservers"); exists { - d.Set("dns_nameservers", s.DNSNameservers) - } - - if _, exists := d.GetOk("host_routes"); exists { - d.Set("host_routes", s.HostRoutes) - } + d.Set("name", s.Name) + d.Set("tenant_id", s.TenantID) + d.Set("allocation_pools", s.AllocationPools) + d.Set("gateway_ip", s.GatewayIP) + d.Set("enable_dhcp", strconv.FormatBool(s.EnableDHCP)) + d.Set("dns_nameservers", s.DNSNameservers) + d.Set("host_routes", s.HostRoutes) return nil } diff --git a/builtin/providers/openstack/resource_openstack_objectstorage_container_v1.go b/builtin/providers/openstack/resource_openstack_objectstorage_container_v1.go index 692ed2e46e..31666a3565 100644 --- a/builtin/providers/openstack/resource_openstack_objectstorage_container_v1.go +++ b/builtin/providers/openstack/resource_openstack_objectstorage_container_v1.go @@ -79,7 +79,7 @@ func resourceObjectStorageContainerV1Create(d *schema.ResourceData, meta interfa Metadata: resourceContainerMetadataV2(d), } - log.Printf("[INFO] Requesting container creation") + log.Printf("[DEBUG] Create Options: %#v", createOpts) _, err = containers.Create(objectStorageClient, cn, createOpts).Extract() if err != nil { return fmt.Errorf("Error creating OpenStack container: %s", err) From 0092946f748f77770e7807d16f6c3e48ae6b14d1 Mon Sep 17 00:00:00 2001 From: Chris Buben Date: Fri, 20 Mar 2015 18:55:42 -0400 Subject: [PATCH 132/132] user_data support Mostly stolen from: https://github.com/jtopjian/terraform-provider-openstack/blob/master/openstack/resource_openstack_instance.go --- .../resource_openstack_compute_instance_v2.go | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/builtin/providers/openstack/resource_openstack_compute_instance_v2.go b/builtin/providers/openstack/resource_openstack_compute_instance_v2.go index 63508ffa72..5a4c16c7e5 100644 --- a/builtin/providers/openstack/resource_openstack_compute_instance_v2.go +++ b/builtin/providers/openstack/resource_openstack_compute_instance_v2.go @@ -2,6 +2,8 @@ package openstack import ( "bytes" + "crypto/sha1" + "encoding/hex" "fmt" "log" "time" @@ -75,6 +77,21 @@ func resourceComputeInstanceV2() *schema.Resource { Optional: true, ForceNew: false, }, + "user_data": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + // just stash the hash for state & diff comparisons + StateFunc: func(v interface{}) string { + switch v.(type) { + case string: + hash := sha1.Sum([]byte(v.(string))) + return hex.EncodeToString(hash[:]) + default: + return "" + } + }, + }, "security_groups": &schema.Schema{ Type: schema.TypeList, Optional: true, @@ -224,6 +241,7 @@ func resourceComputeInstanceV2Create(d *schema.ResourceData, meta interface{}) e Metadata: resourceInstanceMetadataV2(d), ConfigDrive: d.Get("config_drive").(bool), AdminPass: d.Get("admin_pass").(string), + UserData: []byte(d.Get("user_data").(string)), } if keyName, ok := d.Get("key_pair").(string); ok && keyName != "" {