added new template variables to replace PACKER_KEY_INTERVAL with tunable key and keygroup intervals depending on driver used

This commit is contained in:
Megan Marsh 2018-08-22 11:25:43 -07:00
parent 41898ec7ba
commit 918db58604
23 changed files with 153 additions and 47 deletions

View File

@ -21,10 +21,11 @@ type bootCommandTemplateData struct {
// This step "types" the boot command into the VM via the Hyper-V virtual keyboard // This step "types" the boot command into the VM via the Hyper-V virtual keyboard
type StepTypeBootCommand struct { type StepTypeBootCommand struct {
BootCommand string BootCommand string
BootWait time.Duration BootWait time.Duration
SwitchName string SwitchName string
Ctx interpolate.Context Ctx interpolate.Context
GroupInterval int
} }
func (s *StepTypeBootCommand) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { func (s *StepTypeBootCommand) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
@ -66,7 +67,7 @@ func (s *StepTypeBootCommand) Run(ctx context.Context, state multistep.StateBag)
scanCodesToSendString := strings.Join(codes, " ") scanCodesToSendString := strings.Join(codes, " ")
return driver.TypeScanCodes(vmName, scanCodesToSendString) return driver.TypeScanCodes(vmName, scanCodesToSendString)
} }
d := bootcommand.NewPCXTDriver(sendCodes, -1) d := bootcommand.NewPCXTDriver(sendCodes, -1, s.GroupInterval)
ui.Say("Typing the boot command...") ui.Say("Typing the boot command...")
command, err := interpolate.Render(s.BootCommand, &s.Ctx) command, err := interpolate.Render(s.BootCommand, &s.Ctx)

View File

@ -434,10 +434,11 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
}, },
&hypervcommon.StepTypeBootCommand{ &hypervcommon.StepTypeBootCommand{
BootCommand: b.config.FlatBootCommand(), BootCommand: b.config.FlatBootCommand(),
BootWait: b.config.BootWait, BootWait: b.config.BootWait,
SwitchName: b.config.SwitchName, SwitchName: b.config.SwitchName,
Ctx: b.config.ctx, Ctx: b.config.ctx,
GroupInterval: b.config.BootConfig.BootGroupInterval,
}, },
// configure the communicator ssh, winrm // configure the communicator ssh, winrm

View File

@ -443,10 +443,11 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
}, },
&hypervcommon.StepTypeBootCommand{ &hypervcommon.StepTypeBootCommand{
BootCommand: b.config.FlatBootCommand(), BootCommand: b.config.FlatBootCommand(),
BootWait: b.config.BootWait, BootWait: b.config.BootWait,
SwitchName: b.config.SwitchName, SwitchName: b.config.SwitchName,
Ctx: b.config.ctx, Ctx: b.config.ctx,
GroupInterval: b.config.BootConfig.BootGroupInterval,
}, },
// configure the communicator ssh, winrm // configure the communicator ssh, winrm

View File

@ -26,6 +26,7 @@ type StepTypeBootCommand struct {
HostInterfaces []string HostInterfaces []string
VMName string VMName string
Ctx interpolate.Context Ctx interpolate.Context
GroupInterval int
} }
// Run types the boot command by sending key scancodes into the VM. // Run types the boot command by sending key scancodes into the VM.
@ -79,7 +80,7 @@ func (s *StepTypeBootCommand) Run(ctx context.Context, state multistep.StateBag)
sendCodes := func(codes []string) error { sendCodes := func(codes []string) error {
return driver.SendKeyScanCodes(s.VMName, codes...) return driver.SendKeyScanCodes(s.VMName, codes...)
} }
d := bootcommand.NewPCXTDriver(sendCodes, -1) d := bootcommand.NewPCXTDriver(sendCodes, -1, s.GroupInterval)
ui.Say("Typing the boot command...") ui.Say("Typing the boot command...")
command, err := interpolate.Render(s.BootCommand, &s.Ctx) command, err := interpolate.Render(s.BootCommand, &s.Ctx)

View File

