示例#1
0
    def power_on(self):
        if not os.path.exists(self.xml_file):
            db.enqueue_instance_error(self.db_entry['uuid'],
                                      'missing domain file in power on')

        libvirt = util.get_libvirt()
        with open(self.xml_file) as f:
            xml = f.read()

        instance = self._get_domain()
        if not instance:
            conn = libvirt.open(None)
            instance = conn.defineXML(xml)
            if not instance:
                db.enqueue_instance_error(self.db_entry['uuid'],
                                          'power on failed to create domain')
                raise exceptions.NoDomainException()

        try:
            instance.create()
        except libvirt.libvirtError as e:
            if not str(e).startswith(
                    'Requested operation is not valid: domain is already running'
            ):
                LOG.withObj(self).warning('Instance start error: %s' % e)
                return False

        instance.setAutostart(1)
        db.update_instance_power_state(
            self.db_entry['uuid'], util.extract_power_state(libvirt, instance))
        db.add_event('instance', self.db_entry['uuid'], 'poweron', 'complete',
                     None, None)
        return True
示例#2
0
    def delete(self):
        with util.RecordedOperation('delete domain', self):
            try:
                self.power_off()

                instance = self._get_domain()
                if instance:
                    instance.undefine()
            except Exception as e:
                util.ignore_exception('instance delete', e)

        with util.RecordedOperation('delete disks', self):
            try:
                if os.path.exists(self.instance_path):
                    shutil.rmtree(self.instance_path)
            except Exception as e:
                util.ignore_exception('instance delete', e)

        with util.RecordedOperation('release network addresses', self):
            for ni in db.get_instance_interfaces(self.db_entry['uuid']):
                db.update_network_interface_state(ni['uuid'], 'deleted')
                with db.get_lock('ipmanager', None, ni['network_uuid'],
                                 ttl=120):
                    ipm = db.get_ipmanager(ni['network_uuid'])
                    ipm.release(ni['ipv4'])
                    db.persist_ipmanager(ni['network_uuid'], ipm.save())

        db.update_instance_power_state(self.db_entry['uuid'], 'off')
        db.free_console_port(self.db_entry['console_port'])
        db.free_console_port(self.db_entry['vdi_port'])
示例#3
0
    def unpause(self):
        libvirt = util.get_libvirt()
        instance = self._get_domain()
        instance.resume()
        db.update_instance_power_state(
            self.db_entry['uuid'], util.extract_power_state(libvirt, instance))

        db.add_event('instance', self.db_entry['uuid'], 'unpause', 'complete',
                     None, None)
示例#4
0
    def power_off(self):
        libvirt = util.get_libvirt()
        instance = self._get_domain()
        if not instance:
            return

        try:
            instance.destroy()
        except libvirt.libvirtError as e:
            LOG.withObj(self).error('Failed to delete domain: %s' % e)

        db.update_instance_power_state(self.db_entry['uuid'], 'off')
        db.add_event('instance', self.db_entry['uuid'], 'poweroff', 'complete',
                     None, None)
示例#5
0
    def test_update_instance_power_state(self, mock_put, mock_get):
        db.update_instance_power_state('uuid42', 'off')
        mock_get.assert_called()

        etcd_write = mock_put.mock_calls[0][1]
        self.assertEqual(('instance', None, 'uuid42'), etcd_write[0:3])
        self.assertTrue(time.time() - etcd_write[3]['power_state_updated'] < 3)
        del etcd_write[3]['power_state_updated']
        self.assertEqual(
            {
                'power_state': 'off',
                'power_state_previous': 'on',
                'uuid': 'uuid42',
                'video': {
                    'memory': 16384,
                    'model': 'cirrus'
                },
                'error_message': None,
            }, etcd_write[3])
示例#6
0
 def test_update_instance_power_state_transition_new(
         self, mock_put, mock_get):
     db.update_instance_power_state('uuid42', 'on')
     mock_get.assert_called()
     mock_put.assert_not_called()
