From 6e92e60eef8f71cf0f93010904aeb4205d3a2e80 Mon Sep 17 00:00:00 2001 From: Tom Dooner Date: Tue, 17 Feb 2015 05:23:21 +0000 Subject: [PATCH] Add Rackconnect support This adds two config options that we need in order to successfully build our Rackspace images. First, a boolean `rackconnect_wait` option which waits for the RackConnect metadata to appear. Second, an `ssh_interface` option, for rackconnect users who have more prohibitive firewalls on the 'public' interface and want to ensure all traffic to the server goes over the 'private' one. Finishes #952. --- builder/openstack/builder.go | 5 ++- builder/openstack/run_config.go | 3 ++ builder/openstack/ssh.go | 7 ++- .../openstack/step_wait_for_rackconnect.go | 45 +++++++++++++++++++ 4 files changed, 58 insertions(+), 2 deletions(-) create mode 100644 builder/openstack/step_wait_for_rackconnect.go 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) { +}