Merge pull request #919 from nebula/manage_floating_ips
[OpenStack] Add flexible IP pool/address handling.
This commit is contained in:
commit
4a725409af
|
@ -92,6 +92,10 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
||||||
Flavor: b.config.Flavor,
|
Flavor: b.config.Flavor,
|
||||||
SourceImage: b.config.SourceImage,
|
SourceImage: b.config.SourceImage,
|
||||||
},
|
},
|
||||||
|
&StepAllocateIp{
|
||||||
|
FloatingIpPool: b.config.FloatingIpPool,
|
||||||
|
FloatingIp: b.config.FloatingIp,
|
||||||
|
},
|
||||||
&common.StepConnectSSH{
|
&common.StepConnectSSH{
|
||||||
SSHAddress: SSHAddress(csp, b.config.SSHPort),
|
SSHAddress: SSHAddress(csp, b.config.SSHPort),
|
||||||
SSHConfig: SSHConfig(b.config.SSHUsername),
|
SSHConfig: SSHConfig(b.config.SSHUsername),
|
||||||
|
|
|
@ -16,6 +16,9 @@ type RunConfig struct {
|
||||||
SSHUsername string `mapstructure:"ssh_username"`
|
SSHUsername string `mapstructure:"ssh_username"`
|
||||||
SSHPort int `mapstructure:"ssh_port"`
|
SSHPort int `mapstructure:"ssh_port"`
|
||||||
OpenstackProvider string `mapstructure:"openstack_provider"`
|
OpenstackProvider string `mapstructure:"openstack_provider"`
|
||||||
|
UseFloatingIp bool `mapstructure:"use_floating_ip"`
|
||||||
|
FloatingIpPool string `mapstructure:"floating_ip_pool"`
|
||||||
|
FloatingIp string `mapstructure:"floating_ip"`
|
||||||
|
|
||||||
// Unexported fields that are calculated from others
|
// Unexported fields that are calculated from others
|
||||||
sshTimeout time.Duration
|
sshTimeout time.Duration
|
||||||
|
@ -43,6 +46,10 @@ func (c *RunConfig) Prepare(t *packer.ConfigTemplate) []error {
|
||||||
c.RawSSHTimeout = "5m"
|
c.RawSSHTimeout = "5m"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if c.UseFloatingIp && c.FloatingIpPool == "" {
|
||||||
|
c.FloatingIpPool = "public"
|
||||||
|
}
|
||||||
|
|
||||||
// Validation
|
// Validation
|
||||||
var err error
|
var err error
|
||||||
errs := make([]error, 0)
|
errs := make([]error, 0)
|
||||||
|
|
|
@ -13,24 +13,35 @@ import (
|
||||||
// for determining the SSH address based on the server AccessIPv4 setting..
|
// for determining the SSH address based on the server AccessIPv4 setting..
|
||||||
func SSHAddress(csp gophercloud.CloudServersProvider, port int) func(multistep.StateBag) (string, error) {
|
func SSHAddress(csp gophercloud.CloudServersProvider, port int) func(multistep.StateBag) (string, error) {
|
||||||
return func(state multistep.StateBag) (string, error) {
|
return func(state multistep.StateBag) (string, error) {
|
||||||
for j := 0; j < 2; j++ {
|
s := state.Get("server").(*gophercloud.Server)
|
||||||
s := state.Get("server").(*gophercloud.Server)
|
|
||||||
if s.AccessIPv4 != "" {
|
|
||||||
return fmt.Sprintf("%s:%d", s.AccessIPv4, port), nil
|
|
||||||
}
|
|
||||||
if s.AccessIPv6 != "" {
|
|
||||||
return fmt.Sprintf("[%s]:%d", s.AccessIPv6, port), nil
|
|
||||||
}
|
|
||||||
serverState, err := csp.ServerById(s.Id)
|
|
||||||
|
|
||||||
if err != nil {
|
if ip := state.Get("access_ip").(gophercloud.FloatingIp); ip.Ip != "" {
|
||||||
return "", err
|
return fmt.Sprintf("%s:%d", ip.Ip, port), nil
|
||||||
}
|
|
||||||
|
|
||||||
state.Put("server", serverState)
|
|
||||||
time.Sleep(1 * time.Second)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ip_pools, err := s.AllAddressPools()
|
||||||
|
if err != nil {
|
||||||
|
return "", errors.New("Error parsing SSH addresses")
|
||||||
|
}
|
||||||
|
for pool, addresses := range ip_pools {
|
||||||
|
if pool != "" {
|
||||||
|
for _, address := range addresses {
|
||||||
|
if address.Addr != "" {
|
||||||
|
return fmt.Sprintf("%s:%d", address.Addr, port), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
serverState, err := csp.ServerById(s.Id)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
state.Put("server", serverState)
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
|
||||||
return "", errors.New("couldn't determine IP address for server")
|
return "", errors.New("couldn't determine IP address for server")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,66 @@
|
||||||
|
package openstack
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/mitchellh/multistep"
|
||||||
|
"github.com/mitchellh/packer/packer"
|
||||||
|
"github.com/rackspace/gophercloud"
|
||||||
|
)
|
||||||
|
|
||||||
|
type StepAllocateIp struct {
|
||||||
|
FloatingIpPool string
|
||||||
|
FloatingIp string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StepAllocateIp) Run(state multistep.StateBag) multistep.StepAction {
|
||||||
|
ui := state.Get("ui").(packer.Ui)
|
||||||
|
csp := state.Get("csp").(gophercloud.CloudServersProvider)
|
||||||
|
server := state.Get("server").(*gophercloud.Server)
|
||||||
|
|
||||||
|
var instanceIp gophercloud.FloatingIp
|
||||||
|
// This is here in case we error out before putting instanceIp into the
|
||||||
|
// statebag below, because it is requested by Cleanup()
|
||||||
|
state.Put("access_ip", instanceIp)
|
||||||
|
|
||||||
|
if s.FloatingIp != "" {
|
||||||
|
instanceIp.Ip = s.FloatingIp
|
||||||
|
} else if s.FloatingIpPool != "" {
|
||||||
|
newIp, err := csp.CreateFloatingIp(s.FloatingIpPool)
|
||||||
|
if err != nil {
|
||||||
|
err := fmt.Errorf("Error creating floating ip from pool '%s'", s.FloatingIpPool)
|
||||||
|
state.Put("error", err)
|
||||||
|
ui.Error(err.Error())
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
instanceIp = newIp
|
||||||
|
ui.Say(fmt.Sprintf("Created temporary floating IP %s...", instanceIp.Ip))
|
||||||
|
}
|
||||||
|
|
||||||
|
if instanceIp.Ip != "" {
|
||||||
|
if err := csp.AssociateFloatingIp(server.Id, instanceIp); err != nil {
|
||||||
|
err := fmt.Errorf("Error associating floating IP %s with instance.", instanceIp.Ip)
|
||||||
|
state.Put("error", err)
|
||||||
|
ui.Error(err.Error())
|
||||||
|
return multistep.ActionHalt
|
||||||
|
} else {
|
||||||
|
ui.Say(fmt.Sprintf("Added floating IP %s to instance...", instanceIp.Ip))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
state.Put("access_ip", instanceIp)
|
||||||
|
|
||||||
|
return multistep.ActionContinue
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StepAllocateIp) Cleanup(state multistep.StateBag) {
|
||||||
|
ui := state.Get("ui").(packer.Ui)
|
||||||
|
csp := state.Get("csp").(gophercloud.CloudServersProvider)
|
||||||
|
instanceIp := state.Get("access_ip").(gophercloud.FloatingIp)
|
||||||
|
if s.FloatingIpPool != "" && instanceIp.Id != 0 {
|
||||||
|
if err := csp.DeleteFloatingIp(instanceIp); err != nil {
|
||||||
|
ui.Error(fmt.Sprintf("Error deleting temporary floating IP %s", instanceIp.Ip))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ui.Say(fmt.Sprintf("Deleted temporary floating IP %s", instanceIp.Ip))
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue