Merge pull request #4403 from mitchellh/f-fast-boot

Improve delay between key events
This commit is contained in:
Matthew Hooker 2017-01-14 21:05:26 -08:00 committed by GitHub
commit 4fb38015a5
7 changed files with 89 additions and 95 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,13 @@ func vncSendString(c *vnc.ClientConn, original string) {
shiftedChars := "~!@#$%^&*()_+{}|:\"<>?"
waitRe := regexp.MustCompile(`^<wait([0-9hms]+)>`)
// We delay (default 100ms) between each key event to allow for CPU or
// network latency. See PackerKeyEnv for tuning.
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 +166,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 +176,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 +186,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 +196,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 +206,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 +216,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 +226,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 +236,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 +246,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 +256,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 +266,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 +276,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 +334,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

@ -4,6 +4,7 @@ import (
"fmt"
"log"
"net"
"os"
"runtime"
"strings"
"time"
@ -12,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"
)
@ -177,6 +179,13 @@ func vncSendString(c *vnc.ClientConn, original string) {
shiftedChars := "~!@#$%^&*()_+{}|:\"<>?"
// We delay (default 100ms) between each key event to allow for CPU or
// network latency. See PackerKeyEnv for tuning.
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
@ -188,7 +197,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
}
@ -199,7 +208,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
}
@ -210,7 +219,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
}
@ -221,7 +230,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
}
@ -232,7 +241,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
}
@ -243,7 +252,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
}
@ -254,7 +263,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
}
@ -265,7 +274,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
}
@ -276,7 +285,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
}
@ -287,7 +296,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
}
@ -298,7 +307,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
}
@ -309,7 +318,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
}
@ -357,13 +366,10 @@ 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.
c.KeyEvent(keyCode, true)
time.Sleep(100 * time.Millisecond)
time.Sleep(keyInterval)
c.KeyEvent(keyCode, false)
time.Sleep(100 * time.Millisecond)
time.Sleep(keyInterval)
if keyShift {
c.KeyEvent(KeyLeftShift, 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,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
e.g. `PACKER_KEY_INTERVAL=10ms` to speed through the boot command.
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
e.g. `PACKER_KEY_INTERVAL=10ms` to speed through the boot command.
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
e.g. `PACKER_KEY_INTERVAL=10ms` to speed through the boot command.
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