[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,
|
SourceMostRecent: b.config.SourceImageFilters.MostRecent,
|
||||||
SourceProperties: b.config.SourceImageFilters.Filters.Properties,
|
SourceProperties: b.config.SourceImageFilters.Filters.Properties,
|
||||||
},
|
},
|
||||||
|
&StepDiscoverNetwork{
|
||||||
|
Networks: b.config.Networks,
|
||||||
|
NetworkDiscoveryCIDRs: b.config.NetworkDiscoveryCIDRs,
|
||||||
|
Ports: b.config.Ports,
|
||||||
|
},
|
||||||
&StepCreateVolume{
|
&StepCreateVolume{
|
||||||
UseBlockStorageVolume: b.config.UseBlockStorageVolume,
|
UseBlockStorageVolume: b.config.UseBlockStorageVolume,
|
||||||
VolumeName: b.config.VolumeName,
|
VolumeName: b.config.VolumeName,
|
||||||
|
@ -110,8 +115,6 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
|
||||||
&StepRunSourceServer{
|
&StepRunSourceServer{
|
||||||
Name: b.config.InstanceName,
|
Name: b.config.InstanceName,
|
||||||
SecurityGroups: b.config.SecurityGroups,
|
SecurityGroups: b.config.SecurityGroups,
|
||||||
Networks: b.config.Networks,
|
|
||||||
Ports: b.config.Ports,
|
|
||||||
AvailabilityZone: b.config.AvailabilityZone,
|
AvailabilityZone: b.config.AvailabilityZone,
|
||||||
UserData: b.config.UserData,
|
UserData: b.config.UserData,
|
||||||
UserDataFile: b.config.UserDataFile,
|
UserDataFile: b.config.UserDataFile,
|
||||||
|
|
|
@ -98,6 +98,7 @@ type FlatConfig struct {
|
||||||
SecurityGroups []string `mapstructure:"security_groups" required:"false" cty:"security_groups"`
|
SecurityGroups []string `mapstructure:"security_groups" required:"false" cty:"security_groups"`
|
||||||
Networks []string `mapstructure:"networks" required:"false" cty:"networks"`
|
Networks []string `mapstructure:"networks" required:"false" cty:"networks"`
|
||||||
Ports []string `mapstructure:"ports" required:"false" cty:"ports"`
|
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"`
|
UserData *string `mapstructure:"user_data" required:"false" cty:"user_data"`
|
||||||
UserDataFile *string `mapstructure:"user_data_file" required:"false" cty:"user_data_file"`
|
UserDataFile *string `mapstructure:"user_data_file" required:"false" cty:"user_data_file"`
|
||||||
InstanceName *string `mapstructure:"instance_name" required:"false" cty:"instance_name"`
|
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},
|
"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},
|
"networks": &hcldec.AttrSpec{Name: "networks", Type: cty.List(cty.String), Required: false},
|
||||||
"ports": &hcldec.AttrSpec{Name: "ports", 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": &hcldec.AttrSpec{Name: "user_data", Type: cty.String, Required: false},
|
||||||
"user_data_file": &hcldec.AttrSpec{Name: "user_data_file", 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},
|
"instance_name": &hcldec.AttrSpec{Name: "instance_name", Type: cty.String, Required: false},
|
||||||
|
|
|
@ -3,6 +3,7 @@ package openstack
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
"net"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/gophercloud/gophercloud"
|
"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/external"
|
||||||
"github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/floatingips"
|
"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/networks"
|
||||||
|
"github.com/gophercloud/gophercloud/openstack/networking/v2/subnets"
|
||||||
"github.com/gophercloud/gophercloud/pagination"
|
"github.com/gophercloud/gophercloud/pagination"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -136,3 +138,43 @@ func GetFloatingIPNetworkIDByName(client *gophercloud.ServiceClient, networkName
|
||||||
|
|
||||||
return externalNetworks[0].ID, nil
|
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"`
|
Networks []string `mapstructure:"networks" required:"false"`
|
||||||
// A list of ports by UUID to attach to this instance.
|
// A list of ports by UUID to attach to this instance.
|
||||||
Ports []string `mapstructure:"ports" required:"false"`
|
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
|
// 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
|
// careful about escaping characters due to the templates being JSON. It is
|
||||||
// often more convenient to use user_data_file, instead. Packer will not
|
// 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 {
|
type StepRunSourceServer struct {
|
||||||
Name string
|
Name string
|
||||||
SecurityGroups []string
|
SecurityGroups []string
|
||||||
Networks []string
|
|
||||||
Ports []string
|
|
||||||
AvailabilityZone string
|
AvailabilityZone string
|
||||||
UserData string
|
UserData string
|
||||||
UserDataFile string
|
UserDataFile string
|
||||||
|
@ -32,6 +30,7 @@ func (s *StepRunSourceServer) Run(ctx context.Context, state multistep.StateBag)
|
||||||
config := state.Get("config").(*Config)
|
config := state.Get("config").(*Config)
|
||||||
flavor := state.Get("flavor_id").(string)
|
flavor := state.Get("flavor_id").(string)
|
||||||
sourceImage := state.Get("source_image").(string)
|
sourceImage := state.Get("source_image").(string)
|
||||||
|
networks := state.Get("networks").([]servers.Network)
|
||||||
ui := state.Get("ui").(packer.Ui)
|
ui := state.Get("ui").(packer.Ui)
|
||||||
|
|
||||||
// We need the v2 compute client
|
// We need the v2 compute client
|
||||||
|
@ -42,15 +41,6 @@ func (s *StepRunSourceServer) Run(ctx context.Context, state multistep.StateBag)
|
||||||
return multistep.ActionHalt
|
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)
|
userData := []byte(s.UserData)
|
||||||
if s.UserDataFile != "" {
|
if s.UserDataFile != "" {
|
||||||
userData, err = ioutil.ReadFile(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/external
|
||||||
github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/layer3/floatingips
|
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/networks
|
||||||
|
github.com/gophercloud/gophercloud/openstack/networking/v2/subnets
|
||||||
github.com/gophercloud/gophercloud/openstack/utils
|
github.com/gophercloud/gophercloud/openstack/utils
|
||||||
github.com/gophercloud/gophercloud/pagination
|
github.com/gophercloud/gophercloud/pagination
|
||||||
# github.com/gophercloud/utils v0.0.0-20190124192022-a5c25e7a53a6
|
# 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.
|
- `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
|
- `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
|
careful about escaping characters due to the templates being JSON. It is
|
||||||
often more convenient to use user_data_file, instead. Packer will not
|
often more convenient to use user_data_file, instead. Packer will not
|
||||||
|
|
Loading…
Reference in New Issue