Commit 85ab8621 authored by Mitchell Hashimoto's avatar Mitchell Hashimoto

builder/vmware: Randomize HTTP port to avoid collisions

parent 56108f2b
......@@ -26,6 +26,8 @@ type config struct {
VMName string `mapstructure:"vm_name"`
OutputDir string `mapstructure:"output_directory"`
HTTPDir string `mapstructure:"http_directory"`
HTTPPortMin uint `mapstructure:"http_port_min"`
HTTPPortMax uint `mapstructure:"http_port_max"`
BootCommand []string `mapstructure:"boot_command"`
BootWait time.Duration
ShutdownCommand string `mapstructure:"shutdown_command"`
......@@ -55,6 +57,14 @@ func (b *Builder) Prepare(raw interface{}) (err error) {
b.config.VMName = "packer"
}
if b.config.HTTPPortMin == 0 {
b.config.HTTPPortMin = 8000
}
if b.config.HTTPPortMax == 0 {
b.config.HTTPPortMax = 9000
}
if b.config.VNCPortMin == 0 {
b.config.VNCPortMin = 5900
}
......@@ -70,6 +80,10 @@ func (b *Builder) Prepare(raw interface{}) (err error) {
// Accumulate any errors
errs := make([]error, 0)
if b.config.HTTPPortMin > b.config.HTTPPortMax {
errs = append(errs, errors.New("http_port_min must be less than http_port_max"))
}
if b.config.ISOUrl == "" {
errs = append(errs, errors.New("An iso_url must be specified."))
}
......
......@@ -65,6 +65,34 @@ func TestBuilderPrepare_Defaults(t *testing.T) {
}
}
func TestBuilderPrepare_HTTPPort(t *testing.T) {
var b Builder
config := testConfig()
// Bad
config["http_port_min"] = 1000
config["http_port_max"] = 500
err := b.Prepare(config)
if err == nil {
t.Fatal("should have error")
}
// Bad
config["http_port_min"] = -500
err = b.Prepare(config)
if err == nil {
t.Fatal("should have error")
}
// Good
config["http_port_min"] = 500
config["http_port_max"] = 1000
err = b.Prepare(config)
if err != nil {
t.Fatalf("should not have error: %s", err)
}
}
func TestBuilderPrepare_ISOUrl(t *testing.T) {
var b Builder
config := testConfig()
......
......@@ -4,6 +4,8 @@ import (
"fmt"
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/packer"
"log"
"math/rand"
"net"
"net/http"
)
......@@ -25,26 +27,31 @@ func (s *stepHTTPServer) Run(state map[string]interface{}) multistep.StepAction
config := state["config"].(*config)
ui := state["ui"].(packer.Ui)
httpPort := 0
if config.HTTPDir != "" {
httpPort = 8080
httpAddr := fmt.Sprintf(":%d", httpPort)
ui.Say(fmt.Sprintf("Starting HTTP server on port %d", httpPort))
var httpPort uint = 0
if config.HTTPDir == "" {
state["http_port"] = httpPort
}
// Start the TCP listener
// Find an available TCP port for our HTTP server
var httpAddr string
portRange := int(config.HTTPPortMax - config.HTTPPortMin)
for {
var err error
httpPort = uint(rand.Intn(portRange)) + config.HTTPPortMin
httpAddr = fmt.Sprintf(":%d", httpPort)
log.Printf("Trying port: %d", httpPort)
s.l, err = net.Listen("tcp", httpAddr)
if err != nil {
ui.Error(fmt.Sprintf("Error starting HTTP server: %s", err))
return multistep.ActionHalt
if err == nil {
break
}
}
ui.Say(fmt.Sprintf("Starting HTTP server on port %d", httpPort))
// Start the HTTP server and run it in the background
fileServer := http.FileServer(http.Dir(config.HTTPDir))
server := &http.Server{Addr: httpAddr, Handler: fileServer}
go server.Serve(s.l)
}
// Save the address into the state so it can be accessed in the future
state["http_port"] = httpPort
......
......@@ -19,7 +19,7 @@ const KeyLeftShift uint32 = 0xFFE1
type bootCommandTemplateData struct {
HTTPIP string
HTTPPort int
HTTPPort uint
Name string
}
......@@ -37,7 +37,7 @@ type stepTypeBootCommand struct{}
func (s *stepTypeBootCommand) Run(state map[string]interface{}) multistep.StepAction {
config := state["config"].(*config)
httpPort := state["http_port"].(int)
httpPort := state["http_port"].(uint)
ui := state["ui"].(packer.Ui)
vncPort := state["vnc_port"].(uint)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment