[builder/openstack] adds option to discover provisioning network
This commit is contained in:
parent
0b9391b092
commit
5da5b00e1c
|
@ -101,6 +101,11 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
|
|||
SourceMostRecent: b.config.SourceImageFilters.MostRecent,
|
||||
SourceProperties: b.config.SourceImageFilters.Filters.Properties,
|
||||
},
|
||||
&StepDiscoverNetwork{
|
||||
Networks: b.config.Networks,
|
||||
NetworkDiscoveryCIDRs: b.config.NetworkDiscoveryCIDRs,
|
||||
Ports: b.config.Ports,
|
||||
},
|
||||
&StepCreateVolume{
|
||||
UseBlockStorageVolume: b.config.UseBlockStorageVolume,
|
||||
VolumeName: b.config.VolumeName,
|
||||
|
@ -110,8 +115,6 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
|
|||
&StepRunSourceServer{
|
||||
Name: b.config.InstanceName,
|
||||
SecurityGroups: b.config.SecurityGroups,
|
||||
Networks: b.config.Networks,
|
||||
Ports: b.config.Ports,
|
||||
AvailabilityZone: b.config.AvailabilityZone,
|
||||
UserData: b.config.UserData,
|
||||
UserDataFile: b.config.UserDataFile,
|
||||
|
|
|
@ -98,6 +98,7 @@ type FlatConfig struct {
|
|||
SecurityGroups []string `mapstructure:"security_groups" required:"false" cty:"security_groups"`
|
||||
Networks []string `mapstructure:"networks" required:"false" cty:"networks"`
|
||||
Ports []string `mapstructure:"ports" required:"false" cty:"ports"`
|
||||
NetworkDiscoveryCIDRs []string `mapstructure:"network_discovery_cidrs" required:"false" cty:"network_discovery_cidrs"`
|
||||
UserData *string `mapstructure:"user_data" required:"false" cty:"user_data"`
|
||||
UserDataFile *string `mapstructure:"user_data_file" required:"false" cty:"user_data_file"`
|
||||
InstanceName *string `mapstructure:"instance_name" required:"false" cty:"instance_name"`
|
||||
|
@ -211,6 +212,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
|
|||
"security_groups": &hcldec.AttrSpec{Name: "security_groups", Type: cty.List(cty.String), Required: false},
|
||||
"networks": &hcldec.AttrSpec{Name: "networks", Type: cty.List(cty.String), Required: false},
|
||||
"ports": &hcldec.AttrSpec{Name: "ports", Type: cty.List(cty.String), Required: false},
|
||||
"network_discovery_cidrs": &hcldec.AttrSpec{Name: "network_discovery_cidrs", Type: cty.List(cty.String), Required: false},
|
||||
"user_data": &hcldec.AttrSpec{Name: "user_data", Type: cty.String, Required: false},
|
||||
"user_data_file": &hcldec.AttrSpec{Name: "user_data_file", Type: cty.String, Required: false},
|
||||
"instance_name": &hcldec.AttrSpec{Name: "instance_name", Type: cty.String, Required: false},
|
||||
|
|
|
@ -3,6 +3,7 @@ package openstack
|
|||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/gophercloud/gophercloud"
|
||||
|
@ -10,6 +11,7 @@ import (
|
|||
"github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/external"
|
||||
"github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/floatingips"
|
||||
"github.com/gophercloud/gophercloud/openstack/networking/v2/networks"
|
||||
"github.com/gophercloud/gophercloud/openstack/networking/v2/subnets"
|
||||
"github.com/gophercloud/gophercloud/pagination"
|
||||
)
|
||||
|
||||
|
@ -136,3 +138,43 @@ func GetFloatingIPNetworkIDByName(client *gophercloud.ServiceClient, networkName
|
|||
|
||||
return externalNetworks[0].ID, nil
|
||||
}
|
||||
|
||||
// DiscoverProvisioningNetwork finds the first network whose subnet matches the given network ranges.
|
||||
func DiscoverProvisioningNetwork(client *gophercloud.ServiceClient, cidrs []string) (string, error) {
|
||||
allPages, err := subnets.List(client, subnets.ListOpts{}).AllPages()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
allSubnets, err := subnets.ExtractSubnets(allPages)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
for _, subnet := range allSubnets {
|
||||
_, tenantIPNet, err := net.ParseCIDR(subnet.CIDR)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
for _, cidr := range cidrs {
|
||||
_, candidateIPNet, err := net.ParseCIDR(cidr)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if containsNet(candidateIPNet, tenantIPNet) {
|
||||
return subnet.NetworkID, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("failed to discover a provisioning network")
|
||||
}
|
||||
|
||||
// containsNet returns true whenever IPNet `a` contains IPNet `b`
|
||||
func containsNet(a *net.IPNet, b *net.IPNet) bool {
|
||||
aMask, _ := a.Mask.Size()
|
||||
bMask, _ := b.Mask.Size()
|
||||
return a.Contains(b.IP) && aMask <= bMask
|
||||
}
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
package openstack
|
||||
|
||||
import (
|
||||
"net"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func testYes(t *testing.T, a, b string) {
|
||||
var m, n *net.IPNet
|
||||
_, m, _ = net.ParseCIDR(a)
|
||||
_, n, _ = net.ParseCIDR(b)
|
||||
if !containsNet(m, n) {
|
||||
t.Errorf("%s expected to contain %s", m, n)
|
||||
}
|
||||
}
|
||||
|
||||
func testNot(t *testing.T, a, b string) {
|
||||
var m, n *net.IPNet
|
||||
_, m, _ = net.ParseCIDR(a)
|
||||
_, n, _ = net.ParseCIDR(b)
|
||||
if containsNet(m, n) {
|
||||
t.Errorf("%s expected to not contain %s", m, n)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNetworkDiscovery_SubnetContainsGood_IPv4(t *testing.T) {
|
||||
testYes(t, "192.168.0.0/23", "192.168.0.0/24")
|
||||
testYes(t, "192.168.0.0/24", "192.168.0.0/24")
|
||||
testNot(t, "192.168.0.0/25", "192.168.0.0/24")
|
||||
|
||||
testYes(t, "192.168.101.202/16", "192.168.202.101/16")
|
||||
testNot(t, "192.168.101.202/24", "192.168.202.101/24")
|
||||
testNot(t, "192.168.202.101/24", "192.168.101.202/24")
|
||||
|
||||
testYes(t, "0.0.0.0/0", "192.168.0.0/24")
|
||||
testYes(t, "0.0.0.0/0", "0.0.0.0/1")
|
||||
testNot(t, "192.168.0.0/24", "0.0.0.0/0")
|
||||
testNot(t, "0.0.0.0/1", "0.0.0.0/0")
|
||||
}
|
||||
|
||||
func TestNetworkDiscovery_SubnetContainsGood_IPv6(t *testing.T) {
|
||||
testYes(t, "2001:db8::/63", "2001:db8::/64")
|
||||
testYes(t, "2001:db8::/64", "2001:db8::/64")
|
||||
testNot(t, "2001:db8::/65", "2001:db8::/64")
|
||||
|
||||
testYes(t, "2001:db8:fefe:b00b::/32", "2001:db8:b00b:fefe::/32")
|
||||
testNot(t, "2001:db8:fefe:b00b::/64", "2001:db8:b00b:fefe::/64")
|
||||
testNot(t, "2001:db8:b00b:fefe::/64", "2001:db8:fefe:b00b::/64")
|
||||
|
||||
testYes(t, "::/0", "2001:db8::/64")
|
||||
testYes(t, "::/0", "::/1")
|
||||
testNot(t, "2001:db8::/64", "::/0")
|
||||
testNot(t, "::/1", "::/0")
|
||||
}
|
|
@ -118,6 +118,10 @@ type RunConfig struct {
|
|||
Networks []string `mapstructure:"networks" required:"false"`
|
||||
// A list of ports by UUID to attach to this instance.
|
||||
Ports []string `mapstructure:"ports" required:"false"`
|
||||
// A list of network CIDRs to discover the network to attach to this instance.
|
||||
// The first network whose subnet is contained within any of the given CIDRs
|
||||
// is used. Ignored if either of the above two options are provided.
|
||||
NetworkDiscoveryCIDRs []string `mapstructure:"network_discovery_cidrs" required:"false"`
|
||||
// User data to apply when launching the instance. Note that you need to be
|
||||
// careful about escaping characters due to the templates being JSON. It is
|
||||
// often more convenient to use user_data_file, instead. Packer will not
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
package openstack
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/gophercloud/gophercloud/openstack/compute/v2/servers"
|
||||
"github.com/hashicorp/packer/helper/multistep"
|
||||
"github.com/hashicorp/packer/packer"
|
||||
)
|
||||
|
||||
type StepDiscoverNetwork struct {
|
||||
Networks []string
|
||||
NetworkDiscoveryCIDRs []string
|
||||
Ports []string
|
||||
}
|
||||
|
||||
func (s *StepDiscoverNetwork) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
config := state.Get("config").(*Config)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
networkClient, err := config.networkV2Client()
|
||||
if err != nil {
|
||||
err = fmt.Errorf("Error initializing network client: %s", err)
|
||||
state.Put("error", err)
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
networks := []servers.Network{}
|
||||
for _, port := range s.Ports {
|
||||
networks = append(networks, servers.Network{Port: port})
|
||||
}
|
||||
for _, uuid := range s.Networks {
|
||||
networks = append(networks, servers.Network{UUID: uuid})
|
||||
}
|
||||
|
||||
cidrs := s.NetworkDiscoveryCIDRs
|
||||
if len(networks) == 0 && len(cidrs) > 0 {
|
||||
ui.Say(fmt.Sprintf("Discovering provisioning network..."))
|
||||
|
||||
networkID, err := DiscoverProvisioningNetwork(networkClient, cidrs)
|
||||
if err != nil {
|
||||
state.Put("error", err)
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
ui.Message(fmt.Sprintf("Found network ID: %s", networkID))
|
||||
networks = append(networks, servers.Network{UUID: networkID})
|
||||
}
|
||||
|
||||
state.Put("networks", networks)
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *StepDiscoverNetwork) Cleanup(state multistep.StateBag) {}
|
|
@ -16,8 +16,6 @@ import (
|
|||
type StepRunSourceServer struct {
|
||||
Name string
|
||||
SecurityGroups []string
|
||||
Networks []string
|
||||
Ports []string
|
||||
AvailabilityZone string
|
||||
UserData string
|
||||
UserDataFile string
|
||||
|
@ -32,6 +30,7 @@ func (s *StepRunSourceServer) Run(ctx context.Context, state multistep.StateBag)
|
|||
config := state.Get("config").(*Config)
|
||||
flavor := state.Get("flavor_id").(string)
|
||||
sourceImage := state.Get("source_image").(string)
|
||||
networks := state.Get("networks").([]servers.Network)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
// We need the v2 compute client
|
||||
|
@ -42,15 +41,6 @@ func (s *StepRunSourceServer) Run(ctx context.Context, state multistep.StateBag)
|
|||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
networks := make([]servers.Network, len(s.Networks)+len(s.Ports))
|
||||
i := 0
|
||||
for ; i < len(s.Ports); i++ {
|
||||
networks[i].Port = s.Ports[i]
|
||||
}
|
||||
for ; i < len(networks); i++ {
|
||||
networks[i].UUID = s.Networks[i-len(s.Ports)]
|
||||
}
|
||||
|
||||
userData := []byte(s.UserData)
|
||||
if s.UserDataFile != "" {
|
||||
userData, err = ioutil.ReadFile(s.UserDataFile)
|
||||
|
|
135
vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/subnets/doc.go
generated
vendored
Normal file
135
vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/subnets/doc.go
generated
vendored
Normal file
|
@ -0,0 +1,135 @@
|
|||
/*
|
||||
Package subnets contains functionality for working with Neutron subnet
|
||||
resources. A subnet represents an IP address block that can be used to
|
||||
assign IP addresses to virtual instances. Each subnet must have a CIDR and
|
||||
must be associated with a network. IPs can either be selected from the whole
|
||||
subnet CIDR or from allocation pools specified by the user.
|
||||
|
||||
A subnet can also have a gateway, a list of DNS name servers, and host routes.
|
||||
This information is pushed to instances whose interfaces are associated with
|
||||
the subnet.
|
||||
|
||||
Example to List Subnets
|
||||
|
||||
listOpts := subnets.ListOpts{
|
||||
IPVersion: 4,
|
||||
}
|
||||
|
||||
allPages, err := subnets.List(networkClient, listOpts).AllPages()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
allSubnets, err := subnets.ExtractSubnets(allPages)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
for _, subnet := range allSubnets {
|
||||
fmt.Printf("%+v\n", subnet)
|
||||
}
|
||||
|
||||
Example to Create a Subnet With Specified Gateway
|
||||
|
||||
var gatewayIP = "192.168.199.1"
|
||||
createOpts := subnets.CreateOpts{
|
||||
NetworkID: "d32019d3-bc6e-4319-9c1d-6722fc136a22",
|
||||
IPVersion: 4,
|
||||
CIDR: "192.168.199.0/24",
|
||||
GatewayIP: &gatewayIP,
|
||||
AllocationPools: []subnets.AllocationPool{
|
||||
{
|
||||
Start: "192.168.199.2",
|
||||
End: "192.168.199.254",
|
||||
},
|
||||
},
|
||||
DNSNameservers: []string{"foo"},
|
||||
}
|
||||
|
||||
subnet, err := subnets.Create(networkClient, createOpts).Extract()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
Example to Create a Subnet With No Gateway
|
||||
|
||||
var noGateway = ""
|
||||
|
||||
createOpts := subnets.CreateOpts{
|
||||
NetworkID: "d32019d3-bc6e-4319-9c1d-6722fc136a23",
|
||||
IPVersion: 4,
|
||||
CIDR: "192.168.1.0/24",
|
||||
GatewayIP: &noGateway,
|
||||
AllocationPools: []subnets.AllocationPool{
|
||||
{
|
||||
Start: "192.168.1.2",
|
||||
End: "192.168.1.254",
|
||||
},
|
||||
},
|
||||
DNSNameservers: []string{},
|
||||
}
|
||||
|
||||
subnet, err := subnets.Create(networkClient, createOpts).Extract()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
Example to Create a Subnet With a Default Gateway
|
||||
|
||||
createOpts := subnets.CreateOpts{
|
||||
NetworkID: "d32019d3-bc6e-4319-9c1d-6722fc136a23",
|
||||
IPVersion: 4,
|
||||
CIDR: "192.168.1.0/24",
|
||||
AllocationPools: []subnets.AllocationPool{
|
||||
{
|
||||
Start: "192.168.1.2",
|
||||
End: "192.168.1.254",
|
||||
},
|
||||
},
|
||||
DNSNameservers: []string{},
|
||||
}
|
||||
|
||||
subnet, err := subnets.Create(networkClient, createOpts).Extract()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
Example to Update a Subnet
|
||||
|
||||
subnetID := "db77d064-e34f-4d06-b060-f21e28a61c23"
|
||||
dnsNameservers := []string{"8.8.8.8"}
|
||||
name := "new_name"
|
||||
|
||||
updateOpts := subnets.UpdateOpts{
|
||||
Name: &name,
|
||||
DNSNameservers: &dnsNameservers,
|
||||
}
|
||||
|
||||
subnet, err := subnets.Update(networkClient, subnetID, updateOpts).Extract()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
Example to Remove a Gateway From a Subnet
|
||||
|
||||
var noGateway = ""
|
||||
subnetID := "db77d064-e34f-4d06-b060-f21e28a61c23"
|
||||
|
||||
updateOpts := subnets.UpdateOpts{
|
||||
GatewayIP: &noGateway,
|
||||
}
|
||||
|
||||
subnet, err := subnets.Update(networkClient, subnetID, updateOpts).Extract()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
Example to Delete a Subnet
|
||||
|
||||
subnetID := "db77d064-e34f-4d06-b060-f21e28a61c23"
|
||||
err := subnets.Delete(networkClient, subnetID).ExtractErr()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
*/
|
||||
package subnets
|
269
vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/subnets/requests.go
generated
vendored
Normal file
269
vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/subnets/requests.go
generated
vendored
Normal file
|
@ -0,0 +1,269 @@
|
|||
package subnets
|
||||
|
||||
import (
|
||||
"github.com/gophercloud/gophercloud"
|
||||
"github.com/gophercloud/gophercloud/pagination"
|
||||
)
|
||||
|
||||
// ListOptsBuilder allows extensions to add additional parameters to the
|
||||
// List request.
|
||||
type ListOptsBuilder interface {
|
||||
ToSubnetListQuery() (string, error)
|
||||
}
|
||||
|
||||
// ListOpts allows the filtering and sorting of paginated collections through
|
||||
// the API. Filtering is achieved by passing in struct field values that map to
|
||||
// the subnet attributes you want to see returned. SortKey allows you to sort
|
||||
// by a particular subnet attribute. SortDir sets the direction, and is either
|
||||
// `asc' or `desc'. Marker and Limit are used for pagination.
|
||||
type ListOpts struct {
|
||||
Name string `q:"name"`
|
||||
Description string `q:"description"`
|
||||
EnableDHCP *bool `q:"enable_dhcp"`
|
||||
NetworkID string `q:"network_id"`
|
||||
TenantID string `q:"tenant_id"`
|
||||
ProjectID string `q:"project_id"`
|
||||
IPVersion int `q:"ip_version"`
|
||||
GatewayIP string `q:"gateway_ip"`
|
||||
CIDR string `q:"cidr"`
|
||||
IPv6AddressMode string `q:"ipv6_address_mode"`
|
||||
IPv6RAMode string `q:"ipv6_ra_mode"`
|
||||
ID string `q:"id"`
|
||||
SubnetPoolID string `q:"subnetpool_id"`
|
||||
Limit int `q:"limit"`
|
||||
Marker string `q:"marker"`
|
||||
SortKey string `q:"sort_key"`
|
||||
SortDir string `q:"sort_dir"`
|
||||
Tags string `q:"tags"`
|
||||
TagsAny string `q:"tags-any"`
|
||||
NotTags string `q:"not-tags"`
|
||||
NotTagsAny string `q:"not-tags-any"`
|
||||
}
|
||||
|
||||
// ToSubnetListQuery formats a ListOpts into a query string.
|
||||
func (opts ListOpts) ToSubnetListQuery() (string, error) {
|
||||
q, err := gophercloud.BuildQueryString(opts)
|
||||
return q.String(), err
|
||||
}
|
||||
|
||||
// List returns a Pager which allows you to iterate over a collection of
|
||||
// subnets. It accepts a ListOpts struct, which allows you to filter and sort
|
||||
// the returned collection for greater efficiency.
|
||||
//
|
||||
// Default policy settings return only those subnets that are owned by the tenant
|
||||
// who submits the request, unless the request is submitted by a user with
|
||||
// administrative rights.
|
||||
func List(c *gophercloud.ServiceClient, opts ListOptsBuilder) pagination.Pager {
|
||||
url := listURL(c)
|
||||
if opts != nil {
|
||||
query, err := opts.ToSubnetListQuery()
|
||||
if err != nil {
|
||||
return pagination.Pager{Err: err}
|
||||
}
|
||||
url += query
|
||||
}
|
||||
return pagination.NewPager(c, url, func(r pagination.PageResult) pagination.Page {
|
||||
return SubnetPage{pagination.LinkedPageBase{PageResult: r}}
|
||||
})
|
||||
}
|
||||
|
||||
// Get retrieves a specific subnet based on its unique ID.
|
||||
func Get(c *gophercloud.ServiceClient, id string) (r GetResult) {
|
||||
_, r.Err = c.Get(getURL(c, id), &r.Body, nil)
|
||||
return
|
||||
}
|
||||
|
||||
// CreateOptsBuilder allows extensions to add additional parameters to the
|
||||
// List request.
|
||||
type CreateOptsBuilder interface {
|
||||
ToSubnetCreateMap() (map[string]interface{}, error)
|
||||
}
|
||||
|
||||
// CreateOpts represents the attributes used when creating a new subnet.
|
||||
type CreateOpts struct {
|
||||
// NetworkID is the UUID of the network the subnet will be associated with.
|
||||
NetworkID string `json:"network_id" required:"true"`
|
||||
|
||||
// CIDR is the address CIDR of the subnet.
|
||||
CIDR string `json:"cidr,omitempty"`
|
||||
|
||||
// Name is a human-readable name of the subnet.
|
||||
Name string `json:"name,omitempty"`
|
||||
|
||||
// Description of the subnet.
|
||||
Description string `json:"description,omitempty"`
|
||||
|
||||
// The UUID of the project who owns the Subnet. Only administrative users
|
||||
// can specify a project UUID other than their own.
|
||||
TenantID string `json:"tenant_id,omitempty"`
|
||||
|
||||
// The UUID of the project who owns the Subnet. Only administrative users
|
||||
// can specify a project UUID other than their own.
|
||||
ProjectID string `json:"project_id,omitempty"`
|
||||
|
||||
// AllocationPools are IP Address pools that will be available for DHCP.
|
||||
AllocationPools []AllocationPool `json:"allocation_pools,omitempty"`
|
||||
|
||||
// GatewayIP sets gateway information for the subnet. Setting to nil will
|
||||
// cause a default gateway to automatically be created. Setting to an empty
|
||||
// string will cause the subnet to be created with no gateway. Setting to
|
||||
// an explicit address will set that address as the gateway.
|
||||
GatewayIP *string `json:"gateway_ip,omitempty"`
|
||||
|
||||
// IPVersion is the IP version for the subnet.
|
||||
IPVersion gophercloud.IPVersion `json:"ip_version,omitempty"`
|
||||
|
||||
// EnableDHCP will either enable to disable the DHCP service.
|
||||
EnableDHCP *bool `json:"enable_dhcp,omitempty"`
|
||||
|
||||
// DNSNameservers are the nameservers to be set via DHCP.
|
||||
DNSNameservers []string `json:"dns_nameservers,omitempty"`
|
||||
|
||||
// HostRoutes are any static host routes to be set via DHCP.
|
||||
HostRoutes []HostRoute `json:"host_routes,omitempty"`
|
||||
|
||||
// The IPv6 address modes specifies mechanisms for assigning IPv6 IP addresses.
|
||||
IPv6AddressMode string `json:"ipv6_address_mode,omitempty"`
|
||||
|
||||
// The IPv6 router advertisement specifies whether the networking service
|
||||
// should transmit ICMPv6 packets.
|
||||
IPv6RAMode string `json:"ipv6_ra_mode,omitempty"`
|
||||
|
||||
// SubnetPoolID is the id of the subnet pool that subnet should be associated to.
|
||||
SubnetPoolID string `json:"subnetpool_id,omitempty"`
|
||||
|
||||
// Prefixlen is used when user creates a subnet from the subnetpool. It will
|
||||
// overwrite the "default_prefixlen" value of the referenced subnetpool.
|
||||
Prefixlen int `json:"prefixlen,omitempty"`
|
||||
}
|
||||
|
||||
// ToSubnetCreateMap builds a request body from CreateOpts.
|
||||
func (opts CreateOpts) ToSubnetCreateMap() (map[string]interface{}, error) {
|
||||
b, err := gophercloud.BuildRequestBody(opts, "subnet")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if m := b["subnet"].(map[string]interface{}); m["gateway_ip"] == "" {
|
||||
m["gateway_ip"] = nil
|
||||
}
|
||||
|
||||
return b, nil
|
||||
}
|
||||
|
||||
// Create accepts a CreateOpts struct and creates a new subnet using the values
|
||||
// provided. You must remember to provide a valid NetworkID, CIDR and IP
|
||||
// version.
|
||||
func Create(c *gophercloud.ServiceClient, opts CreateOptsBuilder) (r CreateResult) {
|
||||
b, err := opts.ToSubnetCreateMap()
|
||||
if err != nil {
|
||||
r.Err = err
|
||||
return
|
||||
}
|
||||
_, r.Err = c.Post(createURL(c), b, &r.Body, nil)
|
||||
return
|
||||
}
|
||||
|
||||
// UpdateOptsBuilder allows extensions to add additional parameters to the
|
||||
// Update request.
|
||||
type UpdateOptsBuilder interface {
|
||||
ToSubnetUpdateMap() (map[string]interface{}, error)
|
||||
}
|
||||
|
||||
// UpdateOpts represents the attributes used when updating an existing subnet.
|
||||
type UpdateOpts struct {
|
||||
// Name is a human-readable name of the subnet.
|
||||
Name *string `json:"name,omitempty"`
|
||||
|
||||
// Description of the subnet.
|
||||
Description *string `json:"description,omitempty"`
|
||||
|
||||
// AllocationPools are IP Address pools that will be available for DHCP.
|
||||
AllocationPools []AllocationPool `json:"allocation_pools,omitempty"`
|
||||
|
||||
// GatewayIP sets gateway information for the subnet. Setting to nil will
|
||||
// cause a default gateway to automatically be created. Setting to an empty
|
||||
// string will cause the subnet to be created with no gateway. Setting to
|
||||
// an explicit address will set that address as the gateway.
|
||||
GatewayIP *string `json:"gateway_ip,omitempty"`
|
||||
|
||||
// DNSNameservers are the nameservers to be set via DHCP.
|
||||
DNSNameservers *[]string `json:"dns_nameservers,omitempty"`
|
||||
|
||||
// HostRoutes are any static host routes to be set via DHCP.
|
||||
HostRoutes *[]HostRoute `json:"host_routes,omitempty"`
|
||||
|
||||
// EnableDHCP will either enable to disable the DHCP service.
|
||||
EnableDHCP *bool `json:"enable_dhcp,omitempty"`
|
||||
}
|
||||
|
||||
// ToSubnetUpdateMap builds a request body from UpdateOpts.
|
||||
func (opts UpdateOpts) ToSubnetUpdateMap() (map[string]interface{}, error) {
|
||||
b, err := gophercloud.BuildRequestBody(opts, "subnet")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if m := b["subnet"].(map[string]interface{}); m["gateway_ip"] == "" {
|
||||
m["gateway_ip"] = nil
|
||||
}
|
||||
|
||||
return b, nil
|
||||
}
|
||||
|
||||
// Update accepts a UpdateOpts struct and updates an existing subnet using the
|
||||
// values provided.
|
||||
func Update(c *gophercloud.ServiceClient, id string, opts UpdateOptsBuilder) (r UpdateResult) {
|
||||
b, err := opts.ToSubnetUpdateMap()
|
||||
if err != nil {
|
||||
r.Err = err
|
||||
return
|
||||
}
|
||||
_, r.Err = c.Put(updateURL(c, id), b, &r.Body, &gophercloud.RequestOpts{
|
||||
OkCodes: []int{200, 201},
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// Delete accepts a unique ID and deletes the subnet associated with it.
|
||||
func Delete(c *gophercloud.ServiceClient, id string) (r DeleteResult) {
|
||||
_, r.Err = c.Delete(deleteURL(c, id), nil)
|
||||
return
|
||||
}
|
||||
|
||||
// IDFromName is a convenience function that returns a subnet's ID,
|
||||
// given its name.
|
||||
func IDFromName(client *gophercloud.ServiceClient, name string) (string, error) {
|
||||
count := 0
|
||||
id := ""
|
||||
|
||||
listOpts := ListOpts{
|
||||
Name: name,
|
||||
}
|
||||
|
||||
pages, err := List(client, listOpts).AllPages()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
all, err := ExtractSubnets(pages)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
for _, s := range all {
|
||||
if s.Name == name {
|
||||
count++
|
||||
id = s.ID
|
||||
}
|
||||
}
|
||||
|
||||
switch count {
|
||||
case 0:
|
||||
return "", gophercloud.ErrResourceNotFound{Name: name, ResourceType: "subnet"}
|
||||
case 1:
|
||||
return id, nil
|
||||
default:
|
||||
return "", gophercloud.ErrMultipleResourcesFound{Name: name, Count: count, ResourceType: "subnet"}
|
||||
}
|
||||
}
|
152
vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/subnets/results.go
generated
vendored
Normal file
152
vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/subnets/results.go
generated
vendored
Normal file
|
@ -0,0 +1,152 @@
|
|||
package subnets
|
||||
|
||||
import (
|
||||
"github.com/gophercloud/gophercloud"
|
||||
"github.com/gophercloud/gophercloud/pagination"
|
||||
)
|
||||
|
||||
type commonResult struct {
|
||||
gophercloud.Result
|
||||
}
|
||||
|
||||
// Extract is a function that accepts a result and extracts a subnet resource.
|
||||
func (r commonResult) Extract() (*Subnet, error) {
|
||||
var s struct {
|
||||
Subnet *Subnet `json:"subnet"`
|
||||
}
|
||||
err := r.ExtractInto(&s)
|
||||
return s.Subnet, err
|
||||
}
|
||||
|
||||
// CreateResult represents the result of a create operation. Call its Extract
|
||||
// method to interpret it as a Subnet.
|
||||
type CreateResult struct {
|
||||
commonResult
|
||||
}
|
||||
|
||||
// GetResult represents the result of a get operation. Call its Extract
|
||||
// method to interpret it as a Subnet.
|
||||
type GetResult struct {
|
||||
commonResult
|
||||
}
|
||||
|
||||
// UpdateResult represents the result of an update operation. Call its Extract
|
||||
// method to interpret it as a Subnet.
|
||||
type UpdateResult struct {
|
||||
commonResult
|
||||
}
|
||||
|
||||
// DeleteResult represents the result of a delete operation. Call its
|
||||
// ExtractErr method to determine if the request succeeded or failed.
|
||||
type DeleteResult struct {
|
||||
gophercloud.ErrResult
|
||||
}
|
||||
|
||||
// AllocationPool represents a sub-range of cidr available for dynamic
|
||||
// allocation to ports, e.g. {Start: "10.0.0.2", End: "10.0.0.254"}
|
||||
type AllocationPool struct {
|
||||
Start string `json:"start"`
|
||||
End string `json:"end"`
|
||||
}
|
||||
|
||||
// HostRoute represents a route that should be used by devices with IPs from
|
||||
// a subnet (not including local subnet route).
|
||||
type HostRoute struct {
|
||||
DestinationCIDR string `json:"destination"`
|
||||
NextHop string `json:"nexthop"`
|
||||
}
|
||||
|
||||
// Subnet represents a subnet. See package documentation for a top-level
|
||||
// description of what this is.
|
||||
type Subnet struct {
|
||||
// UUID representing the subnet.
|
||||
ID string `json:"id"`
|
||||
|
||||
// UUID of the parent network.
|
||||
NetworkID string `json:"network_id"`
|
||||
|
||||
// Human-readable name for the subnet. Might not be unique.
|
||||
Name string `json:"name"`
|
||||
|
||||
// Description for the subnet.
|
||||
Description string `json:"description"`
|
||||
|
||||
// IP version, either `4' or `6'.
|
||||
IPVersion int `json:"ip_version"`
|
||||
|
||||
// CIDR representing IP range for this subnet, based on IP version.
|
||||
CIDR string `json:"cidr"`
|
||||
|
||||
// Default gateway used by devices in this subnet.
|
||||
GatewayIP string `json:"gateway_ip"`
|
||||
|
||||
// DNS name servers used by hosts in this subnet.
|
||||
DNSNameservers []string `json:"dns_nameservers"`
|
||||
|
||||
// Sub-ranges of CIDR available for dynamic allocation to ports.
|
||||
// See AllocationPool.
|
||||
AllocationPools []AllocationPool `json:"allocation_pools"`
|
||||
|
||||
// Routes that should be used by devices with IPs from this subnet
|
||||
// (not including local subnet route).
|
||||
HostRoutes []HostRoute `json:"host_routes"`
|
||||
|
||||
// Specifies whether DHCP is enabled for this subnet or not.
|
||||
EnableDHCP bool `json:"enable_dhcp"`
|
||||
|
||||
// TenantID is the project owner of the subnet.
|
||||
TenantID string `json:"tenant_id"`
|
||||
|
||||
// ProjectID is the project owner of the subnet.
|
||||
ProjectID string `json:"project_id"`
|
||||
|
||||
// The IPv6 address modes specifies mechanisms for assigning IPv6 IP addresses.
|
||||
IPv6AddressMode string `json:"ipv6_address_mode"`
|
||||
|
||||
// The IPv6 router advertisement specifies whether the networking service
|
||||
// should transmit ICMPv6 packets.
|
||||
IPv6RAMode string `json:"ipv6_ra_mode"`
|
||||
|
||||
// SubnetPoolID is the id of the subnet pool associated with the subnet.
|
||||
SubnetPoolID string `json:"subnetpool_id"`
|
||||
|
||||
// Tags optionally set via extensions/attributestags
|
||||
Tags []string `json:"tags"`
|
||||
}
|
||||
|
||||
// SubnetPage is the page returned by a pager when traversing over a collection
|
||||
// of subnets.
|
||||
type SubnetPage struct {
|
||||
pagination.LinkedPageBase
|
||||
}
|
||||
|
||||
// NextPageURL is invoked when a paginated collection of subnets has reached
|
||||
// the end of a page and the pager seeks to traverse over a new one. In order
|
||||
// to do this, it needs to construct the next page's URL.
|
||||
func (r SubnetPage) NextPageURL() (string, error) {
|
||||
var s struct {
|
||||
Links []gophercloud.Link `json:"subnets_links"`
|
||||
}
|
||||
err := r.ExtractInto(&s)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return gophercloud.ExtractNextURL(s.Links)
|
||||
}
|
||||
|
||||
// IsEmpty checks whether a SubnetPage struct is empty.
|
||||
func (r SubnetPage) IsEmpty() (bool, error) {
|
||||
is, err := ExtractSubnets(r)
|
||||
return len(is) == 0, err
|
||||
}
|
||||
|
||||
// ExtractSubnets accepts a Page struct, specifically a SubnetPage struct,
|
||||
// and extracts the elements into a slice of Subnet structs. In other words,
|
||||
// a generic collection is mapped into a relevant slice.
|
||||
func ExtractSubnets(r pagination.Page) ([]Subnet, error) {
|
||||
var s struct {
|
||||
Subnets []Subnet `json:"subnets"`
|
||||
}
|
||||
err := (r.(SubnetPage)).ExtractInto(&s)
|
||||
return s.Subnets, err
|
||||
}
|
31
vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/subnets/urls.go
generated
vendored
Normal file
31
vendor/github.com/gophercloud/gophercloud/openstack/networking/v2/subnets/urls.go
generated
vendored
Normal file
|
@ -0,0 +1,31 @@
|
|||
package subnets
|
||||
|
||||
import "github.com/gophercloud/gophercloud"
|
||||
|
||||
func resourceURL(c *gophercloud.ServiceClient, id string) string {
|
||||
return c.ServiceURL("subnets", id)
|
||||
}
|
||||
|
||||
func rootURL(c *gophercloud.ServiceClient) string {
|
||||
return c.ServiceURL("subnets")
|
||||
}
|
||||
|
||||
func listURL(c *gophercloud.ServiceClient) string {
|
||||
return rootURL(c)
|
||||
}
|
||||
|
||||
func getURL(c *gophercloud.ServiceClient, id string) string {
|
||||
return resourceURL(c, id)
|
||||
}
|
||||
|
||||
func createURL(c *gophercloud.ServiceClient) string {
|
||||
return rootURL(c)
|
||||
}
|
||||
|
||||
func updateURL(c *gophercloud.ServiceClient, id string) string {
|
||||
return resourceURL(c, id)
|
||||
}
|
||||
|
||||
func deleteURL(c *gophercloud.ServiceClient, id string) string {
|
||||
return resourceURL(c, id)
|
||||
}
|
|
@ -275,6 +275,7 @@ github.com/gophercloud/gophercloud/openstack/imageservice/v2/members
|
|||
github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/external
|
||||
github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/floatingips
|
||||
github.com/gophercloud/gophercloud/openstack/networking/v2/networks
|
||||
github.com/gophercloud/gophercloud/openstack/networking/v2/subnets
|
||||
github.com/gophercloud/gophercloud/openstack/utils
|
||||
github.com/gophercloud/gophercloud/pagination
|
||||
# github.com/gophercloud/utils v0.0.0-20190124192022-a5c25e7a53a6
|
||||
|
|
|
@ -41,6 +41,10 @@
|
|||
|
||||
- `ports` ([]string) - A list of ports by UUID to attach to this instance.
|
||||
|
||||
- `network_discovery_cidrs` ([]string) - A list of network CIDRs to discover the network to attach to this instance.
|
||||
The first network whose subnet is contained within any of the given CIDRs
|
||||
is used. Ignored if either of the above two options are provided.
|
||||
|
||||
- `user_data` (string) - User data to apply when launching the instance. Note that you need to be
|
||||
careful about escaping characters due to the templates being JSON. It is
|
||||
often more convenient to use user_data_file, instead. Packer will not
|
||||
|
|
Loading…
Reference in New Issue