Fixing the placement of instance on spawn

- Fixed the placement of nova instances on correct composed nodes
 - Tracks the resources of correct provider in placement
 - Updated unit tests

Change-Id: If27e1c4b45680a0011dfed0a0ca611d7636c8eb1
Signed-off-by: Helena McGough <helena.mcgough@intel.com>
This commit is contained in:
Helena McGough 2019-03-01 14:18:52 +00:00
parent 31d08ff0d4
commit 97ab8e835e
2 changed files with 109 additions and 104 deletions

View File

@ -60,13 +60,14 @@ CONF = cfg.CONF
class FakeInstance(object):
"""A class to fake out nova instances."""
def __init__(self, name, state, uuid, new_flavor):
def __init__(self, name, state, uuid, new_flavor, node):
"""Initialize the variables for fake instances."""
self.name = name
self.power_state = state
self.uuid = uuid
self.display_description = None
self.flavor = new_flavor
self.node = node
def __getitem__(self, key):
"""Method to retrieve fake instance variables."""
@ -110,7 +111,8 @@ class TestRSDDriver(base.BaseTestCase):
mock_connector.return_value = self.root_conn
# Create sample collections and instances of Chassis/System/Nodes
with open('rsd_virt_for_nova/tests/json_samples/root.json', 'r') as f:
with open('rsd_virt_for_nova/tests/json_samples/root.json',
'r') as f:
self.root_conn.get.return_value.json.return_value = json.loads(
f.read())
self.rsd = rsd_lib.main.RSDLib('http://foo.bar:8442', username='foo',
@ -188,10 +190,11 @@ class TestRSDDriver(base.BaseTestCase):
self.system_inst.identity,
spec)
self.inst1 = FakeInstance('inst1', power_state.RUNNING,
'inst1id', self.flavor)
'inst1id', self.flavor,
"/redfish/v1/Chassis/Chassis1")
self.invalid_inst = FakeInstance(
'inv_inst', power_state.RUNNING, 'inv_inst_id',
self.flavor)
self.flavor, "/redfish/v1/Chassis/Chassis1")
self.RSD.instances = {self.inst1.uuid: self.inst1}
# A provider tree for testing on the placement API
@ -320,9 +323,15 @@ class TestRSDDriver(base.BaseTestCase):
node_col.members_identities = ['/redfish/v1/Nodes/Node1']
self.RSD.driver.PODM.get_node.return_value = self.node_ass_inst
mock_context = context.get_admin_context()
self.RSD.rsd_flavors = {self.flavor.flavorid: {
'id': 'flav_id',
'rsd_systems': [self.system_inst.identity]}}
self.RSD.rsd_flavors = {
self.flavor.flavorid: {
'id': 'flav_id',
'rsd_systems': {
'/redfish/v1/Chassis/Chassis1':
self.system_inst.identity
}
}
}
image_meta = objects.ImageMeta.from_dict(self.test_image_meta)
# Run spawning test
self.RSD.spawn(mock_context, self.inst1, image_meta,
@ -695,18 +704,23 @@ class TestRSDDriver(base.BaseTestCase):
'/redfish/v1/Systems/System3',
'/redfish/v1/Systems/System4'])
@mock.patch.object(driver.RSDDriver, 'check_chassis_systems')
@mock.patch.object(context, 'get_admin_context')
@mock.patch.object(flavor.Flavor, '_flavor_get_by_flavor_id_from_db')
@mock.patch.object(flavor, '_flavor_create')
@mock.patch.object(fields.ResourceClass, 'normalize_name')
@mock.patch.object(driver.RSDDriver, 'conv_GiB_to_MiB')
def test_create_flavors_success(self, conv_mem, norm_name, flav_create,
get_flav, admin_context):
get_flav, admin_context, check_chas):
"""Test creation of new flavors for a System, success."""
# Set up the mock objects for a sucessful creation test
sys_col = self.RSD.driver.PODM.get_system_collection.return_value
chas_col = self.RSD.driver.PODM.get_chassis_collection.return_value
chas_col.members_identities = ['/redfish/v1/Chassis/Chassis1']
sys_col.members_identities = ['/redfish/v1/Systems/System1']
sys_col.get_member.return_value = self.system_inst
chas_col.get_member.return_value = self.chassis_inst
check_chas.return_value = ['/redfish/v1/Systems/System1']
spec = 'resources:' + norm_name.return_value
mem = conv_mem.return_value - 512
proc = self.system_inst.processors.summary.count
@ -716,6 +730,9 @@ class TestRSDDriver(base.BaseTestCase):
# Check the function calls for the test
self.RSD.driver.PODM.get_system_collection.assert_called_once()
self.RSD.driver.PODM.get_chassis_collection.assert_called()
chas_col.get_member.assert_called_with('/redfish/v1/Chassis/Chassis1')
check_chas.assert_called()
sys_col.get_member.assert_called_with('/redfish/v1/Systems/System1')
conv_mem.assert_called_with(self.system_inst.memory_summary.size_gib)
norm_name.assert_called_with(flav_id)
@ -732,49 +749,6 @@ class TestRSDDriver(base.BaseTestCase):
'extra_specs': {spec: '1'}})
get_flav.assert_not_called()
@mock.patch.object(context, 'get_admin_context')
@mock.patch.object(flavor.Flavor, '_flavor_get_by_flavor_id_from_db')
@mock.patch.object(flavor, '_flavor_create')
@mock.patch.object(fields.ResourceClass, 'normalize_name')
@mock.patch.object(driver.RSDDriver, 'conv_GiB_to_MiB')
def test_create_flavors_exists(self, conv_mem, norm_name, flav_create,
get_flav, admin_context):
"""Test failing to create a flavor that already exists."""
# Set up mocks to ensure flavors fail to be created
sys_col = self.RSD.driver.PODM.get_system_collection.return_value
sys_col.members_identities = ['/redfish/v1/Systems/System1']
sys_col.get_member.return_value = self.system_inst
spec = 'resources:' + norm_name.return_value
mem = conv_mem.return_value - 512
proc = self.system_inst.processors.summary.count
flav_id = str(mem) + 'MB-' + str(proc) + 'vcpus'
self.RSD.rsd_flavors = {flav_id: {
'id': flav_create.return_value['id'],
'rsd_systems': [self.system_inst.identity]
}}
flav_create.return_value = Exception
# Run test to try and create new flavors based on available systems
self.RSD._create_flavors()
# Confirm no new flavors have been created
self.RSD.driver.PODM.get_system_collection.assert_called_once()
sys_col.get_member.assert_called_with('/redfish/v1/Systems/System1')
conv_mem.assert_called_with(self.system_inst.memory_summary.size_gib)
norm_name.assert_called_with(flav_id)
admin_context.assert_called()
# Flavor creation call check
flav_create.assert_called_once_with(
admin_context.return_value,
{'name': 'RSD-' + flav_id,
'flavorid': flav_id,
'memory_mb': mem,
'vcpus': self.system_inst.processors.summary.count,
'root_gb': 0,
'extra_specs': {spec: '1'}})
# Confirm that the flavor already exists
get_flav.assert_called_once_with(admin_context.return_value, flav_id)
@mock.patch.object(flavor.Flavor, '_flavor_get_by_flavor_id_from_db')
@mock.patch.object(flavor, '_flavor_create')
@mock.patch.object(fields.ResourceClass, 'normalize_name')
@ -818,8 +792,14 @@ class TestRSDDriver(base.BaseTestCase):
sys_col = self.RSD.driver.PODM.get_system_collection.return_value
sys_col.get_member.return_value = self.system_inst
self.RSD.rsd_flavors = {
'mock_flav_id': {'id': 'flav_id',
'rsd_systems': [self.system_inst.identity]}}
'mock_flav_id': {
'id': 'flav_id',
'rsd_systems': {
'/redfish/v1/Chassis/Chassis1':
self.system_inst.identity
}
}
}
self.RSD.check_flavors(sys_col, ['/redfish/v1/Systems/System1'])
# Confirm the list of available flavors
@ -827,4 +807,4 @@ class TestRSDDriver(base.BaseTestCase):
get_context.assert_called()
flav_list.assert_called_with(get_context.return_value)
sys_col.get_member.assert_called_with('/redfish/v1/Systems/System1')
flav_destroy.assert_not_called()
flav_destroy.assert_called()

