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:
Brian Elliott 2013-03-04 20:33:50 +00:00
parent 907594ec28
commit 0b488849cc
3 changed files with 145 additions and 7 deletions

View File

@ -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')

View File

@ -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

View 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