From 8396a2db1e5f914ddb70cc59b2fae45984ddd0b9 Mon Sep 17 00:00:00 2001 From: Nathan Mische Date: Sat, 13 Feb 2016 15:53:46 -0500 Subject: [PATCH 1/2] Adding ability to select IP version for SSH connections to OpenStack instances. Addresses #3047 --- builder/openstack/builder.go | 3 ++- builder/openstack/run_config.go | 1 + builder/openstack/ssh.go | 24 +++++++++++++++---- .../docs/builders/openstack.html.markdown | 2 ++ 4 files changed, 25 insertions(+), 5 deletions(-) diff --git a/builder/openstack/builder.go b/builder/openstack/builder.go index a97effa7c..8b4a88f81 100644 --- a/builder/openstack/builder.go +++ b/builder/openstack/builder.go @@ -102,7 +102,8 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe Config: &b.config.RunConfig.Comm, Host: CommHost( computeClient, - b.config.SSHInterface), + b.config.SSHInterface, + b.config.SSHIPVersion), SSHConfig: SSHConfig(b.config.RunConfig.Comm.SSHUsername), }, &common.StepProvision{}, diff --git a/builder/openstack/run_config.go b/builder/openstack/run_config.go index c5d3bd532..42512c837 100644 --- a/builder/openstack/run_config.go +++ b/builder/openstack/run_config.go @@ -13,6 +13,7 @@ type RunConfig struct { Comm communicator.Config `mapstructure:",squash"` SSHKeyPairName string `mapstructure:"ssh_keypair_name"` SSHInterface string `mapstructure:"ssh_interface"` + SSHIPVersion string `mapstructure:"ssh_ip_version"` SourceImage string `mapstructure:"source_image"` SourceImageName string `mapstructure:"source_image_name"` diff --git a/builder/openstack/ssh.go b/builder/openstack/ssh.go index 6201f1390..5b99666f9 100644 --- a/builder/openstack/ssh.go +++ b/builder/openstack/ssh.go @@ -4,6 +4,7 @@ import ( "errors" "fmt" "log" + "strconv" "time" "github.com/mitchellh/multistep" @@ -16,13 +17,14 @@ import ( // CommHost looks up the host for the communicator. func CommHost( client *gophercloud.ServiceClient, - sshinterface string) func(multistep.StateBag) (string, error) { + sshinterface string, + sshipversion string) func(multistep.StateBag) (string, error) { return func(state multistep.StateBag) (string, error) { s := state.Get("server").(*servers.Server) // If we have a specific interface, try that if sshinterface != "" { - if addr := sshAddrFromPool(s, sshinterface); addr != "" { + if addr := sshAddrFromPool(s, sshinterface, sshipversion); addr != "" { log.Printf("[DEBUG] Using IP address %s from specified interface %s to connect", addr, sshinterface) return addr, nil } @@ -41,7 +43,7 @@ func CommHost( } // Try to get it from the requested interface - if addr := sshAddrFromPool(s, sshinterface); addr != "" { + if addr := sshAddrFromPool(s, sshinterface, sshipversion); addr != "" { log.Printf("[DEBUG] Using IP address %s to connect", addr) return addr, nil } @@ -79,7 +81,13 @@ func SSHConfig(username string) func(multistep.StateBag) (*ssh.ClientConfig, err } } -func sshAddrFromPool(s *servers.Server, desired string) string { +func sshAddrFromPool(s *servers.Server, desired string, sshIPVersion string) string { + + ipVersion, err := strconv.Atoi(sshIPVersion) + if err != nil { + log.Printf("[ERROR] Invalid ssh IP version: %s", sshIPVersion) + } + // Get all the addresses associated with this server. This // was taken directly from Terraform. for pool, networkAddresses := range s.Addresses { @@ -104,6 +112,14 @@ func sshAddrFromPool(s *servers.Server, desired string) string { address := element.(map[string]interface{}) if address["OS-EXT-IPS:type"] == "floating" { addr = address["addr"].(string) + } else if ipVersion == 4 { + if address["version"].(float64) == 4 { + addr = address["addr"].(string) + } + } else if ipVersion == 6 { + if address["version"].(float64) == 6 { + addr = fmt.Sprintf("[%s]", address["addr"].(string)) + } } else { if address["version"].(float64) == 6 { addr = fmt.Sprintf("[%s]", address["addr"].(string)) diff --git a/website/source/docs/builders/openstack.html.markdown b/website/source/docs/builders/openstack.html.markdown index f3195ac1f..6e929270b 100644 --- a/website/source/docs/builders/openstack.html.markdown +++ b/website/source/docs/builders/openstack.html.markdown @@ -115,6 +115,8 @@ builder. useful for Rackspace are "public" or "private", and the default behavior is to connect via whichever is returned first from the OpenStack API. +- `ssh_ip_version` (string) - The IP version to use for SSH connections, valid values are `4` and `6`. Useful on dual stacked instances where the default behaviour is to connect via whichever IP address is returned first from the OpenStack API. + - `ssh_keypair_name` (string) - If specified, this is the key that will be used for SSH with the machine. By default, this is blank, and Packer will generate a temporary keypair. From 335a2010bf9424b96a2167c1fb781e6e9b7ebfe3 Mon Sep 17 00:00:00 2001 From: Nathan Mische Date: Sun, 14 Feb 2016 15:23:56 -0500 Subject: [PATCH 2/2] Moving SSH IP version validation to prepare function. --- builder/openstack/run_config.go | 4 ++++ builder/openstack/ssh.go | 11 ++--------- website/source/docs/builders/openstack.html.markdown | 5 ++++- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/builder/openstack/run_config.go b/builder/openstack/run_config.go index 42512c837..df6290ed0 100644 --- a/builder/openstack/run_config.go +++ b/builder/openstack/run_config.go @@ -56,5 +56,9 @@ func (c *RunConfig) Prepare(ctx *interpolate.Context) []error { errs = append(errs, errors.New("A flavor must be specified")) } + if c.SSHIPVersion != "" && c.SSHIPVersion != "4" && c.SSHIPVersion != "6" { + errs = append(errs, errors.New("SSH IP version must be either 4 or 6")) + } + return errs } diff --git a/builder/openstack/ssh.go b/builder/openstack/ssh.go index 5b99666f9..f7fb2d5a9 100644 --- a/builder/openstack/ssh.go +++ b/builder/openstack/ssh.go @@ -4,7 +4,6 @@ import ( "errors" "fmt" "log" - "strconv" "time" "github.com/mitchellh/multistep" @@ -82,12 +81,6 @@ func SSHConfig(username string) func(multistep.StateBag) (*ssh.ClientConfig, err } func sshAddrFromPool(s *servers.Server, desired string, sshIPVersion string) string { - - ipVersion, err := strconv.Atoi(sshIPVersion) - if err != nil { - log.Printf("[ERROR] Invalid ssh IP version: %s", sshIPVersion) - } - // Get all the addresses associated with this server. This // was taken directly from Terraform. for pool, networkAddresses := range s.Addresses { @@ -112,11 +105,11 @@ func sshAddrFromPool(s *servers.Server, desired string, sshIPVersion string) str address := element.(map[string]interface{}) if address["OS-EXT-IPS:type"] == "floating" { addr = address["addr"].(string) - } else if ipVersion == 4 { + } else if sshIPVersion == "4" { if address["version"].(float64) == 4 { addr = address["addr"].(string) } - } else if ipVersion == 6 { + } else if sshIPVersion == "6" { if address["version"].(float64) == 6 { addr = fmt.Sprintf("[%s]", address["addr"].(string)) } diff --git a/website/source/docs/builders/openstack.html.markdown b/website/source/docs/builders/openstack.html.markdown index 6e929270b..c1c9c84aa 100644 --- a/website/source/docs/builders/openstack.html.markdown +++ b/website/source/docs/builders/openstack.html.markdown @@ -115,7 +115,10 @@ builder. useful for Rackspace are "public" or "private", and the default behavior is to connect via whichever is returned first from the OpenStack API. -- `ssh_ip_version` (string) - The IP version to use for SSH connections, valid values are `4` and `6`. Useful on dual stacked instances where the default behaviour is to connect via whichever IP address is returned first from the OpenStack API. +- `ssh_ip_version` (string) - The IP version to use for SSH connections, valid + values are `4` and `6`. Useful on dual stacked instances where the default + behaviour is to connect via whichever IP address is returned first from the + OpenStack API. - `ssh_keypair_name` (string) - If specified, this is the key that will be used for SSH with the machine. By default, this is blank, and Packer will