@ -192,6 +192,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
HostInterfaces: b.config.HostInterfaces, HostInterfaces: b.config.HostInterfaces,
VMName: b.config.VMName, VMName: b.config.VMName,
Ctx: b.config.ctx, Ctx: b.config.ctx,
GroupInterval: b.config.BootConfig.BootGroupInterval,
}, },
&communicator.StepConnect{ &communicator.StepConnect{
Config: &b.config.SSHConfig.Comm, Config: &b.config.SSHConfig.Comm,

View File

@ -81,6 +81,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
HostInterfaces: []string{}, HostInterfaces: []string{},
VMName: b.config.VMName, VMName: b.config.VMName,
Ctx: b.config.ctx, Ctx: b.config.ctx,
GroupInterval: b.config.BootConfig.BootGroupInterval,
}, },
&communicator.StepConnect{ &communicator.StepConnect{
Config: &b.config.SSHConfig.Comm, Config: &b.config.SSHConfig.Comm,

View File

@ -95,7 +95,7 @@ func (s *stepTypeBootCommand) Run(ctx context.Context, state multistep.StateBag)
config.VMName, config.VMName,
} }
d := bootcommand.NewVNCDriver(c) d := bootcommand.NewVNCDriver(c, config.VNCConfig.BootKeyInterval)
ui.Say("Typing the boot command over VNC...") ui.Say("Typing the boot command over VNC...")
command, err := interpolate.Render(config.VNCConfig.FlatBootCommand(), &configCtx) command, err := interpolate.Render(config.VNCConfig.FlatBootCommand(), &configCtx)

View File

@ -21,10 +21,11 @@ type bootCommandTemplateData struct {
} }
type StepTypeBootCommand struct { type StepTypeBootCommand struct {
BootCommand string BootCommand string
BootWait time.Duration BootWait time.Duration
VMName string VMName string
Ctx interpolate.Context Ctx interpolate.Context
GroupInterval int
} }
func (s *StepTypeBootCommand) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { func (s *StepTypeBootCommand) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
@ -64,7 +65,7 @@ func (s *StepTypeBootCommand) Run(ctx context.Context, state multistep.StateBag)
return driver.VBoxManage(args...) return driver.VBoxManage(args...)
} }
d := bootcommand.NewPCXTDriver(sendCodes, 25) d := bootcommand.NewPCXTDriver(sendCodes, 25, s.GroupInterval)
ui.Say("Typing the boot command...") ui.Say("Typing the boot command...")
command, err := interpolate.Render(s.BootCommand, &s.Ctx) command, err := interpolate.Render(s.BootCommand, &s.Ctx)

View File

