Пример #1
0
    def _vm_apply_new_disk_size(
        self, vm: VM, offline: bool, offline_transport: str,
        transaction: Transaction, disk_size: int = 0,
    ):
        """
        If the new VM disk size is set, checks if it's correct and sufficient
        and commit the new size. Rolls it back on the interrupted migration

        :param VM vm: The migrating VM
        :param str offline_transport: offline migration transport
        :param Transaction transaction: The transaction to rollback
        :param int disk_size: the new disk_size_gib attribute
        """
        size = self.vm_new_disk_size(vm, offline,
                                     offline_transport, disk_size)
        if size == vm.dataset_obj['disk_size_gib']:
            return

        old_size = vm.dataset_obj['disk_size_gib']
        vm.dataset_obj['disk_size_gib'] = size
        vm.dataset_obj.commit()

        if transaction:
            def restore_size():
                vm.dataset_obj['disk_size_gib'] = old_size
                vm.dataset_obj.commit()
            transaction.on_rollback('reset_disk_size', restore_size)
Пример #2
0
def change_address(
        vm_hostname, new_address,
        offline=False, migrate=False, allow_reserved_hv=False,
        offline_transport='drbd',
):
    """Change VMs IP address

    This is done by changing data in Serveradmin, running Puppet in VM and
    rebooting it.
    """

    if not offline:
        raise IGVMError('IP address change can be only performed offline')

    with _get_vm(vm_hostname) as vm:
        new_address = ip_address(new_address)

        if vm.dataset_obj['intern_ip'] == new_address:
            raise ConfigError('New IP address is the same as the old one!')

        if not vm.hypervisor.get_vlan_network(new_address) and not migrate:
            err = 'Current hypervisor does not support new subnet!'
            raise ConfigError(err)

        new_network = Query(
            {
                'servertype': 'route_network',
                'state': 'online',
                'network_type': 'internal',
                'intern_ip': Contains(new_address),
            }
        ).get()['hostname']

        vm_was_running = vm.is_running()

        with Transaction() as transaction:
            if vm_was_running:
                vm.shutdown(
                    transaction=transaction,
                    check_vm_up_on_transaction=False,
                )
            vm.change_address(
                new_address, new_network, transaction=transaction,
            )

            if migrate:
                vm_migrate(
                    vm_object=vm,
                    run_puppet=True, offline=True, no_shutdown=True,
                    allow_reserved_hv=allow_reserved_hv,
                    offline_transport=offline_transport,
                )
            else:
                vm.hypervisor.mount_vm_storage(vm, transaction=transaction)
                vm.run_puppet()
                vm.hypervisor.redefine_vm(vm)
                vm.hypervisor.umount_vm_storage(vm)

            if vm_was_running:
                vm.start()
Пример #3
0
Файл: vm.py Проект: seqizz/igvm
    def rename(self, new_hostname):
        """Rename the VM"""
        self.dataset_obj['hostname'] = new_hostname
        self.check_serveradmin_config()

        fd = BytesIO()
        fd.write(bytes(new_hostname, 'utf-8'))
        self.put('/etc/hostname', fd)
        self.put('/etc/mailname', fd)

        hosts_file = [
            line for line in self.run('cat /etc/hosts').splitlines()
            if not line.startswith(str(self.dataset_obj['intern_ip']))
        ]
        hosts_file.append('{0}\t{1}'.format(self.dataset_obj['intern_ip'],
                                            new_hostname))
        self.run("echo '{0}' > /etc/hosts".format('\n'.join(hosts_file)))

        with Transaction() as transaction:
            self.shutdown(transaction=transaction)
            self.hypervisor.redefine_vm(self, new_fqdn=new_hostname)

            self.dataset_obj.commit()

            self.start(transaction=transaction)
Пример #4
0
    def build(self,
              run_puppet=True,
              debug_puppet=False,
              postboot=None,
              cleanup_cert=False):
        """Builds a VM."""
        hypervisor = self.hypervisor
        self.check_serveradmin_config()

        image = self.dataset_obj['os'] + '-base.tar.gz'

        # Can VM run on given hypervisor?
        self.hypervisor.check_vm(self, offline=True)

        if not run_puppet or self.dataset_obj['puppet_disabled']:
            log.warn(
                'Puppet is disabled on the VM.  It will not receive network '
                'configuration.  Expect things to go south.')

        with Transaction() as transaction:
            # Clean up the certificate if the build fails for any reason
            transaction.on_rollback('Clean cert', clean_cert, self.dataset_obj)

            # Perform operations on the hypervisor
            self.hypervisor.create_vm_storage(self, transaction)
            mount_path = self.hypervisor.format_vm_storage(self, transaction)

            self.hypervisor.download_and_extract_image(image, mount_path)

            self.prepare_vm()

            if run_puppet:
                self.run_puppet(clear_cert=cleanup_cert, debug=debug_puppet)

            if postboot is not None:
                self.copy_postboot_script(postboot)

            self.hypervisor.umount_vm_storage(self)
            hypervisor.define_vm(self, transaction)

            # We are updating the information on the Serveradmin, before
            # starting the VM, because the VM would still be on the hypervisor
            # even if it fails to start.
            self.dataset_obj.commit()

            self.start()

        # Perform operations on Virtual Machine
        if postboot is not None:
            self.run('/buildvm-postboot')
            self.run('rm /buildvm-postboot')

        log.info('"{}" is successfully built.'.format(self.fqdn))
