Update list_allocations in hosts plugin to expose start and end dates

This change modifies the DB utility to fetch reservation allocations so
that a list of reservations is returned with host_ids as an attribute to
each reservation.

This allows the host plugin to include more information when listing
allocations, namely start and end dates. This can be used to see when
resources are available, and for the creation of a reservation calendar
(blueprint calendar-view).

Change-Id: I464898bdeda6b55a028c8a14a54eb137c92a83c1
This commit is contained in:
Mark Powers 2021-08-20 21:19:05 +00:00 committed by Pierre Riteau
parent 39c67f09b8
commit bf38e16ec3
10 changed files with 382 additions and 102 deletions

View File

@ -280,6 +280,8 @@ Response
- reservations: reservation_allocation
- reservation.id: reservation_id
- reservation.lease_id: lease_id
- reservation.start_date: allocation_start_date
- reservation.end_date: allocation_end_date
**Example of List Allocations Response**
@ -319,6 +321,8 @@ Response
- reservations: reservation_allocation
- reservation.id: reservation_id
- reservation.lease_id: lease_id
- reservation.start_date: allocation_start_date
- reservation.end_date: allocation_end_date
**Example of Get Allocation Response**

View File

@ -67,6 +67,18 @@ allocation:
in: body
required: true
type: array
allocation_end_date:
description: |
The end date of the lease.
in: body
required: true
type: string
allocation_start_date:
description: |
The start date of the lease.
in: body
required: true
type: string
allocations:
description: |
A list of ``allocation`` objects.

View File

