Add ability to control max utilization of a cell
Add a 'reserve_percent' config flag to cells to control the maximum free capacity that a child cell will be advertised to its parent(s). This gives the ability to leave some reserve capacity in child cells for operational maintenance. Change-Id: I1dae1eae4f61ca8079c6f24e60176c31fd8a759d
This commit is contained in:
parent
907594ec28
commit
0b488849cc
@ -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')
|
||||
|
@ -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
|
||||
|
||||
|
128
nova/tests/cells/test_cells_state_manager.py
Normal file
128
nova/tests/cells/test_cells_state_manager.py
Normal file
@ -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
|
Loading…
Reference in New Issue
Block a user