diff --git a/builder/virtualbox/common/run_config.go b/builder/virtualbox/common/run_config.go index 16ce1c4ad..653b19294 100644 --- a/builder/virtualbox/common/run_config.go +++ b/builder/virtualbox/common/run_config.go @@ -11,6 +11,9 @@ type RunConfig struct { Headless bool `mapstructure:"headless"` RawBootWait string `mapstructure:"boot_wait"` + VRDPPortMin uint `mapstructure:"vrdp_port_min"` + VRDPPortMax uint `mapstructure:"vrdp_port_max"` + BootWait time.Duration `` } @@ -19,6 +22,14 @@ func (c *RunConfig) Prepare(ctx *interpolate.Context) []error { c.RawBootWait = "10s" } + if c.VRDPPortMin == 0 { + c.VRDPPortMin = 5900 + } + + if c.VRDPPortMax == 0 { + c.VRDPPortMax = 6000 + } + var errs []error var err error c.BootWait, err = time.ParseDuration(c.RawBootWait) @@ -26,5 +37,10 @@ func (c *RunConfig) Prepare(ctx *interpolate.Context) []error { errs = append(errs, fmt.Errorf("Failed parsing boot_wait: %s", err)) } + if c.VRDPPortMin > c.VRDPPortMax { + errs = append( + errs, fmt.Errorf("vrdp_port_min must be less than vrdp_port_max")) + } + return errs } diff --git a/builder/virtualbox/common/step_configure_vrdp.go b/builder/virtualbox/common/step_configure_vrdp.go new file mode 100644 index 000000000..578455df3 --- /dev/null +++ b/builder/virtualbox/common/step_configure_vrdp.go @@ -0,0 +1,73 @@ +package common + +import ( + "fmt" + "log" + "math/rand" + "net" + + "github.com/mitchellh/multistep" + "github.com/mitchellh/packer/packer" +) + +// This step configures the VM to enable the VRDP server +// on the guest machine. +// +// Uses: +// driver Driver +// ui packer.Ui +// vmName string +// +// Produces: +// vrdp_port unit - The port that VRDP is configured to listen on. +type StepConfigureVRDP struct { + VRDPPortMin uint + VRDPPortMax uint +} + +func (s *StepConfigureVRDP) Run(state multistep.StateBag) multistep.StepAction { + driver := state.Get("driver").(Driver) + ui := state.Get("ui").(packer.Ui) + vmName := state.Get("vmName").(string) + + log.Printf("Looking for available port between %d and %d", s.VRDPPortMin, s.VRDPPortMax) + var vrdpPort uint + portRange := int (s.VRDPPortMax - s.VRDPPortMin) + + for { + if portRange > 0 { + vrdpPort = uint(rand.Intn(portRange)) + s.VRDPPortMin + } else { + vrdpPort = s.VRDPPortMin + } + + log.Printf("Trying port: %d", vrdpPort) + l, err := net.Listen("tcp", fmt.Sprintf(":%d", vrdpPort)) + if err == nil { + defer l.Close() + break + } + } + + command := []string{ + "modifyvm", vmName, + "--vrdeaddress", "127.0.0.1", + "--vrdeauthtype", "null", + "--vrde", "on", + "--vrdeport", + fmt.Sprintf("%d", vrdpPort), + } + if err := driver.VBoxManage(command...); err != nil { + err := fmt.Errorf("Error enabling VRDP: %s", err) + state.Put("error", err) + ui.Error(err.Error()) + return multistep.ActionHalt + } + + state.Put("vrdpIp", "127.0.0.1") + state.Put("vrdpPort", vrdpPort) + + return multistep.ActionContinue +} + +func (s *StepConfigureVRDP) Cleanup(state multistep.StateBag) {} diff --git a/builder/virtualbox/common/step_run.go b/builder/virtualbox/common/step_run.go index 0718ad7f3..eaf3cc354 100644 --- a/builder/virtualbox/common/step_run.go +++ b/builder/virtualbox/common/step_run.go @@ -30,9 +30,22 @@ func (s *StepRun) Run(state multistep.StateBag) multistep.StepAction { ui.Say("Starting the virtual machine...") guiArgument := "gui" if s.Headless == true { - ui.Message("WARNING: The VM will be started in headless mode, as configured.\n" + - "In headless mode, errors during the boot sequence or OS setup\n" + - "won't be easily visible. Use at your own discretion.") + vrdpIpRaw, vrdpIpOk := state.GetOk("vrdpIp") + vrdpPortRaw, vrdpPortOk := state.GetOk("vrdpPort") + + if vrdpIpOk && vrdpPortOk { + vrdpIp := vrdpIpRaw.(string) + vrdpPort := vrdpPortRaw.(uint) + + ui.Message(fmt.Sprintf( + "The VM will be run headless, without a GUI. If you want to\n"+ + "view the screen of the VM, connect via VRDP without a password to\n"+ + "%s:%d", vrdpIp, vrdpPort)) + } else { + ui.Message("The VM will be run headless, without a GUI, as configured.\n" + + "If the run isn't succeeding as you expect, please enable the GUI\n" + + "to inspect the progress of the build.") + } guiArgument = "headless" } command := []string{"startvm", vmName, "--type", guiArgument} diff --git a/builder/virtualbox/iso/builder.go b/builder/virtualbox/iso/builder.go index b8b08959a..19c9fd1fb 100644 --- a/builder/virtualbox/iso/builder.go +++ b/builder/virtualbox/iso/builder.go @@ -208,6 +208,10 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe &vboxcommon.StepAttachGuestAdditions{ GuestAdditionsMode: b.config.GuestAdditionsMode, }, + &vboxcommon.StepConfigureVRDP{ + VRDPPortMin: b.config.VRDPPortMin, + VRDPPortMax: b.config.VRDPPortMax, + }, new(vboxcommon.StepAttachFloppy), &vboxcommon.StepForwardSSH{ CommConfig: &b.config.SSHConfig.Comm, diff --git a/builder/virtualbox/ovf/builder.go b/builder/virtualbox/ovf/builder.go index 894fe1689..70a1122f3 100644 --- a/builder/virtualbox/ovf/builder.go +++ b/builder/virtualbox/ovf/builder.go @@ -76,6 +76,10 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe &vboxcommon.StepAttachGuestAdditions{ GuestAdditionsMode: b.config.GuestAdditionsMode, }, + &vboxcommon.StepConfigureVRDP{ + VRDPPortMin: b.config.VRDPPortMin, + VRDPPortMax: b.config.VRDPPortMax, + }, new(vboxcommon.StepAttachFloppy), &vboxcommon.StepForwardSSH{ CommConfig: &b.config.SSHConfig.Comm, diff --git a/website/source/docs/builders/virtualbox-iso.html.markdown b/website/source/docs/builders/virtualbox-iso.html.markdown index 79c080762..dd02c6f25 100644 --- a/website/source/docs/builders/virtualbox-iso.html.markdown +++ b/website/source/docs/builders/virtualbox-iso.html.markdown @@ -242,6 +242,12 @@ builder. machine, without the file extension. By default this is "packer-BUILDNAME", where "BUILDNAME" is the name of the build. +- `vrdp_port_min` and `vrdp_port_max` (integer) - The minimum and maximum port + to use for VRDP access to the virtual machine. Packer uses a randomly chosen + port in this range that appears available. By default this is 5900 to 6000. + The minimum and maximum ports are inclusive. + + ## Boot Command The `boot_command` configuration is very important: it specifies the keys to diff --git a/website/source/docs/builders/virtualbox-ovf.html.markdown b/website/source/docs/builders/virtualbox-ovf.html.markdown index af7ab643d..fe1e66b5e 100644 --- a/website/source/docs/builders/virtualbox-ovf.html.markdown +++ b/website/source/docs/builders/virtualbox-ovf.html.markdown @@ -207,6 +207,11 @@ builder. is exported. By default this is "packer-BUILDNAME", where "BUILDNAME" is the name of the build. +- `vrdp_port_min` and `vrdp_port_max` (integer) - The minimum and maximum port + to use for VRDP access to the virtual machine. Packer uses a randomly chosen + port in this range that appears available. By default this is 5900 to 6000. + The minimum and maximum ports are inclusive. + ## Guest Additions Packer will automatically download the proper guest additions for the version of