Move the NovaInventory class to utils/openstack/nova.py

The new instance reservation feature also uses the NovaInventory class
to handle compute hosts in the freepool. However, the class is located
under the oshosts plugin directory.

This commit moves the NovaInventory class in utils/openstack/nova.py
to enable both the host reservation plugin and the instance reservation
plugin to use the class.

Partially implements: blueprint new-instance-reservation

Change-Id: I8d7f53b0bb10f03b2b94f149fef1fd782f508468
This commit is contained in:
Masahito Muroi
2017-05-25 18:45:41 +09:00
committed by Hiroaki Kobayashi
parent cb3632a80a
commit d677ee17bc
6 changed files with 178 additions and 231 deletions

View File

@@ -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:

View File

@@ -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

View File

@@ -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)

View File

@@ -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')

View File

@@ -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)

View File

@@ -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