%PDF- %PDF-
Direktori : /proc/thread-self/root/usr/lib/python2.7/site-packages/salt/modules/ |
Current File : //proc/thread-self/root/usr/lib/python2.7/site-packages/salt/modules/vmctl.py |
# -*- coding: utf-8 -*- ''' Manage vms running on the OpenBSD VMM hypervisor using vmctl(8). .. versionadded:: 2019.2.0 :codeauthor: ``Jasper Lievisse Adriaanse <jasper@openbsd.org>`` .. note:: This module requires the `vmd` service to be running on the OpenBSD target machine. ''' from __future__ import absolute_import # Import python libs import logging import re # Imoprt salt libs: import salt.utils.path from salt.exceptions import (CommandExecutionError, SaltInvocationError) from salt.ext.six.moves import zip log = logging.getLogger(__name__) def __virtual__(): ''' Only works on OpenBSD with vmctl(8) present. ''' if __grains__['os'] == 'OpenBSD' and salt.utils.path.which('vmctl'): return True return (False, 'The vmm execution module cannot be loaded: either the system is not OpenBSD or the vmctl binary was not found') def _id_to_name(id): ''' Lookup the name associated with a VM id. ''' vm = status(id=id) if vm == {}: return None else: return vm['name'] def create_disk(name, size): ''' Create a VMM disk with the specified `name` and `size`. size: Size in megabytes, or use a specifier such as M, G, T. CLI Example: .. code-block:: bash salt '*' vmctl.create_disk /path/to/disk.img size=10G ''' ret = False cmd = 'vmctl create {0} -s {1}'.format(name, size) result = __salt__['cmd.run_all'](cmd, output_loglevel='trace', python_shell=False) if result['retcode'] == 0: ret = True else: raise CommandExecutionError( 'Problem encountered creating disk image', info={'errors': [result['stderr']], 'changes': ret} ) return ret def load(path): ''' Load additional configuration from the specified file. path Path to the configuration file. CLI Example: .. code-block:: bash salt '*' vmctl.load path=/etc/vm.switches.conf ''' ret = False cmd = 'vmctl load {0}'.format(path) result = __salt__['cmd.run_all'](cmd, output_loglevel='trace', python_shell=False) if result['retcode'] == 0: ret = True else: raise CommandExecutionError( 'Problem encountered running vmctl', info={'errors': [result['stderr']], 'changes': ret} ) return ret def reload(): ''' Remove all stopped VMs and reload configuration from the default configuration file. CLI Example: .. code-block:: bash salt '*' vmctl.reload ''' ret = False cmd = 'vmctl reload' result = __salt__['cmd.run_all'](cmd, output_loglevel='trace', python_shell=False) if result['retcode'] == 0: ret = True else: raise CommandExecutionError( 'Problem encountered running vmctl', info={'errors': [result['stderr']], 'changes': ret} ) return ret def reset(all=False, vms=False, switches=False): ''' Reset the running state of VMM or a subsystem. all: Reset the running state. switches: Reset the configured switches. vms: Reset and terminate all VMs. CLI Example: .. code-block:: bash salt '*' vmctl.reset all=True ''' ret = False cmd = ['vmctl', 'reset'] if all: cmd.append('all') elif vms: cmd.append('vms') elif switches: cmd.append('switches') result = __salt__['cmd.run_all'](cmd, output_loglevel='trace', python_shell=False) if result['retcode'] == 0: ret = True else: raise CommandExecutionError( 'Problem encountered running vmctl', info={'errors': [result['stderr']], 'changes': ret} ) return ret def start(name=None, id=None, bootpath=None, disk=None, disks=None, local_iface=False, memory=None, nics=0, switch=None): ''' Starts a VM defined by the specified parameters. When both a name and id are provided, the id is ignored. name: Name of the defined VM. id: VM id. bootpath: Path to a kernel or BIOS image to load. disk: Path to a single disk to use. disks: List of multiple disks to use. local_iface: Whether to add a local network interface. See "LOCAL INTERFACES" in the vmctl(8) manual page for more information. memory: Memory size of the VM specified in megabytes. switch: Add a network interface that is attached to the specified virtual switch on the host. CLI Example: .. code-block:: bash salt '*' vmctl.start 2 # start VM with id 2 salt '*' vmctl.start name=web1 bootpath='/bsd.rd' nics=2 memory=512M disk='/disk.img' ''' ret = {'changes': False, 'console': None} cmd = ['vmctl', 'start'] if not (name or id): raise SaltInvocationError('Must provide either "name" or "id"') elif name: cmd.append(name) else: cmd.append(id) name = _id_to_name(id) if nics > 0: cmd.append('-i {0}'.format(nics)) # Paths cannot be appended as otherwise the inserted whitespace is treated by # vmctl as being part of the path. if bootpath: cmd.extend(['-b', bootpath]) if memory: cmd.append('-m {0}'.format(memory)) if switch: cmd.append('-n {0}'.format(switch)) if local_iface: cmd.append('-L') if disk and (disks and len(disks) > 0): raise SaltInvocationError('Must provide either "disks" or "disk"') if disk: cmd.extend(['-d', disk]) if disks and len(disks) > 0: cmd.extend(['-d', x] for x in disks) # Before attempting to define a new VM, make sure it doesn't already exist. # Otherwise return to indicate nothing was changed. if len(cmd) > 3: vmstate = status(name) if vmstate: ret['comment'] = 'VM already exists and cannot be redefined' return ret result = __salt__['cmd.run_all'](cmd, output_loglevel='trace', python_shell=False) if result['retcode'] == 0: ret['changes'] = True m = re.match(r'.*successfully, tty (\/dev.*)', result['stderr']) if m: ret['console'] = m.groups()[0] else: m = re.match(r'.*Operation already in progress$', result['stderr']) if m: ret['changes'] = False else: raise CommandExecutionError( 'Problem encountered running vmctl', info={'errors': [result['stderr']], 'changes': ret} ) return ret def status(name=None, id=None): ''' List VMs running on the host, or only the VM specified by ``id``. When both a name and id are provided, the id is ignored. name: Name of the defined VM. id: VM id. CLI Example: .. code-block:: bash salt '*' vmctl.status # to list all VMs salt '*' vmctl.status name=web1 # to get a single VM ''' ret = {} cmd = ['vmctl', 'status'] result = __salt__['cmd.run_all'](cmd, output_loglevel='trace', python_shell=False) if result['retcode'] != 0: raise CommandExecutionError( 'Problem encountered running vmctl', info={'error': [result['stderr']], 'changes': ret} ) # Grab the header and save it with the lowercase names. header = result['stdout'].splitlines()[0].split() header = list([x.lower() for x in header]) # A VM can be in one of the following states (from vmm.c:vcpu_state_decode()) # - stopped # - running # - requesting termination # - terminated # - unknown for line in result['stdout'].splitlines()[1:]: data = line.split() vm = dict(list(zip(header, data))) vmname = vm.pop('name') if vm['pid'] == '-': # If the VM has no PID it's not running. vm['state'] = 'stopped' elif vmname and data[-2] == '-': # When a VM does have a PID and the second to last field is a '-', it's # transitioning to another state. A VM name itself cannot contain a # '-' so it's safe to split on '-'. vm['state'] = data[-1] else: vm['state'] = 'running' # When the status is requested of a single VM (by name) which is stopping, # vmctl doesn't print the status line. So we'll parse the full list and # return when we've found the requested VM. if id and int(vm['id']) == id: return {vmname: vm} elif name and vmname == name: return {vmname: vm} else: ret[vmname] = vm # Assert we've not come this far when an id or name have been provided. That # means the requested VM does not exist. if id or name: return {} return ret def stop(name=None, id=None): ''' Stop (terminate) the VM identified by the given id or name. When both a name and id are provided, the id is ignored. name: Name of the defined VM. id: VM id. CLI Example: .. code-block:: bash salt '*' vmctl.stop name=alpine ''' ret = {} cmd = ['vmctl', 'stop'] if not (name or id): raise SaltInvocationError('Must provide either "name" or "id"') elif name: cmd.append(name) else: cmd.append(id) result = __salt__['cmd.run_all'](cmd, output_loglevel='trace', python_shell=False) if result['retcode'] == 0: if re.match('^vmctl: sent request to terminate vm.*', result['stderr']): ret['changes'] = True else: ret['changes'] = False else: raise CommandExecutionError( 'Problem encountered running vmctl', info={'errors': [result['stderr']], 'changes': ret} ) return ret