mirror of
https://github.com/hashicorp/packer.git
synced 2026-05-28 04:35:38 -04:00
Support for local HTTP server (#116)
This commit is contained in:
commit
a62012a78c
3 changed files with 77 additions and 5 deletions
|
|
@ -63,12 +63,19 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
|||
Datastore: b.config.Datastore,
|
||||
Host: b.config.Host,
|
||||
},
|
||||
&packerCommon.StepHTTPServer{
|
||||
HTTPDir: b.config.HTTPDir,
|
||||
HTTPPortMin: b.config.HTTPPortMin,
|
||||
HTTPPortMax: b.config.HTTPPortMax,
|
||||
},
|
||||
&common.StepRun{
|
||||
Config: &b.config.RunConfig,
|
||||
SetOrder: true,
|
||||
},
|
||||
&StepBootCommand{
|
||||
Config: &b.config.BootConfig,
|
||||
Ctx: b.config.ctx,
|
||||
VMName: b.config.VMName,
|
||||
},
|
||||
&common.StepWaitForIp{},
|
||||
&communicator.StepConnect{
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import (
|
|||
|
||||
type Config struct {
|
||||
packerCommon.PackerConfig `mapstructure:",squash"`
|
||||
packerCommon.HTTPConfig `mapstructure:",squash"`
|
||||
|
||||
common.ConnectConfig `mapstructure:",squash"`
|
||||
CreateConfig `mapstructure:",squash"`
|
||||
|
|
@ -36,6 +37,11 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) {
|
|||
err := config.Decode(c, &config.DecodeOpts{
|
||||
Interpolate: true,
|
||||
InterpolateContext: &c.ctx,
|
||||
InterpolateFilter: &interpolate.RenderFilter{
|
||||
Exclude: []string{
|
||||
"boot_command",
|
||||
},
|
||||
},
|
||||
}, raws...)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
|
|
@ -46,6 +52,7 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) {
|
|||
errs = packer.MultiErrorAppend(errs, c.CreateConfig.Prepare()...)
|
||||
errs = packer.MultiErrorAppend(errs, c.LocationConfig.Prepare()...)
|
||||
errs = packer.MultiErrorAppend(errs, c.HardwareConfig.Prepare()...)
|
||||
errs = packer.MultiErrorAppend(errs, c.HTTPConfig.Prepare(&c.ctx)...)
|
||||
|
||||
errs = packer.MultiErrorAppend(errs, c.CDRomConfig.Prepare()...)
|
||||
errs = packer.MultiErrorAppend(errs, c.BootConfig.Prepare()...)
|
||||
|
|
|
|||
|
|
@ -3,12 +3,14 @@ package iso
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/hashicorp/packer/common"
|
||||
packerCommon "github.com/hashicorp/packer/common"
|
||||
"github.com/hashicorp/packer/helper/multistep"
|
||||
"github.com/hashicorp/packer/packer"
|
||||
"github.com/hashicorp/packer/template/interpolate"
|
||||
"github.com/jetbrains-infra/packer-builder-vsphere/driver"
|
||||
"golang.org/x/mobile/event/key"
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
|
@ -18,10 +20,17 @@ import (
|
|||
type BootConfig struct {
|
||||
BootCommand []string `mapstructure:"boot_command"`
|
||||
RawBootWait string `mapstructure:"boot_wait"` // example: "1m30s"; default: "10s"
|
||||
HTTPIP string `mapstructure:"http_ip"`
|
||||
|
||||
bootWait time.Duration
|
||||
}
|
||||
|
||||
type bootCommandTemplateData struct {
|
||||
HTTPIP string
|
||||
HTTPPort uint
|
||||
Name string
|
||||
}
|
||||
|
||||
func (c *BootConfig) Prepare() []error {
|
||||
var errs []error
|
||||
|
||||
|
|
@ -40,6 +49,8 @@ func (c *BootConfig) Prepare() []error {
|
|||
|
||||
type StepBootCommand struct {
|
||||
Config *BootConfig
|
||||
VMName string
|
||||
Ctx interpolate.Context
|
||||
}
|
||||
|
||||
var special = map[string]key.Code{
|
||||
|
|
@ -71,10 +82,10 @@ var special = map[string]key.Code{
|
|||
"<down>": key.CodeDownArrow,
|
||||
}
|
||||
|
||||
var keyInterval = common.PackerKeyDefault
|
||||
var keyInterval = packerCommon.PackerKeyDefault
|
||||
|
||||
func init() {
|
||||
if delay, err := time.ParseDuration(os.Getenv(common.PackerKeyEnv)); err == nil {
|
||||
if delay, err := time.ParseDuration(os.Getenv(packerCommon.PackerKeyEnv)); err == nil {
|
||||
keyInterval = delay
|
||||
}
|
||||
}
|
||||
|
|
@ -101,13 +112,35 @@ WAITLOOP:
|
|||
}
|
||||
}
|
||||
|
||||
ui.Say("Typing boot command...")
|
||||
ip, err := getHostIP(s.Config.HTTPIP)
|
||||
if err != nil {
|
||||
state.Put("error", err)
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
err = packerCommon.SetHTTPIP(ip)
|
||||
if err != nil {
|
||||
state.Put("error", err)
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
port := state.Get("http_port").(uint)
|
||||
s.Ctx.Data = &bootCommandTemplateData{
|
||||
ip,
|
||||
port,
|
||||
s.VMName,
|
||||
}
|
||||
ui.Say(fmt.Sprintf("HTTP server is working at http://%v:%v/", ip, port))
|
||||
|
||||
ui.Say("Typing boot command...")
|
||||
var keyAlt bool
|
||||
var keyCtrl bool
|
||||
var keyShift bool
|
||||
for _, command := range s.Config.BootCommand {
|
||||
message, err := interpolate.Render(command, &s.Ctx)
|
||||
if err != nil {
|
||||
state.Put("error", err)
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
for _, message := range s.Config.BootCommand {
|
||||
for len(message) > 0 {
|
||||
if _, ok := state.GetOk(multistep.StateCancelled); ok {
|
||||
return multistep.ActionHalt
|
||||
|
|
@ -205,3 +238,28 @@ WAITLOOP:
|
|||
}
|
||||
|
||||
func (s *StepBootCommand) Cleanup(state multistep.StateBag) {}
|
||||
|
||||
func getHostIP(s string) (string, error) {
|
||||
if s != "" {
|
||||
if net.ParseIP(s) != nil {
|
||||
return s, nil
|
||||
} else {
|
||||
return "", fmt.Errorf("invalid IP address")
|
||||
}
|
||||
}
|
||||
|
||||
addrs, err := net.InterfaceAddrs()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
for _, a := range addrs {
|
||||
ipnet, ok := a.(*net.IPNet)
|
||||
if ok && !ipnet.IP.IsLoopback() {
|
||||
if ipnet.IP.To4() != nil {
|
||||
return ipnet.IP.String(), nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return "", fmt.Errorf("IP not found")
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue