provider/openstack: Add support provider network (#10265)

* provider:openstack Add support provider network

* revert vendor file changes

* vendor: Updating Gophercloud for OpenStack Provider

* create provider network if parameter has segments

* segments is not computed resource

* extract to generate []provider.Segment

* change segmentstion id type
This commit is contained in:
Ryo Takaishi 2017-05-30 12:30:41 +09:00 committed by Joe Topjian
parent 6d0f507175
commit c501cb1063
7 changed files with 282 additions and 2 deletions

View File

@ -10,6 +10,7 @@ import (
"github.com/hashicorp/terraform/helper/schema" "github.com/hashicorp/terraform/helper/schema"
"github.com/gophercloud/gophercloud" "github.com/gophercloud/gophercloud"
"github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/provider"
"github.com/gophercloud/gophercloud/openstack/networking/v2/networks" "github.com/gophercloud/gophercloud/openstack/networking/v2/networks"
) )
@ -58,6 +59,30 @@ func resourceNetworkingNetworkV2() *schema.Resource {
ForceNew: true, ForceNew: true,
Computed: 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{ "value_specs": &schema.Schema{
Type: schema.TypeMap, Type: schema.TypeMap,
Optional: true, Optional: true,
@ -100,11 +125,23 @@ func resourceNetworkingNetworkV2Create(d *schema.ResourceData, meta interface{})
createOpts.Shared = &shared createOpts.Shared = &shared
} }
log.Printf("[DEBUG] Create Options: %#v", createOpts) segments := resourceNetworkingNetworkV2Segments(d)
n, err := networks.Create(networkingClient, createOpts).Extract()
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 { if err != nil {
return fmt.Errorf("Error creating OpenStack Neutron network: %s", err) return fmt.Errorf("Error creating OpenStack Neutron network: %s", err)
} }
log.Printf("[INFO] Network ID: %s", n.ID) log.Printf("[INFO] Network ID: %s", n.ID)
log.Printf("[DEBUG] Waiting for Network (%s) to become available", 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 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 { func waitForNetworkActive(networkingClient *gophercloud.ServiceClient, networkId string) resource.StateRefreshFunc {
return func() (interface{}, string, error) { return func() (interface{}, string, error) {
n, err := networks.Get(networkingClient, networkId).Extract() n, err := networks.Get(networkingClient, networkId).Extract()

View File

@ -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 { func testAccCheckNetworkingV2NetworkDestroy(s *terraform.State) error {
config := testAccProvider.Meta().(*Config) config := testAccProvider.Meta().(*Config)
networkingClient, err := config.networkingV2Client(OS_REGION_NAME) 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"
}
`

View File

@ -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/<network-id> operation, this implies the user submitting the
// request is not authorized to view or manipulate provider network attributes.
package provider

View File

@ -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
}

View File

@ -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
}

6
vendor/vendor.json vendored
View File

@ -1840,6 +1840,12 @@
"revision": "0f64da0e36de86a0ca1a8f2fc1b0570a0d3f7504", "revision": "0f64da0e36de86a0ca1a8f2fc1b0570a0d3f7504",
"revisionTime": "2017-03-10T01:59:53Z" "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=", "checksumSHA1": "qabBGU1tfT99h1YXyxO9nGxMghE=",
"path": "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/security/groups", "path": "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/security/groups",

View File

@ -82,8 +82,16 @@ The following arguments are supported:
Acceptable values are "true" and "false". Changing this value updates the Acceptable values are "true" and "false". Changing this value updates the
state of the existing network. state of the existing network.
* `segments` - (Optional) An array of one or more provider segment objects.
* `value_specs` - (Optional) Map of additional options. * `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 ## Attributes Reference
The following attributes are exported: The following attributes are exported: