Implement list and get allocations methods to compute hosts plugin

The two methods return allocations mapped to a host. The list
allocations method returns all allocations in Blazar compute hosts. The
get allocation methods returns all allocations on a specific host.

Partially Implements: blueprint resource-allocation-api
Change-Id: I0a12584d5ec08723101b5dcfa4e9491a94cd6292
This commit is contained in:
Masahito Muroi 2018-07-09 19:07:37 +09:00 committed by Pierre Riteau
parent 848a68783e
commit 201dc7e7e4
5 changed files with 188 additions and 0 deletions

View File

@ -88,6 +88,18 @@ def get_reservations_by_host_ids(host_ids, start_date, end_date):
return query.all()
def get_reservation_allocations_by_host_ids(host_ids, start_date, end_date):
session = get_session()
border0 = models.Lease.end_date < start_date
border1 = models.Lease.start_date > end_date
query = (session.query(models.Reservation, models.ComputeHostAllocation)
.join(models.Lease).join(models.ComputeHostAllocation)
.filter(models.ComputeHostAllocation.compute_host_id
.in_(host_ids))
.filter(~sa.or_(border0, border1)))
return query.all()
def get_plugin_reservation(resource_type, resource_id):
if resource_type == host_plugin.RESOURCE_TYPE:
return api.host_reservation_get(resource_id)

View File

@ -111,6 +111,11 @@ def get_reservations_by_host_ids(host_ids, start_date, end_date):
return IMPL.get_reservations_by_host_ids(host_ids, start_date, end_date)
def get_reservation_allocations_by_host_ids(host_ids, start_date, end_date):
return IMPL.get_reservation_allocations_by_host_ids(host_ids, start_date,
end_date)
def get_plugin_reservation(resource_type, resource_id):
return IMPL.get_plugin_reservation(resource_type, resource_id)

View File

