summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLars Wirzenius <liw@liw.fi>2020-05-03 11:49:43 +0300
committerLars Wirzenius <liw@liw.fi>2020-05-03 11:49:43 +0300
commitf249a884b0351c5bc6ed6af9b9985fe17a022e90 (patch)
tree351ab8e887f1d15f6efec7aea803a82cb9ff40fd
parentfe338b9dd6abdbcbe4f7dd63a702a3511edaaa57 (diff)
downloadick-contractor-f249a884b0351c5bc6ed6af9b9985fe17a022e90.tar.gz
Change: add script to run manager VM directly via Qemu
-rw-r--r--README.md10
-rwxr-xr-xcontractor62
-rwxr-xr-xvm-qemu.sh51
3 files changed, 97 insertions, 26 deletions
diff --git a/README.md b/README.md
index 7ff9c98..734f9a8 100644
--- a/README.md
+++ b/README.md
@@ -59,10 +59,18 @@ the [vmdb2][] tool installed.
`sudo ./vm.sh`
-* Create the outer, manager VM:
+* Create the outer, manager VM, using libvirt:
`./vm-libvirt.sh`
+* Alternatively, create it using qemu only (this will run until you
+ shut down the VM):
+
+ `./vm-qemu.sh vm.img 7777`
+
+ You need to specify `--manager-address` (or `-m`) and
+ `--manager-port` (or `-p) when using contractor.
+
## Try the Contractor
diff --git a/contractor b/contractor
index e8d0a3d..a879417 100755
--- a/contractor
+++ b/contractor
@@ -41,6 +41,12 @@ class ContractorApplication(cliapp.Application):
'address of the manager VM',
metavar='ADDR')
+ self.settings.integer(
+ ['manager-port', 'p'],
+ 'SSH port of the manager VM',
+ default=22,
+ metavar='ADDR')
+
self.settings.string(
['manager-user'],
'user of the manager in the manager VM',
@@ -59,13 +65,13 @@ class ContractorApplication(cliapp.Application):
def cmd_build(self, args):
self.verbose('building according to {}'.format(args[0]))
bs = self.load_build_spec(args[0])
- dest = self.manager_destination()
- manager = RemoteServer(dest, verbose=self.verbose)
- self.verbose('manager is at {}'.format(dest))
+ dest, port = self.manager_destination()
+ manager = RemoteServer(dest, port, verbose=self.verbose)
+ self.verbose('manager is at {} (port {})'.format(dest, port))
with Timer(self.verbose, 'complete-run'):
with Timer(self.verbose, 'upload-worker-image'):
- self.upload_worker_image(bs.worker_image(), dest)
+ self.upload_worker_image(bs.worker_image(), dest, port)
# Do the minimum needed to start worker VM. The VM takes a
# while to boot and we can do other things while that
@@ -86,14 +92,14 @@ class ContractorApplication(cliapp.Application):
with Timer(self.verbose, 'upload-saved-workspace'):
ws = bs.workspace()
if os.path.exists(ws):
- self.sync_to_workspace(ws, dest, '.')
+ self.sync_to_workspace(ws, dest, port, '.')
with Timer(self.verbose, 'upload-source'):
self.exec_quietly(
manager, Mkdir(
'/mnt/src', owner=WORKER_UID, group=WORKER_GID))
src = bs.source()
- self.sync_to_workspace(src, dest, 'src')
+ self.sync_to_workspace(src, dest, port, 'src')
with Timer(self.verbose, 'wait-for-worker-to-be-available'):
execs = [
@@ -108,7 +114,7 @@ class ContractorApplication(cliapp.Application):
worker_dest = 'worker@{}'.format(worker_ip)
self.verbose(
'worker is at {} (via manager)'.format(worker_dest))
- worker = OnWorker(dest, worker_dest, verbose=self.verbose)
+ worker = OnWorker(dest, port, worker_dest, verbose=self.verbose)
self.exec_quietly(
worker, Mkdir('/workspace'), MountWSonWorker())
@@ -134,7 +140,7 @@ class ContractorApplication(cliapp.Application):
with Timer(self.verbose, 'save-workspace'):
if ws:
self.verbose('saving workspace to {}'.format(ws))
- self.sync_from_workspace(dest, ws)
+ self.sync_from_workspace(dest, port, ws)
self.verbose('build finished OK')
@@ -142,28 +148,30 @@ class ContractorApplication(cliapp.Application):
with open(filename) as f:
return BuildSpec(f.read())
- def upload_worker_image(self, filename, dest):
+ def upload_worker_image(self, filename, dest, port):
self.verbose(
'uploading to manager local worker image {}'.format(filename))
target = '{}:{}'.format(dest, WORKER_IMG)
- if rsync(filename, target).failed():
+ if rsync(filename, target, port).failed():
self.error('could not upload image to worker')
sys.exit(1)
- def sync_to_workspace(self, frm, dest, subdir):
+ def sync_to_workspace(self, frm, dest, port, subdir):
destdir = '/mnt/{}'.format(subdir)
self.verbose('syncing local {} to manager {}'.format(frm, destdir))
er = rsync(
- '{}/.'.format(frm), '{}:{}/.'.format(dest, destdir))
+ '{}/.'.format(frm),
+ '{}:{}/.'.format(dest, destdir),
+ port)
if er.failed():
self.error('Failed to rsync saved workspace to worker')
sys.exit(1)
- def sync_from_workspace(self, dest, ws):
+ def sync_from_workspace(self, dest, port, ws):
self.verbose('syncing manager /mnt to local {}'.format(ws))
if not os.path.exists(ws):
os.makedirs(ws)
- er = rsync('{}:/mnt/.'.format(dest), '{}/.'.format(ws))
+ er = rsync('{}:/mnt/.'.format(dest), '{}/.'.format(ws), port)
if er.failed():
self.error('Failed to rsync workspace from worker')
sys.exit(1)
@@ -182,8 +190,8 @@ class ContractorApplication(cliapp.Application):
return self.exec_sequence(manager.verbosely, *execs)
def cmd_manager_status(self, args):
- dest = self.manager_destination()
- manager = RemoteServer(dest)
+ dest, port = self.manager_destination()
+ manager = RemoteServer(dest, port)
if manager.quietly(TrueCmd()).failed():
self.error('Manager VM is NOT available')
sys.exit(1)
@@ -192,7 +200,8 @@ class ContractorApplication(cliapp.Application):
def manager_destination(self):
user = self.settings['manager-user']
addr = self.settings['manager-address']
- return '{}@{}'.format(user, addr)
+ port = self.settings['manager-port']
+ return '{}@{}'.format(user, addr), port
def error(self, msg):
sys.stderr.write('ERROR: {}\n'.format(msg))
@@ -216,8 +225,9 @@ class ExecResult:
return self.exit_code != 0
-def ssh(target, argv, quiet=False):
- argv = ['ssh', '--', target] + [shlex.quote(arg) for arg in argv]
+def ssh(target, port, argv, quiet=False):
+ ssh_argv = ['ssh', '-p', str(port), '--', target]
+ argv = ssh_argv + [shlex.quote(arg) for arg in argv]
logging.info('SSH: {!r}'.format(argv))
stdout = None
if quiet:
@@ -230,9 +240,9 @@ def ssh(target, argv, quiet=False):
return ExecResult(out, err, p.returncode)
-def rsync(filename, target):
+def rsync(filename, target, port):
argv = [
- 'rsync', '-aHSs', '--delete', '--exclude=lost+found', '--',
+ 'rsync', '-essh -p{}'.format(port), '-aHSs', '--delete', '--exclude=lost+found', '--',
filename, target,
]
logging.info('RSYNC: {!r}'.format(argv))
@@ -243,8 +253,9 @@ def rsync(filename, target):
class RemoteServer:
- def __init__(self, ssh_destination, verbose=None):
+ def __init__(self, ssh_destination, ssh_port, verbose=None):
self._dest = ssh_destination
+ self._port = ssh_port
self._where = 'manager: {}'.format(ssh_destination)
self._verbose = verbose
@@ -268,13 +279,14 @@ class RemoteServer:
def _execute(self, *execs, quiet=None):
assert quiet is not None
- return ssh(self._dest, self._argv(execs), quiet=quiet)
+ return ssh(self._dest, self._port, self._argv(execs), quiet=quiet)
class OnWorker(RemoteServer):
- def __init__(self, manager, worker, verbose=None):
+ def __init__(self, manager, ssh_port, worker, verbose=None):
self._dest = manager
+ self._port = ssh_port
self._where = 'worker: {}'.format(worker)
self._prefix = ['ssh', worker, '--']
self._verbose = verbose
@@ -282,7 +294,7 @@ class OnWorker(RemoteServer):
def _execute(self, *execs, quiet=None):
assert quiet is not None
argv = [shlex.quote(a) for a in self._argv(execs)]
- return ssh(self._dest, self._prefix + argv, quiet=quiet)
+ return ssh(self._dest, self._port, self._prefix + argv, quiet=quiet)
class RemoteExecution:
diff --git a/vm-qemu.sh b/vm-qemu.sh
new file mode 100755
index 0000000..2b8f550
--- /dev/null
+++ b/vm-qemu.sh
@@ -0,0 +1,51 @@
+#!/bin/sh
+#
+# Create a new VM using libvirt on the local host.
+
+set -eu
+
+
+verbose()
+{
+ echo "INFO: $@"
+}
+
+
+die()
+{
+ echo "$@" 1>&2
+ exit 1
+}
+
+
+# Check parameters.
+
+if [ "$#" -lt 2 ]
+then
+ die "Usage: $ IMAGE PORT"
+fi
+
+
+# Command line parameters: image file and port number for SSH.
+image="$1"
+port="$2"
+verbose "creating VM from image $image"
+verbose "once it's running, log in from another terminal: ssh -p $port manager@localhost"
+
+shift 2
+
+# Does the image exist?
+if [ ! -e "$image" ]
+then
+ echo "$image does not exist" 1>&2
+ exit 1
+fi
+
+# Start VM.
+qemu-system-x86_64 \
+ -enable-kvm \
+ -m 8192 \
+ -drive "file=$image,format=raw,if=virtio" \
+ -device virtio-net,netdev=user.0 \
+ -netdev "user,id=user.0,hostfwd=tcp::$port-:22"
+