import argparse import os from pathlib import Path from uncloud.vmm import VMM from uncloud.host.virtualmachine import update_radvd_conf, create_vxlan_br_tap from . import virtualmachine, logger ### # Argument parser loaded by scripts/uncloud. arg_parser = argparse.ArgumentParser('oneshot', add_help=False) # Actions. arg_parser.add_argument('--list', action='store_true', help='list UUID and name of running VMs') arg_parser.add_argument('--start', nargs=3, metavar=('IMAGE', 'UPSTREAM_INTERFACE', 'NETWORK'), help='start a VM using the OS IMAGE (full path), configuring networking on NETWORK IPv6 prefix') arg_parser.add_argument('--stop', metavar='UUID', help='stop a VM') arg_parser.add_argument('--get-status', metavar='UUID', help='return the status of the VM') arg_parser.add_argument('--get-vnc', metavar='UUID', help='return the path of the VNC socket of the VM') arg_parser.add_argument('--reconfigure-radvd', metavar='NETWORK', help='regenerate and reload RADVD configuration for NETWORK IPv6 prefix') # Arguments. arg_parser.add_argument('--workdir', default=Path.home(), help='Working directory, defaulting to $HOME') arg_parser.add_argument('--mac', help='MAC address of the VM to create (--start)') arg_parser.add_argument('--memory', type=int, help='Memory (MB) to allocate (--start)') arg_parser.add_argument('--cores', type=int, help='Number of cores to allocate (--start)') arg_parser.add_argument('--threads', type=int, help='Number of threads to allocate (--start)') arg_parser.add_argument('--image-format', choices=['raw', 'qcow2'], help='Format of OS image (--start)') arg_parser.add_argument('--accel', choices=['kvm', 'tcg'], default='tcg', help='QEMU acceleration to use (--start)') arg_parser.add_argument('--upstream-interface', default='eth0', help='Name of upstream interface (--start)') ### # Helpers. # XXX: check if it is possible to use the type returned by ETCD queries. class UncloudEntryWrapper: def __init__(self, value): self.value = value def value(self): return self.value def status_line(vm): return "VM: {} {} {}".format(vm.get_uuid(), vm.get_name(), vm.get_status()) ### # Entrypoint. def main(arguments): # Initialize VMM. workdir = arguments['workdir'] vmm = VMM(vmm_backend=workdir) # Harcoded debug values. net_id = 0 # Build VM configuration. vm_config = {} vm_options = [ 'mac', 'memory', 'cores', 'threads', 'image', 'image_format', '--upstream_interface', 'upstream_interface', 'network' ] for option in vm_options: if arguments.get(option): vm_config[option] = arguments[option] vm_config['net_id'] = net_id # Execute requested VM action. if arguments['reconfigure_radvd']: # TODO: check that RADVD is available. prefix = arguments['reconfigure_radvd'] network = UncloudEntryWrapper({ 'id': net_id, 'ipv6': prefix }) # Make use of uncloud.host.virtualmachine for network configuration. update_radvd_conf([network]) elif arguments['start']: # Extract from --start positional arguments. Quite fragile. vm_config['image'] = arguments['start'][0] vm_config['network'] = arguments['start'][1] vm_config['upstream_interface'] = arguments['start'][2] vm_config['tap_interface'] = "uc{}".format(len(vmm.discover())) vm = virtualmachine.VM(vmm, vm_config) vm.start() elif arguments['stop']: vm = virtualmachine.VM(vmm, {'uuid': arguments['stop']}) vm = virtualmachine.VM(vmm, vm_config) vm.stop() elif arguments['get_status']: vm = virtualmachine.VM(vmm, {'uuid': arguments['get_status']}) print(status_line(vm)) elif arguments['get_vnc']: vm = virtualmachine.VM(vmm, {'uuid': arguments['get_vnc']}) print(vm.get_vnc_addr()) elif arguments['list']: vms = vmm.discover() print("Found {} VMs.".format(len(vms))) for uuid in vms: vm = virtualmachine.VM(vmm, {'uuid': uuid}) print(status_line(vm)) else: print('Please specify an action: --start, --stop, --list,\ --get-status, --get-vnc, --reconfigure-radvd')