@ -131,9 +131,11 @@ def get_reservation_allocations_by_host_ids(host_ids, start_date, end_date,
lease_id=None,
reservation_id=None):
session = get_session()
# Get all reservations applicable
reservations = get_reservations_for_allocations(
session, start_date, end_date, lease_id, reservation_id)
# Select (reservation_id, host_id) for all reservations
allocations_query = (session.query(
models.ComputeHostAllocation.reservation_id,
models.ComputeHostAllocation.compute_host_id)
@ -141,17 +143,15 @@ def get_reservation_allocations_by_host_ids(host_ids, start_date, end_date,
.filter(models.ComputeHostAllocation.reservation_id.in_(
list(set([x['id'] for x in reservations])))))
# Create a mapping of reservation_id to list of host_ids
allocations = defaultdict(list)
for row in allocations_query.all():
allocations[row[0]].append(row[1])
allocs = []
# Copy the host id lists to the corresponding reservation
for r in reservations:
for host in allocations[r['id']]:
allocs.append((r['id'], r['lease_id'], host))
return allocs
r['host_ids'] = allocations[r['id']]
return reservations
def get_reservation_allocations_by_fip_ids(fip_ids, start_date, end_date,

View File

@ -161,6 +161,8 @@ class VirtualInstancePlugin(base.BasePlugin, nova.NovaClientWrapper):
{
'lease_id': lease_id,
'id': reservation_id
'start_date': lease_start_date,
'end_date': lease_end_date,
},
]
}.
@ -170,13 +172,17 @@ class VirtualInstancePlugin(base.BasePlugin, nova.NovaClientWrapper):
# To reduce overhead, this method only executes one query
# to get the allocation information
rsv_lease_host = db_utils.get_reservation_allocations_by_host_ids(
reservations = db_utils.get_reservation_allocations_by_host_ids(
hosts, start, end, lease_id, reservation_id)
hosts_allocs = collections.defaultdict(list)
for rsv, lease, host in rsv_lease_host:
hosts_allocs[host].append({'lease_id': lease, 'id': rsv})
return hosts_allocs
host_allocs = {h: [] for h in hosts}
attributes_to_copy = ["id", "lease_id", "start_date", "end_date"]
for reservation in reservations:
for host_id in reservation['host_ids']:
if host_id in host_allocs.keys():
host_allocs[host_id].append({
k: v for k, v in reservation.items()
if k in attributes_to_copy})
return host_allocs
def query_available_hosts(self, cpus=None, memory=None, disk=None,
resource_properties=None,

View File

@ -14,7 +14,6 @@
# License for the specific language governing permissions and limitations
# under the License.
import collections
import datetime
from novaclient import exceptions as nova_exceptions
@ -527,7 +526,9 @@ class PhysicalHostPlugin(base.BasePlugin, nova.NovaClientWrapper):
'host-id': [
{
'lease_id': lease_id,
'id': reservation_id
'id': reservation_id,
'start_date': lease_start_date,
'end_date': lease_end_date,
},
]
}.
@ -537,13 +538,17 @@ class PhysicalHostPlugin(base.BasePlugin, nova.NovaClientWrapper):
# To reduce overhead, this method only executes one query
# to get the allocation information
rsv_lease_host = db_utils.get_reservation_allocations_by_host_ids(
reservations = db_utils.get_reservation_allocations_by_host_ids(
hosts, start, end, lease_id, reservation_id)
hosts_allocs = collections.defaultdict(list)
for rsv, lease, host in rsv_lease_host:
hosts_allocs[host].append({'lease_id': lease, 'id': rsv})
return hosts_allocs
host_allocs = {h: [] for h in hosts}
attributes_to_copy = ["id", "lease_id", "start_date", "end_date"]
for reservation in reservations:
for host_id in reservation['host_ids']:
if host_id in host_allocs.keys():
host_allocs[host_id].append({
k: v for k, v in reservation.items()
if k in attributes_to_copy})
return host_allocs
def allocation_candidates(self, values):
self._check_params(values)

View File

@ -259,32 +259,69 @@ class SQLAlchemyDBUtilsTestCase(tests.DBTestCase):
self.check_reservation([], ['r4'],
'2030-01-01 07:00', '2030-01-01 15:00')
def _create_allocation_tuple(self, 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'],
reservation['lease_id'],
allocation['compute_host_id'])
def test_get_reservation_allocations_by_host_ids(self):
self._setup_leases()
# query all allocations of lease1, lease2 and lease3
expected = [
self._create_allocation_tuple('lease1'),
self._create_allocation_tuple('lease2'),
self._create_allocation_tuple('lease3'),
{
"id": db_api.reservation_get_all_by_lease_id(
"lease1")[0]["id"],
"status": None,
"lease_id": "lease1",
"start_date": datetime.datetime(2030, 1, 1, 9, 0),
"end_date": datetime.datetime(2030, 1, 1, 10, 30),
"lease_name": "fake_phys_lease_r1",
"project_id": None,
"host_ids": ["r1"]
},
{
"id": db_api.reservation_get_all_by_lease_id(
"lease2")[0]["id"],
"status": None,
"lease_id": "lease2",
"start_date": datetime.datetime(2030, 1, 1, 11, 0),
"end_date": datetime.datetime(2030, 1, 1, 12, 45),
"lease_name": "fake_phys_lease_r2",
"project_id": None, "host_ids": ["r2"]
},
{
"id": db_api.reservation_get_all_by_lease_id(
"lease3")[0]["id"],
"status": None,
"lease_id": "lease3",
"start_date": datetime.datetime(2030, 1, 1, 13, 0),
"end_date": datetime.datetime(2030, 1, 1, 14, 0),
"lease_name": "fake_phys_lease_r3",
"project_id": None, "host_ids": ["r1"]
}
]
ret = db_utils.get_reservation_allocations_by_host_ids(
['r1', 'r2'], '2030-01-01 08:00', '2030-01-01 15:00')
self.assertListEqual(expected, ret)
# query allocations of lease2 and lease3
expected = [
self._create_allocation_tuple('lease2'),
self._create_allocation_tuple('lease3'),
{
"id": db_api.reservation_get_all_by_lease_id(
"lease2")[0]["id"],
"status": None,
"lease_id": "lease2",
"start_date": datetime.datetime(2030, 1, 1, 11, 0),
"end_date": datetime.datetime(2030, 1, 1, 12, 45),
"lease_name": "fake_phys_lease_r2",
"project_id": None, "host_ids": ["r2"]
},
{
"id": db_api.reservation_get_all_by_lease_id(
"lease3")[0]["id"],
"status": None,
"lease_id": "lease3",
"start_date": datetime.datetime(2030, 1, 1, 13, 0),
"end_date": datetime.datetime(2030, 1, 1, 14, 0),
"lease_name": "fake_phys_lease_r3",
"project_id": None, "host_ids": ["r1"]
}
]
ret = db_utils.get_reservation_allocations_by_host_ids(
['r1', 'r2'], '2030-01-01 11:30', '2030-01-01 15:00')
@ -296,7 +333,17 @@ class SQLAlchemyDBUtilsTestCase(tests.DBTestCase):
# query all allocations of lease1, lease2 and lease3
expected = [
self._create_allocation_tuple('lease1'),
{
"id": db_api.reservation_get_all_by_lease_id(
"lease1")[0]["id"],
"status": None,
"lease_id": "lease1",
"start_date": datetime.datetime(2030, 1, 1, 9, 0),
"end_date": datetime.datetime(2030, 1, 1, 10, 30),
"lease_name": "fake_phys_lease_r1",
"project_id": None,
"host_ids": ["r1"]
},
]
ret = db_utils.get_reservation_allocations_by_host_ids(
['r1', 'r2'], '2030-01-01 08:00', '2030-01-01 15:00', 'lease1')
@ -309,7 +356,17 @@ class SQLAlchemyDBUtilsTestCase(tests.DBTestCase):
# query allocations of lease1
expected = [
self._create_allocation_tuple('lease1'),
{
"id": db_api.reservation_get_all_by_lease_id(
"lease1")[0]["id"],
"status": None,
"lease_id": "lease1",
"start_date": datetime.datetime(2030, 1, 1, 9, 0),
"end_date": datetime.datetime(2030, 1, 1, 10, 30),
"lease_name": "fake_phys_lease_r1",
"project_id": None,
"host_ids": ["r1"]
},
]
ret = db_utils.get_reservation_allocations_by_host_ids(
['r1', 'r2'], '2030-01-01 08:00', '2030-01-01 15:00',

View File

@ -435,34 +435,94 @@ class PhysicalHostPluginTestCase(tests.TestCase):
self.db_get_reserv_allocs = self.patch(
self.db_utils, 'get_reservation_allocations_by_host_ids')
self.db_host_list.return_value = [
{'id': '3001'},
{'id': '3002'},
{'id': '3003'},
{'id': '3004'},
]
# Expecting a list of (Reservation, Allocation)
self.db_get_reserv_allocs.return_value = [
('reservation-1', 'lease-1', 'host-1'),
('reservation-1', 'lease-1', 'host-2'),
('reservation-2', 'lease-1', 'host-2'),
('reservation-2', 'lease-1', 'host-3'),
('reservation-3', 'lease-2', 'host-1'),
{
'id': '1001',
'lease_id': '2001',
'start_date': datetime.datetime(2021, 8, 20, 20, 18),
'end_date': datetime.datetime(2021, 8, 30, 20, 0),
'host_ids': ['3002']
},
{
'id': '1002',
'lease_id': '2002',
'start_date': datetime.datetime(2021, 8, 20, 16, 34),
'end_date': datetime.datetime(2021, 8, 21, 16, 34),
'host_ids': ['3003', '3004']
},
{
'id': '1003',
'lease_id': '2003',
'start_date': datetime.datetime(2021, 8, 19, 20, 18),
'end_date': datetime.datetime(2021, 8, 27, 20, 18),
'host_ids': ['3001']
},
{
'id': '1004',
'lease_id': '2004',
'start_date': datetime.datetime(2021, 8, 25, 20, 18),
'end_date': datetime.datetime(2021, 8, 30, 20, 0),
'host_ids': ['3003']
}
]
expected = [
{
'resource_id': 'host-1',
'resource_id': '3001',
'reservations': [
{'id': 'reservation-1', 'lease_id': 'lease-1'},
{'id': 'reservation-3', 'lease_id': 'lease-2'},
{
'id': '1003',
'lease_id': '2003',
'start_date': datetime.datetime(2021, 8, 19, 20, 18),
'end_date': datetime.datetime(2021, 8, 27, 20, 18)
}
]
},
{
'resource_id': 'host-2',
'resource_id': '3002',
'reservations': [
{'id': 'reservation-1', 'lease_id': 'lease-1'},
{'id': 'reservation-2', 'lease_id': 'lease-1'},
{
'id': '1001',
'lease_id': '2001',
'start_date': datetime.datetime(2021, 8, 20, 20, 18),
'end_date': datetime.datetime(2021, 8, 30, 20, 0)
},
]
},
{
'resource_id': 'host-3',
'resource_id': '3003',
'reservations': [
{'id': 'reservation-2', 'lease_id': 'lease-1'},
{
'id': '1002',
'lease_id': '2002',
'start_date': datetime.datetime(2021, 8, 20, 16, 34),
'end_date': datetime.datetime(2021, 8, 21, 16, 34)
},
{
'id': '1004',
'lease_id': '2004',
'start_date': datetime.datetime(2021, 8, 25, 20, 18),
'end_date': datetime.datetime(2021, 8, 30, 20, 0)
}
]
},
{
'resource_id': '3004',
'reservations': [
{
'id': '1002',
'lease_id': '2002',
'start_date': datetime.datetime(2021, 8, 20, 16, 34),
'end_date': datetime.datetime(2021, 8, 21, 16, 34)
}
]
}
]
@ -479,37 +539,49 @@ class PhysicalHostPluginTestCase(tests.TestCase):
self.db_get_reserv_allocs = self.patch(
self.db_utils, 'get_reservation_allocations_by_host_ids')
self.db_host_list.return_value = [
{'id': '3001'},
{'id': '3002'},
{'id': '3003'},
{'id': '3004'},
]
# Expecting a list of (Reservation, Allocation)
self.db_get_reserv_allocs.return_value = [
('reservation-1', 'lease-1', 'host-1'),
('reservation-1', 'lease-1', 'host-2'),
('reservation-2', 'lease-1', 'host-2'),
('reservation-2', 'lease-1', 'host-3'),
{
'id': '1001',
'lease_id': '2001',
'start_date': datetime.datetime(2021, 8, 20, 20, 18),
'end_date': datetime.datetime(2021, 8, 30, 20, 0),
'host_ids': ['3002']
},
]
expected = [
{
'resource_id': 'host-1',
'resource_id': '3001',
'reservations': []
},
{
'resource_id': '3002',
'reservations': [
{'id': 'reservation-1', 'lease_id': 'lease-1'},
{
'id': '1001',
'lease_id': '2001',
'start_date': datetime.datetime(2021, 8, 20, 20, 18),
'end_date': datetime.datetime(2021, 8, 30, 20, 0)
}
]
},
{
'resource_id': 'host-2',
'reservations': [
{'id': 'reservation-1', 'lease_id': 'lease-1'},
{'id': 'reservation-2', 'lease_id': 'lease-1'},
]
'resource_id': '3003',
'reservations': []
},
{
'resource_id': 'host-3',
'reservations': [
{'id': 'reservation-2', 'lease_id': 'lease-1'},
]
}
'resource_id': '3004',
'reservations': []
},
]
ret = self.fake_phys_plugin.list_allocations({'lease_id': 'lease-1'})
ret = self.fake_phys_plugin.list_allocations({'lease_id': '2001'})
# Sort returned value to use assertListEqual
for r in ret:
r['reservations'].sort(key=lambda x: x['id'])
@ -521,28 +593,58 @@ class PhysicalHostPluginTestCase(tests.TestCase):
self.db_get_reserv_allocs = self.patch(
self.db_utils, 'get_reservation_allocations_by_host_ids')
self.db_host_list.return_value = [
{'id': "3001"},
{'id': "3002"},
{'id': "3003"},
{'id': "3004"},
]
# Expecting a list of (Reservation, Allocation)
self.db_get_reserv_allocs.return_value = [
('reservation-1', 'lease-1', 'host-1'),
('reservation-1', 'lease-1', 'host-2'),
{
'id': '1002',
'lease_id': '2002',
'start_date': datetime.datetime(2021, 8, 20, 16, 34),
'end_date': datetime.datetime(2021, 8, 21, 16, 34),
'host_ids': ['3003', '3004']
},
]
expected = [
{
'resource_id': 'host-1',
'resource_id': '3001',
'reservations': []
},
{
'resource_id': '3002',
'reservations': []
},
{
'resource_id': '3003',
'reservations': [
{'id': 'reservation-1', 'lease_id': 'lease-1'},
{
'id': '1002',
'lease_id': '2002',
'start_date': datetime.datetime(2021, 8, 20, 16, 34),
'end_date': datetime.datetime(2021, 8, 21, 16, 34)
},
]
},
{
'resource_id': 'host-2',
'resource_id': '3004',
'reservations': [
{'id': 'reservation-1', 'lease_id': 'lease-1'},
{
'id': '1002',
'lease_id': '2002',
'start_date': datetime.datetime(2021, 8, 20, 16, 34),
'end_date': datetime.datetime(2021, 8, 21, 16, 34)
}
]
},
]
ret = self.fake_phys_plugin.list_allocations(
{'reservation_id': 'reservation-1'})
{'reservation_id': '1002'})
# Sort returned value to use assertListEqual
for r in ret:
@ -557,21 +659,54 @@ class PhysicalHostPluginTestCase(tests.TestCase):
# Expecting a list of (Reservation, Allocation)
self.db_get_reserv_allocs.return_value = [
('reservation-1', 'lease-1', 'host-1'),
('reservation-1', 'lease-1', 'host-2'),
('reservation-2', 'lease-1', 'host-2'),
('reservation-2', 'lease-1', 'host-3'),
('reservation-3', 'lease-2', 'host-1'),
{
'id': '1001',
'lease_id': '2001',
'start_date': datetime.datetime(2021, 8, 20, 20, 18),
'end_date': datetime.datetime(2021, 8, 30, 20, 0),
'host_ids': ['3002']
},
{
'id': '1002',
'lease_id': '2002',
'start_date': datetime.datetime(2021, 8, 20, 16, 34),
'end_date': datetime.datetime(2021, 8, 21, 16, 34),
'host_ids': ['3003', '3004']
},
{
'id': '1003',
'lease_id': '2003',
'start_date': datetime.datetime(2021, 8, 19, 20, 18),
'end_date': datetime.datetime(2021, 8, 27, 20, 18),
'host_ids': ['3001']
},
{
'id': '1004',
'lease_id': '2004',
'start_date': datetime.datetime(2021, 8, 25, 20, 18),
'end_date': datetime.datetime(2021, 8, 30, 20, 0),
'host_ids': ['3003']
}
]
expected = {
'resource_id': 'host-1',
'resource_id': '3003',
'reservations': [
{'id': 'reservation-1', 'lease_id': 'lease-1'},
{'id': 'reservation-3', 'lease_id': 'lease-2'},
{
'id': '1002',
'lease_id': '2002',
'start_date': datetime.datetime(2021, 8, 20, 16, 34),
'end_date': datetime.datetime(2021, 8, 21, 16, 34)
},
{
'id': '1004',
'lease_id': '2004',
'start_date': datetime.datetime(2021, 8, 25, 20, 18),
'end_date': datetime.datetime(2021, 8, 30, 20, 0)
}
]
}
ret = self.fake_phys_plugin.get_allocations('host-1', {})
ret = self.fake_phys_plugin.get_allocations('3003', {})
# sort returned value to use assertListEqual
ret['reservations'].sort(key=lambda x: x['id'])
@ -584,17 +719,29 @@ class PhysicalHostPluginTestCase(tests.TestCase):
# Expecting a list of (Reservation, Allocation)
self.db_get_reserv_allocs.return_value = [
('reservation-1', 'lease-1', 'host-1'),
{
'id': '1001',
'lease_id': '2001',
'start_date': datetime.datetime(2021, 8, 20, 20, 18),
'end_date': datetime.datetime(2021, 8, 30, 20, 0),
'host_ids': ['3002']
},
]
expected = {
'resource_id': 'host-1',
'resource_id': '3002',
'reservations': [
{'id': 'reservation-1', 'lease_id': 'lease-1'},
{
'id': '1001',
'lease_id': '2001',
'start_date': datetime.datetime(2021, 8, 20, 20, 18),
'end_date': datetime.datetime(2021, 8, 30, 20, 0)
}
]
}
ret = self.fake_phys_plugin.get_allocations('host-1',
{'lease_id': 'lease-1'})
ret = self.fake_phys_plugin.get_allocations('3002',
{'lease_id': '2001'})
# sort returned value to use assertListEqual
ret['reservations'].sort(key=lambda x: x['id'])
@ -607,17 +754,28 @@ class PhysicalHostPluginTestCase(tests.TestCase):
# Expecting a list of (Reservation, Allocation)
self.db_get_reserv_allocs.return_value = [
('reservation-1', 'lease-1', 'host-1'),
{
'id': '1001',
'lease_id': '2001',
'start_date': datetime.datetime(2021, 8, 20, 20, 18),
'end_date': datetime.datetime(2021, 8, 30, 20, 0),
'host_ids': ['3002']
},
]
expected = {
'resource_id': 'host-1',
'resource_id': '3002',
'reservations': [
{'id': 'reservation-1', 'lease_id': 'lease-1'},
{
'id': '1001',
'lease_id': '2001',
'start_date': datetime.datetime(2021, 8, 20, 20, 18),
'end_date': datetime.datetime(2021, 8, 30, 20, 0)
}
]
}
ret = self.fake_phys_plugin.get_allocations(
'host-1', {'reservation_id': 'reservation-1'})
'3002', {'reservation_id': '1001'})
# sort returned value to use assertListEqual
ret['reservations'].sort(key=lambda x: x['id'])
@ -630,11 +788,34 @@ class PhysicalHostPluginTestCase(tests.TestCase):
# Expecting a list of (Reservation, Allocation)
self.db_get_reserv_allocs.return_value = [
('reservation-1', 'lease-1', 'host-1'),
('reservation-1', 'lease-1', 'host-2'),
('reservation-2', 'lease-1', 'host-2'),
('reservation-2', 'lease-1', 'host-3'),
('reservation-3', 'lease-2', 'host-1'),
{
'id': '1001',
'lease_id': '2001',
'start_date': datetime.datetime(2021, 8, 20, 20, 18),
'end_date': datetime.datetime(2021, 8, 30, 20, 0),
'host_ids': ['3002']
},
{
'id': '1002',
'lease_id': '2002',
'start_date': datetime.datetime(2021, 8, 20, 16, 34),
'end_date': datetime.datetime(2021, 8, 21, 16, 34),
'host_ids': ['3003', '3004']
},
{
'id': '1003',
'lease_id': '2003',
'start_date': datetime.datetime(2021, 8, 19, 20, 18),
'end_date': datetime.datetime(2021, 8, 27, 20, 18),
'host_ids': ['3001']
},
{
'id': '1004',
'lease_id': '2004',
'start_date': datetime.datetime(2021, 8, 25, 20, 18),
'end_date': datetime.datetime(2021, 8, 30, 20, 0),
'host_ids': ['3003']
}
]
expected = {'resource_id': 'no-reserved-host', 'reservations': []}
ret = self.fake_phys_plugin.get_allocations('no-reserved-host', {})

