diff --git a/builtin/providers/openstack/config.go b/builtin/providers/openstack/config.go index cb06a9848..d877fcd80 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 b9bb5d29b..b9f756ef9 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 000000000..c819aa0f4 --- /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 +}