diff --git a/builtin/providers/openstack/resource_openstack_networking_network_v2.go b/builtin/providers/openstack/resource_openstack_networking_network_v2.go index 9f1af3e28..60161faaa 100644 --- a/builtin/providers/openstack/resource_openstack_networking_network_v2.go +++ b/builtin/providers/openstack/resource_openstack_networking_network_v2.go @@ -10,6 +10,7 @@ import ( "github.com/hashicorp/terraform/helper/schema" "github.com/gophercloud/gophercloud" + "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/provider" "github.com/gophercloud/gophercloud/openstack/networking/v2/networks" ) @@ -58,6 +59,30 @@ func resourceNetworkingNetworkV2() *schema.Resource { ForceNew: true, Computed: true, }, + "segments": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + ForceNew: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "physical_network": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "network_type": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "segmentation_id": &schema.Schema{ + Type: schema.TypeInt, + Optional: true, + ForceNew: true, + }, + }, + }, + }, "value_specs": &schema.Schema{ Type: schema.TypeMap, Optional: true, @@ -100,11 +125,23 @@ func resourceNetworkingNetworkV2Create(d *schema.ResourceData, meta interface{}) createOpts.Shared = &shared } - log.Printf("[DEBUG] Create Options: %#v", createOpts) - n, err := networks.Create(networkingClient, createOpts).Extract() + segments := resourceNetworkingNetworkV2Segments(d) + + n := &networks.Network{} + if len(segments) > 0 { + providerCreateOpts := provider.CreateOptsExt{ + CreateOptsBuilder: createOpts, + Segments: segments, + } + n, err = networks.Create(networkingClient, providerCreateOpts).Extract() + } else { + n, err = networks.Create(networkingClient, createOpts).Extract() + } + if err != nil { return fmt.Errorf("Error creating OpenStack Neutron network: %s", err) } + log.Printf("[INFO] Network ID: %s", n.ID) log.Printf("[DEBUG] Waiting for Network (%s) to become available", n.ID) @@ -215,6 +252,29 @@ func resourceNetworkingNetworkV2Delete(d *schema.ResourceData, meta interface{}) return nil } +func resourceNetworkingNetworkV2Segments(d *schema.ResourceData) (providerSegments []provider.Segment) { + segments := d.Get("segments").([]interface{}) + for _, v := range segments { + var segment provider.Segment + segmentMap := v.(map[string]interface{}) + + if v, ok := segmentMap["physical_network"].(string); ok { + segment.PhysicalNetwork = v + } + + if v, ok := segmentMap["network_type"].(string); ok { + segment.NetworkType = v + } + + if v, ok := segmentMap["segmentation_id"].(int); ok { + segment.SegmentationID = v + } + + providerSegments = append(providerSegments, segment) + } + return +} + func waitForNetworkActive(networkingClient *gophercloud.ServiceClient, networkId string) resource.StateRefreshFunc { return func() (interface{}, string, error) { n, err := networks.Get(networkingClient, networkId).Extract() diff --git a/builtin/providers/openstack/resource_openstack_networking_network_v2_test.go b/builtin/providers/openstack/resource_openstack_networking_network_v2_test.go index b2e9ac32b..b19048cfc 100644 --- a/builtin/providers/openstack/resource_openstack_networking_network_v2_test.go +++ b/builtin/providers/openstack/resource_openstack_networking_network_v2_test.go @@ -108,6 +108,24 @@ func TestAccNetworkingV2Network_timeout(t *testing.T) { }) } +func TestAccNetworkingV2Network_with_multiple_segment_mappings(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_with_multiple_segment_mappings, + Check: resource.ComposeTestCheckFunc( + testAccCheckNetworkingV2NetworkExists("openstack_networking_network_v2.network_1", &network), + ), + }, + }, + }) +} + func testAccCheckNetworkingV2NetworkDestroy(s *terraform.State) error { config := testAccProvider.Meta().(*Config) networkingClient, err := config.networkingV2Client(OS_REGION_NAME) @@ -255,3 +273,16 @@ resource "openstack_networking_network_v2" "network_1" { } } ` + +const testAccNetworkingV2Network_with_multiple_segment_mappings = ` +resource "openstack_networking_network_v2" "network_1" { + name = "network_1" + segments =[ + { + segmentation_id = 2, + network_type = "vxlan" + } + ], + admin_state_up = "true" +} +` diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/provider/doc.go b/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/provider/doc.go new file mode 100755 index 000000000..373da44f8 --- /dev/null +++ b/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/provider/doc.go @@ -0,0 +1,21 @@ +// Package provider gives access to the provider Neutron plugin, allowing +// network extended attributes. The provider extended attributes for networks +// enable administrative users to specify how network objects map to the +// underlying networking infrastructure. These extended attributes also appear +// when administrative users query networks. +// +// For more information about extended attributes, see the NetworkExtAttrs +// struct. The actual semantics of these attributes depend on the technology +// back end of the particular plug-in. See the plug-in documentation and the +// OpenStack Cloud Administrator Guide to understand which values should be +// specific for each of these attributes when OpenStack Networking is deployed +// with a particular plug-in. The examples shown in this chapter refer to the +// Open vSwitch plug-in. +// +// The default policy settings enable only users with administrative rights to +// specify these parameters in requests and to see their values in responses. By +// default, the provider network extension attributes are completely hidden from +// regular tenants. As a rule of thumb, if these attributes are not visible in a +// GET /networks/ operation, this implies the user submitting the +// request is not authorized to view or manipulate provider network attributes. +package provider diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/provider/requests.go b/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/provider/requests.go new file mode 100644 index 000000000..32c27970a --- /dev/null +++ b/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/provider/requests.go @@ -0,0 +1,28 @@ +package provider + +import ( + "github.com/gophercloud/gophercloud/openstack/networking/v2/networks" +) + +// CreateOptsExt adds a Segments option to the base Network CreateOpts. +type CreateOptsExt struct { + networks.CreateOptsBuilder + Segments []Segment `json:"segments,omitempty"` +} + +// ToNetworkCreateMap adds segments to the base network creation options. +func (opts CreateOptsExt) ToNetworkCreateMap() (map[string]interface{}, error) { + base, err := opts.CreateOptsBuilder.ToNetworkCreateMap() + if err != nil { + return nil, err + } + + if opts.Segments == nil { + return base, nil + } + + providerMap := base["network"].(map[string]interface{}) + providerMap["segments"] = opts.Segments + + return base, nil +} diff --git a/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/provider/results.go b/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/provider/results.go new file mode 100644 index 000000000..55770d8b8 --- /dev/null +++ b/vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/provider/results.go @@ -0,0 +1,126 @@ +package provider + +import ( + "encoding/json" + "strconv" + + "github.com/gophercloud/gophercloud/openstack/networking/v2/networks" + "github.com/gophercloud/gophercloud/pagination" +) + +// NetworkExtAttrs represents an extended form of a Network with additional fields. +type NetworkExtAttrs struct { + // UUID for the network + ID string `json:"id"` + + // Human-readable name for the network. Might not be unique. + Name string `json:"name"` + + // The administrative state of network. If false (down), the network does not forward packets. + AdminStateUp bool `json:"admin_state_up"` + + // Indicates whether network is currently operational. Possible values include + // `ACTIVE', `DOWN', `BUILD', or `ERROR'. Plug-ins might define additional values. + Status string `json:"status"` + + // Subnets associated with this network. + Subnets []string `json:"subnets"` + + // Owner of network. Only admin users can specify a tenant_id other than its own. + TenantID string `json:"tenant_id"` + + // Specifies whether the network resource can be accessed by any tenant or not. + Shared bool `json:"shared"` + + // Specifies the nature of the physical network mapped to this network + // resource. Examples are flat, vlan, or gre. + NetworkType string `json:"provider:network_type"` + + // Identifies the physical network on top of which this network object is + // being implemented. The OpenStack Networking API does not expose any facility + // for retrieving the list of available physical networks. As an example, in + // the Open vSwitch plug-in this is a symbolic name which is then mapped to + // specific bridges on each compute host through the Open vSwitch plug-in + // configuration file. + PhysicalNetwork string `json:"provider:physical_network"` + + // Identifies an isolated segment on the physical network; the nature of the + // segment depends on the segmentation model defined by network_type. For + // instance, if network_type is vlan, then this is a vlan identifier; + // otherwise, if network_type is gre, then this will be a gre key. + SegmentationID string `json:"provider:segmentation_id"` + + // Segments is an array of Segment which defines multiple physical bindings to logical networks. + Segments []Segment `json:"segments"` +} + +// Segment defines a physical binding to a logical network. +type Segment struct { + PhysicalNetwork string `json:"provider:physical_network"` + NetworkType string `json:"provider:network_type"` + SegmentationID int `json:"provider:segmentation_id"` +} + +func (n *NetworkExtAttrs) UnmarshalJSON(b []byte) error { + type tmp NetworkExtAttrs + var networkExtAttrs *struct { + tmp + SegmentationID interface{} `json:"provider:segmentation_id"` + } + + if err := json.Unmarshal(b, &networkExtAttrs); err != nil { + return err + } + + *n = NetworkExtAttrs(networkExtAttrs.tmp) + + switch t := networkExtAttrs.SegmentationID.(type) { + case float64: + n.SegmentationID = strconv.FormatFloat(t, 'f', -1, 64) + case string: + n.SegmentationID = string(t) + } + + return nil +} + +// ExtractGet decorates a GetResult struct returned from a networks.Get() +// function with extended attributes. +func ExtractGet(r networks.GetResult) (*NetworkExtAttrs, error) { + var s struct { + Network *NetworkExtAttrs `json:"network"` + } + err := r.ExtractInto(&s) + return s.Network, err +} + +// ExtractCreate decorates a CreateResult struct returned from a networks.Create() +// function with extended attributes. +func ExtractCreate(r networks.CreateResult) (*NetworkExtAttrs, error) { + var s struct { + Network *NetworkExtAttrs `json:"network"` + } + err := r.ExtractInto(&s) + return s.Network, err +} + +// ExtractUpdate decorates a UpdateResult struct returned from a +// networks.Update() function with extended attributes. +func ExtractUpdate(r networks.UpdateResult) (*NetworkExtAttrs, error) { + var s struct { + Network *NetworkExtAttrs `json:"network"` + } + err := r.ExtractInto(&s) + return s.Network, err +} + +// ExtractList accepts a Page struct, specifically a NetworkPage struct, and +// extracts the elements into a slice of NetworkExtAttrs structs. In other +// words, a generic collection is mapped into a relevant slice. +func ExtractList(r pagination.Page) ([]NetworkExtAttrs, error) { + var s struct { + Networks []NetworkExtAttrs `json:"networks" json:"networks"` + } + err := (r.(networks.NetworkPage)).ExtractInto(&s) + return s.Networks, err +} diff --git a/vendor/vendor.json b/vendor/vendor.json index 636963326..de2222210 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -1840,6 +1840,12 @@ "revision": "0f64da0e36de86a0ca1a8f2fc1b0570a0d3f7504", "revisionTime": "2017-03-10T01:59:53Z" }, + { + "checksumSHA1": "z4Wpu5WejbJzYMztu8UlCR3riBA=", + "path": "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/provider", + "revision": "5a6e13341e63bd202a0da558a2a7187720042676", + "revisionTime": "2017-05-22T01:35:44Z" + }, { "checksumSHA1": "qabBGU1tfT99h1YXyxO9nGxMghE=", "path": "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/security/groups", diff --git a/website/source/docs/providers/openstack/r/networking_network_v2.html.markdown b/website/source/docs/providers/openstack/r/networking_network_v2.html.markdown index 5eb4ca0fd..e14b5f28f 100644 --- a/website/source/docs/providers/openstack/r/networking_network_v2.html.markdown +++ b/website/source/docs/providers/openstack/r/networking_network_v2.html.markdown @@ -82,8 +82,16 @@ The following arguments are supported: Acceptable values are "true" and "false". Changing this value updates the state of the existing network. +* `segments` - (Optional) An array of one or more provider segment objects. + * `value_specs` - (Optional) Map of additional options. +The `segments` block supports: + +* `physical_network` - The phisical network where this network is implemented. +* `segmentation_id` - An isolated segment on the physical network. +* `network_type` - The type of physical network. + ## Attributes Reference The following attributes are exported: