From f135835563008ec367a7ccabd604efc0e901a950 Mon Sep 17 00:00:00 2001 From: Mark Powers Date: Tue, 12 Aug 2025 13:42:08 -0500 Subject: [PATCH 1/2] Improve KVM support --- chi/lease.py | 19 +++++++++++++++---- chi/server.py | 27 +++++++++++++++++---------- 2 files changed, 32 insertions(+), 14 deletions(-) diff --git a/chi/lease.py b/chi/lease.py index ca4d149..360423a 100644 --- a/chi/lease.py +++ b/chi/lease.py @@ -484,14 +484,25 @@ def add_fip_reservation(self, amount: int): """ add_fip_reservation(reservation_list=self.fip_reservations, count=amount) - def add_flavor_reservation(self, id, amount=1): + def add_flavor_reservation(self, id=None, name=None, amount=1): """ - Add a reservation for a KVM flavor to the list of reservations. + Add a reservation for a KVM flavor to the list of reservations by name or ID. Args: id (str): The ID of the flavor to reserve - count (int): The number of floating IPs to reserve. + name (str): The name of the flavor to reserve + amount (int): The number of instances of this flavor to reserve """ + # Do not permit both or neither name and id. + if (name and id) or not (name or id): + raise CHIValueError( + "You must specify exactly one of id or name" + ) + + # Blazar API requires flavor ID, so we must convert from name + if not id: + id = server.get_flavor(name).id + self.flavor_reservations.append( { "resource_type": "flavor:instance", @@ -784,7 +795,7 @@ def get_reserved_flavors(self): flavors = [] for res in self.flavor_reservations: flavors.extend( - server.list_flavors(reservable=True, reservation_id=res.get("id")) + server.list_flavors(reservation_id=res.get("id")) ) return flavors diff --git a/chi/server.py b/chi/server.py index c020857..21aee26 100644 --- a/chi/server.py +++ b/chi/server.py @@ -699,11 +699,12 @@ def __repr__(self): return f"<{self.__class__.__name__} '{self.name}' {self.description} (disk={self.disk}) (ram={self.ram}) (vcpus={self.vcpus})>" -def list_flavors(reservable=None, reservation_id=None) -> List[Flavor]: - """Get a list of all available flavors. +def list_flavors(reservable=None, gpu=None, reservation_id=None) -> List[Flavor]: + """Get a list of flavors Args: - reservable (bool): Whether to filter by reservable flavors. Defaults to True. + reservable (bool): If given, whether to filter by reservable flavors. + gpu (bool): If given, whether to filter by GPU flavors. reservation_id (str, optional): The reservation ID to filter by. Defaults to None. Returns: @@ -715,13 +716,19 @@ def list_flavors(reservable=None, reservation_id=None) -> List[Flavor]: chi_flavors = [] for f in flavors: extras = f.get_keys() - # include a flavor if: - # - not filtering by reservable - # - is reservable in blazar & not an active reservation flavor - if not reservable or ( - extras.get("aggregate_instance_extra_specs:reservation") - == reservation_id - and extras.get("trait:CUSTOM_BLAZAR_FLAVOR_RESERVATION") == "required" + is_reservable = not any( + e.startswith("resources:CUSTOM_RESERVATION_") + for e in extras + ) + is_gpu = f.extra_specs.get("trait:CUSTOM_GPU") == "required" + matching_reservation = ( + reservation_id is None or + extras.get("aggregate_instance_extra_specs:reservation", None) == reservation_id + ) + if ( + (reservable is None or reservable == is_reservable) + and (gpu is None or gpu == is_gpu) + and matching_reservation ): chi_flavors.append( Flavor( From c63e0f57bcc50fdb0ed47c460be091235d4ec9b1 Mon Sep 17 00:00:00 2001 From: Mark Powers Date: Tue, 12 Aug 2025 13:45:29 -0500 Subject: [PATCH 2/2] Format --- chi/lease.py | 8 ++------ chi/server.py | 8 ++++---- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/chi/lease.py b/chi/lease.py index 360423a..819d4f5 100644 --- a/chi/lease.py +++ b/chi/lease.py @@ -495,9 +495,7 @@ def add_flavor_reservation(self, id=None, name=None, amount=1): """ # Do not permit both or neither name and id. if (name and id) or not (name or id): - raise CHIValueError( - "You must specify exactly one of id or name" - ) + raise CHIValueError("You must specify exactly one of id or name") # Blazar API requires flavor ID, so we must convert from name if not id: @@ -794,9 +792,7 @@ def get_reserved_flavors(self): """ flavors = [] for res in self.flavor_reservations: - flavors.extend( - server.list_flavors(reservation_id=res.get("id")) - ) + flavors.extend(server.list_flavors(reservation_id=res.get("id"))) return flavors diff --git a/chi/server.py b/chi/server.py index 21aee26..54665dd 100644 --- a/chi/server.py +++ b/chi/server.py @@ -717,13 +717,13 @@ def list_flavors(reservable=None, gpu=None, reservation_id=None) -> List[Flavor] for f in flavors: extras = f.get_keys() is_reservable = not any( - e.startswith("resources:CUSTOM_RESERVATION_") - for e in extras + e.startswith("resources:CUSTOM_RESERVATION_") for e in extras ) is_gpu = f.extra_specs.get("trait:CUSTOM_GPU") == "required" matching_reservation = ( - reservation_id is None or - extras.get("aggregate_instance_extra_specs:reservation", None) == reservation_id + reservation_id is None + or extras.get("aggregate_instance_extra_specs:reservation", None) + == reservation_id ) if ( (reservable is None or reservable == is_reservable)