Esempio n. 1
0
    def get_state(self):
        """Return the current mount state.

        _HostMountStateManager will not permit a new state object to be
        created while any previous state object is still in use.

        get_state will raise HypervisorUnavailable if the libvirt connection is
        currently down.

        :rtype: _HostMountState
        """

        # We hold the instance lock here so that if a _HostMountState is
        # currently initialising we'll wait for it to complete rather than
        # fail.
        with self.cond:
            state = self.state
            if state is None:
                raise exception.HypervisorUnavailable()
            self.use_count += 1

        try:
            LOG.debug('Got _HostMountState generation %(gen)i',
                      {'gen': state.generation})

            yield state
        finally:
            with self.cond:
                self.use_count -= 1
                self.cond.notify_all()
Esempio n. 2
0
    def get_session(self, host=None):
        """Returns a connection to the LXD hypervisor

        This method should be used to create a connection
        to the LXD hypervisor via the pylxd API call.

        :param host: host is the LXD daemon to connect to
        :return: pylxd object
        """
        try:
            if host:
                return api.API(host=host)
            else:
                return api.API()
        except Exception as ex:
            # notify the compute host that the connection failed
            # via an rpc call
            LOG.exception(_LE('Connection to LXD failed'))
            payload = dict(ip=CONF.host,
                           method='_connect',
                           reason=ex)
            rpc.get_notifier('compute').error(nova_context.get_admin_context,
                                              'compute.nova_lxd.error',
                                              payload)
            raise exception.HypervisorUnavailable(host=CONF.host)
Esempio n. 3
0
    def _connect(uri, read_only):
        auth = [[libvirt.VIR_CRED_AUTHNAME,
                 libvirt.VIR_CRED_ECHOPROMPT,
                 libvirt.VIR_CRED_REALM,
                 libvirt.VIR_CRED_PASSPHRASE,
                 libvirt.VIR_CRED_NOECHOPROMPT,
                 libvirt.VIR_CRED_EXTERNAL],
                LibvirtDriver._connect_auth_cb,
                None]

        try:
            flags = 0
            if read_only:
                flags = libvirt.VIR_CONNECT_RO
            # tpool.proxy_call creates a native thread. Due to limitations
            # with eventlet locking we cannot use the logging API inside
            # the called function.
            return tpool.proxy_call(
                (libvirt.virDomain, libvirt.virConnect),
                libvirt.openAuth, uri, auth, flags)
        except libvirt.libvirtError as ex:
            LOG.exception(_LE("Connection to libvirt failed: %s"), ex)
            payload = dict(ip=LibvirtDriver.get_host_ip_addr(),
                           method='_connect',
                           reason=ex)
            rpc.get_notifier('compute').error(nova_context.get_admin_context(),
                                              'compute.libvirt.error',
                                              payload)
            raise exception.HypervisorUnavailable(host=CONF.host)
Esempio n. 4
0
    def test_finish_snapshot_based_resize_at_dest_spawn_fails(self):
        """Negative test where the driver spawn fails on the dest host during
        finish_snapshot_based_resize_at_dest which triggers a rollback of the
        instance data in the target cell. Furthermore, the test will hard
        reboot the server in the source cell to recover it from ERROR status.
        """
        # Create a volume-backed server. This is more interesting for rollback
        # testing to make sure the volume attachments in the target cell were
        # cleaned up on failure.
        flavors = self.api.get_flavors()
        server = self._create_server(flavors[0], volume_backed=True)

        # Now mock out the spawn method on the destination host to fail
        # during _finish_snapshot_based_resize_at_dest_spawn and then resize
        # the server.
        error = exception.HypervisorUnavailable(host='host2')
        with mock.patch.object(self.computes['host2'].driver,
                               'spawn',
                               side_effect=error):
            flavor2 = flavors[1]['id']
            body = {'resize': {'flavorRef': flavor2}}
            self.api.post_server_action(server['id'], body)
            # The server should go to ERROR state with a fault record and
            # the API should still be showing the server from the source cell
            # because the instance mapping was not updated.
            server = self._wait_for_server_parameter(
                self.admin_api, server, {
                    'status': 'ERROR',
                    'OS-EXT-STS:task_state': None
                })

        # The migration should be in 'error' status.
        self._wait_for_migration_status(server, ['error'])
        # Assert a fault was recorded.
        self.assertIn('fault', server)
        self.assertIn('Connection to the hypervisor is broken',
                      server['fault']['message'])
        # The instance in the target cell DB should have been hard-deleted.
        self._assert_instance_not_in_cell('cell2', server['id'])

        # Assert that there is only one volume attachment for the server, i.e.
        # the one in the target cell was deleted.
        self.assertEqual(1, self._count_volume_attachments(server['id']),
                         self.cinder.volume_to_attachment)

        # Assert that migration-based allocations were properly reverted.
        self._assert_allocation_revert_on_fail(server)

        # Now hard reboot the server in the source cell and it should go back
        # to ACTIVE.
        self.api.post_server_action(server['id'], {'reboot': {'type': 'HARD'}})
        self._wait_for_state_change(self.admin_api, server, 'ACTIVE')

        # Now retry the resize without the fault in the target host to make
        # sure things are OK (no duplicate entry errors in the target DB).
        self.api.post_server_action(server['id'], body)
        self._wait_for_state_change(self.admin_api, server, 'VERIFY_RESIZE')
