diff --git a/builder/cloudstack/builder.go b/builder/cloudstack/builder.go index e46e56086..5c82e3188 100644 --- a/builder/cloudstack/builder.go +++ b/builder/cloudstack/builder.go @@ -80,10 +80,12 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe &communicator.StepConnect{ Config: &b.config.Comm, Host: commHost, - SSHConfig: SSHConfig( + SSHConfig: sshConfig( b.config.Comm.SSHAgentAuth, b.config.Comm.SSHUsername, b.config.Comm.SSHPassword), + SSHPort: commPort, + WinRMPort: commPort, }, &common.StepProvision{}, &stepShutdownInstance{}, diff --git a/builder/cloudstack/config.go b/builder/cloudstack/config.go index 35026f6e3..7a617c6cd 100644 --- a/builder/cloudstack/config.go +++ b/builder/cloudstack/config.go @@ -58,9 +58,7 @@ type Config struct { TemplateScalable bool `mapstructure:"template_scalable"` TemplateTag string `mapstructure:"template_tag"` - ctx interpolate.Context - hostAddress string // The host address used by the communicators. - instanceSource string // This can be either a template ID or an ISO ID. + ctx interpolate.Context } // NewConfig parses and validates the given config. diff --git a/builder/cloudstack/ssh.go b/builder/cloudstack/ssh.go index ab350d053..7a4c2fcba 100644 --- a/builder/cloudstack/ssh.go +++ b/builder/cloudstack/ssh.go @@ -7,28 +7,29 @@ import ( packerssh "github.com/hashicorp/packer/communicator/ssh" "github.com/mitchellh/multistep" - "github.com/xanzy/go-cloudstack/cloudstack" "golang.org/x/crypto/ssh" "golang.org/x/crypto/ssh/agent" ) func commHost(state multistep.StateBag) (string, error) { - client := state.Get("client").(*cloudstack.CloudStackClient) - config := state.Get("config").(*Config) - - if config.hostAddress == "" { - ipAddr, _, err := client.Address.GetPublicIpAddressByID(config.PublicIPAddress) - if err != nil { - return "", fmt.Errorf("Failed to retrieve IP address: %s", err) - } - - config.hostAddress = ipAddr.Ipaddress + ip, hasIP := state.Get("ipaddress").(string) + if !hasIP { + return "", fmt.Errorf("Failed to retrieve IP address") } - return config.hostAddress, nil + return ip, nil } -func SSHConfig(useAgent bool, username, password string) func(state multistep.StateBag) (*ssh.ClientConfig, error) { +func commPort(state multistep.StateBag) (int, error) { + commPort, hasPort := state.Get("commPort").(int) + if !hasPort { + return 0, fmt.Errorf("Failed to retrieve communication port") + } + + return commPort, nil +} + +func sshConfig(useAgent bool, username, password string) func(state multistep.StateBag) (*ssh.ClientConfig, error) { return func(state multistep.StateBag) (*ssh.ClientConfig, error) { if useAgent { authSock := os.Getenv("SSH_AUTH_SOCK") diff --git a/builder/cloudstack/step_configure_networking.go b/builder/cloudstack/step_configure_networking.go index 48a3742ab..d9a6a365c 100644 --- a/builder/cloudstack/step_configure_networking.go +++ b/builder/cloudstack/step_configure_networking.go @@ -25,6 +25,7 @@ func (s *stepSetupNetworking) Run(state multistep.StateBag) multistep.StepAction if config.UseLocalIPAddress { ui.Message("Using the local IP address...") + state.Put("commPort", config.Comm.Port()) ui.Message("Networking has been setup!") return multistep.ActionContinue } @@ -32,18 +33,11 @@ func (s *stepSetupNetworking) Run(state multistep.StateBag) multistep.StepAction // Generate a random public port used to configure our port forward. rand.Seed(time.Now().UnixNano()) s.publicPort = 50000 + rand.Intn(10000) + state.Put("commPort", s.publicPort) // Set the currently configured port to be the private port. s.privatePort = config.Comm.Port() - // Set the SSH or WinRM port to be the randomly generated public port. - switch config.Comm.Type { - case "ssh": - config.Comm.SSHPort = s.publicPort - case "winrm": - config.Comm.WinRMPort = s.publicPort - } - // Retrieve the instance ID from the previously saved state. instanceID, ok := state.Get("instance_id").(string) if !ok || instanceID == "" { @@ -91,7 +85,7 @@ func (s *stepSetupNetworking) Run(state multistep.StateBag) multistep.StepAction // Set the IP address and it's ID. config.PublicIPAddress = ipAddr.Id - config.hostAddress = ipAddr.Ipaddress + state.Put("ipaddress", ipAddr.Ipaddress) // Store the IP address ID. state.Put("ip_address_id", ipAddr.Id) diff --git a/builder/cloudstack/step_create_instance.go b/builder/cloudstack/step_create_instance.go index 538a062b9..3e37fad14 100644 --- a/builder/cloudstack/step_create_instance.go +++ b/builder/cloudstack/step_create_instance.go @@ -37,7 +37,7 @@ func (s *stepCreateInstance) Run(state multistep.StateBag) multistep.StepAction // Create a new parameter struct. p := client.VirtualMachine.NewDeployVirtualMachineParams( config.ServiceOffering, - config.instanceSource, + state.Get("source").(string), config.Zone, ) @@ -140,7 +140,7 @@ func (s *stepCreateInstance) Run(state multistep.StateBag) multistep.StepAction // Set the host address when using the local IP address to connect. if config.UseLocalIPAddress { - config.hostAddress = instance.Nic[0].Ipaddress + state.Put("ipaddress", instance.Nic[0].Ipaddress) } // Store the instance ID so we can remove it later. diff --git a/builder/cloudstack/step_prepare_config.go b/builder/cloudstack/step_prepare_config.go index 6cfb5c478..4d6353c6a 100644 --- a/builder/cloudstack/step_prepare_config.go +++ b/builder/cloudstack/step_prepare_config.go @@ -53,26 +53,34 @@ func (s *stepPrepareConfig) Run(state multistep.StateBag) multistep.StepAction { } } - if config.PublicIPAddress != "" && !isUUID(config.PublicIPAddress) { - // Save the public IP address before replacing it with it's UUID. - config.hostAddress = config.PublicIPAddress + if config.PublicIPAddress != "" { + if isUUID(config.PublicIPAddress) { + ip, _, err := client.Address.GetPublicIpAddressByID(config.PublicIPAddress) + if err != nil { + errs = packer.MultiErrorAppend(errs, fmt.Errorf("Failed to retrieve IP address: %s", err)) + } + state.Put("ipaddress", ip.Ipaddress) + } else { + // Save the public IP address before replacing it with it's UUID. + state.Put("ipaddress", config.PublicIPAddress) - p := client.Address.NewListPublicIpAddressesParams() - p.SetIpaddress(config.PublicIPAddress) + p := client.Address.NewListPublicIpAddressesParams() + p.SetIpaddress(config.PublicIPAddress) - if config.Project != "" { - p.SetProjectid(config.Project) - } + if config.Project != "" { + p.SetProjectid(config.Project) + } - ipAddrs, err := client.Address.ListPublicIpAddresses(p) - if err != nil { - errs = packer.MultiErrorAppend(errs, &retrieveErr{"IP address", config.PublicIPAddress, err}) - } - if err == nil && ipAddrs.Count != 1 { - errs = packer.MultiErrorAppend(errs, &retrieveErr{"IP address", config.PublicIPAddress, ipAddrs}) - } - if err == nil && ipAddrs.Count == 1 { - config.PublicIPAddress = ipAddrs.PublicIpAddresses[0].Id + ipAddrs, err := client.Address.ListPublicIpAddresses(p) + if err != nil { + errs = packer.MultiErrorAppend(errs, &retrieveErr{"IP address", config.PublicIPAddress, err}) + } + if err == nil && ipAddrs.Count != 1 { + errs = packer.MultiErrorAppend(errs, &retrieveErr{"IP address", config.PublicIPAddress, ipAddrs}) + } + if err == nil && ipAddrs.Count == 1 { + config.PublicIPAddress = ipAddrs.PublicIpAddresses[0].Id + } } } @@ -104,23 +112,25 @@ func (s *stepPrepareConfig) Run(state multistep.StateBag) multistep.StepAction { if config.SourceISO != "" { if isUUID(config.SourceISO) { - config.instanceSource = config.SourceISO + state.Put("source", config.SourceISO) } else { - config.instanceSource, _, err = client.ISO.GetIsoID(config.SourceISO, "executable", config.Zone) + isoID, _, err := client.ISO.GetIsoID(config.SourceISO, "executable", config.Zone) if err != nil { errs = packer.MultiErrorAppend(errs, &retrieveErr{"ISO", config.SourceISO, err}) } + state.Put("source", isoID) } } if config.SourceTemplate != "" { if isUUID(config.SourceTemplate) { - config.instanceSource = config.SourceTemplate + state.Put("source", config.SourceTemplate) } else { - config.instanceSource, _, err = client.Template.GetTemplateID(config.SourceTemplate, "executable", config.Zone) + templateID, _, err := client.Template.GetTemplateID(config.SourceTemplate, "executable", config.Zone) if err != nil { errs = packer.MultiErrorAppend(errs, &retrieveErr{"template", config.SourceTemplate, err}) } + state.Put("source", templateID) } }