diff --git a/blazarclient/v1/client.py b/blazarclient/v1/client.py index 071df33..ffad4cd 100644 --- a/blazarclient/v1/client.py +++ b/blazarclient/v1/client.py @@ -17,6 +17,7 @@ from blazarclient.v1 import devices from blazarclient.v1 import allocations +from blazarclient.v1 import flavor_instances from blazarclient.v1 import floatingips from blazarclient.v1 import hosts from blazarclient.v1 import leases @@ -83,3 +84,9 @@ def __init__(self, blazar_url=None, auth_token=None, session=None, session=self.session, version=self.version, **kwargs) + self.flavor_instance = flavor_instances.FlavorInstanceClientManager( + blazar_url=self.blazar_url, + auth_token=self.auth_token, + session=self.session, + version=self.version, + **kwargs) diff --git a/blazarclient/v1/flavor_instances.py b/blazarclient/v1/flavor_instances.py new file mode 100644 index 0000000..032ea1b --- /dev/null +++ b/blazarclient/v1/flavor_instances.py @@ -0,0 +1,34 @@ +# Copyright (c) 2024 University of Chicago. +# +# 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. + +from blazarclient import base + + +class FlavorInstanceClientManager(base.BaseClientManager): + """Manager for flavor instance availability requests.""" + + def get_availability(self, flavor_id=None, start_date=None, end_date=None): + """Get slot availability timeline for one or all Nova flavors.""" + query_parts = [] + if flavor_id: + query_parts.append('flavor_id=%s' % flavor_id) + if start_date: + query_parts.append('start_date=%s' % start_date) + if end_date: + query_parts.append('end_date=%s' % end_date) + url = '/flavor-instances/availability' + if query_parts: + url += '?' + '&'.join(query_parts) + resp, body = self.request_manager.get(url) + return body diff --git a/blazarclient/v1/shell_commands/flavor_instances.py b/blazarclient/v1/shell_commands/flavor_instances.py new file mode 100644 index 0000000..aaa5b13 --- /dev/null +++ b/blazarclient/v1/shell_commands/flavor_instances.py @@ -0,0 +1,70 @@ +# Copyright (c) 2024 University of Chicago. +# +# 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. + +import logging + +from cliff import lister + +from blazarclient import command + + +class ListFlavorInstanceAvailability(command.BlazarCommand, lister.Lister): + """List availability slots for Nova flavors.""" + resource = 'flavor_instance' + log = logging.getLogger(__name__ + '.ListFlavorInstanceAvailability') + list_columns = ['flavor_id', 'start', 'end', 'available', 'total'] + + def get_parser(self, prog_name): + parser = super(ListFlavorInstanceAvailability, self).get_parser( + prog_name) + parser.add_argument( + 'flavor_id', + metavar='FLAVOR_ID', + nargs='?', + default=None, + help='Nova flavor UUID to check availability for (default: all flavors)' + ) + parser.add_argument( + '--start-date', + metavar='', + default=None, + help="Start of the availability window (format: 'YYYY-MM-DD HH:MM'," + " default: now)" + ) + parser.add_argument( + '--end-date', + metavar='', + default=None, + help="End of the availability window (format: 'YYYY-MM-DD HH:MM'," + " default: 30 days from start)" + ) + return parser + + def take_action(self, parsed_args): + self.log.debug('take_action(%s)' % parsed_args) + blazar_client = self.get_client() + result = blazar_client.flavor_instance.get_availability( + flavor_id=parsed_args.flavor_id, + start_date=parsed_args.start_date, + end_date=parsed_args.end_date, + ) + flavor_results = result.get('flavor_instances', []) + columns = self.list_columns + rows = ( + (fr['flavor_id'], seg['start'], seg['end'], + seg['available'], seg['total']) + for fr in flavor_results + for seg in fr.get('availability', []) + ) + return columns, rows diff --git a/setup.cfg b/setup.cfg index 12f4b4c..4dc7c86 100644 --- a/setup.cfg +++ b/setup.cfg @@ -50,6 +50,7 @@ openstack.reservation.v1 = reservation_device_show = blazarclient.v1.shell_commands.devices:ShowDevice reservation_allocation_list = blazarclient.v1.shell_commands.allocations:ListAllocations reservation_allocation_show = blazarclient.v1.shell_commands.allocations:ShowAllocations + reservation_flavor_instance_availability_list = blazarclient.v1.shell_commands.flavor_instances:ListFlavorInstanceAvailability reservation_floatingip_create = blazarclient.v1.shell_commands.floatingips:CreateFloatingIP reservation_floatingip_delete = blazarclient.v1.shell_commands.floatingips:DeleteFloatingIP reservation_floatingip_list = blazarclient.v1.shell_commands.floatingips:ListFloatingIPs