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:
committed by
Hiroaki Kobayashi
parent
cb3632a80a
commit
d677ee17bc
@@ -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:
|
||||
|
||||
@@ -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
|
||||
@@ -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)
|
||||
@@ -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')
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user