Пример #5
0
def change_address(vm_hostname, new_address, offline=False):
    """Change VMs IP address

    This is done by changing data in Serveradmin, running Puppet in VM and
    rebooting it.
    """

    if not offline:
        raise IGVMError('IP address change can be only performed offline')

    with _get_vm(vm_hostname) as vm:
        if vm.dataset_obj['igvm_operation_mode'] != 'kvm':
            raise NotImplementedError(
                'This operation is not yet supported for {}'.format(
                    vm.dataset_obj['igvm_operation_mode']))

        old_address = vm.dataset_obj['intern_ip']
        new_address = ip_address(new_address)

        if old_address == new_address:
            raise ConfigError('New IP address is the same as the old one!')

        vm_was_running = vm.is_running()

        vm.dataset_obj['intern_ip'] = new_address
        vm.dataset_obj.commit()

        if vm_was_running:
            vm.shutdown()

        try:
            with Transaction() as transaction:
                vm.hypervisor.mount_vm_storage(vm, transaction)
                vm.run_puppet()
                vm.hypervisor.redefine_vm(vm)
                vm.hypervisor.umount_vm_storage(vm)
                if vm_was_running:
                    vm.start()
        except BaseException:
            vm.dataset_obj['intern_ip'] = old_address
            vm.dataset_obj.commit()
            raise
Пример #6
0
    def rename(self, new_hostname):
        """Rename the VM"""
        with Transaction() as transaction:
            self.set_hostname(new_hostname, transaction=transaction)
            self.check_serveradmin_config()

            self.shutdown(transaction=transaction)

            self.hypervisor.redefine_vm(self, new_fqdn=new_hostname)
            log.warning(
                'Domain redefinition cannot be rolled back properly. Your '
                'domain is still defined with the new name.')

            self.hypervisor.mount_vm_storage(self, transaction=transaction)

            self.run_puppet()

            self.hypervisor.umount_vm_storage(self)

            self.start(transaction=transaction)
