builder/vmware: Randomize HTTP port to avoid collisions
This commit is contained in:
parent
56108f2b16
commit
85ab8621d4
|
@ -26,6 +26,8 @@ type config struct {
|
||||||
VMName string `mapstructure:"vm_name"`
|
VMName string `mapstructure:"vm_name"`
|
||||||
OutputDir string `mapstructure:"output_directory"`
|
OutputDir string `mapstructure:"output_directory"`
|
||||||
HTTPDir string `mapstructure:"http_directory"`
|
HTTPDir string `mapstructure:"http_directory"`
|
||||||
|
HTTPPortMin uint `mapstructure:"http_port_min"`
|
||||||
|
HTTPPortMax uint `mapstructure:"http_port_max"`
|
||||||
BootCommand []string `mapstructure:"boot_command"`
|
BootCommand []string `mapstructure:"boot_command"`
|
||||||
BootWait time.Duration
|
BootWait time.Duration
|
||||||
ShutdownCommand string `mapstructure:"shutdown_command"`
|
ShutdownCommand string `mapstructure:"shutdown_command"`
|
||||||
|
@ -55,6 +57,14 @@ func (b *Builder) Prepare(raw interface{}) (err error) {
|
||||||
b.config.VMName = "packer"
|
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 {
|
if b.config.VNCPortMin == 0 {
|
||||||
b.config.VNCPortMin = 5900
|
b.config.VNCPortMin = 5900
|
||||||
}
|
}
|
||||||
|
@ -70,6 +80,10 @@ func (b *Builder) Prepare(raw interface{}) (err error) {
|
||||||
// Accumulate any errors
|
// Accumulate any errors
|
||||||
errs := make([]error, 0)
|
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 == "" {
|
if b.config.ISOUrl == "" {
|
||||||
errs = append(errs, errors.New("An iso_url must be specified."))
|
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) {
|
func TestBuilderPrepare_ISOUrl(t *testing.T) {
|
||||||
var b Builder
|
var b Builder
|
||||||
config := testConfig()
|
config := testConfig()
|
||||||
|
|
|
@ -4,6 +4,8 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/mitchellh/multistep"
|
"github.com/mitchellh/multistep"
|
||||||
"github.com/mitchellh/packer/packer"
|
"github.com/mitchellh/packer/packer"
|
||||||
|
"log"
|
||||||
|
"math/rand"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
@ -25,27 +27,32 @@ func (s *stepHTTPServer) Run(state map[string]interface{}) multistep.StepAction
|
||||||
config := state["config"].(*config)
|
config := state["config"].(*config)
|
||||||
ui := state["ui"].(packer.Ui)
|
ui := state["ui"].(packer.Ui)
|
||||||
|
|
||||||
httpPort := 0
|
var httpPort uint = 0
|
||||||
if config.HTTPDir != "" {
|
if config.HTTPDir == "" {
|
||||||
httpPort = 8080
|
state["http_port"] = httpPort
|
||||||
httpAddr := fmt.Sprintf(":%d", httpPort)
|
|
||||||
|
|
||||||
ui.Say(fmt.Sprintf("Starting HTTP server on port %d", httpPort))
|
|
||||||
|
|
||||||
// Start the TCP listener
|
|
||||||
var err error
|
|
||||||
s.l, err = net.Listen("tcp", httpAddr)
|
|
||||||
if err != nil {
|
|
||||||
ui.Error(fmt.Sprintf("Error starting HTTP server: %s", err))
|
|
||||||
return multistep.ActionHalt
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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 {
|
||||||
|
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
|
// Save the address into the state so it can be accessed in the future
|
||||||
state["http_port"] = httpPort
|
state["http_port"] = httpPort
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ const KeyLeftShift uint32 = 0xFFE1
|
||||||
|
|
||||||
type bootCommandTemplateData struct {
|
type bootCommandTemplateData struct {
|
||||||
HTTPIP string
|
HTTPIP string
|
||||||
HTTPPort int
|
HTTPPort uint
|
||||||
Name string
|
Name string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,7 +37,7 @@ type stepTypeBootCommand struct{}
|
||||||
|
|
||||||
func (s *stepTypeBootCommand) Run(state map[string]interface{}) multistep.StepAction {
|
func (s *stepTypeBootCommand) Run(state map[string]interface{}) multistep.StepAction {
|
||||||
config := state["config"].(*config)
|
config := state["config"].(*config)
|
||||||
httpPort := state["http_port"].(int)
|
httpPort := state["http_port"].(uint)
|
||||||
ui := state["ui"].(packer.Ui)
|
ui := state["ui"].(packer.Ui)
|
||||||
vncPort := state["vnc_port"].(uint)
|
vncPort := state["vnc_port"].(uint)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue