Skip to content

Commit

Permalink
builder/parallels: Bundle python version of prltype
Browse files Browse the repository at this point in the history
Uses the Python API from Parallels Virtualization SDK to write
boot commands.

This eliminates a 3rd party requirement and makes it easier for people
not using homebrew to get started with packer.
  • Loading branch information
JessThrysoee committed Sep 19, 2014
1 parent 5e4ffb5 commit 16b82d6
Show file tree
Hide file tree
Showing 7 changed files with 113 additions and 25 deletions.
2 changes: 1 addition & 1 deletion builder/parallels/common/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ type Driver interface {
// Version reads the version of Parallels that is installed.
Version() (string, error)

// Send scancodes to the vm using the prltype tool.
// Send scancodes to the vm using the prltype python script.
SendKeyScanCodes(string, ...string) error

// Finds the MAC address of the NIC nic0
Expand Down
23 changes: 21 additions & 2 deletions builder/parallels/common/driver_9.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package common
import (
"bytes"
"fmt"
"io/ioutil"
"log"
"os"
"os/exec"
Expand Down Expand Up @@ -182,11 +183,29 @@ func (d *Parallels9Driver) Version() (string, error) {
func (d *Parallels9Driver) SendKeyScanCodes(vmName string, codes ...string) error {
var stdout, stderr bytes.Buffer

if codes == nil || len(codes) == 0 {
log.Printf("No scan codes to send")
return nil
}

f, err := ioutil.TempFile("", "prltype")
if err != nil {
return err
}
defer os.Remove(f.Name())

script := []byte(Prltype)
_, err = f.Write(script)
if err != nil {
return err
}

args := prepend(vmName, codes)
cmd := exec.Command("prltype", args...)
args = prepend(f.Name(), args)
cmd := exec.Command("/usr/bin/python", args...)
cmd.Stdout = &stdout
cmd.Stderr = &stderr
err := cmd.Run()
err = cmd.Run()

stdoutString := strings.TrimSpace(stdout.String())
stderrString := strings.TrimSpace(stderr.String())
Expand Down
76 changes: 76 additions & 0 deletions builder/parallels/common/prltype.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package common

const Prltype string = `
import sys
import prlsdkapi
##
def main():
if len(sys.argv) < 3:
print "Usage: prltype VM_NAME SCANCODE..."
sys.exit(1)
vm_name = sys.argv[1]
scancodes = sys.argv[2:]
server = login()
vm, vm_io = connect(server, vm_name)
send(scancodes, vm, vm_io)
disconnect(server, vm, vm_io)
##
def login():
prlsdkapi.prlsdk.InitializeSDK(prlsdkapi.prlsdk.consts.PAM_DESKTOP_MAC)
server = prlsdkapi.Server()
login_job=server.login_local()
login_job.wait()
return server
##
def connect(server, vm_name):
vm_list_job = server.get_vm_list()
result = vm_list_job.wait()
vm_list = [result.get_param_by_index(i) for i in range(result.get_params_count())]
vm = [vm for vm in vm_list if vm.get_name() == vm_name]
if not vm:
vm_names = [vm.get_name() for vm in vm_list]
raise Exception("%s: No such VM. Available VM's are:\n%s" % (vm_name, "\n".join(vm_names)))
vm = vm[0]
vm_io = prlsdkapi.VmIO()
vm_io.connect_to_vm(vm).wait()
return (vm, vm_io)
##
def disconnect(server, vm, vm_io):
if vm and vm_io:
vm_io.disconnect_from_vm(vm)
if server:
server.logoff()
prlsdkapi.deinit_sdk
##
def send(scancodes, vm, vm_io):
timeout = 10
consts = prlsdkapi.prlsdk.consts
for scancode in scancodes:
c = int(scancode, 16)
if (c < 128):
vm_io.send_key_event(vm, (c,), consts.PKE_PRESS, timeout)
else:
vm_io.send_key_event(vm, (c - 128,) , consts.PKE_RELEASE, timeout)
##
if __name__ == "__main__":
main()
`
4 changes: 2 additions & 2 deletions builder/parallels/common/step_type_boot_command.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ type bootCommandTemplateData struct {
Name string
}

// This step "types" the boot command into the VM via prltype, built on the
// Parallels Virtualization SDK - C API.
// This step "types" the boot command into the VM via the prltype script, built on the
// Parallels Virtualization SDK - Python API.
//
// Uses:
// driver Driver
Expand Down
10 changes: 5 additions & 5 deletions website/source/docs/builders/parallels-iso.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -212,11 +212,11 @@ As documented above, the `boot_command` is an array of strings. The
strings are all typed in sequence. It is an array only to improve readability
within the template.

The boot command is "typed" character for character using the `prltype` (part
of prl-utils, see [Parallels Builder](/docs/builders/parallels.html))
command connected 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:
The boot command is "typed" character for character (using the Parallels
Virtualization SDK, see [Parallels Builder](/docs/builders/parallels.html))
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:

* `<enter>` and `<return>` - Simulates an actual "enter" or "return" keypress.

Expand Down
10 changes: 5 additions & 5 deletions website/source/docs/builders/parallels-pvm.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -161,11 +161,11 @@ As documented above, the `boot_command` is an array of strings. The
strings are all typed in sequence. It is an array only to improve readability
within the template.

The boot command is "typed" character for character using the `prltype` (part
of prl-utils, see [Parallels Builder](/docs/builders/parallels.html))
command connected 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:
The boot command is "typed" character for character (using the Parallels
Virtualization SDK, see [Parallels Builder](/docs/builders/parallels.html))
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:

* `<enter>` and `<return>` - Simulates an actual "enter" or "return" keypress.

Expand Down
13 changes: 3 additions & 10 deletions website/source/docs/builders/parallels.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,7 @@ Packer supports the following Parallels builders:

## Requirements

In addition to [Parallels Desktop for Mac](http://www.parallels.com/products/desktop/) this requires:
In addition to [Parallels Desktop for Mac](http://www.parallels.com/products/desktop/) this requires the
[Parallels Virtualization SDK](http://www.parallels.com/downloads/desktop/).

- [Parallels Virtualization SDK 9 for Mac](http://download.parallels.com//desktop/v9/pde.hf1/ParallelsVirtualizationSDK-9.0.24172.951362.dmg)
- [prl-utils](https://github.com/rickard-von-essen/prl-utils/)

The SDK can be installed by downloading and following the instructions in the dmg. The easiest way to install _prl-utils_ is using [Homebrew](http://brew.sh/)

```
brew tap rickard-von-essen/homebrew-formulae
brew install --HEAD prl-utils
```
The SDK can be installed by downloading and following the instructions in the dmg.

0 comments on commit 16b82d6

Please sign in to comment.