package proxmox import ( "fmt" "strings" "time" "unicode" "github.com/Telmate/proxmox-api-go/proxmox" "github.com/hashicorp/packer/common/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 }