Source code for vmupdate.host

"""
    Provide functions to find and update VM's.
"""

import logging
import os
import platform
import time

from .config import config
from .pkgmgr import get_pkgmgrs, run_pkgmgr
from .virtualizers import get_virtualizer, VM_STOPPED, VM_UNKNOWN
from .vm import VM

log = logging.getLogger(__name__)


[docs]def update_all_vms(): """ Update all virtual machines on the system. :return: exitcode :rtype: int """ log.info('Starting update on all VMs') vms = _get_all_vms() log.info('Found %i VM(s) to update', len(vms)) available_ports = iter(_get_available_ports(vms)) for vm in vms: vm_orig_status = VM_UNKNOWN try: if not any(vm.get_ssh_info()): if vm.get_status() == VM_STOPPED: log.info('Enabling SSH for %s', vm.uid) vm.enable_ssh(next(available_ports)) else: log.warn('SSH cannot be enabled for %s unless it is stopped', vm.uid) log.info('Skipping %s', vm.uid) continue log.info('Starting update on %s', vm.uid) vm_orig_status = vm.get_status() if vm_orig_status == VM_STOPPED: log.info('Starting %s', vm.uid) vm.start() time.sleep(config.general.wait_after_start) for pkgmgr, cmds in get_pkgmgrs(vm): run_pkgmgr(vm, pkgmgr, cmds) except: log.exception('Failed while updating %s', vm.uid) if vm_orig_status == VM_STOPPED: log.info('Stopping %s', vm.uid) time.sleep(config.general.wait_before_stop) vm.stop() log.info('Finished update on %s', vm.uid) log.info('Finished update on all VMs') return 0
def _get_all_vms(): """ Return all virtual machines on the system. Ignores machines where ``Ignore`` is ``True`` in the config. :return: list of virtual machines :rtype: list(:class:`~.vm.VM`) """ vms = [] virtualizers = _find_virtualizers() for virt_name, virt_path in virtualizers.items(): log.info('Querying virtualizer %s', virt_name) virtualizer = get_virtualizer(virt_name, virt_path) for vm_name, vm_uuid in virtualizer.list_vms(): if _should_skip(vm_name): log.info('Skipping VM %s', vm_name) else: log.info('Found VM %s', vm_name) vms.append(VM(virtualizer, vm_name)) return vms def _find_virtualizers(): """ Return all virtualizers found on the system. :return: dictionary of names and paths :rtype: dict(str, str) """ log.info('Finding virtualizers') virtualizers = {} for name, paths in config.virtualizers[platform.system()].items(): try: for path in paths: path = os.path.expandvars(path) log.debug('Checking virtualizer "%s"', path) if os.path.isfile(path): log.debug('Found virtualizer "%s"', path) virtualizers[name] = path except: log.exception('Failed while locating virtualizer %s', name) return virtualizers def _get_available_ports(vms): """ Return ports in the configured range not in use by the ``vms``. :param vms: list of virtual machines :type vms: list(:class:`~.vm.VM`) :return: list of ports :rtype: list(int) """ used_ports = _get_used_ports(vms) min_port = config.network.ssh.host_min_port max_port = config.network.ssh.host_max_port return [p for p in range(min_port, max_port) if p not in used_ports] def _get_used_ports(vms): """ Return a set of ports in use by the ``vms``. :param vms: list of virtual machines :type vms: list(:class:`~.vm.VM`) :return: set of ports :rtype: set(int) """ used_ports = set() for vm in vms: ip, port = vm.get_ssh_info() if port: used_ports.add(port) return used_ports def _should_skip(name): """ Return whether to skip a machine. :param str name: name of the machine to check :rtype: bool """ return name in config.machines and config.machines[name].ignore