packer-cn/builder/proxmox/common/bootcommand_driver.go

164 lines
4.2 KiB
Go

package proxmox
import (
"fmt"
"strings"
"time"
"unicode"
"github.com/Telmate/proxmox-api-go/proxmox"
"github.com/hashicorp/packer-plugin-sdk/bootcommand"
)
type proxmoxDriver struct {
client commandTyper
vmRef *proxmox.VmRef
specialMap map[string]string
runeMap map[rune]string
interval time.Duration
specialBuffer []string
normalBuffer []string
}
func NewProxmoxDriver(c commandTyper, vmRef *proxmox.VmRef, interval time.Duration) *proxmoxDriver {
// Mappings for packer shorthand to qemu qkeycodes
sMap := map[string]string{
"spacebar": "spc",
"bs": "backspace",
"del": "delete",
"return": "ret",
"enter": "ret",
"pageUp": "pgup",
"pageDown": "pgdn",
"leftshift": "shift",
"rightshift": "shift",
"leftalt": "alt",
"rightalt": "alt_r",
"leftctrl": "ctrl",
"rightctrl": "ctrl_r",
"leftsuper": "meta_l",
"rightsuper": "meta_r",
}
// Mappings for runes that need to be translated to special qkeycodes
// Taken from https://github.com/qemu/qemu/blob/master/pc-bios/keymaps/en-us
rMap := map[rune]string{
// Clean mappings
' ': "spc",
'.': "dot",
',': "comma",
';': "semicolon",
'*': "asterisk",
'-': "minus",
'[': "bracket_left",
']': "bracket_right",
'=': "equal",
'\'': "apostrophe",
'`': "grave_accent",
'/': "slash",
'\\': "backslash",
'!': "shift-1", // "exclam"
'@': "shift-2", // "at"
'#': "shift-3", // "numbersign"
'$': "shift-4", // "dollar"
'%': "shift-5", // "percent"
'^': "shift-6", // "asciicircum"
'&': "shift-7", // "ampersand"
'(': "shift-9", // "parenleft"
')': "shift-0", // "parenright"
'{': "shift-bracket_left", // "braceleft"
'}': "shift-bracket_right", // "braceright"
'"': "shift-apostrophe", // "quotedbl"
'+': "shift-equal", // "plus"
'_': "shift-minus", // "underscore"
':': "shift-semicolon", // "colon"
'<': "shift-comma", // "less" is recognized, but seem to map to '/'?
'>': "shift-dot", // "greater"
'~': "shift-grave_accent", // "asciitilde"
'?': "shift-slash", // "question"
'|': "shift-backslash", // "bar"
}
return &proxmoxDriver{
client: c,
vmRef: vmRef,
specialMap: sMap,
runeMap: rMap,
interval: interval,
}
}
func (p *proxmoxDriver) SendKey(key rune, action bootcommand.KeyAction) error {
switch action.String() {
case "Press":
if special, ok := p.runeMap[key]; ok {
return p.send(special)
}
var keys string
if unicode.IsUpper(key) {
keys = fmt.Sprintf("shift-%c", unicode.ToLower(key))
} else {
keys = fmt.Sprintf("%c", key)
}
return p.send(keys)
case "On":
key := fmt.Sprintf("%c", key)
p.normalBuffer = addKeyToBuffer(p.normalBuffer, key)
case "Off":
key := fmt.Sprintf("%c", key)
p.normalBuffer = removeKeyFromBuffer(p.normalBuffer, key)
}
return nil
}
func (p *proxmoxDriver) SendSpecial(special string, action bootcommand.KeyAction) error {
keys := special
if replacement, ok := p.specialMap[special]; ok {
keys = replacement
}
switch action.String() {
case "Press":
return p.send(keys)
case "On":
p.specialBuffer = addKeyToBuffer(p.specialBuffer, keys)
case "Off":
p.specialBuffer = removeKeyFromBuffer(p.specialBuffer, keys)
}
return nil
}
func (p *proxmoxDriver) send(key string) error {
keys := append(p.specialBuffer, p.normalBuffer...)
keys = append(keys, key)
keyEventString := bufferToKeyEvent(keys)
err := p.client.Sendkey(p.vmRef, keyEventString)
if err != nil {
return err
}
time.Sleep(p.interval)
return nil
}
func (p *proxmoxDriver) Flush() error { return nil }
func bufferToKeyEvent(keys []string) string {
return strings.Join(keys, "-")
}
func addKeyToBuffer(buffer []string, key string) []string {
for _, value := range buffer {
if value == key {
return buffer
}
}
return append(buffer, key)
}
func removeKeyFromBuffer(buffer []string, key string) []string {
for index, value := range buffer {
if value == key {
buffer[index] = buffer[len(buffer)-1]
return buffer[:len(buffer)-1]
}
}
return buffer
}