Esempio n. 5
0
    def get_available_nodes(self, refresh=True):
        """Returns nodenames of all nodes managed by the compute service."""

        LOG.debug(_("get_available_nodes"))

        node_list = self._get_available_nodes(refresh)

        # node_list is None only when exception is throwed.
        if node_list is None:
            raise nova_exc.HypervisorUnavailable(host='fc-nova-compute')
        else:
            return node_list
Esempio n. 6
0
    def test_prep_snapshot_based_resize_at_source_destroy_fails(self):
        """Negative test where prep_snapshot_based_resize_at_source fails
        destroying the guest for the non-volume backed server and asserts
        resources are rolled back.
        """
        # Create a non-volume backed server for the snapshot flow.
        flavors = self.api.get_flavors()
        flavor1 = flavors[0]
        server = self._create_server(flavor1)

        # Now mock out the snapshot method on the source host to fail
        # during _prep_snapshot_based_resize_at_source and then resize
        # the server.
        source_host = server['OS-EXT-SRV-ATTR:host']
        error = exception.HypervisorUnavailable(host=source_host)
        with mock.patch.object(self.computes[source_host].driver,
                               'destroy',
                               side_effect=error):
            flavor2 = flavors[1]['id']
            body = {'resize': {'flavorRef': flavor2}}
            self.api.post_server_action(server['id'], body)
            # The server should go to ERROR state with a fault record and
            # the API should still be showing the server from the source cell
            # because the instance mapping was not updated.
            server = self._wait_for_server_parameter(
                self.admin_api, server, {
                    'status': 'ERROR',
                    'OS-EXT-STS:task_state': None
                })

        # The migration should be in 'error' status.
        self._wait_for_migration_status(server, ['error'])
        # Assert a fault was recorded.
        self.assertIn('fault', server)
        self.assertIn('Connection to the hypervisor is broken',
                      server['fault']['message'])
        # The instance in the target cell DB should have been hard-deleted.
        self._assert_instance_not_in_cell('cell2', server['id'])
        # Assert that migration-based allocations were properly reverted.
        self._assert_allocation_revert_on_fail(server)

        # Now hard reboot the server in the source cell and it should go back
        # to ACTIVE.
        self.api.post_server_action(server['id'], {'reboot': {'type': 'HARD'}})
        self._wait_for_state_change(self.admin_api, server, 'ACTIVE')

        # Now retry the resize without the fault in the target host to make
        # sure things are OK (no duplicate entry errors in the target DB).
        self.api.post_server_action(server['id'], body)
        self._wait_for_state_change(self.admin_api, server, 'VERIFY_RESIZE')
Esempio n. 7
0
    def get_connection(self):
        """Returns a connection to the hypervisor

        This method should be used to create and return a well
        configured connection to the hypervisor.

        :returns: a libvirt.virConnect object
        """
        try:
            conn = self._get_connection()
        except libvirt.libvirtError as ex:
            LOG.exception(_("Connection to libvirt failed: %s"), ex)
            payload = dict(ip=CONF.my_ip, method='_connect', reason=ex)
            rpc.get_notifier('compute').error(nova_context.get_admin_context(),
                                              'compute.libvirt.error', payload)
            raise exception.HypervisorUnavailable(host=CONF.host)

        return conn
Esempio n. 8
0
 def test_migrate_live_hypervisor_unavailable(self):
     self._test_migrate_live_failed_with_exception(
         exception.HypervisorUnavailable(host=""))