Improve delay between key events

- Can now tune delay using PACKER_KEY_INTERVAL
- Added implementation to all of VMware and QEMU
- Removed double delay for QEMU
- Default key delay of 100ms (as before)
- Added docs to QEMU and VMware pages
This commit is contained in:
Chris Bednarski 2017-01-14 17:56:04 -08:00
parent d0c64f90d5
commit ee2d636840
7 changed files with 90 additions and 98 deletions

View File

@ -12,8 +12,10 @@ import (
"github.com/mitchellh/go-vnc"
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/common"
"github.com/mitchellh/packer/packer"
"github.com/mitchellh/packer/template/interpolate"
"os"
)
const KeyLeftShift uint32 = 0xFFE1
@ -146,6 +148,14 @@ func vncSendString(c *vnc.ClientConn, original string) {
shiftedChars := "~!@#$%^&*()_+{}|:\"<>?"
waitRe := regexp.MustCompile(`^<wait([0-9hms]+)>`)
// Send the key events. We add a 100ms sleep after each key event
// to deal with network latency and the OS responding to the keystroke.
// It is kind of arbitrary but it is better than nothing.
keyInterval := common.PackerKeyDefault
if delay, err := time.ParseDuration(os.Getenv(common.PackerKeyEnv)); err == nil {
keyInterval = delay
}
// TODO(mitchellh): Ripe for optimizations of some point, perhaps.
for len(original) > 0 {
var keyCode uint32
@ -157,11 +167,7 @@ func vncSendString(c *vnc.ClientConn, original string) {
log.Printf("Special code '<leftAltOn>' found, replacing with: %d", keyCode)
c.KeyEvent(keyCode, true)
time.Sleep(time.Second / 10)
// qemu is picky, so no matter what, wait a small period
time.Sleep(100 * time.Millisecond)
time.Sleep(keyInterval)
continue
}
@ -171,11 +177,7 @@ func vncSendString(c *vnc.ClientConn, original string) {
log.Printf("Special code '<leftCtrlOn>' found, replacing with: %d", keyCode)
c.KeyEvent(keyCode, true)
time.Sleep(time.Second / 10)
// qemu is picky, so no matter what, wait a small period
time.Sleep(100 * time.Millisecond)
time.Sleep(keyInterval)
continue
}
@ -185,11 +187,7 @@ func vncSendString(c *vnc.ClientConn, original string) {
log.Printf("Special code '<leftShiftOn>' found, replacing with: %d", keyCode)
c.KeyEvent(keyCode, true)
time.Sleep(time.Second / 10)
// qemu is picky, so no matter what, wait a small period
time.Sleep(100 * time.Millisecond)
time.Sleep(keyInterval)
continue
}
@ -199,11 +197,7 @@ func vncSendString(c *vnc.ClientConn, original string) {
log.Printf("Special code '<leftAltOff>' found, replacing with: %d", keyCode)
c.KeyEvent(keyCode, false)
time.Sleep(time.Second / 10)
// qemu is picky, so no matter what, wait a small period
time.Sleep(100 * time.Millisecond)
time.Sleep(keyInterval)
continue
}
@ -213,11 +207,7 @@ func vncSendString(c *vnc.ClientConn, original string) {
log.Printf("Special code '<leftCtrlOff>' found, replacing with: %d", keyCode)
c.KeyEvent(keyCode, false)
time.Sleep(time.Second / 10)
// qemu is picky, so no matter what, wait a small period
time.Sleep(100 * time.Millisecond)
time.Sleep(keyInterval)
continue
}
@ -227,11 +217,7 @@ func vncSendString(c *vnc.ClientConn, original string) {
log.Printf("Special code '<leftShiftOff>' found, replacing with: %d", keyCode)
c.KeyEvent(keyCode, false)
time.Sleep(time.Second / 10)
// qemu is picky, so no matter what, wait a small period
time.Sleep(100 * time.Millisecond)
time.Sleep(keyInterval)
continue
}
@ -241,11 +227,7 @@ func vncSendString(c *vnc.ClientConn, original string) {
log.Printf("Special code '<rightAltOn>' found, replacing with: %d", keyCode)
c.KeyEvent(keyCode, true)
time.Sleep(time.Second / 10)
// qemu is picky, so no matter what, wait a small period
time.Sleep(100 * time.Millisecond)
time.Sleep(keyInterval)
continue
}
@ -255,11 +237,7 @@ func vncSendString(c *vnc.ClientConn, original string) {
log.Printf("Special code '<rightCtrlOn>' found, replacing with: %d", keyCode)
c.KeyEvent(keyCode, true)
time.Sleep(time.Second / 10)
// qemu is picky, so no matter what, wait a small period
time.Sleep(100 * time.Millisecond)
time.Sleep(keyInterval)
continue
}
@ -269,11 +247,7 @@ func vncSendString(c *vnc.ClientConn, original string) {
log.Printf("Special code '<rightShiftOn>' found, replacing with: %d", keyCode)
c.KeyEvent(keyCode, true)
time.Sleep(time.Second / 10)
// qemu is picky, so no matter what, wait a small period
time.Sleep(100 * time.Millisecond)
time.Sleep(keyInterval)
continue
}
@ -283,11 +257,7 @@ func vncSendString(c *vnc.ClientConn, original string) {
log.Printf("Special code '<rightAltOff>' found, replacing with: %d", keyCode)
c.KeyEvent(keyCode, false)
time.Sleep(time.Second / 10)
// qemu is picky, so no matter what, wait a small period
time.Sleep(100 * time.Millisecond)
time.Sleep(keyInterval)
continue
}
@ -297,11 +267,7 @@ func vncSendString(c *vnc.ClientConn, original string) {
log.Printf("Special code '<rightCtrlOff>' found, replacing with: %d", keyCode)
c.KeyEvent(keyCode, false)
time.Sleep(time.Second / 10)
// qemu is picky, so no matter what, wait a small period
time.Sleep(100 * time.Millisecond)
time.Sleep(keyInterval)
continue
}
@ -311,11 +277,7 @@ func vncSendString(c *vnc.ClientConn, original string) {
log.Printf("Special code '<rightShiftOff>' found, replacing with: %d", keyCode)
c.KeyEvent(keyCode, false)
time.Sleep(time.Second / 10)
// qemu is picky, so no matter what, wait a small period
time.Sleep(100 * time.Millisecond)
time.Sleep(keyInterval)
continue
}
@ -373,15 +335,14 @@ func vncSendString(c *vnc.ClientConn, original string) {
}
c.KeyEvent(keyCode, true)
time.Sleep(time.Second / 10)
time.Sleep(keyInterval)
c.KeyEvent(keyCode, false)
time.Sleep(time.Second / 10)
time.Sleep(keyInterval)
if keyShift {
c.KeyEvent(KeyLeftShift, false)
}
// qemu is picky, so no matter what, wait a small period
time.Sleep(100 * time.Millisecond)
time.Sleep(keyInterval)
}
}