Пример #7
0
def vm_migrate(
        vm_hostname: str = None,
        vm_object=None,
        hypervisor_hostname: Optional[str] = None,
        run_puppet: bool = False,
        debug_puppet: bool = False,
        offline: bool = False,
        offline_transport: str = 'drbd',
        allow_reserved_hv: bool = False,
        no_shutdown: bool = False,
        enforce_vm_env: bool = False,
        disk_size: Optional[int] = None,
        soft_preferences: bool = False,
):
    """Migrate a VM to a new hypervisor."""

    if not (bool(vm_hostname) ^ bool(vm_object)):
        raise IGVMError(
            'Only one of vm_hostname or vm_object can be given!'
        )

    with ExitStack() as es:
        if vm_object:
            # VM given as object and hopefully already locked
            _vm = vm_object
        else:
            _vm = es.enter_context(
                _get_vm(vm_hostname, allow_retired=True)
            )

        # We have to check migration settings before searching for a HV,
        # because the new disk size must be checked and set
        current_size_gib = _vm.dataset_obj['disk_size_gib']
        _vm.dataset_obj['disk_size_gib'] = _vm.hypervisor.vm_new_disk_size(
            _vm, offline, offline_transport, disk_size
        )

        if hypervisor_hostname:
            hypervisor = es.enter_context(_get_hypervisor(
                hypervisor_hostname, allow_reserved=allow_reserved_hv
            ))
            if _vm.hypervisor.fqdn == hypervisor.fqdn:
                raise IGVMError(
                    'Source and destination Hypervisor is the same!'
                )
        else:
            hypervisor = es.enter_context(_get_best_hypervisor(
                _vm,
                ['online', 'online_reserved'] if allow_reserved_hv
                else ['online'],
                offline,
                enforce_vm_env,
                soft_preferences,
            ))

        # After the HV is chosen, disk_size_gib must be restored
        # to pass _check_attributes(_vm)
        _vm.dataset_obj['disk_size_gib'] = current_size_gib

        was_running = _vm.is_running()

        # There is no point of online migration, if the VM is already shutdown.
        if not was_running:
            offline = True

        if not offline and run_puppet:
            raise IGVMError('Online migration cannot run Puppet.')

        # Validate destination hypervisor can run the VM (needs to happen after
        # setting new IP!)
        hypervisor.check_vm(_vm, offline)

        # Require VM to be in sync with serveradmin
        _check_attributes(_vm)

        _vm.check_serveradmin_config()

        with Transaction() as transaction:
            _vm.hypervisor.migrate_vm(
                _vm, hypervisor, offline, offline_transport, transaction,
                no_shutdown, disk_size,
            )

            previous_hypervisor = _vm.hypervisor
            _vm.hypervisor = hypervisor

            def _reset_hypervisor():
                _vm.hypervisor = previous_hypervisor

            transaction.on_rollback('reset hypervisor', _reset_hypervisor)

            if run_puppet:
                hypervisor.mount_vm_storage(_vm, transaction)
                _vm.run_puppet(debug=debug_puppet)
                hypervisor.umount_vm_storage(_vm)

            if offline and was_running:
                _vm.start(transaction=transaction)
            _vm.reset_state()

            # Add migration log entries to hypervisor and previous_hypervisor
            hypervisor.log_migration(_vm, '+')
            transaction.on_rollback(
                'reset hypervisor log',
                hypervisor.log_migration,
                _vm,
                '-',
            )

            previous_hypervisor.log_migration(_vm, '-')
            transaction.on_rollback(
                'reset previous hypervisor log',
                previous_hypervisor.log_migration,
                _vm,
                '+',
            )

            # Update Serveradmin
            _vm.dataset_obj['hypervisor'] = hypervisor.dataset_obj['hostname']
            _vm.dataset_obj.commit()

        # If removing the existing VM fails we shouldn't risk undoing the newly
        # migrated one.
        previous_hypervisor.undefine_vm(_vm)
Пример #8
0
def vm_migrate(vm_hostname,
               hypervisor_hostname=None,
               run_puppet=False,
               debug_puppet=False,
               offline=False,
               offline_transport='drbd',
               allow_reserved_hv=False,
               no_shutdown=False):
    """Migrate a VM to a new hypervisor."""

    with ExitStack() as es:
        vm = es.enter_context(_get_vm(vm_hostname, allow_retired=True))

        if vm.dataset_obj['igvm_operation_mode'] != 'kvm':
            raise NotImplementedError(
                'This operation is not yet supported for {}'.format(
                    vm.dataset_obj['igvm_operation_mode']))

        if hypervisor_hostname:
            hypervisor = es.enter_context(
                _get_hypervisor(hypervisor_hostname,
                                allow_reserved=allow_reserved_hv))
            if vm.hypervisor.fqdn == hypervisor.fqdn:
                raise IGVMError(
                    'Source and destination Hypervisor is the same!')
        else:
            hypervisor = es.enter_context(
                _get_best_hypervisor(
                    vm,
                    ['online', 'online_reserved']
                    if allow_reserved_hv else ['online'],
                    offline,
                ))

        was_running = vm.is_running()

        # There is no point of online migration, if the VM is already shutdown.
        if not was_running:
            offline = True

        if not offline and run_puppet:
            raise IGVMError('Online migration cannot run Puppet.')

        # Validate destination hypervisor can run the VM (needs to happen after
        # setting new IP!)
        hypervisor.check_vm(vm, offline)

        # Require VM to be in sync with serveradmin
        _check_attributes(vm)

        vm.check_serveradmin_config()

        with Transaction() as transaction:
            vm.hypervisor.migrate_vm(
                vm,
                hypervisor,
                offline,
                offline_transport,
                transaction,
                no_shutdown,
            )

            previous_hypervisor = vm.hypervisor
            vm.hypervisor = hypervisor

            def _reset_hypervisor():
                vm.hypervisor = previous_hypervisor

            transaction.on_rollback('reset hypervisor', _reset_hypervisor)

            if run_puppet:
                hypervisor.mount_vm_storage(vm, transaction)
                vm.run_puppet(debug=debug_puppet)
                hypervisor.umount_vm_storage(vm)

            if offline and was_running:
                vm.start(transaction=transaction)
            vm.reset_state()

            # Update Serveradmin
            vm.dataset_obj['hypervisor'] = hypervisor.dataset_obj['hostname']
            vm.dataset_obj.commit()

        # If removing the existing VM fails we shouldn't risk undoing the newly
        # migrated one.
        previous_hypervisor.undefine_vm(vm)