diff options
| author | Jenkins <jenkins@review.openstack.org> | 2013-03-11 17:34:11 +0000 |
|---|---|---|
| committer | Gerrit Code Review <review@openstack.org> | 2013-03-11 17:34:11 +0000 |
| commit | 79ea0ab67a864c9a4edaa7b89e6eec3d27266879 (patch) | |
| tree | 9f6b491cb7883b3a55e5437a8b95a09065a1d0eb | |
| parent | fb18fb32c05a8fc082653423331af1cd78db2b43 (diff) | |
| parent | 0b488849cce3bfd4dc4b5b9ad001a17c29376823 (diff) | |
Merge "Add ability to control max utilization of a cell"
| -rw-r--r-- | nova/cells/opts.py | 4 | ||||
| -rw-r--r-- | nova/cells/state.py | 20 | ||||
| -rw-r--r-- | nova/tests/cells/test_cells_state_manager.py | 128 |
3 files changed, 145 insertions, 7 deletions
diff --git a/nova/cells/opts.py b/nova/cells/opts.py index b66dd6b42..203f98687 100644 --- a/nova/cells/opts.py +++ b/nova/cells/opts.py @@ -39,6 +39,10 @@ cells_opts = [ cfg.IntOpt('call_timeout', default=60, help='Seconds to wait for response from a call to a cell.'), + cfg.FloatOpt('reserve_percent', + default=10.0, + help='Percentage of cell capacity to hold in reserve. ' + 'Affects both memory and disk utilization'), ] cfg.CONF.register_opts(cells_opts, group='cells') diff --git a/nova/cells/state.py b/nova/cells/state.py index 53c536888..d7646c528 100644 --- a/nova/cells/state.py +++ b/nova/cells/state.py @@ -40,6 +40,7 @@ LOG = logging.getLogger(__name__) CONF = cfg.CONF CONF.import_opt('name', 'nova.cells.opts', group='cells') +CONF.import_opt('reserve_percent', 'nova.cells.opts', group='cells') #CONF.import_opt('capabilities', 'nova.cells.opts', group='cells') CONF.register_opts(cell_state_manager_opts, group='cells') @@ -196,6 +197,7 @@ class CellStateManager(base.Base): available per instance_type. """ + reserve_level = CONF.cells.reserve_percent / 100.0 compute_hosts = {} def _get_compute_hosts(): @@ -207,7 +209,9 @@ class CellStateManager(base.Base): host = service['host'] compute_hosts[host] = { 'free_ram_mb': compute['free_ram_mb'], - 'free_disk_mb': compute['free_disk_gb'] * 1024} + 'free_disk_mb': compute['free_disk_gb'] * 1024, + 'total_ram_mb': compute['memory_mb'], + 'total_disk_mb': compute['local_gb'] * 1024} _get_compute_hosts() if not compute_hosts: @@ -219,9 +223,11 @@ class CellStateManager(base.Base): total_ram_mb_free = 0 total_disk_mb_free = 0 - def _free_units(tot, per_inst): + def _free_units(total, free, per_inst): if per_inst: - return max(0, int(tot / per_inst)) + min_free = total * reserve_level + free = max(0, free - min_free) + return int(free / per_inst) else: return 0 @@ -231,10 +237,10 @@ class CellStateManager(base.Base): instance_type['ephemeral_gb']) * 1024 ram_mb_free_units.setdefault(str(memory_mb), 0) disk_mb_free_units.setdefault(str(disk_mb), 0) - ram_free_units = _free_units(compute_values['free_ram_mb'], - memory_mb) - disk_free_units = _free_units(compute_values['free_disk_mb'], - disk_mb) + ram_free_units = _free_units(compute_values['total_ram_mb'], + compute_values['free_ram_mb'], memory_mb) + disk_free_units = _free_units(compute_values['total_disk_mb'], + compute_values['free_disk_mb'], disk_mb) ram_mb_free_units[str(memory_mb)] += ram_free_units disk_mb_free_units[str(disk_mb)] += disk_free_units diff --git a/nova/tests/cells/test_cells_state_manager.py b/nova/tests/cells/test_cells_state_manager.py new file mode 100644 index 000000000..078578926 --- /dev/null +++ b/nova/tests/cells/test_cells_state_manager.py @@ -0,0 +1,128 @@ +# 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 CellsStateManager +""" + +from nova.cells import state +from nova import db +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_ITYPES = [ + (0, 0, 0), + (50, 12, 13), +] + + +def _fake_compute_node_get_all(context): + def _node(host, total_mem, total_disk, free_mem, free_disk): + service = {'host': host, 'disabled': False} + return {'service': service, + 'memory_mb': total_mem, + 'local_gb': total_disk, + 'free_ram_mb': free_mem, + 'free_disk_gb': free_disk} + + return [_node(*fake) for fake in FAKE_COMPUTES] + + +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.TestCase): + + def setUp(self): + super(TestCellsStateManager, self).setUp() + + self.stubs.Set(db, 'compute_node_get_all', _fake_compute_node_get_all) + self.stubs.Set(db, 'instance_type_get_all', _fake_instance_type_all) + + 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 _capacity(self, reserve_percent): + self.flags(reserve_percent=reserve_percent, group='cells') + + mgr = state.CellStateManager() + my_state = mgr.get_my_state() + return my_state.capacities |