View File

@ -13,6 +13,7 @@ import (
"github.com/mitchellh/go-vnc"
"github.com/mitchellh/multistep"
"github.com/mitchellh/packer/common"
"github.com/mitchellh/packer/packer"
"github.com/mitchellh/packer/template/interpolate"
)
@ -178,6 +179,14 @@ func vncSendString(c *vnc.ClientConn, original string) {
shiftedChars := "~!@#$%^&*()_+{}|:\"<>?"
// Send the key events. We add a 100ms sleep after each key event
// to deal with network latency and the OS responding to the keystroke.
// It is kind of arbitrary but it is better than nothing.
keyInterval := common.PackerKeyDefault
if delay, err := time.ParseDuration(os.Getenv(common.PackerKeyEnv)); err == nil {
keyInterval = delay
}
// TODO(mitchellh): Ripe for optimizations of some point, perhaps.
for len(original) > 0 {
var keyCode uint32
@ -189,7 +198,7 @@ func vncSendString(c *vnc.ClientConn, original string) {
log.Printf("Special code '<leftAltOn>' found, replacing with: %d", keyCode)
c.KeyEvent(keyCode, true)
time.Sleep(time.Second / 10)
time.Sleep(keyInterval)
continue
}
@ -200,7 +209,7 @@ func vncSendString(c *vnc.ClientConn, original string) {
log.Printf("Special code '<leftCtrlOn>' found, replacing with: %d", keyCode)
c.KeyEvent(keyCode, true)
time.Sleep(time.Second / 10)
time.Sleep(keyInterval)
continue
}
@ -211,7 +220,7 @@ func vncSendString(c *vnc.ClientConn, original string) {
log.Printf("Special code '<leftShiftOn>' found, replacing with: %d", keyCode)
c.KeyEvent(keyCode, true)
time.Sleep(time.Second / 10)
time.Sleep(keyInterval)
continue
}
@ -222,7 +231,7 @@ func vncSendString(c *vnc.ClientConn, original string) {
log.Printf("Special code '<leftAltOff>' found, replacing with: %d", keyCode)
c.KeyEvent(keyCode, false)
time.Sleep(time.Second / 10)
time.Sleep(keyInterval)
continue
}
@ -233,7 +242,7 @@ func vncSendString(c *vnc.ClientConn, original string) {
log.Printf("Special code '<leftCtrlOff>' found, replacing with: %d", keyCode)
c.KeyEvent(keyCode, false)
time.Sleep(time.Second / 10)
time.Sleep(keyInterval)
continue
}
@ -244,7 +253,7 @@ func vncSendString(c *vnc.ClientConn, original string) {
log.Printf("Special code '<leftShiftOff>' found, replacing with: %d", keyCode)
c.KeyEvent(keyCode, false)
time.Sleep(time.Second / 10)
time.Sleep(keyInterval)
continue
}
@ -255,7 +264,7 @@ func vncSendString(c *vnc.ClientConn, original string) {
log.Printf("Special code '<rightAltOn>' found, replacing with: %d", keyCode)
c.KeyEvent(keyCode, true)
time.Sleep(time.Second / 10)
time.Sleep(keyInterval)
continue
}
@ -266,7 +275,7 @@ func vncSendString(c *vnc.ClientConn, original string) {
log.Printf("Special code '<rightCtrlOn>' found, replacing with: %d", keyCode)
c.KeyEvent(keyCode, true)
time.Sleep(time.Second / 10)
time.Sleep(keyInterval)
continue
}
@ -277,7 +286,7 @@ func vncSendString(c *vnc.ClientConn, original string) {
log.Printf("Special code '<rightShiftOn>' found, replacing with: %d", keyCode)
c.KeyEvent(keyCode, true)
time.Sleep(time.Second / 10)
time.Sleep(keyInterval)
continue
}
@ -288,7 +297,7 @@ func vncSendString(c *vnc.ClientConn, original string) {
log.Printf("Special code '<rightAltOff>' found, replacing with: %d", keyCode)
c.KeyEvent(keyCode, false)
time.Sleep(time.Second / 10)
time.Sleep(keyInterval)
continue
}
@ -299,7 +308,7 @@ func vncSendString(c *vnc.ClientConn, original string) {
log.Printf("Special code '<rightCtrlOff>' found, replacing with: %d", keyCode)
c.KeyEvent(keyCode, false)
time.Sleep(time.Second / 10)
time.Sleep(keyInterval)
continue
}
@ -310,7 +319,7 @@ func vncSendString(c *vnc.ClientConn, original string) {
log.Printf("Special code '<rightShiftOff>' found, replacing with: %d", keyCode)
c.KeyEvent(keyCode, false)
time.Sleep(time.Second / 10)
time.Sleep(keyInterval)
continue
}
@ -358,14 +367,6 @@ func vncSendString(c *vnc.ClientConn, original string) {
c.KeyEvent(KeyLeftShift, true)
}
// Send the key events. We add a 100ms sleep after each key event
// to deal with network latency and the OS responding to the keystroke.
// It is kind of arbitrary but it is better than nothing.
keyInterval := 100 * time.Millisecond
if envInterval, err := time.ParseDuration(os.Getenv("PACKER_KEY_INTERVAL")); err == nil {
keyInterval = envInterval
}
c.KeyEvent(keyCode, true)
time.Sleep(keyInterval)
c.KeyEvent(keyCode, false)

View File

@ -23,7 +23,7 @@ import (
dockerbuilder "github.com/mitchellh/packer/builder/docker"
filebuilder "github.com/mitchellh/packer/builder/file"
googlecomputebuilder "github.com/mitchellh/packer/builder/googlecompute"
hypervbuilder "github.com/mitchellh/packer/builder/hyperv/iso"
hypervisobuilder "github.com/mitchellh/packer/builder/hyperv/iso"
nullbuilder "github.com/mitchellh/packer/builder/null"
oneandonebuilder "github.com/mitchellh/packer/builder/oneandone"
openstackbuilder "github.com/mitchellh/packer/builder/openstack"
@ -36,7 +36,6 @@ import (
virtualboxovfbuilder "github.com/mitchellh/packer/builder/virtualbox/ovf"
vmwareisobuilder "github.com/mitchellh/packer/builder/vmware/iso"
vmwarevmxbuilder "github.com/mitchellh/packer/builder/vmware/vmx"
amazonimportpostprocessor "github.com/mitchellh/packer/post-processor/amazon-import"
artificepostprocessor "github.com/mitchellh/packer/post-processor/artifice"
atlaspostprocessor "github.com/mitchellh/packer/post-processor/atlas"
@ -52,11 +51,11 @@ import (
vagrantpostprocessor "github.com/mitchellh/packer/post-processor/vagrant"
vagrantcloudpostprocessor "github.com/mitchellh/packer/post-processor/vagrant-cloud"
vspherepostprocessor "github.com/mitchellh/packer/post-processor/vsphere"
ansibleprovisioner "github.com/mitchellh/packer/provisioner/ansible"
ansiblelocalprovisioner "github.com/mitchellh/packer/provisioner/ansible-local"
chefclientprovisioner "github.com/mitchellh/packer/provisioner/chef-client"
chefsoloprovisioner "github.com/mitchellh/packer/provisioner/chef-solo"
convergeprovisioner "github.com/mitchellh/packer/provisioner/converge"
fileprovisioner "github.com/mitchellh/packer/provisioner/file"
powershellprovisioner "github.com/mitchellh/packer/provisioner/powershell"
puppetmasterlessprovisioner "github.com/mitchellh/packer/provisioner/puppet-masterless"
@ -83,7 +82,7 @@ var Builders = map[string]packer.Builder{
"docker": new(dockerbuilder.Builder),
"file": new(filebuilder.Builder),
"googlecompute": new(googlecomputebuilder.Builder),
"hyperv-iso": new(hypervbuilder.Builder),
"hyperv-iso": new(hypervisobuilder.Builder),
"null": new(nullbuilder.Builder),
"oneandone": new(oneandonebuilder.Builder),
"openstack": new(openstackbuilder.Builder),
@ -103,6 +102,7 @@ var Provisioners = map[string]packer.Provisioner{
"ansible-local": new(ansiblelocalprovisioner.Provisioner),
"chef-client": new(chefclientprovisioner.Provisioner),
"chef-solo": new(chefsoloprovisioner.Provisioner),
"converge": new(convergeprovisioner.Provisioner),
"file": new(fileprovisioner.Provisioner),
"powershell": new(powershellprovisioner.Provisioner),
"puppet-masterless": new(puppetmasterlessprovisioner.Provisioner),

View File

@ -7,8 +7,18 @@ import (
"path/filepath"
"runtime"
"strings"
"time"
)
// PackerKeyEnv is used to specify the key interval (delay) between keystrokes
// sent to the VM, typically in boot commands. This is to prevent host CPU
// utilization from causing key presses to be skipped or repeated incorrectly.
const PackerKeyEnv = "PACKER_KEY_INTERVAL"
// PackerKeyDefault 100ms is appropriate for shared build infrastructure while a
// shorter delay (e.g. 10ms) can be used on a workstation. See PackerKeyEnv.
const PackerKeyDefault = 100 * time.Millisecond
// ScrubConfig is a helper that returns a string representation of
// any struct with the given values stripped out.
func ScrubConfig(target interface{}, values ...string) string {

View File

@ -357,9 +357,17 @@ all typed in sequence. It is an array only to improve readability within the
template.
The boot command is "typed" character for character over a VNC connection to the
machine, simulating a human actually typing the keyboard. There are a set of
special keys available. If these are in your boot command, they will be replaced
by the proper key:
machine, simulating a human actually typing the keyboard.
-> Keystrokes are typed as separate key up/down events over VNC with a
default 100ms delay. The delay alleviates issues with latency and CPU
contention. For local builds you can tune this delay by specifying
`PACKER_KEY_INTERVAL` to speed through the boot command. For example:
PACKER_KEY_INTERVAL=10ms packer build packer.json
There are a set of special keys available. If these are in your boot
command, they will be replaced by the proper key:
- `<bs>` - Backspace

View File

@ -304,9 +304,15 @@ all typed in sequence. It is an array only to improve readability within the
template.
The boot command is "typed" character for character over a VNC connection to the
machine, simulating a human actually typing the keyboard. There are a set of
special keys available. If these are in your boot command, they will be replaced
by the proper key:
machine, simulating a human actually typing the keyboard.
-> Keystrokes are typed as separate key up/down events over VNC with a
default 100ms delay. The delay alleviates issues with latency and CPU
contention. For local builds you can tune this delay by specifying
`PACKER_KEY_INTERVAL` to speed through the boot command. For example:
There are a set of special keys available. If these are in your boot
command, they will be replaced by the proper key:
- `<bs>` - Backspace

View File

@ -185,9 +185,15 @@ all typed in sequence. It is an array only to improve readability within the
template.
The boot command is "typed" character for character over a VNC connection to the
machine, simulating a human actually typing the keyboard. There are a set of
special keys available. If these are in your boot command, they will be replaced
by the proper key:
machine, simulating a human actually typing the keyboard.
-> Keystrokes are typed as separate key up/down events over VNC with a
default 100ms delay. The delay alleviates issues with latency and CPU
contention. For local builds you can tune this delay by specifying
`PACKER_KEY_INTERVAL` to speed through the boot command. For example:
There are a set of special keys available. If these are in your boot
command, they will be replaced by the proper key:
- `<bs>` - Backspace