示例#7
0
 def test_update_instance_power_state_duplicate(self, mock_put, mock_get):
     db.update_instance_power_state('uuid42', 'on')
     mock_get.assert_called()
     mock_put.assert_not_called()
示例#8
0
    def _update_power_states(self):
        libvirt = util.get_libvirt()
        conn = libvirt.open(None)
        try:
            seen = []

            # Active VMs have an ID. Active means running in libvirt
            # land.
            for domain_id in conn.listDomainsID():
                domain = conn.lookupByID(domain_id)
                if not domain.name().startswith('sf:'):
                    continue

                instance_uuid = domain.name().split(':')[1]
                log_ctx = LOG.withInstance(instance_uuid)

                instance = db.get_instance(instance_uuid)
                if not instance:
                    # Instance is SF but not in database. Kill to reduce load.
                    log_ctx.warning('Destroying unknown instance')
                    util.execute(None, 'virsh destroy "sf:%s"' % instance_uuid)
                    continue

                db.place_instance(instance_uuid, config.NODE_NAME)
                seen.append(domain.name())

                if instance.get('state') == 'deleted':
                    # NOTE(mikal): a delete might be in-flight in the queue.
                    # We only worry about instances which should have gone
                    # away five minutes ago.
                    if time.time() - instance['state_updated'] < 300:
                        continue

                    db.instance_enforced_deletes_increment(instance_uuid)
                    attempts = instance.get('enforced_deletes', 0)

                    if attempts > 5:
                        # Sometimes we just can't delete the VM. Try the big hammer instead.
                        log_ctx.warning(
                            'Attempting alternate delete method for instance')
                        util.execute(None,
                                     'virsh destroy "sf:%s"' % instance_uuid)

                        db.add_event('instance', instance_uuid,
                                     'enforced delete', 'complete', None, None)
                    else:
                        i = virt.from_db(instance_uuid)
                        i.delete()
                        i.update_instance_state('deleted')

                    log_ctx.withField(
                        'attempt', attempts).warning('Deleting stray instance')

                    continue

                state = util.extract_power_state(libvirt, domain)
                db.update_instance_power_state(instance_uuid, state)
                if state == 'crashed':
                    db.update_instance_state(instance_uuid, 'error')

            # Inactive VMs just have a name, and are powered off
            # in our state system.
            for domain_name in conn.listDefinedDomains():
                if not domain_name.startswith('sf:'):
                    continue

                if domain_name not in seen:
                    instance_uuid = domain_name.split(':')[1]
                    log_ctx = LOG.withInstance(instance_uuid)
                    instance = db.get_instance(instance_uuid)

                    if not instance:
                        # Instance is SF but not in database. Kill because unknown.
                        log_ctx.warning('Removing unknown inactive instance')
                        domain = conn.lookupByName(domain_name)
                        domain.undefine()
                        continue

                    if instance.get('state') == 'deleted':
                        # NOTE(mikal): a delete might be in-flight in the queue.
                        # We only worry about instances which should have gone
                        # away five minutes ago.
                        if time.time() - instance['state_updated'] < 300:
                            continue

                        domain = conn.lookupByName(domain_name)
                        domain.undefine()
                        log_ctx.info('Detected stray instance')
                        db.add_event('instance', instance_uuid,
                                     'deleted stray', 'complete', None, None)
                        continue

                    db.place_instance(instance_uuid, config.NODE_NAME)
                    instance_path = os.path.join(config.get('STORAGE_PATH'),
                                                 'instances', instance_uuid)

                    if not os.path.exists(instance_path):
                        # If we're inactive and our files aren't on disk,
                        # we have a problem.
                        log_ctx.info('Detected error state for instance')
                        db.update_instance_state(instance_uuid, 'error')

                    elif instance.get('power_state') != 'off':
                        log_ctx.info('Detected power off for instance')
                        db.update_instance_power_state(instance_uuid, 'off')
                        db.add_event('instance', instance_uuid,
                                     'detected poweroff', 'complete', None,
                                     None)

        except libvirt.libvirtError as e:
            LOG.error('Failed to lookup all domains: %s' % e)