diff --git a/blazar/plugins/oshosts/host_plugin.py b/blazar/plugins/oshosts/host_plugin.py index 0566b8fd..b9eb62ad 100644 --- a/blazar/plugins/oshosts/host_plugin.py +++ b/blazar/plugins/oshosts/host_plugin.py @@ -26,7 +26,6 @@ from blazar.db import utils as db_utils from blazar.manager import exceptions as manager_ex from blazar.plugins import base from blazar.plugins import oshosts as plugin -from blazar.plugins.oshosts import nova_inventory from blazar.utils.openstack import nova from blazar.utils import trusts @@ -243,7 +242,7 @@ class PhysicalHostPlugin(base.BasePlugin, nova.NovaClientWrapper): raise manager_ex.InvalidHost(host=host_values) with trusts.create_ctx_from_trust(trust_id): - inventory = nova_inventory.NovaInventory() + inventory = nova.NovaInventory() servers = inventory.get_servers_per_host(host_ref) if servers: raise manager_ex.HostHavingServers(host=host_ref, @@ -326,7 +325,7 @@ class PhysicalHostPlugin(base.BasePlugin, nova.NovaClientWrapper): with trusts.create_ctx_from_trust(host['trust_id']): # TODO(sbauza): # - Check if no leases having this host scheduled - inventory = nova_inventory.NovaInventory() + inventory = nova.NovaInventory() servers = inventory.get_servers_per_host( host['hypervisor_hostname']) if servers: diff --git a/blazar/plugins/oshosts/nova_inventory.py b/blazar/plugins/oshosts/nova_inventory.py deleted file mode 100644 index 8861bf5a..00000000 --- a/blazar/plugins/oshosts/nova_inventory.py +++ /dev/null @@ -1,84 +0,0 @@ -# Copyright (c) 2013 Bull. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from novaclient import exceptions as nova_exceptions -from oslo_config import cfg - -from blazar.manager import exceptions as manager_exceptions -from blazar.utils.openstack import nova - - -class NovaInventory(nova.NovaClientWrapper): - def __init__(self): - super(NovaInventory, self).__init__( - username=cfg.CONF.os_admin_username, - password=cfg.CONF.os_admin_password, - user_domain_name=cfg.CONF.os_admin_user_domain_name, - project_name=cfg.CONF.os_admin_project_name, - project_domain_name=cfg.CONF.os_admin_user_domain_name) - - def get_host_details(self, host): - """Get Nova capabilities of a single host - - :param host: UUID or name of nova-compute host - :return: Dict of capabilities or raise HostNotFound - """ - try: - hypervisor = self.nova.hypervisors.get(host) - except nova_exceptions.NotFound: - try: - hypervisors_list = self.nova.hypervisors.search(host) - except nova_exceptions.NotFound: - raise manager_exceptions.HostNotFound(host=host) - if len(hypervisors_list) > 1: - raise manager_exceptions.MultipleHostsFound(host) - else: - hypervisor_id = hypervisors_list[0].id - # NOTE(sbauza): No need to catch the exception as we're sure - # that the hypervisor exists - hypervisor = self.nova.hypervisors.get(hypervisor_id) - try: - return {'id': hypervisor.id, - 'hypervisor_hostname': hypervisor.hypervisor_hostname, - 'service_name': hypervisor.service['host'], - 'vcpus': hypervisor.vcpus, - 'cpu_info': hypervisor.cpu_info, - 'hypervisor_type': hypervisor.hypervisor_type, - 'hypervisor_version': hypervisor.hypervisor_version, - 'memory_mb': hypervisor.memory_mb, - 'local_gb': hypervisor.local_gb} - except AttributeError: - raise manager_exceptions.InvalidHost(host=host) - - def get_servers_per_host(self, host): - """List all servers of a nova-compute host - - :param host: Name (not UUID) of nova-compute host - :return: Dict of servers or None - """ - try: - hypervisors_list = self.nova.hypervisors.search(host, servers=True) - except nova_exceptions.NotFound: - raise manager_exceptions.HostNotFound(host=host) - if len(hypervisors_list) > 1: - raise manager_exceptions.MultipleHostsFound(host) - else: - try: - return hypervisors_list[0].servers - except AttributeError: - # NOTE(sbauza): nova.hypervisors.search(servers=True) returns - # a list of hosts without 'servers' attribute if no servers - # are running on that host - return None diff --git a/blazar/tests/plugins/oshosts/test_nova_inventory.py b/blazar/tests/plugins/oshosts/test_nova_inventory.py deleted file mode 100644 index dabe222c..00000000 --- a/blazar/tests/plugins/oshosts/test_nova_inventory.py +++ /dev/null @@ -1,139 +0,0 @@ -# Copyright (c) 2013 Bull. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from novaclient import exceptions as nova_exceptions -from novaclient.v2 import hypervisors - -from blazar import context -from blazar.manager import exceptions as manager_exceptions -from blazar.plugins.oshosts import nova_inventory -from blazar import tests -from blazar.utils.openstack import base - - -class FakeNovaHypervisors(object): - - class FakeHost(object): - id = 1 - hypervisor_hostname = 'fake_name' - vcpus = 1 - cpu_info = 'fake_cpu' - hypervisor_type = 'fake_type' - hypervisor_version = 1000000 - memory_mb = 8192 - local_gb = 10 - - servers = ['server1', 'server2'] - service = {'host': 'fake_name'} - - @classmethod - def get(cls, host): - try: - host = int(host) - except ValueError: - raise nova_exceptions.NotFound(404) - if host == cls.FakeHost.id: - return cls.FakeHost - else: - raise nova_exceptions.NotFound(404) - - @classmethod - def search(cls, host, servers=False): - if host == 'multiple': - return [cls.FakeHost, cls.FakeHost] - if host == cls.FakeHost.service['host']: - return [cls.FakeHost] - else: - raise nova_exceptions.NotFound(404) - - @classmethod - def expected(cls): - return {'id': cls.FakeHost.id, - 'hypervisor_hostname': cls.FakeHost.hypervisor_hostname, - 'service_name': cls.FakeHost.service['host'], - 'vcpus': cls.FakeHost.vcpus, - 'cpu_info': cls.FakeHost.cpu_info, - 'hypervisor_type': cls.FakeHost.hypervisor_type, - 'hypervisor_version': cls.FakeHost.hypervisor_version, - 'memory_mb': cls.FakeHost.memory_mb, - 'local_gb': cls.FakeHost.local_gb} - - -class NovaInventoryTestCase(tests.TestCase): - def setUp(self): - super(NovaInventoryTestCase, self).setUp() - self.context = context - self.patch(self.context, 'BlazarContext') - self.nova_inventory = nova_inventory - self.patch(base, 'url_for').return_value = 'http://foo.bar' - self.inventory = self.nova_inventory.NovaInventory() - - self.hypervisors_get = self.patch(hypervisors.HypervisorManager, 'get') - self.hypervisors_get.side_effect = FakeNovaHypervisors.get - self.hypervisors_search = self.patch(hypervisors.HypervisorManager, - 'search') - self.hypervisors_search.side_effect = FakeNovaHypervisors.search - - def test_get_host_details_with_host_id(self): - host = self.inventory.get_host_details('1') - expected = FakeNovaHypervisors.expected() - self.assertEqual(expected, host) - - def test_get_host_details_with_host_name(self): - host = self.inventory.get_host_details('fake_name') - expected = FakeNovaHypervisors.expected() - self.assertEqual(expected, host) - - def test_get_host_details_with_host_name_having_multiple_results(self): - self.assertRaises(manager_exceptions.MultipleHostsFound, - self.inventory.get_host_details, 'multiple') - - def test_get_host_details_with_host_id_not_found(self): - self.assertRaises(manager_exceptions.HostNotFound, - self.inventory.get_host_details, '2') - - def test_get_host_details_with_host_name_not_found(self): - self.assertRaises(manager_exceptions.HostNotFound, - self.inventory.get_host_details, 'wrong_name') - - def test_get_host_details_with_invalid_host(self): - invalid_host = FakeNovaHypervisors.FakeHost - del invalid_host.vcpus - self.hypervisors_get.return_value = invalid_host - self.assertRaises(manager_exceptions.InvalidHost, - self.inventory.get_host_details, '1') - - def test_get_servers_per_host(self): - servers = self.inventory.get_servers_per_host('fake_name') - self.assertEqual(FakeNovaHypervisors.FakeHost.servers, servers) - - def test_get_servers_per_host_with_host_id(self): - self.assertRaises(manager_exceptions.HostNotFound, - self.inventory.get_servers_per_host, '1') - - def test_get_servers_per_host_with_host_not_found(self): - self.assertRaises(manager_exceptions.HostNotFound, - self.inventory.get_servers_per_host, 'wrong_name') - - def test_get_servers_per_host_having_multiple_results(self): - self.assertRaises(manager_exceptions.MultipleHostsFound, - self.inventory.get_servers_per_host, 'multiple') - - def test_get_servers_per_host_with_host_having_no_servers(self): - host_with_zero_servers = FakeNovaHypervisors.FakeHost - # NOTE(sbauza): We need to simulate a host having zero servers - del host_with_zero_servers.servers - servers = self.inventory.get_servers_per_host('fake_name') - self.assertIsNone(servers) diff --git a/blazar/tests/plugins/test_physical_host_plugin.py b/blazar/tests/plugins/test_physical_host_plugin.py index a90ae216..aa4384ba 100644 --- a/blazar/tests/plugins/test_physical_host_plugin.py +++ b/blazar/tests/plugins/test_physical_host_plugin.py @@ -27,7 +27,6 @@ from blazar.manager import exceptions as manager_exceptions from blazar.manager import service from blazar.plugins import oshosts as plugin from blazar.plugins.oshosts import host_plugin -from blazar.plugins.oshosts import nova_inventory from blazar import tests from blazar.utils.openstack import base from blazar.utils.openstack import nova @@ -52,7 +51,6 @@ class PhysicalHostPlugingSetupOnlyTestCase(tests.TestCase): self.host_plugin = host_plugin self.fake_phys_plugin = self.host_plugin.PhysicalHostPlugin() self.nova = nova - self.nova_inventory = nova_inventory self.rp_create = self.patch(self.nova.ReservationPool, 'create') self.db_api = db_api self.db_host_extra_capability_get_all_per_host = ( @@ -134,18 +132,17 @@ class PhysicalHostPluginTestCase(tests.TestCase): self.db_api, 'host_extra_capability_update') self.nova = nova - self.nova_inventory = nova_inventory self.rp_create = self.patch(self.nova.ReservationPool, 'create') self.patch(self.nova.ReservationPool, 'get_aggregate_from_name_or_id') self.add_compute_host = self.patch(self.nova.ReservationPool, 'add_computehost') self.remove_compute_host = self.patch(self.nova.ReservationPool, 'remove_computehost') - self.get_host_details = self.patch(self.nova_inventory.NovaInventory, + self.get_host_details = self.patch(self.nova.NovaInventory, 'get_host_details') self.get_host_details.return_value = self.fake_host self.get_servers_per_host = self.patch( - self.nova_inventory.NovaInventory, 'get_servers_per_host') + self.nova.NovaInventory, 'get_servers_per_host') self.get_servers_per_host.return_value = None self.get_extra_capabilities = self.patch( self.fake_phys_plugin, '_get_extra_capabilities') diff --git a/blazar/tests/utils/openstack/test_nova.py b/blazar/tests/utils/openstack/test_nova.py index 9b2919a2..280ede9f 100644 --- a/blazar/tests/utils/openstack/test_nova.py +++ b/blazar/tests/utils/openstack/test_nova.py @@ -18,6 +18,7 @@ from keystoneauth1 import session from keystoneauth1 import token_endpoint from novaclient import client as nova_client from novaclient import exceptions as nova_exceptions +from novaclient.v2 import hypervisors from oslo_config import cfg from blazar import context @@ -405,3 +406,119 @@ class ReservationPoolTestCase(tests.TestCase): check = self.nova.aggregates.set_metadata check.assert_called_once_with(self.fake_aggregate.id, {'projectY': None}) + + +class FakeNovaHypervisors(object): + + class FakeHost(object): + id = 1 + hypervisor_hostname = 'fake_name' + vcpus = 1 + cpu_info = 'fake_cpu' + hypervisor_type = 'fake_type' + hypervisor_version = 1000000 + memory_mb = 8192 + local_gb = 10 + + servers = ['server1', 'server2'] + service = {'host': 'fake_name'} + + @classmethod + def get(cls, host): + try: + host = int(host) + except ValueError: + raise nova_exceptions.NotFound(404) + if host == cls.FakeHost.id: + return cls.FakeHost + else: + raise nova_exceptions.NotFound(404) + + @classmethod + def search(cls, host, servers=False): + if host == 'multiple': + return [cls.FakeHost, cls.FakeHost] + if host == cls.FakeHost.service['host']: + return [cls.FakeHost] + else: + raise nova_exceptions.NotFound(404) + + @classmethod + def expected(cls): + return {'id': cls.FakeHost.id, + 'hypervisor_hostname': cls.FakeHost.hypervisor_hostname, + 'service_name': cls.FakeHost.service['host'], + 'vcpus': cls.FakeHost.vcpus, + 'cpu_info': cls.FakeHost.cpu_info, + 'hypervisor_type': cls.FakeHost.hypervisor_type, + 'hypervisor_version': cls.FakeHost.hypervisor_version, + 'memory_mb': cls.FakeHost.memory_mb, + 'local_gb': cls.FakeHost.local_gb} + + +class NovaInventoryTestCase(tests.TestCase): + def setUp(self): + super(NovaInventoryTestCase, self).setUp() + self.context = context + self.patch(self.context, 'BlazarContext') + self.nova = nova + self.patch(base, 'url_for').return_value = 'http://foo.bar' + self.inventory = self.nova.NovaInventory() + + self.hypervisors_get = self.patch(hypervisors.HypervisorManager, 'get') + self.hypervisors_get.side_effect = FakeNovaHypervisors.get + self.hypervisors_search = self.patch(hypervisors.HypervisorManager, + 'search') + self.hypervisors_search.side_effect = FakeNovaHypervisors.search + + def test_get_host_details_with_host_id(self): + host = self.inventory.get_host_details('1') + expected = FakeNovaHypervisors.expected() + self.assertEqual(expected, host) + + def test_get_host_details_with_host_name(self): + host = self.inventory.get_host_details('fake_name') + expected = FakeNovaHypervisors.expected() + self.assertEqual(expected, host) + + def test_get_host_details_with_host_name_having_multiple_results(self): + self.assertRaises(manager_exceptions.MultipleHostsFound, + self.inventory.get_host_details, 'multiple') + + def test_get_host_details_with_host_id_not_found(self): + self.assertRaises(manager_exceptions.HostNotFound, + self.inventory.get_host_details, '2') + + def test_get_host_details_with_host_name_not_found(self): + self.assertRaises(manager_exceptions.HostNotFound, + self.inventory.get_host_details, 'wrong_name') + + def test_get_host_details_with_invalid_host(self): + invalid_host = FakeNovaHypervisors.FakeHost + del invalid_host.vcpus + self.hypervisors_get.return_value = invalid_host + self.assertRaises(manager_exceptions.InvalidHost, + self.inventory.get_host_details, '1') + + def test_get_servers_per_host(self): + servers = self.inventory.get_servers_per_host('fake_name') + self.assertEqual(FakeNovaHypervisors.FakeHost.servers, servers) + + def test_get_servers_per_host_with_host_id(self): + self.assertRaises(manager_exceptions.HostNotFound, + self.inventory.get_servers_per_host, '1') + + def test_get_servers_per_host_with_host_not_found(self): + self.assertRaises(manager_exceptions.HostNotFound, + self.inventory.get_servers_per_host, 'wrong_name') + + def test_get_servers_per_host_having_multiple_results(self): + self.assertRaises(manager_exceptions.MultipleHostsFound, + self.inventory.get_servers_per_host, 'multiple') + + def test_get_servers_per_host_with_host_having_no_servers(self): + host_with_zero_servers = FakeNovaHypervisors.FakeHost + # NOTE(sbauza): We need to simulate a host having zero servers + del host_with_zero_servers.servers + servers = self.inventory.get_servers_per_host('fake_name') + self.assertEqual(None, servers) diff --git a/blazar/utils/openstack/nova.py b/blazar/utils/openstack/nova.py index 1e341006..08084b5f 100644 --- a/blazar/utils/openstack/nova.py +++ b/blazar/utils/openstack/nova.py @@ -421,3 +421,60 @@ class ReservationPool(NovaClientWrapper): metadata = {project_id: None} return self.nova.aggregates.set_metadata(agg.id, metadata) + + +class NovaInventory(NovaClientWrapper): + + def get_host_details(self, host): + """Get Nova capabilities of a single host + + :param host: UUID or name of nova-compute host + :return: Dict of capabilities or raise HostNotFound + """ + try: + hypervisor = self.nova.hypervisors.get(host) + except nova_exception.NotFound: + try: + hypervisors_list = self.nova.hypervisors.search(host) + except nova_exception.NotFound: + raise manager_exceptions.HostNotFound(host=host) + if len(hypervisors_list) > 1: + raise manager_exceptions.MultipleHostsFound(host) + else: + hypervisor_id = hypervisors_list[0].id + # NOTE(sbauza): No need to catch the exception as we're sure + # that the hypervisor exists + hypervisor = self.nova.hypervisors.get(hypervisor_id) + try: + return {'id': hypervisor.id, + 'hypervisor_hostname': hypervisor.hypervisor_hostname, + 'service_name': hypervisor.service['host'], + 'vcpus': hypervisor.vcpus, + 'cpu_info': hypervisor.cpu_info, + 'hypervisor_type': hypervisor.hypervisor_type, + 'hypervisor_version': hypervisor.hypervisor_version, + 'memory_mb': hypervisor.memory_mb, + 'local_gb': hypervisor.local_gb} + except AttributeError: + raise manager_exceptions.InvalidHost(host=host) + + def get_servers_per_host(self, host): + """List all servers of a nova-compute host + + :param host: Name (not UUID) of nova-compute host + :return: Dict of servers or None + """ + try: + hypervisors_list = self.nova.hypervisors.search(host, servers=True) + except nova_exception.NotFound: + raise manager_exceptions.HostNotFound(host=host) + if len(hypervisors_list) > 1: + raise manager_exceptions.MultipleHostsFound(host) + else: + try: + return hypervisors_list[0].servers + except AttributeError: + # NOTE(sbauza): nova.hypervisors.search(servers=True) returns + # a list of hosts without 'servers' attribute if no servers + # are running on that host + return None