@ -499,6 +499,55 @@ class PhysicalHostPlugin(base.BasePlugin, nova.NovaClientWrapper):
# they have to rerun
raise manager_ex.CantDeleteHost(host=host_id, msg=str(e))
def list_allocations(self, query):
hosts_id_list = [h['id'] for h in db_api.host_list()]
hosts_allocations = self.query_host_allocations(hosts_id_list)
return [{"resource_id": host, "reservations": allocs}
for host, allocs in hosts_allocations.items()]
def get_allocations(self, host_id, query):
host_allocations = self.query_host_allocations([host_id])
if host_id not in host_allocations:
raise manager_ex.HostNotFound(host=host_id)
allocs = host_allocations[host_id]
return {"resource_id": host_id, "reservations": allocs}
def query_host_allocations(self, hosts):
"""Return dict of host and its allocations.
The list element forms
{
'host-id': [
{
'lease_id': lease_id,
'id': reservation_id
},
]
}.
"""
start = datetime.datetime.utcnow()
end = datetime.date.max
# To reduce overhead, this method only executes one query
# to get the allocation information
allocs = db_utils.get_reservation_allocations_by_host_ids(
hosts, start, end)
hosts_allocs = {}
for reservation, alloc in allocs:
if alloc['compute_host_id'] in hosts_allocs:
hosts_allocs[alloc['compute_host_id']].append({
'lease_id': reservation['lease_id'],
'id': reservation['id']
})
else:
hosts_allocs[alloc['compute_host_id']] = [{
'lease_id': reservation['lease_id'],
'id': reservation['id']
}]
return hosts_allocs
def _matching_hosts(self, hypervisor_properties, resource_properties,
count_range, start_date, end_date):
"""Return the matching hosts (preferably not allocated)

View File

@ -407,6 +407,36 @@ class SQLAlchemyDBUtilsTestCase(tests.DBTestCase):
self.check_reservation([], ['r4'],
'2030-01-01 07:00', '2030-01-01 15:00')
def test_get_reservation_allocations_by_host_ids(self):
def create_allocation_tuple(lease_id):
reservation = db_api.reservation_get_all_by_lease_id(lease_id)[0]
allocation = db_api.host_allocation_get_all_by_values(
reservation_id=reservation['id'])[0]
return (reservation['id'], allocation['id'])
self._setup_leases()
# query all allocations of lease1, lease2 and lease3
expected = [
create_allocation_tuple('lease1'),
create_allocation_tuple('lease2'),
create_allocation_tuple('lease3'),
]
ret = db_utils.get_reservation_allocations_by_host_ids(
['r1', 'r2'], '2030-01-01 08:00', '2030-01-01 15:00')
self.assertListEqual(expected, [(r['id'], a['id']) for r, a in ret])
# query allocations of lease2 and lease3
expected = [
create_allocation_tuple('lease2'),
create_allocation_tuple('lease3'),
]
ret = db_utils.get_reservation_allocations_by_host_ids(
['r1', 'r2'], '2030-01-01 11:30', '2030-01-01 15:00')
self.assertListEqual(expected, [(r['id'], a['id']) for r, a in ret])
def test_get_plugin_reservation_with_host(self):
patch_host_reservation_get = self.patch(db_api, 'host_reservation_get')
patch_host_reservation_get.return_value = {

View File

@ -429,6 +429,98 @@ class PhysicalHostPluginTestCase(tests.TestCase):
self.fake_phys_plugin.delete_computehost,
self.fake_host_id)
def test_list_allocations(self):
def reservation_allocation_tuple(r_id, l_id, h_id):
return ({'id': r_id, 'lease_id': l_id}, {'compute_host_id': h_id})
self.db_get_reserv_allocs = self.patch(
self.db_utils, 'get_reservation_allocations_by_host_ids')
# Expecting a list of (Reservation, Allocation)
self.db_get_reserv_allocs.return_value = [
reservation_allocation_tuple('reservation-1', 'lease-1', 'host-1'),
reservation_allocation_tuple('reservation-1', 'lease-1', 'host-2'),
reservation_allocation_tuple('reservation-2', 'lease-1', 'host-2'),
reservation_allocation_tuple('reservation-2', 'lease-1', 'host-3'),
reservation_allocation_tuple('reservation-3', 'lease-2', 'host-1'),
]
expected = [
{
'resource_id': 'host-1',
'reservations': [
{'id': 'reservation-1', 'lease_id': 'lease-1'},
{'id': 'reservation-3', 'lease_id': 'lease-2'},
]
},
{
'resource_id': 'host-2',
'reservations': [
{'id': 'reservation-1', 'lease_id': 'lease-1'},
{'id': 'reservation-2', 'lease_id': 'lease-1'},
]
},
{
'resource_id': 'host-3',
'reservations': [
{'id': 'reservation-2', 'lease_id': 'lease-1'},
]
}
]
ret = self.fake_phys_plugin.list_allocations({})
# Sort returned value to use assertListEqual
for r in ret:
r['reservations'].sort(key=lambda x: x['id'])
ret.sort(key=lambda x: x['resource_id'])
self.assertListEqual(expected, ret)
def test_get_allocations(self):
def reservation_allocation_tuple(r_id, l_id, h_id):
return ({'id': r_id, 'lease_id': l_id}, {'compute_host_id': h_id})
self.db_get_reserv_allocs = self.patch(
self.db_utils, 'get_reservation_allocations_by_host_ids')
# Expecting a list of (Reservation, Allocation)
self.db_get_reserv_allocs.return_value = [
reservation_allocation_tuple('reservation-1', 'lease-1', 'host-1'),
reservation_allocation_tuple('reservation-1', 'lease-1', 'host-2'),
reservation_allocation_tuple('reservation-2', 'lease-1', 'host-2'),
reservation_allocation_tuple('reservation-2', 'lease-1', 'host-3'),
reservation_allocation_tuple('reservation-3', 'lease-2', 'host-1'),
]
expected = {
'resource_id': 'host-1',
'reservations': [
{'id': 'reservation-1', 'lease_id': 'lease-1'},
{'id': 'reservation-3', 'lease_id': 'lease-2'},
]
}
ret = self.fake_phys_plugin.get_allocations('host-1', {})
self.assertDictEqual(expected, ret)
def test_get_allocations_with_invalid_host(self):
def reservation_allocation_tuple(r_id, l_id, h_id):
return ({'id': r_id, 'lease_id': l_id}, {'compute_host_id': h_id})
self.db_get_reserv_allocs = self.patch(
self.db_utils, 'get_reservation_allocations_by_host_ids')
# Expecting a list of (Reservation, Allocation)
self.db_get_reserv_allocs.return_value = [
reservation_allocation_tuple('reservation-1', 'lease-1', 'host-1'),
reservation_allocation_tuple('reservation-1', 'lease-1', 'host-2'),
reservation_allocation_tuple('reservation-2', 'lease-1', 'host-2'),
reservation_allocation_tuple('reservation-2', 'lease-1', 'host-3'),
reservation_allocation_tuple('reservation-3', 'lease-2', 'host-1'),
]
self.assertRaises(manager_exceptions.HostNotFound,
self.fake_phys_plugin.get_allocations,
'no-reserved-host', {})
def test_create_reservation_no_hosts_available(self):
now = datetime.datetime.utcnow()
values = {