Merge "Support lease_id parameter in List and Get Allocations API"

This commit is contained in:
Zuul 2019-01-23 06:30:50 +00:00 committed by Gerrit Code Review
commit 91cb4b5f46
8 changed files with 141 additions and 12 deletions

View File

@ -265,7 +265,9 @@ Internal Server Error(500)
Request
-------
No body content, path, nor query option.
.. rest_parameters:: parameters.yaml
- lease_id: allocation_lease_id_query
Response
--------
@ -303,6 +305,7 @@ Request
.. rest_parameters:: parameters.yaml
- host_id: host_id_path
- lease_id: allocation_lease_id_query
Response
--------

View File

@ -12,6 +12,16 @@ lease_id_path:
required: true
type: string
# variables in query
allocation_lease_id_query:
description: |
Filter allocations results by lease id
in: query
required: false
type: string
# variables in body
allocation:
description: |

View File

@ -88,7 +88,8 @@ 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):
def get_reservation_allocations_by_host_ids(host_ids, start_date, end_date,
lease_id=None):
session = get_session()
border0 = models.Lease.end_date < start_date
border1 = models.Lease.start_date > end_date
@ -97,6 +98,8 @@ def get_reservation_allocations_by_host_ids(host_ids, start_date, end_date):
.filter(models.ComputeHostAllocation.compute_host_id
.in_(host_ids))
.filter(~sa.or_(border0, border1)))
if lease_id:
query = query.filter(models.Reservation.lease_id == lease_id)
return query.all()

View File

@ -111,9 +111,10 @@ 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):
def get_reservation_allocations_by_host_ids(host_ids, start_date, end_date,
lease_id=None):
return IMPL.get_reservation_allocations_by_host_ids(host_ids, start_date,
end_date)
end_date, lease_id)
def get_plugin_reservation(resource_type, resource_id):

View File

@ -32,6 +32,7 @@ class BasePlugin(object):
title = None
description = None
monitor = None
query_options = None
def get_plugin_opts(self):
"""Plugin can expose some options that should be specified in conf file
@ -99,6 +100,15 @@ class BasePlugin(object):
"""
raise NotImplementedError
def get_query_options(self, params, index_type):
options = {k: params[k] for k in params
if k in self.query_options[index_type]}
unsupported = set(params) - set(options)
if unsupported:
LOG.debug('Unsupported query key is specified in API request: %s',
unsupported)
return options
@six.add_metaclass(abc.ABCMeta)
class BaseMonitorPlugin():

View File

@ -72,6 +72,8 @@ LOG = logging.getLogger(__name__)
before_end_options = ['', 'snapshot', 'default']
QUERY_TYPE_ALLOCATION = 'allocation'
class PhysicalHostPlugin(base.BasePlugin, nova.NovaClientWrapper):
"""Plugin for physical host resource."""
@ -80,6 +82,9 @@ class PhysicalHostPlugin(base.BasePlugin, nova.NovaClientWrapper):
description = 'This plugin starts and shutdowns the hosts.'
freepool_name = CONF.nova.aggregate_freepool_name
pool = None
query_options = {
QUERY_TYPE_ALLOCATION: ['lease_id']
}
def __init__(self):
super(PhysicalHostPlugin, self).__init__(
@ -501,19 +506,22 @@ class PhysicalHostPlugin(base.BasePlugin, nova.NovaClientWrapper):
def list_allocations(self, query):
hosts_id_list = [h['id'] for h in db_api.host_list()]
options = self.get_query_options(query, QUERY_TYPE_ALLOCATION)
hosts_allocations = self.query_host_allocations(hosts_id_list)
hosts_allocations = self.query_host_allocations(hosts_id_list,
**options)
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])
options = self.get_query_options(query, QUERY_TYPE_ALLOCATION)
host_allocations = self.query_host_allocations([host_id], **options)
if host_id not in host_allocations:
raise manager_ex.HostNotFound(host=host_id)
host_allocations = {host_id: []}
allocs = host_allocations[host_id]
return {"resource_id": host_id, "reservations": allocs}
def query_host_allocations(self, hosts):
def query_host_allocations(self, hosts, lease_id=None):
"""Return dict of host and its allocations.
The list element forms
@ -532,7 +540,7 @@ class PhysicalHostPlugin(base.BasePlugin, nova.NovaClientWrapper):
# 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, start, end, lease_id)
hosts_allocs = {}
for reservation, alloc in allocs:

View File

@ -437,6 +437,24 @@ class SQLAlchemyDBUtilsTestCase(tests.DBTestCase):
self.assertListEqual(expected, [(r['id'], a['id']) for r, a in ret])
def test_get_reservation_allocations_by_host_ids_with_lease_id(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'),
]
ret = db_utils.get_reservation_allocations_by_host_ids(
['r1', 'r2'], '2030-01-01 08:00', '2030-01-01 15:00', 'lease1')
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

@ -476,6 +476,51 @@ class PhysicalHostPluginTestCase(tests.TestCase):
self.assertListEqual(expected, ret)
def test_list_allocations_with_lease_id(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'),
]
expected = [
{
'resource_id': 'host-1',
'reservations': [
{'id': 'reservation-1', 'lease_id': 'lease-1'},
]
},
{
'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({'lease_id': 'lease-1'})
# 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})
@ -500,6 +545,36 @@ class PhysicalHostPluginTestCase(tests.TestCase):
]
}
ret = self.fake_phys_plugin.get_allocations('host-1', {})
# sort returned value to use assertListEqual
ret['reservations'].sort(key=lambda x: x['id'])
self.assertDictEqual(expected, ret)
def test_get_allocations_with_lease_id(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'),
]
expected = {
'resource_id': 'host-1',
'reservations': [
{'id': 'reservation-1', 'lease_id': 'lease-1'},
]
}
ret = self.fake_phys_plugin.get_allocations('host-1',
{'lease_id': 'lease-1'})
# sort returned value to use assertListEqual
ret['reservations'].sort(key=lambda x: x['id'])
self.assertDictEqual(expected, ret)
def test_get_allocations_with_invalid_host(self):
@ -517,9 +592,10 @@ class PhysicalHostPluginTestCase(tests.TestCase):
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', {})
expected = {'resource_id': 'no-reserved-host', 'reservations': []}
ret = self.fake_phys_plugin.get_allocations('no-reserved-host', {})
self.assertDictEqual(expected, ret)
def test_create_reservation_no_hosts_available(self):
now = datetime.datetime.utcnow()