Support updating capacity of reservations

Change-Id: Ia990e126607657c8811fe92f23f6c30cc9889946
Partially-Implements: blueprint update-reserved-capacity
This commit is contained in:
Hiroaki Kobayashi 2017-07-11 11:28:33 +09:00 committed by Pierre Riteau
parent cf31fb3f95
commit 4eeba937f0
9 changed files with 840 additions and 126 deletions

View File

@ -16,7 +16,6 @@
from oslo_log import log as logging
from blazar import context
from blazar import exceptions
from blazar.manager import rpcapi as manager_rpcapi
from blazar import policy
from blazar.utils import trusts
@ -67,28 +66,13 @@ class API(object):
@policy.authorize('leases', 'update')
def update_lease(self, lease_id, data):
"""Update lease. Only name changing and prolonging may be proceeded.
"""Update lease.
:param lease_id: ID of the lease in Blazar DB.
:type lease_id: str
:param data: New lease characteristics.
:type data: dict
"""
new_name = data.pop('name', None)
end_date = data.pop('end_date', None)
start_date = data.pop('start_date', None)
if data:
raise exceptions.BlazarException('Only name changing and '
'dates changing may be '
'proceeded.')
data = {}
if new_name:
data['name'] = new_name
if end_date:
data['end_date'] = end_date
if start_date:
data['start_date'] = start_date
return self.manager_rpcapi.update_lease(lease_id, data)
@policy.authorize('leases', 'delete')

View File

@ -50,7 +50,7 @@ def leases_get(lease_id):
@rest.put('/leases/<lease_id>')
@validation.check_exists(_api.get_lease, lease_id='lease_id')
def leases_update(lease_id, data):
"""Update lease. Only name changing and prolonging may be proceeded."""
"""Update lease."""
return api_utils.render(lease=_api.update_lease(lease_id, data))

View File

@ -165,3 +165,8 @@ class InvalidRange(exceptions.BlazarException):
code = 400
msg_fmt = _('Invalid values for min/max of hosts. '
'Max must be equal to or larger than min.')
class CantUpdateParameter(exceptions.BlazarException):
code = 409
msg_fmt = _("%(param)s cannot be updated")

View File

@ -353,14 +353,26 @@ class ManagerService(service_utils.RPCServer):
raise e
# TODO(frossigneux) rollback if an exception is raised
reservations = values.get('reservations', [])
for reservation in (
db_api.reservation_get_all_by_lease_id(lease_id)):
reservation['start_date'] = values['start_date']
reservation['end_date'] = values['end_date']
resource_type = reservation['resource_type']
v = {}
v['start_date'] = values['start_date']
v['end_date'] = values['end_date']
try:
v.update(filter(lambda x: x['id'] == reservation['id'],
reservations).pop())
except KeyError:
raise exceptions.MissingParameter(param='reservation ID')
except IndexError:
pass
resource_type = v.get('resource_type',
reservation['resource_type'])
if resource_type != reservation['resource_type']:
raise exceptions.CantUpdateParameter(
param='resource_type')
self.plugins[resource_type].update_reservation(
reservation['id'],
reservation)
reservation['id'], v)
event = db_api.event_get_first_sorted_by_filters(
'lease_id',
@ -392,6 +404,10 @@ class ManagerService(service_utils.RPCServer):
self._update_before_end_event(lease, values, notifications,
before_end_date)
try:
del values['reservations']
except KeyError:
pass
db_api.lease_update(lease_id, values)
lease = db_api.lease_get(lease_id)

View File

@ -110,63 +110,40 @@ class PhysicalHostPlugin(base.BasePlugin, nova.NovaClientWrapper):
"""Update reservation."""
reservation = db_api.reservation_get(reservation_id)
lease = db_api.lease_get(reservation['lease_id'])
if (values['start_date'] < lease['start_date'] or
values['end_date'] > lease['end_date']):
allocations = []
hosts_in_pool = []
for allocation in db_api.host_allocation_get_all_by_values(
reservation_id=reservation_id):
full_periods = db_utils.get_full_periods(
allocation['compute_host_id'],
values['start_date'],
values['end_date'],
datetime.timedelta(seconds=1))
if lease['start_date'] < values['start_date']:
max_start = values['start_date']
else:
max_start = lease['start_date']
if lease['end_date'] < values['end_date']:
min_end = lease['end_date']
else:
min_end = values['end_date']
if not (len(full_periods) == 0 or
(len(full_periods) == 1 and
full_periods[0][0] == max_start and
full_periods[0][1] == min_end)):
allocations.append(allocation)
if allocations:
if reservation['status'] == 'active':
raise manager_ex.NotEnoughHostsAvailable()
if (not filter(lambda x: x in ['min', 'max', 'hypervisor_properties',
'resource_properties'], values.keys())
and values['start_date'] >= lease['start_date']
and values['end_date'] <= lease['end_date']):
# Nothing to update
return
dates_before = {'start_date': lease['start_date'],
'end_date': lease['end_date']}
dates_after = {'start_date': values['start_date'],
'end_date': values['end_date']}
host_reservation = db_api.host_reservation_get(
reservation['resource_id'])
pool = nova.ReservationPool()
hosts_in_pool.extend(pool.get_computehosts(
host_reservation['aggregate_id']))
host_ids = self._matching_hosts(
host_reservation['hypervisor_properties'],
host_reservation['resource_properties'],
str(len(allocations)) + '-' + str(len(allocations)),
values['start_date'],
values['end_date'])
if not host_ids:
raise manager_ex.NotEnoughHostsAvailable()
if hosts_in_pool:
old_hosts = [db_api.host_get(allocation['compute_host_id'])
for allocation in allocations]
old_hostnames = [old_host['service_name']
for old_host in old_hosts]
pool.remove_computehost(host_reservation['aggregate_id'],
old_hostnames)
for allocation in allocations:
db_api.host_allocation_destroy(allocation['id'])
for host_id in host_ids:
db_api.host_allocation_create(
{'compute_host_id': host_id,
'reservation_id': reservation_id})
if hosts_in_pool:
host = db_api.host_get(host_id)
pool.add_computehost(host_reservation['aggregate_id'],
host['service_name'])
self._update_allocations(dates_before, dates_after, reservation_id,
reservation['status'], host_reservation,
values)
updates = {}
if 'min' in values or 'max' in values:
count_range = str(values.get(
'min', host_reservation['count_range'].split('-')[0])
) + '-' + str(values.get(
'max', host_reservation['count_range'].split('-')[1])
)
updates['count_range'] = count_range
if 'hypervisor_properties' in values:
updates['hypervisor_properties'] = values.get(
'hypervisor_properties')
if 'resource_properties' in values:
updates['resource_properties'] = values.get(
'resource_properties')
if updates:
db_api.host_reservation_update(host_reservation['id'], updates)
def on_start(self, resource_id):
"""Add the hosts in the pool."""
@ -433,3 +410,101 @@ class PhysicalHostPlugin(base.BasePlugin, nova.NovaClientWrapper):
values['before_end'] = 'default'
if values['before_end'] not in before_end_options:
raise manager_ex.MalformedParameter(param='before_end')
def _update_allocations(self, dates_before, dates_after, reservation_id,
reservation_status, host_reservation, values):
min_hosts = self._convert_int_param(values.get(
'min', host_reservation['count_range'].split('-')[0]), 'min')
max_hosts = self._convert_int_param(values.get(
'max', host_reservation['count_range'].split('-')[1]), 'max')
if min_hosts < 0 or max_hosts < min_hosts:
raise manager_ex.InvalidRange()
hypervisor_properties = values.get(
'hypervisor_properties',
host_reservation['hypervisor_properties'])
resource_properties = values.get(
'resource_properties',
host_reservation['resource_properties'])
allocs = db_api.host_allocation_get_all_by_values(
reservation_id=reservation_id)
allocs_to_remove = self._allocations_to_remove(
dates_before, dates_after, max_hosts, hypervisor_properties,
resource_properties, allocs)
if allocs_to_remove and reservation_status == 'active':
raise manager_ex.NotEnoughHostsAvailable()
kept_hosts = len(allocs) - len(allocs_to_remove)
if kept_hosts < max_hosts:
min_hosts = min_hosts - kept_hosts \
if (min_hosts - kept_hosts) > 0 else 0
max_hosts = max_hosts - kept_hosts
host_ids = self._matching_hosts(
hypervisor_properties, resource_properties,
str(min_hosts) + '-' + str(max_hosts),
dates_after['start_date'], dates_after['end_date'])
if len(host_ids) >= min_hosts:
for host_id in host_ids:
db_api.host_allocation_create(
{'compute_host_id': host_id,
'reservation_id': reservation_id})
else:
raise manager_ex.NotEnoughHostsAvailable()
for allocation in allocs_to_remove:
db_api.host_allocation_destroy(allocation['id'])
def _allocations_to_remove(self, dates_before, dates_after, max_hosts,
hypervisor_properties, resource_properties,
allocs):
allocs_to_remove = []
requested_host_ids = [host['id'] for host in
self._filter_hosts_by_properties(
hypervisor_properties, resource_properties)]
for alloc in allocs:
if alloc['compute_host_id'] not in requested_host_ids:
allocs_to_remove.append(alloc)
continue
if (dates_before['start_date'] > dates_after['start_date'] or
dates_before['end_date'] < dates_after['end_date']):
full_periods = db_utils.get_full_periods(
alloc['compute_host_id'],
dates_after['start_date'],
dates_after['end_date'],
datetime.timedelta(seconds=1))
max_start = max(dates_before['start_date'],
dates_after['start_date'])
min_end = min(dates_before['end_date'],
dates_after['end_date'])
if not (len(full_periods) == 0 or
(len(full_periods) == 1 and
full_periods[0][0] == max_start and
full_periods[0][1] == min_end)):
allocs_to_remove.append(alloc)
continue
kept_hosts = len(allocs) - len(allocs_to_remove)
if kept_hosts > max_hosts:
allocs_to_remove.extend(
[allocation for allocation in allocs
if allocation not in allocs_to_remove
][:(kept_hosts - max_hosts)]
)
return allocs_to_remove
def _filter_hosts_by_properties(self, hypervisor_properties,
resource_properties):
filter = []
if hypervisor_properties:
filter += plugins_utils.convert_requirements(hypervisor_properties)
if resource_properties:
filter += plugins_utils.convert_requirements(resource_properties)
if filter:
return db_api.host_get_all_by_queries(filter)
else:
return db_api.host_list()

View File

@ -628,8 +628,6 @@ class ServiceTestCase(tests.TestCase):
{
'id': u'593e7028-c0d1-4d76-8642-2ffd890b324c',
'resource_type': 'virtual:instance',
'start_date': datetime.datetime(2013, 12, 20, 20, 00),
'end_date': datetime.datetime(2013, 12, 20, 21, 00)
}
]
event_get = self.patch(db_api, 'event_get_first_sorted_by_filters')
@ -643,8 +641,6 @@ class ServiceTestCase(tests.TestCase):
self.fake_plugin.update_reservation.assert_called_with(
'593e7028-c0d1-4d76-8642-2ffd890b324c',
{
'id': '593e7028-c0d1-4d76-8642-2ffd890b324c',
'resource_type': 'virtual:instance',
'start_date': datetime.datetime(2015, 12, 1, 20, 00),
'end_date': datetime.datetime(2015, 12, 1, 22, 00)
}
@ -659,6 +655,116 @@ class ServiceTestCase(tests.TestCase):
self.event_update.assert_has_calls(calls)
self.lease_update.assert_called_once_with(self.lease_id, lease_values)
def test_update_modify_reservations(self):
def fake_event_get(sort_key, sort_dir, filters):
if filters['event_type'] == 'start_lease':
return {'id': u'2eeb784a-2d84-4a89-a201-9d42d61eecb1'}
elif filters['event_type'] == 'end_lease':
return {'id': u'7085381b-45e0-4e5d-b24a-f965f5e6e5d7'}
elif filters['event_type'] == 'before_end_lease':
delta = datetime.timedelta(hours=1)
return {'id': u'452bf850-e223-4035-9d13-eb0b0197228f',
'time': self.lease['end_date'] - delta,
'status': 'UNDONE'}
lease_values = {
'reservations': [
{
'id': u'593e7028-c0d1-4d76-8642-2ffd890b324c',
'min': 3,
'max': 3
}
]
}
reservation_get_all = (
self.patch(self.db_api, 'reservation_get_all_by_lease_id'))
reservation_get_all.return_value = [
{
'id': u'593e7028-c0d1-4d76-8642-2ffd890b324c',
'resource_type': 'virtual:instance',
}
]
event_get = self.patch(db_api, 'event_get_first_sorted_by_filters')
event_get.side_effect = fake_event_get
target = datetime.datetime(2013, 12, 15)
with mock.patch.object(datetime,
'datetime',
mock.Mock(wraps=datetime.datetime)) as patched:
patched.utcnow.return_value = target
self.manager.update_lease(self.lease_id, lease_values)
self.fake_plugin.update_reservation.assert_called_with(
'593e7028-c0d1-4d76-8642-2ffd890b324c',
{
'start_date': datetime.datetime(2013, 12, 20, 13, 00),
'end_date': datetime.datetime(2013, 12, 20, 15, 00),
'id': u'593e7028-c0d1-4d76-8642-2ffd890b324c',
'min': 3,
'max': 3
}
)
calls = [mock.call('2eeb784a-2d84-4a89-a201-9d42d61eecb1',
{'time': datetime.datetime(2013, 12, 20, 13, 00)}),
mock.call('7085381b-45e0-4e5d-b24a-f965f5e6e5d7',
{'time': datetime.datetime(2013, 12, 20, 15, 00)}),
mock.call('452bf850-e223-4035-9d13-eb0b0197228f',
{'time': datetime.datetime(2013, 12, 20, 14, 00)})
]
self.event_update.assert_has_calls(calls)
self.lease_update.assert_called_once_with(self.lease_id, lease_values)
def test_update_modify_reservations_with_invalid_param(self):
lease_values = {
'reservations': [
{
'id': u'593e7028-c0d1-4d76-8642-2ffd890b324c',
'resource_type': 'invalid',
'min': 3,
'max': 3
}
]
}
reservation_get_all = (
self.patch(self.db_api, 'reservation_get_all_by_lease_id'))
reservation_get_all.return_value = [
{
'id': u'593e7028-c0d1-4d76-8642-2ffd890b324c',
'resource_type': 'virtual:instance',
}
]
target = datetime.datetime(2013, 12, 15)
with mock.patch.object(datetime,
'datetime',
mock.Mock(wraps=datetime.datetime)) as patched:
patched.utcnow.return_value = target
self.assertRaises(
manager_ex.CantUpdateParameter, self.manager.update_lease,
self.lease_id, lease_values)
def test_update_modify_reservations_without_reservation_id(self):
lease_values = {
'reservations': [
{
'max': 3
}
]
}
reservation_get_all = (
self.patch(self.db_api, 'reservation_get_all_by_lease_id'))
reservation_get_all.return_value = [
{
'id': u'593e7028-c0d1-4d76-8642-2ffd890b324c',
'resource_type': 'virtual:instance',
}
]
target = datetime.datetime(2013, 12, 15)
with mock.patch.object(datetime,
'datetime',
mock.Mock(wraps=datetime.datetime)) as patched:
patched.utcnow.return_value = target
self.assertRaises(
manager_ex.MissingParameter, self.manager.update_lease,
self.lease_id, lease_values)
def test_update_lease_started_modify_end_date_without_before_end(self):
def fake_event_get(sort_key, sort_dir, filters):
if filters['event_type'] == 'start_lease':
@ -693,8 +799,6 @@ class ServiceTestCase(tests.TestCase):
self.fake_plugin.update_reservation.assert_called_with(
'593e7028-c0d1-4d76-8642-2ffd890b324c',
{
'id': '593e7028-c0d1-4d76-8642-2ffd890b324c',
'resource_type': 'virtual:instance',
'start_date': datetime.datetime(2013, 12, 20, 13, 00),
'end_date': datetime.datetime(2013, 12, 20, 16, 00)
}
@ -744,8 +848,6 @@ class ServiceTestCase(tests.TestCase):
self.fake_plugin.update_reservation.assert_called_with(
'593e7028-c0d1-4d76-8642-2ffd890b324c',
{
'id': '593e7028-c0d1-4d76-8642-2ffd890b324c',
'resource_type': 'virtual:instance',
'start_date': datetime.datetime(2013, 12, 20, 13, 00),
'end_date': datetime.datetime(2013, 12, 20, 16, 00)
}
@ -810,8 +912,6 @@ class ServiceTestCase(tests.TestCase):
self.fake_plugin.update_reservation.assert_called_with(
'593e7028-c0d1-4d76-8642-2ffd890b324c',
{
'id': '593e7028-c0d1-4d76-8642-2ffd890b324c',
'resource_type': 'virtual:instance',
'start_date': datetime.datetime(2013, 12, 20, 13, 00),
'end_date': datetime.datetime(2013, 12, 20, 16, 00)
}

View File

@ -482,7 +482,6 @@ class PhysicalHostPluginTestCase(tests.TestCase):
reservation_get = self.patch(self.db_api, 'reservation_get')
reservation_get.return_value = {
'lease_id': u'10870923-6d56-45c9-b592-f788053f5baa',
'resource_id': u'91253650-cc34-4c4f-bbe8-c943aa7d0c9b'
}
lease_get = self.patch(self.db_api, 'lease_get')
lease_get.return_value = {
@ -490,19 +489,11 @@ class PhysicalHostPluginTestCase(tests.TestCase):
'end_date': datetime.datetime(2013, 12, 19, 21, 00)
}
host_reservation_get = self.patch(self.db_api, 'host_reservation_get')
host_reservation_get.return_value = {
'aggregate_id': 1
}
get_computehosts = self.patch(self.nova.ReservationPool,
'get_computehosts')
get_computehosts.return_value = ['host1']
host_allocation_get_all = self.patch(
self.db_api,
'host_allocation_get_all_by_values')
self.fake_phys_plugin.update_reservation(
'706eb3bc-07ed-4383-be93-b32845ece672',
values)
host_allocation_get_all.assert_not_called()
host_reservation_get.assert_not_called()
def test_update_reservation_extend(self):
values = {
@ -512,7 +503,8 @@ class PhysicalHostPluginTestCase(tests.TestCase):
reservation_get = self.patch(self.db_api, 'reservation_get')
reservation_get.return_value = {
'lease_id': u'10870923-6d56-45c9-b592-f788053f5baa',
'resource_id': u'91253650-cc34-4c4f-bbe8-c943aa7d0c9b'
'resource_id': u'91253650-cc34-4c4f-bbe8-c943aa7d0c9b',
'status': 'pending'
}
lease_get = self.patch(self.db_api, 'lease_get')
lease_get.return_value = {
@ -520,6 +512,11 @@ class PhysicalHostPluginTestCase(tests.TestCase):
'end_date': datetime.datetime(2013, 12, 19, 21, 00)
}
host_reservation_get = self.patch(self.db_api, 'host_reservation_get')
host_reservation_get.return_value = {
'count_range': '1-1',
'hypervisor_properties': '["=", "$memory_mb", "256"]',
'resource_properties': ''
}
host_allocation_get_all = self.patch(
self.db_api,
'host_allocation_get_all_by_values')
@ -529,15 +526,26 @@ class PhysicalHostPluginTestCase(tests.TestCase):
'compute_host_id': 'host1'
}
]
host_get_all_by_queries = self.patch(self.db_api,
'host_get_all_by_queries')
host_get_all_by_queries.return_value = [{'id': 'host1'}]
get_full_periods = self.patch(self.db_utils, 'get_full_periods')
get_full_periods.return_value = [
(datetime.datetime(2013, 12, 19, 20, 00),
datetime.datetime(2013, 12, 19, 21, 00))
]
host_allocation_create = self.patch(
self.db_api,
'host_allocation_create')
host_allocation_destroy = self.patch(
self.db_api,
'host_allocation_destroy')
self.fake_phys_plugin.update_reservation(
'706eb3bc-07ed-4383-be93-b32845ece672',
values)
host_reservation_get.assert_not_called()
host_allocation_create.assert_not_called()
host_allocation_destroy.assert_not_called()
def test_update_reservation_move_failure(self):
values = {
@ -559,7 +567,7 @@ class PhysicalHostPluginTestCase(tests.TestCase):
self.db_api,
'host_reservation_get')
host_reservation_get.return_value = {
'aggregate_id': 1,
'count_range': '1-1',
'hypervisor_properties': '["=", "$memory_mb", "256"]',
'resource_properties': ''
}
@ -572,6 +580,9 @@ class PhysicalHostPluginTestCase(tests.TestCase):
'compute_host_id': 'host1'
}
]
host_get_all_by_queries = self.patch(self.db_api,
'host_get_all_by_queries')
host_get_all_by_queries.return_value = [{'id': 'host1'}]
get_full_periods = self.patch(self.db_utils, 'get_full_periods')
get_full_periods.return_value = [
(datetime.datetime(2013, 12, 20, 20, 30),
@ -581,14 +592,13 @@ class PhysicalHostPluginTestCase(tests.TestCase):
'get_computehosts')
get_computehosts.return_value = ['host1']
matching_hosts = self.patch(self.fake_phys_plugin, '_matching_hosts')
matching_hosts.return_value = ['host2']
matching_hosts.return_value = []
self.assertRaises(
manager_exceptions.NotEnoughHostsAvailable,
self.fake_phys_plugin.update_reservation,
'706eb3bc-07ed-4383-be93-b32845ece672',
values)
reservation_get.assert_called()
host_reservation_get.assert_not_called()
def test_update_reservation_move_overlap(self):
values = {
@ -598,16 +608,22 @@ class PhysicalHostPluginTestCase(tests.TestCase):
reservation_get = self.patch(self.db_api, 'reservation_get')
reservation_get.return_value = {
'lease_id': u'10870923-6d56-45c9-b592-f788053f5baa',
'resource_id': u'91253650-cc34-4c4f-bbe8-c943aa7d0c9b'
'resource_id': u'91253650-cc34-4c4f-bbe8-c943aa7d0c9b',
'status': 'pending'
}
lease_get = self.patch(self.db_api, 'lease_get')
lease_get.return_value = {
'start_date': datetime.datetime(2013, 12, 19, 20, 00),
'end_date': datetime.datetime(2013, 12, 19, 21, 00)
}
host_reservation_get_by_reservation_id = self.patch(
host_reservation_get = self.patch(
self.db_api,
'host_reservation_get_by_reservation_id')
'host_reservation_get')
host_reservation_get.return_value = {
'count_range': '1-1',
'hypervisor_properties': '["=", "$memory_mb", "256"]',
'resource_properties': ''
}
host_allocation_get_all = self.patch(
self.db_api,
'host_allocation_get_all_by_values')
@ -617,18 +633,26 @@ class PhysicalHostPluginTestCase(tests.TestCase):
'compute_host_id': 'host1'
}
]
host_get_all_by_queries = self.patch(self.db_api,
'host_get_all_by_queries')
host_get_all_by_queries.return_value = [{'id': 'host1'}]
get_full_periods = self.patch(self.db_utils, 'get_full_periods')
get_full_periods.return_value = [
(datetime.datetime(2013, 12, 19, 20, 30),
datetime.datetime(2013, 12, 19, 21, 00))
]
get_computehosts = self.patch(self.nova.ReservationPool,
'get_computehosts')
get_computehosts.return_value = []
host_allocation_create = self.patch(
self.db_api,
'host_allocation_create')
host_allocation_destroy = self.patch(
self.db_api,
'host_allocation_destroy')
self.fake_phys_plugin.update_reservation(
'706eb3bc-07ed-4383-be93-b32845ece672',
values)
host_reservation_get_by_reservation_id.assert_not_called()
host_allocation_create.assert_not_called()
host_allocation_destroy.assert_not_called()
def test_update_reservation_move_realloc(self):
values = {
@ -646,14 +670,12 @@ class PhysicalHostPluginTestCase(tests.TestCase):
'start_date': datetime.datetime(2013, 12, 19, 20, 00),
'end_date': datetime.datetime(2013, 12, 19, 21, 00)
}
host_get = self.patch(self.db_api, 'host_get')
host_get.side_effect = ({'service_name': 'host1'},
{'service_name': 'host2'})
host_reservation_get = self.patch(
self.db_api,
'host_reservation_get')
host_reservation_get.return_value = {
'aggregate_id': 1,
'count_range': '1-1',
'hypervisor_properties': '["=", "$memory_mb", "256"]',
'resource_properties': ''
}
@ -666,6 +688,10 @@ class PhysicalHostPluginTestCase(tests.TestCase):
'compute_host_id': 'host1'
}
]
host_get_all_by_queries = self.patch(self.db_api,
'host_get_all_by_queries')
host_get_all_by_queries.return_value = [{'id': 'host1'},
{'id': 'host2'}]
host_allocation_create = self.patch(
self.db_api,
'host_allocation_create')
@ -677,9 +703,6 @@ class PhysicalHostPluginTestCase(tests.TestCase):
(datetime.datetime(2013, 12, 20, 20, 30),
datetime.datetime(2013, 12, 20, 21, 00))
]
get_computehosts = self.patch(self.nova.ReservationPool,
'get_computehosts')
get_computehosts.return_value = ['host1']
matching_hosts = self.patch(self.fake_phys_plugin, '_matching_hosts')
matching_hosts.return_value = ['host2']
self.fake_phys_plugin.update_reservation(
@ -695,14 +718,514 @@ class PhysicalHostPluginTestCase(tests.TestCase):
'reservation_id': '706eb3bc-07ed-4383-be93-b32845ece672'
}
)
self.remove_compute_host.assert_called_with(
1,
['host1']
def test_update_reservation_min_increase_success(self):
values = {
'start_date': datetime.datetime(2017, 7, 12, 20, 00),
'end_date': datetime.datetime(2017, 7, 12, 21, 00),
'min': 3
}
reservation_get = self.patch(self.db_api, 'reservation_get')
reservation_get.return_value = {
'lease_id': '10870923-6d56-45c9-b592-f788053f5baa',
'resource_id': '91253650-cc34-4c4f-bbe8-c943aa7d0c9b',
'status': 'pending'
}
lease_get = self.patch(self.db_api, 'lease_get')
lease_get.return_value = {
'start_date': datetime.datetime(2017, 7, 12, 20, 00),
'end_date': datetime.datetime(2017, 7, 12, 21, 00)
}
host_reservation_get = self.patch(self.db_api, 'host_reservation_get')
host_reservation_get.return_value = {
'id': '91253650-cc34-4c4f-bbe8-c943aa7d0c9b',
'count_range': '2-3',
'hypervisor_properties': '["=", "$memory_mb", "16384"]',
'resource_properties': ''
}
host_allocation_get_all = self.patch(
self.db_api, 'host_allocation_get_all_by_values')
host_allocation_get_all.return_value = [
{
'id': 'dd305477-4df8-4547-87f6-69069ee546a6',
'compute_host_id': 'host1'
},
{
'id': 'dd305477-4df8-4547-87f6-69069ee546a7',
'compute_host_id': 'host2'
}
]
host_get_all_by_queries = self.patch(self.db_api,
'host_get_all_by_queries')
host_get_all_by_queries.return_value = [
{'id': 'host1'},
{'id': 'host2'},
{'id': 'host3'}
]
host_allocation_destroy = self.patch(self.db_api,
'host_allocation_destroy')
host_allocation_create = self.patch(self.db_api,
'host_allocation_create')
matching_hosts = self.patch(self.fake_phys_plugin, '_matching_hosts')
matching_hosts.return_value = ['host3']
host_reservation_update = self.patch(self.db_api,
'host_reservation_update')
self.fake_phys_plugin.update_reservation(
'706eb3bc-07ed-4383-be93-b32845ece672',
values)
host_reservation_get.assert_called_with(
'91253650-cc34-4c4f-bbe8-c943aa7d0c9b')
matching_hosts.assert_called_with(
'["=", "$memory_mb", "16384"]',
'',
'1-1',
datetime.datetime(2017, 7, 12, 20, 00),
datetime.datetime(2017, 7, 12, 21, 00)
)
self.add_compute_host.assert_called_with(
1,
'host2'
host_allocation_destroy.assert_not_called()
host_allocation_create.assert_called_with(
{
'compute_host_id': 'host3',
'reservation_id': '706eb3bc-07ed-4383-be93-b32845ece672'
}
)
host_reservation_update.assert_called_with(
'91253650-cc34-4c4f-bbe8-c943aa7d0c9b',
{'count_range': '3-3'}
)
def test_update_reservation_min_increase_fail(self):
values = {
'start_date': datetime.datetime(2017, 7, 12, 20, 00),
'end_date': datetime.datetime(2017, 7, 12, 21, 00),
'min': 3
}
reservation_get = self.patch(self.db_api, 'reservation_get')
reservation_get.return_value = {
'lease_id': '10870923-6d56-45c9-b592-f788053f5baa',
'resource_id': '91253650-cc34-4c4f-bbe8-c943aa7d0c9b',
'status': 'pending'
}
lease_get = self.patch(self.db_api, 'lease_get')
lease_get.return_value = {
'start_date': datetime.datetime(2017, 7, 12, 20, 00),
'end_date': datetime.datetime(2017, 7, 12, 21, 00)
}
host_reservation_get = self.patch(self.db_api, 'host_reservation_get')
host_reservation_get.return_value = {
'id': '91253650-cc34-4c4f-bbe8-c943aa7d0c9b',
'count_range': '2-3',
'hypervisor_properties': '["=", "$memory_mb", "16384"]',
'resource_properties': ''
}
host_allocation_get_all = self.patch(
self.db_api, 'host_allocation_get_all_by_values')
host_allocation_get_all.return_value = [
{
'id': 'dd305477-4df8-4547-87f6-69069ee546a6',
'compute_host_id': 'host1'
},
{
'id': 'dd305477-4df8-4547-87f6-69069ee546a7',
'compute_host_id': 'host2'
}
]
host_get_all_by_queries = self.patch(self.db_api,
'host_get_all_by_queries')
host_get_all_by_queries.return_value = [
{'id': 'host1'},
{'id': 'host2'}
]
matching_hosts = self.patch(self.fake_phys_plugin, '_matching_hosts')
matching_hosts.return_value = []
self.assertRaises(
manager_exceptions.NotEnoughHostsAvailable,
self.fake_phys_plugin.update_reservation,
'706eb3bc-07ed-4383-be93-b32845ece672',
values)
matching_hosts.assert_called_with(
'["=", "$memory_mb", "16384"]',
'',
'1-1',
datetime.datetime(2017, 7, 12, 20, 00),
datetime.datetime(2017, 7, 12, 21, 00)
)
def test_update_reservation_min_decrease(self):
values = {
'start_date': datetime.datetime(2017, 7, 12, 20, 00),
'end_date': datetime.datetime(2017, 7, 12, 21, 00),
'min': 1
}
reservation_get = self.patch(self.db_api, 'reservation_get')
reservation_get.return_value = {
'lease_id': '10870923-6d56-45c9-b592-f788053f5baa',
'resource_id': '91253650-cc34-4c4f-bbe8-c943aa7d0c9b',
'status': 'pending'
}
lease_get = self.patch(self.db_api, 'lease_get')
lease_get.return_value = {
'start_date': datetime.datetime(2017, 7, 12, 20, 00),
'end_date': datetime.datetime(2017, 7, 12, 21, 00)
}
host_reservation_get = self.patch(self.db_api, 'host_reservation_get')
host_reservation_get.return_value = {
'id': '91253650-cc34-4c4f-bbe8-c943aa7d0c9b',
'count_range': '2-2',
'hypervisor_properties': '["=", "$memory_mb", "16384"]',
'resource_properties': ''
}
host_allocation_get_all = self.patch(
self.db_api, 'host_allocation_get_all_by_values')
host_allocation_get_all.return_value = [
{
'id': 'dd305477-4df8-4547-87f6-69069ee546a6',
'compute_host_id': 'host1'
},
{
'id': 'dd305477-4df8-4547-87f6-69069ee546a7',
'compute_host_id': 'host2'
}
]
host_get_all_by_queries = self.patch(self.db_api,
'host_get_all_by_queries')
host_get_all_by_queries.return_value = [
{'id': 'host1'},
{'id': 'host2'}
]
matching_hosts = self.patch(self.fake_phys_plugin, '_matching_hosts')
host_allocation_destroy = self.patch(self.db_api,
'host_allocation_destroy')
host_allocation_create = self.patch(self.db_api,
'host_allocation_create')
host_reservation_update = self.patch(self.db_api,
'host_reservation_update')
self.fake_phys_plugin.update_reservation(
'706eb3bc-07ed-4383-be93-b32845ece672',
values)
matching_hosts.assert_not_called()
host_allocation_destroy.assert_not_called()
host_allocation_create.assert_not_called()
host_reservation_update.assert_called_with(
'91253650-cc34-4c4f-bbe8-c943aa7d0c9b',
{'count_range': '1-2'}
)
def test_update_reservation_max_increase_alloc(self):
values = {
'start_date': datetime.datetime(2017, 7, 12, 20, 00),
'end_date': datetime.datetime(2017, 7, 12, 21, 00),
'max': 3
}
reservation_get = self.patch(self.db_api, 'reservation_get')
reservation_get.return_value = {
'lease_id': '10870923-6d56-45c9-b592-f788053f5baa',
'resource_id': '91253650-cc34-4c4f-bbe8-c943aa7d0c9b',
'status': 'pending'
}
lease_get = self.patch(self.db_api, 'lease_get')
lease_get.return_value = {
'start_date': datetime.datetime(2017, 7, 12, 20, 00),
'end_date': datetime.datetime(2017, 7, 12, 21, 00)
}
host_reservation_get = self.patch(self.db_api, 'host_reservation_get')
host_reservation_get.return_value = {
'id': '91253650-cc34-4c4f-bbe8-c943aa7d0c9b',
'count_range': '1-2',
'hypervisor_properties': '["=", "$memory_mb", "16384"]',
'resource_properties': ''
}
host_allocation_get_all = self.patch(
self.db_api, 'host_allocation_get_all_by_values')
host_allocation_get_all.return_value = [
{
'id': 'dd305477-4df8-4547-87f6-69069ee546a6',
'compute_host_id': 'host1'
},
{
'id': 'dd305477-4df8-4547-87f6-69069ee546a7',
'compute_host_id': 'host2'
}
]
host_get_all_by_queries = self.patch(self.db_api,
'host_get_all_by_queries')
host_get_all_by_queries.return_value = [
{'id': 'host1'},
{'id': 'host2'},
{'id': 'host3'}
]
host_allocation_destroy = self.patch(self.db_api,
'host_allocation_destroy')
host_allocation_create = self.patch(self.db_api,
'host_allocation_create')
matching_hosts = self.patch(self.fake_phys_plugin, '_matching_hosts')
matching_hosts.return_value = ['host3']
host_reservation_update = self.patch(self.db_api,
'host_reservation_update')
self.fake_phys_plugin.update_reservation(
'706eb3bc-07ed-4383-be93-b32845ece672',
values)
host_reservation_get.assert_called_with(
'91253650-cc34-4c4f-bbe8-c943aa7d0c9b')
matching_hosts.assert_called_with(
'["=", "$memory_mb", "16384"]',
'',
'0-1',
datetime.datetime(2017, 7, 12, 20, 00),
datetime.datetime(2017, 7, 12, 21, 00)
)
host_allocation_destroy.assert_not_called()
host_allocation_create.assert_called_with(
{
'compute_host_id': 'host3',
'reservation_id': '706eb3bc-07ed-4383-be93-b32845ece672'
}
)
host_reservation_update.assert_called_with(
'91253650-cc34-4c4f-bbe8-c943aa7d0c9b',
{'count_range': '1-3'}
)
def test_update_reservation_max_increase_noalloc(self):
values = {
'start_date': datetime.datetime(2017, 7, 12, 20, 00),
'end_date': datetime.datetime(2017, 7, 12, 21, 00),
'max': 3
}
reservation_get = self.patch(self.db_api, 'reservation_get')
reservation_get.return_value = {
'lease_id': '10870923-6d56-45c9-b592-f788053f5baa',
'resource_id': '91253650-cc34-4c4f-bbe8-c943aa7d0c9b',
'status': 'pending'
}
lease_get = self.patch(self.db_api, 'lease_get')
lease_get.return_value = {
'start_date': datetime.datetime(2017, 7, 12, 20, 00),
'end_date': datetime.datetime(2017, 7, 12, 21, 00)
}
host_reservation_get = self.patch(self.db_api, 'host_reservation_get')
host_reservation_get.return_value = {
'id': '91253650-cc34-4c4f-bbe8-c943aa7d0c9b',
'count_range': '1-2',
'hypervisor_properties': '["=", "$memory_mb", "16384"]',
'resource_properties': ''
}
host_allocation_get_all = self.patch(
self.db_api, 'host_allocation_get_all_by_values')
host_allocation_get_all.return_value = [
{
'id': 'dd305477-4df8-4547-87f6-69069ee546a6',
'compute_host_id': 'host1'
},
{
'id': 'dd305477-4df8-4547-87f6-69069ee546a7',
'compute_host_id': 'host2'
}
]
host_get_all_by_queries = self.patch(self.db_api,
'host_get_all_by_queries')
host_get_all_by_queries.return_value = [
{'id': 'host1'},
{'id': 'host2'}
]
matching_hosts = self.patch(self.fake_phys_plugin, '_matching_hosts')
matching_hosts.return_value = []
host_reservation_update = self.patch(self.db_api,
'host_reservation_update')
self.fake_phys_plugin.update_reservation(
'706eb3bc-07ed-4383-be93-b32845ece672',
values)
host_reservation_get.assert_called_with(
'91253650-cc34-4c4f-bbe8-c943aa7d0c9b')
matching_hosts.assert_called_with(
'["=", "$memory_mb", "16384"]',
'',
'0-1',
datetime.datetime(2017, 7, 12, 20, 00),
datetime.datetime(2017, 7, 12, 21, 00)
)
host_reservation_update.assert_called_with(
'91253650-cc34-4c4f-bbe8-c943aa7d0c9b',
{'count_range': '1-3'}
)
def test_update_reservation_max_decrease(self):
values = {
'start_date': datetime.datetime(2017, 7, 12, 20, 00),
'end_date': datetime.datetime(2017, 7, 12, 21, 00),
'max': 1
}
reservation_get = self.patch(self.db_api, 'reservation_get')
reservation_get.return_value = {
'lease_id': '10870923-6d56-45c9-b592-f788053f5baa',
'resource_id': '91253650-cc34-4c4f-bbe8-c943aa7d0c9b',
'status': 'pending'
}
lease_get = self.patch(self.db_api, 'lease_get')
lease_get.return_value = {
'start_date': datetime.datetime(2017, 7, 12, 20, 00),
'end_date': datetime.datetime(2017, 7, 12, 21, 00)
}
host_reservation_get = self.patch(self.db_api, 'host_reservation_get')
host_reservation_get.return_value = {
'id': '91253650-cc34-4c4f-bbe8-c943aa7d0c9b',
'count_range': '1-2',
'hypervisor_properties': '["=", "$memory_mb", "16384"]',
'resource_properties': ''
}
host_allocation_get_all = self.patch(
self.db_api, 'host_allocation_get_all_by_values')
host_allocation_get_all.return_value = [
{
'id': 'dd305477-4df8-4547-87f6-69069ee546a6',
'compute_host_id': 'host1'
},
{
'id': 'dd305477-4df8-4547-87f6-69069ee546a7',
'compute_host_id': 'host2'
}
]
host_get_all_by_queries = self.patch(self.db_api,
'host_get_all_by_queries')
host_get_all_by_queries.return_value = [
{'id': 'host1'},
{'id': 'host2'}
]
host_allocation_destroy = self.patch(self.db_api,
'host_allocation_destroy')
host_reservation_update = self.patch(self.db_api,
'host_reservation_update')
self.fake_phys_plugin.update_reservation(
'706eb3bc-07ed-4383-be93-b32845ece672',
values)
host_reservation_get.assert_called_with(
'91253650-cc34-4c4f-bbe8-c943aa7d0c9b')
host_allocation_destroy.assert_called_with(
'dd305477-4df8-4547-87f6-69069ee546a6')
host_reservation_update.assert_called_with(
'91253650-cc34-4c4f-bbe8-c943aa7d0c9b',
{'count_range': '1-1'}
)
def test_update_reservation_realloc_with_properties_change(self):
values = {
'start_date': datetime.datetime(2017, 7, 12, 20, 00),
'end_date': datetime.datetime(2017, 7, 12, 21, 00),
'hypervisor_properties': '["=", "$memory_mb", "32768"]',
}
reservation_get = self.patch(self.db_api, 'reservation_get')
reservation_get.return_value = {
'lease_id': '10870923-6d56-45c9-b592-f788053f5baa',
'resource_id': '91253650-cc34-4c4f-bbe8-c943aa7d0c9b',
'status': 'pending'
}
lease_get = self.patch(self.db_api, 'lease_get')
lease_get.return_value = {
'start_date': datetime.datetime(2017, 7, 12, 20, 00),
'end_date': datetime.datetime(2017, 7, 12, 21, 00)
}
host_reservation_get = self.patch(self.db_api, 'host_reservation_get')
host_reservation_get.return_value = {
'id': '91253650-cc34-4c4f-bbe8-c943aa7d0c9b',
'count_range': '1-1',
'hypervisor_properties': '["=", "$memory_mb", "16384"]',
'resource_properties': ''
}
host_allocation_get_all = self.patch(
self.db_api, 'host_allocation_get_all_by_values')
host_allocation_get_all.return_value = [
{
'id': 'dd305477-4df8-4547-87f6-69069ee546a6',
'compute_host_id': 'host1'
}
]
host_get_all_by_queries = self.patch(self.db_api,
'host_get_all_by_queries')
host_get_all_by_queries.return_value = [{'id': 'host2'}]
matching_hosts = self.patch(self.fake_phys_plugin, '_matching_hosts')
matching_hosts.return_value = ['host2']
host_allocation_create = self.patch(self.db_api,
'host_allocation_create')
host_allocation_destroy = self.patch(self.db_api,
'host_allocation_destroy')
host_reservation_update = self.patch(self.db_api,
'host_reservation_update')
self.fake_phys_plugin.update_reservation(
'706eb3bc-07ed-4383-be93-b32845ece672',
values)
host_reservation_get.assert_called_with(
'91253650-cc34-4c4f-bbe8-c943aa7d0c9b')
matching_hosts.assert_called_with(
'["=", "$memory_mb", "32768"]',
'',
'1-1',
datetime.datetime(2017, 7, 12, 20, 00),
datetime.datetime(2017, 7, 12, 21, 00)
)
host_allocation_create.assert_called_with(
{
'compute_host_id': 'host2',
'reservation_id': '706eb3bc-07ed-4383-be93-b32845ece672'
}
)
host_allocation_destroy.assert_called_with(
'dd305477-4df8-4547-87f6-69069ee546a6'
)
host_reservation_update.assert_called_with(
'91253650-cc34-4c4f-bbe8-c943aa7d0c9b',
{'hypervisor_properties': '["=", "$memory_mb", "32768"]'}
)
def test_update_reservation_no_requested_hosts_available(self):
values = {
'start_date': datetime.datetime(2017, 7, 12, 20, 00),
'end_date': datetime.datetime(2017, 7, 12, 21, 00),
'resource_properties': '[">=", "$vcpus", "32768"]'
}
reservation_get = self.patch(self.db_api, 'reservation_get')
reservation_get.return_value = {
'lease_id': '10870923-6d56-45c9-b592-f788053f5baa',
'resource_id': '91253650-cc34-4c4f-bbe8-c943aa7d0c9b',
'status': 'pending'
}
lease_get = self.patch(self.db_api, 'lease_get')
lease_get.return_value = {
'start_date': datetime.datetime(2013, 12, 19, 20, 00),
'end_date': datetime.datetime(2013, 12, 19, 21, 00)
}
host_reservation_get = self.patch(self.db_api, 'host_reservation_get')
host_reservation_get.return_value = {
'id': '91253650-cc34-4c4f-bbe8-c943aa7d0c9b',
'count_range': '1-1',
'hypervisor_properties': '["=", "$memory_mb", "16384"]',
'resource_properties': ''
}
host_allocation_get_all = self.patch(
self.db_api, 'host_allocation_get_all_by_values')
host_allocation_get_all.return_value = [
{
'id': 'dd305477-4df8-4547-87f6-69069ee546a6',
'compute_host_id': 'host1'
}
]
host_get_all_by_queries = self.patch(self.db_api,
'host_get_all_by_queries')
host_get_all_by_queries.return_value = []
matching_hosts = self.patch(self.fake_phys_plugin, '_matching_hosts')
matching_hosts.return_value = []
self.assertRaises(
manager_exceptions.NotEnoughHostsAvailable,
self.fake_phys_plugin.update_reservation,
'441c1476-9f8f-4700-9f30-cd9b6fef3509',
values)
def test_on_start(self):
host_reservation_get = self.patch(self.db_api, 'host_reservation_get')

View File

@ -358,6 +358,12 @@ are mentioned.
{
"name": "lease_new_foo",
"end_date": "2017-3-12 12:00",
"reservations": [
{
"id": "087bc740-6d2d-410b-9d47-c7b2b55a9d36",
"max": 3
}
]
}
**response**
@ -381,7 +387,7 @@ are mentioned.
"status": "pending",
"lease_id": "6ee55c78-ac52-41a6-99af-2d2d73bcc466",
"min": 1,
"max": 1,
"max": 3,
"resource_id": "5",
"created_at": "2017-02-21 14:50:38",
"updated_at": null,

View File

@ -0,0 +1,5 @@
---
features:
- |
The lease-update API supports update of reservation properties. e.g. min,
max, hypervisor_properties and resource_properties for host reservation.