View File

@ -4,11 +4,15 @@
"reservations": [
{
"id": "3504fbac-fdb2-458e-a43f-34d27fbd0b86",
"lease_id": "0ec2bed6-75f9-4959-8198-9d9717dde4cb"
"lease_id": "0ec2bed6-75f9-4959-8198-9d9717dde4cb",
"start_date": "2021-12-16T17:11:00.000000",
"end_date": "2021-12-16T17:13:00.000000"
},
{
"id": "4f4743a2-d8c7-44c2-ba39-300eb7659bb9",
"lease_id": "6050288d-5535-4e3c-93d5-083184b86c61"
"lease_id": "6050288d-5535-4e3c-93d5-083184b86c61",
"start_date": "2021-12-16T17:11:00.000000",
"end_date": "2021-12-16T17:13:00.000000"
}
]
}

View File

@ -5,11 +5,15 @@
"reservations": [
{
"id": "3504fbac-fdb2-458e-a43f-34d27fbd0b86",
"lease_id": "0ec2bed6-75f9-4959-8198-9d9717dde4cb"
"lease_id": "0ec2bed6-75f9-4959-8198-9d9717dde4cb",
"start_date": "2021-12-16T17:11:00.000000",
"end_date": "2021-12-16T17:13:00.000000"
},
{
"id": "4f4743a2-d8c7-44c2-ba39-300eb7659bb9",
"lease_id": "6050288d-5535-4e3c-93d5-083184b86c61"
"lease_id": "6050288d-5535-4e3c-93d5-083184b86c61",
"start_date": "2021-12-16T17:11:00.000000",
"end_date": "2021-12-16T17:13:00.000000"
}
]
},
@ -18,7 +22,9 @@
"reservations": [
{
"id": "b2475424-6872-43ec-857d-f4b50b403e97",
"lease_id": "e92b9d47-9078-47ec-a35c-27e67f7b8429"
"lease_id": "e92b9d47-9078-47ec-a35c-27e67f7b8429",
"start_date": "2021-12-16T17:11:00.000000",
"end_date": "2021-12-16T17:13:00.000000"
}
]
}

View File

@ -0,0 +1,5 @@
---
features:
- |
The List Allocation and Get Allocation API have been extended to include
lease start date and end date along with the reservation.