nova/nova/tests/unit/cells/test_cells_state_manager.py

319 lines
12 KiB
Python

# Copyright (c) 2013 Rackspace Hosting
# All Rights Reserved.
#
# 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.
"""
Tests For CellStateManager
"""
import time
import mock
from oslo_config import cfg
from oslo_db import exception as db_exc
import six
from nova.cells import state
from nova import db
from nova.db.sqlalchemy import models
from nova import exception
from nova import objects
from nova.openstack.common import fileutils
from nova import test
FAKE_COMPUTES = [
('host1', 1024, 100, 0, 0),
('host2', 1024, 100, -1, -1),
('host3', 1024, 100, 1024, 100),
('host4', 1024, 100, 300, 30),
]
FAKE_COMPUTES_N_TO_ONE = [
('host1', 1024, 100, 0, 0),
('host1', 1024, 100, -1, -1),
('host2', 1024, 100, 1024, 100),
('host2', 1024, 100, 300, 30),
]
# NOTE(alaski): It's important to have multiple types that end up having the
# same memory and disk requirements. So two types need the same first value,
# and two need the second and third values to add up to the same thing.
FAKE_ITYPES = [
(0, 0, 0),
(50, 12, 13),
(50, 2, 4),
(10, 20, 5),
]
def _create_fake_node(host, total_mem, total_disk, free_mem, free_disk):
return objects.ComputeNode(host=host,
memory_mb=total_mem,
local_gb=total_disk,
free_ram_mb=free_mem,
free_disk_gb=free_disk)
@classmethod
def _fake_service_get_all_by_binary(cls, context, binary):
def _node(host, total_mem, total_disk, free_mem, free_disk):
return objects.Service(host=host, disabled=False)
return [_node(*fake) for fake in FAKE_COMPUTES]
@classmethod
def _fake_compute_node_get_all(cls, context):
return [_create_fake_node(*fake) for fake in FAKE_COMPUTES]
@classmethod
def _fake_compute_node_n_to_one_get_all(cls, context):
return [_create_fake_node(*fake) for fake in FAKE_COMPUTES_N_TO_ONE]
def _fake_cell_get_all(context):
return []
def _fake_instance_type_all(context):
def _type(mem, root, eph):
return {'root_gb': root,
'ephemeral_gb': eph,
'memory_mb': mem}
return [_type(*fake) for fake in FAKE_ITYPES]
class TestCellsStateManager(test.NoDBTestCase):
def setUp(self):
super(TestCellsStateManager, self).setUp()
self.stubs.Set(objects.ComputeNodeList, 'get_all',
_fake_compute_node_get_all)
self.stubs.Set(objects.ServiceList, 'get_by_binary',
_fake_service_get_all_by_binary)
self.stubs.Set(db, 'flavor_get_all', _fake_instance_type_all)
self.stubs.Set(db, 'cell_get_all', _fake_cell_get_all)
def test_cells_config_not_found(self):
self.flags(cells_config='no_such_file_exists.conf', group='cells')
e = self.assertRaises(cfg.ConfigFilesNotFoundError,
state.CellStateManager)
self.assertEqual(['no_such_file_exists.conf'], e.config_files)
@mock.patch.object(cfg.ConfigOpts, 'find_file')
@mock.patch.object(fileutils, 'read_cached_file')
def test_filemanager_returned(self, mock_read_cached_file, mock_find_file):
mock_find_file.return_value = "/etc/nova/cells.json"
mock_read_cached_file.return_value = (False, six.StringIO({}))
self.flags(cells_config='cells.json', group='cells')
manager = state.CellStateManager()
self.assertIsInstance(manager,
state.CellStateManagerFile)
self.assertRaises(exception.CellsUpdateUnsupported,
manager.cell_create, None, None)
self.assertRaises(exception.CellsUpdateUnsupported,
manager.cell_update, None, None, None)
self.assertRaises(exception.CellsUpdateUnsupported,
manager.cell_delete, None, None)
def test_dbmanager_returned(self):
self.assertIsInstance(state.CellStateManager(),
state.CellStateManagerDB)
def test_capacity_no_reserve(self):
# utilize entire cell
cap = self._capacity(0.0)
cell_free_ram = sum(compute[3] for compute in FAKE_COMPUTES)
self.assertEqual(cell_free_ram, cap['ram_free']['total_mb'])
cell_free_disk = 1024 * sum(compute[4] for compute in FAKE_COMPUTES)
self.assertEqual(cell_free_disk, cap['disk_free']['total_mb'])
self.assertEqual(0, cap['ram_free']['units_by_mb']['0'])
self.assertEqual(0, cap['disk_free']['units_by_mb']['0'])
units = cell_free_ram / 50
self.assertEqual(units, cap['ram_free']['units_by_mb']['50'])
sz = 25 * 1024
units = 5 # 4 on host 3, 1 on host4
self.assertEqual(units, cap['disk_free']['units_by_mb'][str(sz)])
def test_capacity_full_reserve(self):
# reserve the entire cell. (utilize zero percent)
cap = self._capacity(100.0)
cell_free_ram = sum(compute[3] for compute in FAKE_COMPUTES)
self.assertEqual(cell_free_ram, cap['ram_free']['total_mb'])
cell_free_disk = 1024 * sum(compute[4] for compute in FAKE_COMPUTES)
self.assertEqual(cell_free_disk, cap['disk_free']['total_mb'])
self.assertEqual(0, cap['ram_free']['units_by_mb']['0'])
self.assertEqual(0, cap['disk_free']['units_by_mb']['0'])
self.assertEqual(0, cap['ram_free']['units_by_mb']['50'])
sz = 25 * 1024
self.assertEqual(0, cap['disk_free']['units_by_mb'][str(sz)])
def test_capacity_part_reserve(self):
# utilize half the cell's free capacity
cap = self._capacity(50.0)
cell_free_ram = sum(compute[3] for compute in FAKE_COMPUTES)
self.assertEqual(cell_free_ram, cap['ram_free']['total_mb'])
cell_free_disk = 1024 * sum(compute[4] for compute in FAKE_COMPUTES)
self.assertEqual(cell_free_disk, cap['disk_free']['total_mb'])
self.assertEqual(0, cap['ram_free']['units_by_mb']['0'])
self.assertEqual(0, cap['disk_free']['units_by_mb']['0'])
units = 10 # 10 from host 3
self.assertEqual(units, cap['ram_free']['units_by_mb']['50'])
sz = 25 * 1024
units = 2 # 2 on host 3
self.assertEqual(units, cap['disk_free']['units_by_mb'][str(sz)])
def _get_state_manager(self, reserve_percent=0.0):
self.flags(reserve_percent=reserve_percent, group='cells')
return state.CellStateManager()
def _capacity(self, reserve_percent):
state_manager = self._get_state_manager(reserve_percent)
my_state = state_manager.get_my_state()
return my_state.capacities
class TestCellsStateManagerNToOne(TestCellsStateManager):
def setUp(self):
super(TestCellsStateManagerNToOne, self).setUp()
self.stubs.Set(objects.ComputeNodeList, 'get_all',
_fake_compute_node_n_to_one_get_all)
def test_capacity_part_reserve(self):
# utilize half the cell's free capacity
cap = self._capacity(50.0)
cell_free_ram = sum(compute[3] for compute in FAKE_COMPUTES_N_TO_ONE)
self.assertEqual(cell_free_ram, cap['ram_free']['total_mb'])
cell_free_disk = (1024 *
sum(compute[4] for compute in FAKE_COMPUTES_N_TO_ONE))
self.assertEqual(cell_free_disk, cap['disk_free']['total_mb'])
self.assertEqual(0, cap['ram_free']['units_by_mb']['0'])
self.assertEqual(0, cap['disk_free']['units_by_mb']['0'])
units = 6 # 6 from host 2
self.assertEqual(units, cap['ram_free']['units_by_mb']['50'])
sz = 25 * 1024
units = 1 # 1 on host 2
self.assertEqual(units, cap['disk_free']['units_by_mb'][str(sz)])
class TestCellStateManagerException(test.NoDBTestCase):
@mock.patch.object(time, 'sleep')
def test_init_db_error(self, mock_sleep):
class TestCellStateManagerDB(state.CellStateManagerDB):
def __init__(self):
self._cell_data_sync = mock.Mock()
self._cell_data_sync.side_effect = [db_exc.DBError(), []]
super(TestCellStateManagerDB, self).__init__()
test = TestCellStateManagerDB()
mock_sleep.assert_called_once_with(30)
self.assertEqual(test._cell_data_sync.call_count, 2)
class TestCellsGetCapacity(TestCellsStateManager):
def setUp(self):
super(TestCellsGetCapacity, self).setUp()
self.capacities = {"ram_free": 1234}
self.state_manager = self._get_state_manager()
cell = models.Cell(name="cell_name")
other_cell = models.Cell(name="other_cell_name")
cell.capacities = self.capacities
other_cell.capacities = self.capacities
self.stubs.Set(self.state_manager, 'child_cells',
{"cell_name": cell,
"other_cell_name": other_cell})
def test_get_cell_capacity_for_all_cells(self):
self.stubs.Set(self.state_manager.my_cell_state, 'capacities',
self.capacities)
capacities = self.state_manager.get_capacities()
self.assertEqual({"ram_free": 3702}, capacities)
def test_get_cell_capacity_for_the_parent_cell(self):
self.stubs.Set(self.state_manager.my_cell_state, 'capacities',
self.capacities)
capacities = self.state_manager.\
get_capacities(self.state_manager.my_cell_state.name)
self.assertEqual({"ram_free": 3702}, capacities)
def test_get_cell_capacity_for_a_cell(self):
self.assertEqual(self.capacities,
self.state_manager.get_capacities(cell_name="cell_name"))
def test_get_cell_capacity_for_non_existing_cell(self):
self.assertRaises(exception.CellNotFound,
self.state_manager.get_capacities,
cell_name="invalid_cell_name")
class FakeCellStateManager(object):
def __init__(self):
self.called = []
def _cell_data_sync(self, force=False):
self.called.append(('_cell_data_sync', force))
class TestSyncDecorators(test.NoDBTestCase):
def test_sync_before(self):
manager = FakeCellStateManager()
def test(inst, *args, **kwargs):
self.assertEqual(inst, manager)
self.assertEqual(args, (1, 2, 3))
self.assertEqual(kwargs, dict(a=4, b=5, c=6))
return 'result'
wrapper = state.sync_before(test)
result = wrapper(manager, 1, 2, 3, a=4, b=5, c=6)
self.assertEqual(result, 'result')
self.assertEqual(manager.called, [('_cell_data_sync', False)])
def test_sync_after(self):
manager = FakeCellStateManager()
def test(inst, *args, **kwargs):
self.assertEqual(inst, manager)
self.assertEqual(args, (1, 2, 3))
self.assertEqual(kwargs, dict(a=4, b=5, c=6))
return 'result'
wrapper = state.sync_after(test)
result = wrapper(manager, 1, 2, 3, a=4, b=5, c=6)
self.assertEqual(result, 'result')
self.assertEqual(manager.called, [('_cell_data_sync', True)])