@ -53,6 +53,7 @@ type Config struct {
KeepRegistered bool `mapstructure:"keep_registered"` KeepRegistered bool `mapstructure:"keep_registered"`
SkipExport bool `mapstructure:"skip_export"` SkipExport bool `mapstructure:"skip_export"`
VMName string `mapstructure:"vm_name"` VMName string `mapstructure:"vm_name"`
KeyInterval int `mapstructure:"key_interval"`
ctx interpolate.Context ctx interpolate.Context
} }
@ -121,6 +122,10 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
b.config.ISOInterface = "ide" b.config.ISOInterface = "ide"
} }
if b.config.KeyInterval == 0 {
b.config.KeyInterval = -1
}
if b.config.VMName == "" { if b.config.VMName == "" {
b.config.VMName = fmt.Sprintf( b.config.VMName = fmt.Sprintf(
"packer-%s-%d", b.config.PackerBuildName, interpolate.InitTime.Unix()) "packer-%s-%d", b.config.PackerBuildName, interpolate.InitTime.Unix())
@ -245,10 +250,11 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
Headless: b.config.Headless, Headless: b.config.Headless,
}, },
&vboxcommon.StepTypeBootCommand{ &vboxcommon.StepTypeBootCommand{
BootWait: b.config.BootWait, BootWait: b.config.BootWait,
BootCommand: b.config.FlatBootCommand(), BootCommand: b.config.FlatBootCommand(),
VMName: b.config.VMName, VMName: b.config.VMName,
Ctx: b.config.ctx, Ctx: b.config.ctx,
GroupInterval: b.config.BootConfig.BootGroupInterval,
}, },
&communicator.StepConnect{ &communicator.StepConnect{
Config: &b.config.SSHConfig.Comm, Config: &b.config.SSHConfig.Comm,

View File

@ -106,10 +106,11 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
Headless: b.config.Headless, Headless: b.config.Headless,
}, },
&vboxcommon.StepTypeBootCommand{ &vboxcommon.StepTypeBootCommand{
BootWait: b.config.BootWait, BootWait: b.config.BootWait,
BootCommand: b.config.FlatBootCommand(), BootCommand: b.config.FlatBootCommand(),
VMName: b.config.VMName, VMName: b.config.VMName,
Ctx: b.config.ctx, Ctx: b.config.ctx,
GroupInterval: b.config.BootConfig.BootGroupInterval,
}, },
&communicator.StepConnect{ &communicator.StepConnect{
Config: &b.config.SSHConfig.Comm, Config: &b.config.SSHConfig.Comm,

View File

@ -30,6 +30,7 @@ type StepTypeBootCommand struct {
BootWait time.Duration BootWait time.Duration
VMName string VMName string
Ctx interpolate.Context Ctx interpolate.Context
KeyInterval int
} }
type bootCommandTemplateData struct { type bootCommandTemplateData struct {
HTTPIP string HTTPIP string
@ -115,7 +116,7 @@ func (s *StepTypeBootCommand) Run(ctx context.Context, state multistep.StateBag)
s.VMName, s.VMName,
} }
d := bootcommand.NewVNCDriver(c) d := bootcommand.NewVNCDriver(c, s.KeyInterval)
ui.Say("Typing the boot command over VNC...") ui.Say("Typing the boot command over VNC...")
command, err := interpolate.Render(s.BootCommand, &s.Ctx) command, err := interpolate.Render(s.BootCommand, &s.Ctx)

View File

@ -339,6 +339,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
BootCommand: b.config.FlatBootCommand(), BootCommand: b.config.FlatBootCommand(),
VMName: b.config.VMName, VMName: b.config.VMName,
Ctx: b.config.ctx, Ctx: b.config.ctx,
KeyInterval: b.config.VNCConfig.BootKeyInterval,
}, },
&communicator.StepConnect{ &communicator.StepConnect{
Config: &b.config.SSHConfig.Comm, Config: &b.config.SSHConfig.Comm,

View File

@ -97,6 +97,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
BootCommand: b.config.FlatBootCommand(), BootCommand: b.config.FlatBootCommand(),
VMName: b.config.VMName, VMName: b.config.VMName,
Ctx: b.config.ctx, Ctx: b.config.ctx,
KeyInterval: b.config.VNCConfig.BootKeyInterval,
}, },
&communicator.StepConnect{ &communicator.StepConnect{
Config: &b.config.SSHConfig.Comm, Config: &b.config.SSHConfig.Comm,

View File

@ -11,6 +11,8 @@ import (
type BootConfig struct { type BootConfig struct {
RawBootWait string `mapstructure:"boot_wait"` RawBootWait string `mapstructure:"boot_wait"`
BootCommand []string `mapstructure:"boot_command"` BootCommand []string `mapstructure:"boot_command"`
// time in ms to wait between each group of 25 key presses
BootGroupInterval int `mapstructure:"boot_keygroup_interval"`
BootWait time.Duration `` BootWait time.Duration ``
} }
@ -18,12 +20,17 @@ type BootConfig struct {
type VNCConfig struct { type VNCConfig struct {
BootConfig `mapstructure:",squash"` BootConfig `mapstructure:",squash"`
DisableVNC bool `mapstructure:"disable_vnc"` DisableVNC bool `mapstructure:"disable_vnc"`
// time in ms to wait between each key press
BootKeyInterval int `mapstructure:"boot_key_interval"`
} }
func (c *BootConfig) Prepare(ctx *interpolate.Context) (errs []error) { func (c *BootConfig) Prepare(ctx *interpolate.Context) (errs []error) {
if c.RawBootWait == "" { if c.RawBootWait == "" {
c.RawBootWait = "10s" c.RawBootWait = "10s"
} }
if c.BootGroupInterval == 0 {
c.BootGroupInterval = -1
}
if c.RawBootWait != "" { if c.RawBootWait != "" {
bw, err := time.ParseDuration(c.RawBootWait) bw, err := time.ParseDuration(c.RawBootWait)
if err != nil { if err != nil {
@ -55,6 +62,9 @@ func (c *VNCConfig) Prepare(ctx *interpolate.Context) (errs []error) {
errs = append(errs, errs = append(errs,
fmt.Errorf("A boot command cannot be used when vnc is disabled.")) fmt.Errorf("A boot command cannot be used when vnc is disabled."))
} }
if c.BootKeyInterval == 0 {
c.BootKeyInterval = -1
}
errs = append(errs, c.BootConfig.Prepare(ctx)...) errs = append(errs, c.BootConfig.Prepare(ctx)...)
return return
} }

View File

@ -38,13 +38,17 @@ func (sc *scancode) makeBreak() []string {
// NewPCXTDriver creates a new boot command driver for VMs that expect PC-XT // NewPCXTDriver creates a new boot command driver for VMs that expect PC-XT
// keyboard codes. `send` should send its argument to the VM. `chunkSize` should // keyboard codes. `send` should send its argument to the VM. `chunkSize` should
// be the maximum number of keyboard codes to send to `send` at one time. // be the maximum number of keyboard codes to send to `send` at one time.
func NewPCXTDriver(send SendCodeFunc, chunkSize int) *pcXTDriver { func NewPCXTDriver(send SendCodeFunc, chunkSize int, interval int) *pcXTDriver {
// We delay (default 100ms) between each input event to allow for CPU or // We delay (default 100ms) between each input event to allow for CPU or
// network latency. See PackerKeyEnv for tuning. // network latency. See PackerKeyEnv for tuning.
keyInterval := common.PackerKeyDefault keyInterval := common.PackerKeyDefault
if delay, err := time.ParseDuration(os.Getenv(common.PackerKeyEnv)); err == nil { if delay, err := time.ParseDuration(os.Getenv(common.PackerKeyEnv)); err == nil {
keyInterval = delay keyInterval = delay
} }
// Override interval based on builder-specific override
if interval >= 0 {
keyInterval = time.Duration(interval) * time.Millisecond
}
// Scancodes reference: https://www.win.tue.nl/~aeb/linux/kbd/scancodes-1.html // Scancodes reference: https://www.win.tue.nl/~aeb/linux/kbd/scancodes-1.html
// https://www.win.tue.nl/~aeb/linux/kbd/scancodes-10.html // https://www.win.tue.nl/~aeb/linux/kbd/scancodes-10.html
// //

View File

@ -79,7 +79,7 @@ func Test_pcxtSpecialOnOff(t *testing.T) {
codes = c codes = c
return nil return nil
} }
d := NewPCXTDriver(sendCodes, -1) d := NewPCXTDriver(sendCodes, -1, -1)
seq, err := GenerateExpressionSequence(in) seq, err := GenerateExpressionSequence(in)
assert.NoError(t, err) assert.NoError(t, err)
err = seq.Do(context.Background(), d) err = seq.Do(context.Background(), d)
@ -95,7 +95,7 @@ func Test_pcxtSpecial(t *testing.T) {
codes = c codes = c
return nil return nil
} }
d := NewPCXTDriver(sendCodes, -1) d := NewPCXTDriver(sendCodes, -1, -1)
seq, err := GenerateExpressionSequence(in) seq, err := GenerateExpressionSequence(in)
assert.NoError(t, err) assert.NoError(t, err)
err = seq.Do(context.Background(), d) err = seq.Do(context.Background(), d)
@ -114,7 +114,7 @@ func Test_flushes(t *testing.T) {
actual = append(actual, c) actual = append(actual, c)
return nil return nil
} }
d := NewPCXTDriver(sendCodes, -1) d := NewPCXTDriver(sendCodes, -1, -1)
seq, err := GenerateExpressionSequence(in) seq, err := GenerateExpressionSequence(in)
assert.NoError(t, err) assert.NoError(t, err)
err = seq.Do(context.Background(), d) err = seq.Do(context.Background(), d)

View File

@ -25,13 +25,17 @@ type vncDriver struct {
err error err error
} }
func NewVNCDriver(c VNCKeyEvent) *vncDriver { func NewVNCDriver(c VNCKeyEvent, interval int) *vncDriver {
// We delay (default 100ms) between each key event to allow for CPU or // We delay (default 100ms) between each key event to allow for CPU or
// network latency. See PackerKeyEnv for tuning. // network latency. See PackerKeyEnv for tuning.
keyInterval := common.PackerKeyDefault keyInterval := common.PackerKeyDefault
if delay, err := time.ParseDuration(os.Getenv(common.PackerKeyEnv)); err == nil { if delay, err := time.ParseDuration(os.Getenv(common.PackerKeyEnv)); err == nil {
keyInterval = delay keyInterval = delay
} }
// override interval based on builder-specific override.
if interval >= 0 {
keyInterval = time.Duration(interval) * time.Millisecond
}
// Scancodes reference: https://github.com/qemu/qemu/blob/master/ui/vnc_keysym.h // Scancodes reference: https://github.com/qemu/qemu/blob/master/ui/vnc_keysym.h
sMap := make(map[string]uint32) sMap := make(map[string]uint32)

View File

@ -30,7 +30,7 @@ func Test_vncSpecialLookup(t *testing.T) {
{0xFFE2, true}, {0xFFE2, true},
} }
s := &sender{} s := &sender{}
d := NewVNCDriver(s) d := NewVNCDriver(s, -1)
seq, err := GenerateExpressionSequence(in) seq, err := GenerateExpressionSequence(in)
assert.NoError(t, err) assert.NoError(t, err)
err = seq.Do(context.Background(), d) err = seq.Do(context.Background(), d)

View File

@ -121,7 +121,7 @@ Linux server and have not enabled X11 forwarding (`ssh -X`).
upstream issue which can be tracked upstream issue which can be tracked
[here](https://github.com/intel/haxm/issues/20). [here](https://github.com/intel/haxm/issues/20).
-> The `hvf` accelerator is new and experimental as of -> The `hvf` accelerator is new and experimental as of
[QEMU 2.12.0](https://wiki.qemu.org/ChangeLog/2.12#Host_support). [QEMU 2.12.0](https://wiki.qemu.org/ChangeLog/2.12#Host_support).
You may encounter issues unrelated to Packer when using it. You may need to You may encounter issues unrelated to Packer when using it. You may need to
add [ "-global", "virtio-pci.disable-modern=on" ] to `qemuargs` depending on the add [ "-global", "virtio-pci.disable-modern=on" ] to `qemuargs` depending on the
@ -386,8 +386,22 @@ machine, simulating a human actually typing the keyboard.
-> Keystrokes are typed as separate key up/down events over VNC with a -> Keystrokes are typed as separate key up/down events over VNC with a
default 100ms delay. The delay alleviates issues with latency and CPU default 100ms delay. The delay alleviates issues with latency and CPU
contention. For local builds you can tune this delay by specifying contention. You can tune this delay on a per-builder basis by specifying
e.g. `PACKER_KEY_INTERVAL=10ms` to speed through the boot command. "boot_key_interval" in your Packer template, for example:
```
{
"builders": [
{
"type": "qemu",
"boot_key_interval": "10"
...
}
]
}
```
Note that this option will always be measured in milliseconds.
<%= partial "partials/builders/boot-command" %> <%= partial "partials/builders/boot-command" %>

View File

@ -337,8 +337,22 @@ template.
The boot command is sent to the VM through the `VBoxManage` utility in as few The boot command is sent to the VM through the `VBoxManage` utility in as few
invocations as possible. We send each character in groups of 25, with a default invocations as possible. We send each character in groups of 25, with a default
delay of 100ms between groups. The delay alleviates issues with latency and CPU delay of 100ms between groups. The delay alleviates issues with latency and CPU
contention. If you notice missing keys, you can tune this delay by specifying e.g. contention. If you notice missing keys, you can tune this delay by specifying
`PACKER_KEY_INTERVAL=500ms` to wait longer between each group of characters. "boot_keygroup_interval" in your Packer template, for example:
```
{
"builders": [
{
"type": "virtualbox",
"boot_keygroup_interval": "500"
...
}
]
}
```
Note that this option will always be measured in milliseconds.
<%= partial "partials/builders/boot-command" %> <%= partial "partials/builders/boot-command" %>

View File

@ -300,8 +300,23 @@ template.
The boot command is sent to the VM through the `VBoxManage` utility in as few The boot command is sent to the VM through the `VBoxManage` utility in as few
invocations as possible. We send each character in groups of 25, with a default invocations as possible. We send each character in groups of 25, with a default
delay of 100ms between groups. The delay alleviates issues with latency and CPU delay of 100ms between groups. The delay alleviates issues with latency and CPU
contention. If you notice missing keys, you can tune this delay by specifying e.g. contention. If you notice missing keys, you can tune this delay by specifying
`PACKER_KEY_INTERVAL=500ms` to wait longer between each group of characters. "boot_keygroup_interval" in your Packer template, for example:
```
{
"builders": [
{
"type": "virtualbox",
"boot_keygroup_interval": "500"
...
}
]
}
```
Note that this option will always be measured in milliseconds.
<%= partial "partials/builders/boot-command" %> <%= partial "partials/builders/boot-command" %>

View File

@ -412,7 +412,7 @@ builder.
wish to bind to all interfaces use `0.0.0.0`. wish to bind to all interfaces use `0.0.0.0`.
- `vnc_disable_password` (boolean) - Don't auto-generate a VNC password that - `vnc_disable_password` (boolean) - Don't auto-generate a VNC password that
is used to secure the VNC communication with the VM. This must be set to is used to secure the VNC communication with the VM. This must be set to
`true` if building on ESXi 6.5 and 6.7 with VNC enabled. Defaults to `true` if building on ESXi 6.5 and 6.7 with VNC enabled. Defaults to
`false`. `false`.
@ -439,8 +439,22 @@ machine, simulating a human actually typing the keyboard.
-&gt; Keystrokes are typed as separate key up/down events over VNC with a -&gt; Keystrokes are typed as separate key up/down events over VNC with a
default 100ms delay. The delay alleviates issues with latency and CPU default 100ms delay. The delay alleviates issues with latency and CPU
contention. For local builds you can tune this delay by specifying contention. You can tune this delay on a per-builder basis by specifying
e.g. `PACKER_KEY_INTERVAL=10ms` to speed through the boot command. "boot_key_interval" in your Packer template, for example:
```
{
"builders": [
{
"type": "vmware-iso",
"boot_key_interval": "10"
...
}
]
}
```
Note that this option will always be measured in milliseconds.
<%= partial "partials/builders/boot-command" %> <%= partial "partials/builders/boot-command" %>

View File

@ -215,8 +215,22 @@ machine, simulating a human actually typing the keyboard.
-&gt; Keystrokes are typed as separate key up/down events over VNC with a -&gt; Keystrokes are typed as separate key up/down events over VNC with a
default 100ms delay. The delay alleviates issues with latency and CPU default 100ms delay. The delay alleviates issues with latency and CPU
contention. For local builds you can tune this delay by specifying contention. You can tune this delay on a per-builder basis by specifying
e.g. `PACKER_KEY_INTERVAL=10ms` to speed through the boot command. "boot_key_interval" in your Packer template, for example:
```
{
"builders": [
{
"type": "vmware-vmx",
"boot_key_interval": "10"
...
}
]
}
```
Note that this option will always be measured in milliseconds.
<%= partial "partials/builders/boot-command" %> <%= partial "partials/builders/boot-command" %>