diff options
author | Lars Wirzenius <liw@liw.fi> | 2020-04-09 10:32:46 +0300 |
---|---|---|
committer | Lars Wirzenius <liw@liw.fi> | 2020-04-09 10:32:46 +0300 |
commit | 6e76b45f9fcf1d47aca42dd0dfad7bdc16f13b75 (patch) | |
tree | 18b926761dfd6e0ea9197d7e8f8188095dd31586 /contractor | |
parent | 677760a88fc4c7ce45cc614959c6c4121004dfa8 (diff) | |
download | ick-contractor-6e76b45f9fcf1d47aca42dd0dfad7bdc16f13b75.tar.gz |
Change: set up worker
Diffstat (limited to 'contractor')
-rwxr-xr-x | contractor | 112 |
1 files changed, 107 insertions, 5 deletions
@@ -21,7 +21,13 @@ def ssh(target, argv, quiet=False): stdout = None if quiet: stdout = PIPE - return subprocess.call(argv, stderr=STDOUT, stdout=stdout) + logging.debug( + 'EXEC: {!r} stdout={!r} stderr={!r}'.format( + argv, stdout, STDOUT)) + p = subprocess.Popen(argv, stderr=STDOUT, stdout=stdout) + out, err = p.communicate() + logging.debug('RESULT: {} {!r} {!r}'.format(p.returncode, out, err)) + return out, err, p.returncode def rsync(filename, target): @@ -63,11 +69,21 @@ class ContractorApplication(cliapp.Application): self.verbose( 'uploading image to worker: {}'.format(bs.worker_image())) - m.upload_image(bs.worker_image()) + m.upload_worker_image(bs.worker_image()) + + self.verbose('starting worker') + if not m.start_worker(): + self.error('could not start worker') + + # install = bs.install() + # if install: + # self.verbose( + # 'installing packages: {}'.format(', '.join(install))) + # else: + # self.verbose('no packages to install') + # m.install_on - # pkgs = build.get('install', []) # if pkgs: - # self.verbose('Installing packages: {}'.format(', '.join(pkgs))) # self.cmd_setup( # ['env', 'DEBIAN_INTERFACE=noninteractive', # 'apt-get', 'install', '-y'] + pkgs) @@ -370,8 +386,94 @@ class Manager: self.virsh(['destroy', 'worker']) self.virsh(['undefine', 'worker']) - def upload_image(self, filename): + def upload_worker_image(self, filename): rsync(filename, '{}:worker.img'.format(self._target)) + def copy_worker_image(self): + self.ssh(['cp', 'worker.img', 'temp.img']) + + def get_cpu_count(self): + out, err, exit_code = self.ssh(['lscpu'], quiet=True) + if exit_code != 0: + logging.error('lscpu on manager failed: {!r}'.format(err)) + return None + + for line in out.decode('UTF8').splitlines(): + if line.startswith('CPU(s):'): + return int(line.split()[-1]) + + logging.error('Could not find number of CPUs on manager') + return None + + def worker_ip(self): + filename = '/var/lib/libvirt/dnsmasq/virbr0.status' + out, err, exit_code = self.ssh(['cat', filename], quiet=True) + if exit_code != 0: + logging.error('Could not read dnsmasq status file') + return None + logging.debug('virbr0.status from manager: {!r}'.format(out)) + + status = json.loads(out) + if not status: + return None + + status.sort(key=lambda e: e['expiry-time']) + return status[-1]['ip-address'] + + def start_worker(self): + self.virsh(['net-autostart', 'default']) + self.virsh(['net-start', 'default']) + n = self.get_cpu_count() + if not isinstance(n, int): + logging.error('Could not start worker due to missing CPU count') + return None + + out, err, exit_code = self.ssh([ + 'virt-install', + '--connect', 'qemu:///system', + '--quiet', + '--name=worker', + '--memory=4096', + '--vcpus={}'.format(n-1), + '--cpu=host', + '--import', + '--os-variant=debian9', + '--disk=path=temp.img,cache=none', + '--disk=path=/dev/vdb,cache=none', + '--network=network=default', + '--graphics=spice', + '--noautoconsole', + ]) + if exit_code != 0: + logging.error('Could not create worker VM') + return None + + return self.wait_for_worker() + + def wait_for_worker(self): + # We look up the IP and try to use it. The IP might be for a + # previous worker instance. + while True: + ip = self.worker_ip() + if ip is None: + continue + w = Worker(self, ip) + out, err, exit_code = w.ssh(['true'], quiet=True) + if exit_code == 0: + return w + time.sleep(2) + + +class Worker: + + def __init__(self, manager, ip): + self._manager = manager + self._target = 'worker@{}'.format(ip) + + def ssh(self, argv, quiet=False): + argv = [shlex.quote(arg) for arg in argv] + argv = ['ssh', self._target, '--'] + argv + return self._manager.ssh(argv, quiet=quiet) + ContractorApplication().run() |