diff --git a/builder/openstack/builder.go b/builder/openstack/builder.go index 0038ea9a0..3b2834063 100644 --- a/builder/openstack/builder.go +++ b/builder/openstack/builder.go @@ -95,12 +95,15 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe SecurityGroups: b.config.SecurityGroups, Networks: b.config.Networks, }, + &StepWaitForRackConnect{ + Wait: b.config.RackconnectWait, + }, &StepAllocateIp{ FloatingIpPool: b.config.FloatingIpPool, FloatingIp: b.config.FloatingIp, }, &common.StepConnectSSH{ - SSHAddress: SSHAddress(csp, b.config.SSHPort), + SSHAddress: SSHAddress(csp, b.config.SSHInterface, b.config.SSHPort), SSHConfig: SSHConfig(b.config.SSHUsername), SSHWaitTimeout: b.config.SSHTimeout(), }, diff --git a/builder/openstack/run_config.go b/builder/openstack/run_config.go index 1e5bdc178..c2b59a118 100644 --- a/builder/openstack/run_config.go +++ b/builder/openstack/run_config.go @@ -15,8 +15,10 @@ type RunConfig struct { RawSSHTimeout string `mapstructure:"ssh_timeout"` SSHUsername string `mapstructure:"ssh_username"` SSHPort int `mapstructure:"ssh_port"` + SSHInterface string `mapstructure:"ssh_interface"` OpenstackProvider string `mapstructure:"openstack_provider"` UseFloatingIp bool `mapstructure:"use_floating_ip"` + RackconnectWait bool `mapstructure:"rackconnect_wait"` FloatingIpPool string `mapstructure:"floating_ip_pool"` FloatingIp string `mapstructure:"floating_ip"` SecurityGroups []string `mapstructure:"security_groups"` @@ -71,6 +73,7 @@ func (c *RunConfig) Prepare(t *packer.ConfigTemplate) []error { "flavor": &c.Flavor, "ssh_timeout": &c.RawSSHTimeout, "ssh_username": &c.SSHUsername, + "ssh_interface": &c.SSHInterface, "source_image": &c.SourceImage, "openstack_provider": &c.OpenstackProvider, "floating_ip_pool": &c.FloatingIpPool, diff --git a/builder/openstack/ssh.go b/builder/openstack/ssh.go index 055850663..cbf2c6b41 100644 --- a/builder/openstack/ssh.go +++ b/builder/openstack/ssh.go @@ -12,7 +12,7 @@ import ( // SSHAddress returns a function that can be given to the SSH communicator // 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, sshinterface string, port int) func(multistep.StateBag) (string, error) { return func(state multistep.StateBag) (string, error) { s := state.Get("server").(*gophercloud.Server) @@ -25,6 +25,11 @@ func SSHAddress(csp gophercloud.CloudServersProvider, port int) func(multistep.S return "", errors.New("Error parsing SSH addresses") } for pool, addresses := range ip_pools { + if sshinterface != "" { + if pool != sshinterface { + continue + } + } if pool != "" { for _, address := range addresses { if address.Addr != "" && address.Version == 4 { diff --git a/builder/openstack/step_wait_for_rackconnect.go b/builder/openstack/step_wait_for_rackconnect.go new file mode 100644 index 000000000..94affbe37 --- /dev/null +++ b/builder/openstack/step_wait_for_rackconnect.go @@ -0,0 +1,45 @@ +package openstack + +import ( + "fmt" + "github.com/mitchellh/multistep" + "github.com/mitchellh/packer/packer" + "time" + + "github.com/mitchellh/gophercloud-fork-40444fb" +) + +type StepWaitForRackConnect struct { + Wait bool +} + +func (s *StepWaitForRackConnect) Run(state multistep.StateBag) multistep.StepAction { + if !s.Wait { + return multistep.ActionContinue + } + + csp := state.Get("csp").(gophercloud.CloudServersProvider) + server := state.Get("server").(*gophercloud.Server) + ui := state.Get("ui").(packer.Ui) + fmt.Printf("%s", server) + + ui.Say(fmt.Sprintf("Waiting for server (%s) to become RackConnect ready...", server.Id)) + + for { + server, err := csp.ServerById(server.Id) + if err != nil { + return multistep.ActionHalt + } + + if server.Metadata["rackconnect_automation_status"] == "DEPLOYED" { + break + } + + time.Sleep(2 * time.Second) + } + + return multistep.ActionContinue +} + +func (s *StepWaitForRackConnect) Cleanup(state multistep.StateBag) { +} diff --git a/website/source/docs/builders/openstack.html.markdown b/website/source/docs/builders/openstack.html.markdown index 7fc8182eb..d5dbbf249 100644 --- a/website/source/docs/builders/openstack.html.markdown +++ b/website/source/docs/builders/openstack.html.markdown @@ -102,12 +102,20 @@ each category, the available configuration keys are alphabetized. * `ssh_username` (string) - The username to use in order to communicate over SSH to the running server. The default is "root". +* `ssh_interface` (string) - The type of interface to connect via SSH. Values + useful for Rackspace are "public" or "private", and the default behavior is + to connect via whichever is returned first from the OpenStack API. + * `tenant_id` (string) - Tenant ID for accessing OpenStack if your installation requires this. * `use_floating_ip` (boolean) - Whether or not to use a floating IP for the instance. Defaults to false. +* `rackconnect_wait` (boolean) - For rackspace, whether or not to wait for + Rackconnect to assign the machine an IP address before connecting via SSH. + Defaults to false. + ## Basic Example: Rackspace public cloud Here is a basic example. This is a working example to build a