View File

@ -75,6 +75,7 @@ class RSDDriver(driver.ComputeDriver):
self.driver = rsd.PODM_connection()
self.instances = OrderedDict()
self.rsd_flavors = OrderedDict()
self.chas_systems = OrderedDict()
self._nodes = []
self._composed_nodes = OrderedDict()
self.instance_node = None
@ -136,7 +137,7 @@ class RSDDriver(driver.ComputeDriver):
COMPOSED_NODE_COL = self.driver.PODM.get_node_collection()
node_inst = None
flav_id = instance.flavor.flavorid
sys_list = self.rsd_flavors[flav_id]['rsd_systems']
sys_list = self.rsd_flavors[flav_id]['rsd_systems'][instance.node]
for n in COMPOSED_NODE_COL.members_identities:
try:
node_inst = self.driver.PODM.get_node(n)
@ -194,6 +195,7 @@ class RSDDriver(driver.ComputeDriver):
def get_available_resource(self, nodename):
"""Update compute manager resource info on ComputeNode table."""
cpu_info = ''
cha_sys = []
SYSTEM_COL = self.driver.PODM.get_system_collection()
members = SYSTEM_COL.members_identities
@ -434,46 +436,66 @@ class RSDDriver(driver.ComputeDriver):
def _create_flavors(self):
"""Auto-generate the flavors for the compute systems available."""
SYSTEM_COL = self.driver.PODM.get_system_collection()
for s in SYSTEM_COL.members_identities:
sys = SYSTEM_COL.get_member(s)
mem = self.conv_GiB_to_MiB(sys.memory_summary.size_gib) - 512
proc = sys.processors.summary.count
flav_id = str(mem) + 'MB-' + str(proc) + 'vcpus'
res = fields.ResourceClass.normalize_name(flav_id)
spec = 'resources:' + res
values = {
'name': 'RSD-' + flav_id,
'flavorid': flav_id,
'memory_mb': mem,
'vcpus': proc,
'root_gb': 0,
'extra_specs': {
spec: '1'}
}
if sys.identity not in self.rsd_flavors:
try:
LOG.debug("New flavor for system: %s", sys.identity)
rsd_flav = flavor._flavor_create(
context.get_admin_context(), values)
self.rsd_flavors[flav_id] = {
'id': rsd_flav['id'],
'rsd_systems': [sys.identity]
}
self._nodes = self._init_nodes()
except Exception as ex:
LOG.debug(
"A flavor already exists for this rsd system: %s", ex)
ex_flav = flavor.Flavor._flavor_get_by_flavor_id_from_db(
context.get_admin_context(), flav_id)
if flav_id not in self.rsd_flavors.keys():
CHASSIS_COL = self.driver.PODM.get_chassis_collection()
for c in CHASSIS_COL.members_identities:
chas = CHASSIS_COL.get_member(c)
cha_sys = self.check_chassis_systems(chas)
for s in cha_sys:
sys = SYSTEM_COL.get_member(s)
mem = self.conv_GiB_to_MiB(sys.memory_summary.size_gib) - 512
proc = sys.processors.summary.count
flav_id = str(mem) + 'MB-' + str(proc) + 'vcpus'
res = fields.ResourceClass.normalize_name(flav_id)
spec = 'resources:' + res
values = {
'name': 'RSD-' + flav_id,
'flavorid': flav_id,
'memory_mb': mem,
'vcpus': proc,
'root_gb': 0,
'extra_specs': {
spec: '1'}
}
if sys.identity not in self.rsd_flavors:
try:
LOG.debug("New flavor for system: %s", sys.identity)
flavor._flavor_create(
context.get_admin_context(), values)
self.chas_systems[str(chas.path)] = [str(sys.identity)]
self.rsd_flavors[flav_id] = {
'id': ex_flav['id'],
'rsd_systems': [sys.identity]
'rsd_systems': self.chas_systems
}
else:
sys_list = self.rsd_flavors[flav_id]['rsd_systems']
sys_list.append(sys.identity)
self.rsd_flavors[flav_id]['rsd_systems'] = sys_list
self._nodes = self._init_nodes()
except Exception as ex:
LOG.debug(
"A flavor already exists for this system: %s", ex)
flavor.Flavor._flavor_get_by_flavor_id_from_db(
context.get_admin_context(), flav_id)
if flav_id not in self.rsd_flavors.keys():
self.chas_systems[str(chas.path)] = [
str(sys.identity)]
self.rsd_flavors[flav_id] = {
'rsd_systems': self.chas_systems
}
else:
chassis_ = self.rsd_flavors[flav_id]['rsd_systems']
if str(chas.path) not in chassis_.keys():
self.chas_systems[str(chas.path)] = [
str(sys.identity)]
self.rsd_flavors[flav_id] = {
'rsd_systems': self.chas_systems
}
else:
systems = self.rsd_flavors[
flav_id]['rsd_systems'][str(chas.path)]
if str(sys.identity) not in systems:
systems.append(str(sys.identity))
self.chas_systems[str(chas.path)] = systems
self.rsd_flavors[flav_id] = {
'rsd_systems': self.chas_systems
}
def check_flavors(self, collection, systems):
"""Check if flavors should be deleted based on system removal."""
@ -500,15 +522,18 @@ class RSDDriver(driver.ComputeDriver):
LOG.warn("Flavor not found exception: %s", ex)
for k in list(self.rsd_flavors):
sys_list = self.rsd_flavors[k]['rsd_systems']
for s in sys_list:
if s not in sys_ids:
try:
rsd_id = self.rsd_flavors[k]['id']
flavor._flavor_destroy(
context.get_admin_context(), rsd_id)
LOG.debug("Deleting flavor for removed systems: %s", k)
del self.rsd_flavors[k]
except KeyError as k_ex:
LOG.warn("Flavor has already been deleted:%s", k_ex)
if k in self.rsd_flavors.keys():
chas_list = self.rsd_flavors[k]['rsd_systems'].keys()
for c in chas_list:
sys_list = self.rsd_flavors[k]['rsd_systems'][c]
for s in sys_list:
if s not in sys_ids:
try:
rsd_id = self.rsd_flavors[k]['id']
flavor._flavor_destroy(
context.get_admin_context(), rsd_id)
LOG.debug("Deleting flavor: %s", k)
del self.rsd_flavors[k]
except KeyError as k_ex:
LOG.warn("Flavor doesn't exist:%s", k_ex)
return