def register_control_types(self, *, control: ABCResourceControl): types = control.get_types() if types is None or len(types) == 0: raise AuthorityException( "Resource control does not specify any types") for t in types: if t is None: raise AuthorityException("Invalid resource type specified") index = 0 try: for rtype in types: if rtype in self.controls_by_resource_type: raise AuthorityException( f"There is already a control associated with resource type {rtype}" ) self.controls_by_resource_type[rtype] = control index += 1 except Exception as e: j = 0 for t in types: if t in self.controls_by_resource_type: self.controls_by_resource_type.pop(t) j += 1 if j == index: break raise e
def recover(self): if self.state == ReservationStates.Ticketed: if self.pending_state == ReservationPendingStates.None_: self.actor.redeem(reservation=self, callback=None, caller=None) elif self.pending_state == ReservationPendingStates.Redeeming: self.transition(prefix="[recover]", state=self.state, pending=ReservationPendingStates.None_) self.actor.redeem(reservation=self, callback=None, caller=None) elif self.pending_state == ReservationPendingStates.Priming: self.pending_recover = True self.actor.close(reservation=self) elif self.pending_state == ReservationPendingStates.Closing: self.actor.close(reservation=self) else: raise AuthorityException( self.UnexpectedExceptionString.format( self.state, self.pending_state)) elif self.state == ReservationStates.Active: if self.pending_state == ReservationPendingStates.None_: self.logger.debug("No op") elif self.pending_state == ReservationPendingStates.ExtendingLease: self.transition(prefix="[recover]", state=self.state, pending=ReservationPendingStates.None_) self.actor.extend_lease(self, None) elif self.pending_state == ReservationPendingStates.Priming: self.pending_recover = True self.actor.close(reservation=self) elif self.pending_state == ReservationPendingStates.Closing: self.actor.close(reservation=self) else: raise AuthorityException( self.UnexpectedExceptionString.format( self.state, self.pending_state)) elif self.state == ReservationStates.Failed: self.logger.debug("No op") else: raise AuthorityException( self.UnexpectedExceptionString.format(self.state, self.pending_state))
def invoke_handler(self, unit: ConfigToken, operation: str): try: handler = self.config_mappings.get(str(unit.get_resource_type()), None) if handler is None: raise AuthorityException( f"No handler found for resource type {unit.get_resource_type()}" ) future = self.executor.submit(self.process_pool_main, operation, handler.get_class_name(), handler.get_module_name(), handler.get_properties(), unit, self.process_pool_lock) self.queue_future(future=future, unit=unit) self.logger.debug( f"Handler operation {operation} scheduled for Resource Type: {unit.get_resource_type()} " f"Unit: {unit.get_id()} Reservation: {unit.get_reservation_id()}" ) except Exception as e: self.logger.error(f"Exception occurred {e}") self.logger.error(traceback.format_exc()) result = { Constants.PROPERTY_TARGET_NAME: operation, Constants.PROPERTY_TARGET_RESULT_CODE: Constants.RESULT_CODE_EXCEPTION, Constants.PROPERTY_ACTION_SEQUENCE_NUMBER: 0 } self.handler_complete(unit=unit, properties=result, old_unit=unit) finally: self.logger.info(f"Executing {operation} completed")
def available(self, *, resources: ResourceSet): rc = self.get_control_by_type(rtype=resources.get_type()) if rc is not None: rc.available(resource_set=resources) else: raise AuthorityException( Constants.UNSUPPORTED_RESOURCE_TYPE.format( resources.get_type()))
def close(self, *, reservation: ABCReservationMixin): self.calendar.remove_schedule_or_in_progress(reservation=reservation) if reservation.get_type() is not None: rc = self.get_control_by_type(rtype=reservation.get_type()) if rc is not None: rc.close(reservation=reservation) else: raise AuthorityException( Constants.UNSUPPORTED_RESOURCE_TYPE.format( reservation.get_type()))
def restore(self): """ Custom restore function. Invoked during recovering the policy object. """ for c in self.controls_by_guid.values(): try: self.register_control_types(control=c) except Exception as e: raise AuthorityException( f"Cannot restore resource control e:{e}")
def modify_lease(self, *, reservation: ABCAuthorityReservation, caller: AuthToken): if caller is None: if not self.recovered: self.modifying_lease.add(reservation=reservation) else: self.wrapper.modify_lease_request(reservation=reservation, caller=reservation.get_client_auth_token(), compare_sequence_numbers=False) else: if not self.is_recovered() or self.stopped: raise AuthorityException(Constants.INVALID_ACTOR_STATE) self.wrapper.modify_lease_request(reservation=reservation, caller=caller, compare_sequence_numbers=True)
def handle_update_lease(self, reservation: ABCReservationMixin, update_data: UpdateData, caller: AuthToken): if self.waiting_for_lease: self.parent.check_incoming_lease(self.request, reservation) self.waiting_for_lease = False self.waiting_for_close = True elif self.waiting_for_close: self.parent.assertTrue(site.get_current_cycle() >= AuthorityCalendarPolicyTest.TicketEndCycle) self.parent.check_incoming_close_lease(self.request, reservation) self.waiting_for_close = False else: raise AuthorityException(Constants.INVALID_STATE)
def assign( self, *, reservation: ABCAuthorityReservation, delegation_name: str, graph_node: BaseSliver, existing_reservations: List[ABCReservationMixin]) -> ResourceSet: """ Assign a reservation :param reservation: reservation :param delegation_name: Name of delegation serving the request :param graph_node: ARM Graph Node serving the reservation :param existing_reservations: Existing Reservations served by the same ARM node :return: ResourceSet with updated sliver annotated with properties :raises: AuthorityException in case the request cannot be satisfied """ reservation.set_send_with_deficit(value=True) requested = reservation.get_requested_resources().get_sliver() self.__dump_sliver(sliver=requested) if not isinstance(requested, NetworkServiceSliver): raise AuthorityException( f"Invalid resource type {requested.get_type()}") current = reservation.get_resources() resource_type = ResourceType(resource_type=str(requested.get_type())) gained = None lost = None if current is None: self.logger.debug("check if sliver can be provisioned") # FIXME Add validation to check ticketed sliver against ARM # Refer Network Node Control for reference self.logger.debug( f"Slice properties: {reservation.get_slice().get_config_properties()}" ) unit = Unit( rid=reservation.get_reservation_id(), slice_id=reservation.get_slice_id(), actor_id=self.authority.get_guid(), sliver=requested, rtype=resource_type, properties=reservation.get_slice().get_config_properties()) gained = UnitSet(plugin=self.authority.get_plugin(), units={unit.reservation_id: unit}) else: # FIXME: handle modify self.logger.info( f"Extend Lease for now, no modify supported res# {reservation}" ) return current result = ResourceSet(gained=gained, lost=lost, rtype=resource_type) result.set_sliver(sliver=requested) return result
def correct_deficit(self, *, reservation: ABCAuthorityReservation): if reservation.get_resources() is not None: rc = self.get_control_by_type( rtype=reservation.get_resources().get_type()) if rc is not None: self.finish_correct_deficit( rset=rc.correct_deficit(reservation=reservation), reservation=reservation) else: raise AuthorityException( Constants.UNSUPPORTED_RESOURCE_TYPE.format( reservation.get_type()))
def handle_duplicate_request(self, *, operation: RequestTypes): # The general idea is to do nothing if we are in the process of # performing a pending operation or about to reissue a # ticket/extendTicket after recovery. If there is nothing pending for # this reservation, we resend the last update. if operation == RequestTypes.RequestRedeem or operation == RequestTypes.RequestExtendLease or \ operation == RequestTypes.RequestModifyLease: if self.pending_state == ReservationPendingStates.None_ and not self.bid_pending and \ not self.pending_recover: self.generate_update() else: raise AuthorityException( "Unsupported operation: {}".format(operation))
def configuration_complete(self, *, action: str, token: ConfigToken, out_properties: dict): super().configuration_complete(action=action, token=token, out_properties=out_properties) rc = self.get_control_by_type(rtype=token.get_resource_type()) if rc is not None: rc.configuration_complete(action=action, token=token, out_properties=out_properties) else: raise AuthorityException( Constants.UNSUPPORTED_RESOURCE_TYPE.format( token.get_resource_type()))
def __check_capacities(self, *, rid: ID, requested_capacities: Capacities, available_capacities: Capacities, existing_reservations: List[ABCReservationMixin]): """ Check if the allocated capacities by the broker can be assigned :param rid: reservation id :param requested_capacities: Requested capacities :param available_capacities: Available capacities :param existing_reservations: Existing Reservations served by the same ARM node :raises: AuthorityException in case the request cannot be satisfied """ self.logger.debug(f"available_capacities: {available_capacities}") self.logger.debug( f"requested_capacities: {requested_capacities} for reservation# {rid}" ) # Remove allocated capacities to the reservations if existing_reservations is not None: for reservation in existing_reservations: if reservation.get_reservation_id() == rid: continue # For Active or Ticketed or Ticketing reservations; reduce the counts from available resource_sliver = None if reservation.is_redeeming( ) and reservation.get_approved_resources() is not None: resource_sliver = reservation.get_approved_resources( ).get_sliver() if reservation.is_active() and reservation.get_resources( ) is not None: resource_sliver = reservation.get_resources().get_sliver() if resource_sliver is not None: self.logger.debug( f"Excluding already allocated resources " f"{resource_sliver.get_capacity_allocations()} to " f"reservation# {reservation.get_reservation_id()}") # Compare the requested against available available_capacities = available_capacities - resource_sliver.get_capacity_allocations( ) # Compare the requested against available available_capacities = available_capacities - requested_capacities negative_fields = available_capacities.negative_fields() if len(negative_fields) > 0: raise AuthorityException( f"Insufficient resources: {negative_fields}")
def redeem(self, *, reservation: ABCReservationMixin, callback: ABCControllerCallbackProxy = None, caller: AuthToken = None): if callback is None and caller is None: if not self.recovered: self.redeeming.add(reservation=reservation) else: self.wrapper.redeem_request(reservation=reservation, caller=reservation.get_client_auth_token(), callback=reservation.get_callback(), compare_sequence_numbers=False) else: if not self.is_recovered() or self.is_stopped(): raise AuthorityException(Constants.INVALID_ACTOR_STATE) if self.plugin.validate_incoming(reservation=reservation, auth=caller): self.wrapper.redeem_request(reservation=reservation, caller=caller, callback=callback, compare_sequence_numbers=True) else: self.logger.error("the redeem request is invalid") self.logger.debug("Completed processing Redeem Request")
def revisit(self, *, reservation: ABCReservationMixin): super().revisit(reservation=reservation) if isinstance(reservation, ABCAuthorityReservation): term = reservation.get_term() if term is None: term = reservation.get_requested_term() self.calendar.add_closing(reservation=reservation, cycle=self.get_close(term=term)) approved = reservation.get_approved_resources() if approved is None: self.logger.debug( "Reservation has no approved resources. Nothing is allocated to it." ) return rtype = approved.get_type() self.logger.debug( f"Resource type for recovered reservation: {rtype}") control = self.get_control_by_type(rtype=rtype) if control is None: raise AuthorityException("Missing resource control") control.revisit(reservation=reservation)
def assign( self, *, reservation: ABCAuthorityReservation, delegation_name: str, graph_node: BaseSliver, existing_reservations: List[ABCReservationMixin]) -> ResourceSet: """ Assign a reservation :param reservation: reservation :param delegation_name: Name of delegation serving the request :param graph_node: ARM Graph Node serving the reservation :param existing_reservations: Existing Reservations served by the same ARM node :return: ResourceSet with updated sliver annotated with properties :raises: AuthorityException in case the request cannot be satisfied """ if graph_node.capacity_delegations is None or reservation is None: raise AuthorityException(Constants.INVALID_ARGUMENT) delegated_capacities = graph_node.get_capacity_delegations() available_delegated_capacity = FimHelper.get_delegation( delegated_capacities=delegated_capacities, delegation_name=delegation_name) if available_delegated_capacity is None: raise AuthorityException( f"Allocated node {graph_node.node_id} does not have delegation: {delegation_name}" ) reservation.set_send_with_deficit(value=True) requested = reservation.get_requested_resources().get_sliver() if not isinstance(requested, NodeSliver): raise AuthorityException( f"Invalid resource type {requested.get_type()}") current = reservation.get_resources() resource_type = ResourceType(resource_type=str(requested.get_type())) gained = None lost = None if current is None: # Check if Capacities can be satisfied by Delegated Capacities self.__check_capacities( rid=reservation.get_reservation_id(), requested_capacities=requested.get_capacity_allocations(), available_capacities=available_delegated_capacity, existing_reservations=existing_reservations) # Check if Capacities can be satisfied by Capacities self.__check_capacities( rid=reservation.get_reservation_id(), requested_capacities=requested.get_capacity_allocations(), available_capacities=graph_node.get_capacities(), existing_reservations=existing_reservations) # Check components # Check if Components can be allocated if requested.attached_components_info is not None: self.__check_components( rid=reservation.get_reservation_id(), requested_components=requested.attached_components_info, graph_node=graph_node, existing_reservations=existing_reservations) self.logger.debug( f"Slice properties: {reservation.get_slice().get_config_properties()}" ) unit = Unit( rid=reservation.get_reservation_id(), slice_id=reservation.get_slice_id(), actor_id=self.authority.get_guid(), sliver=requested, rtype=resource_type, properties=reservation.get_slice().get_config_properties()) gained = UnitSet(plugin=self.authority.get_plugin(), units={unit.reservation_id: unit}) else: # FIX ME: handle modify self.logger.info( f"Extend Lease for now, no modify supported res# {reservation}" ) return current result = ResourceSet(gained=gained, lost=lost, rtype=resource_type) result.set_sliver(sliver=requested) return result
def relinquish(self, *, reservation: ABCReservationMixin, caller: AuthToken): if not self.is_recovered() or self.stopped: raise AuthorityException(Constants.INVALID_ACTOR_STATE) self.wrapper.relinquish_request(reservation=reservation, caller=caller)
def close_by_caller(self, *, reservation: ABCReservationMixin, caller: AuthToken): if not self.is_recovered() or self.is_stopped(): raise AuthorityException(Constants.INVALID_ACTOR_STATE) self.wrapper.close_request(reservation=reservation, caller=caller, compare_sequence_numbers=True)
def __check_components(self, *, rid: ID, requested_components: AttachedComponentsInfo, graph_node: BaseSliver, existing_reservations: List[ABCReservationMixin]): """ Check if the allocated components by the broker can be assigned :param rid: reservation id :param requested_components: Requested components :param graph_node: ARM Graph Node serving the reservation :param existing_reservations: Existing Reservations served by the same ARM node :raises: AuthorityException in case the request cannot be satisfied """ self.logger.debug( f"requested_components: {requested_components} for reservation# {rid}" ) for name, c in requested_components.devices.items(): node_map = c.get_node_map() if node_map is None: raise AuthorityException( f"Component of type: {c.get_type()} " f"does not have allocated BQM Node Id") resource_type = c.get_type() available_components = graph_node.attached_components_info.get_devices_by_type( resource_type=resource_type) self.logger.debug( f"Resource Type: {resource_type} available_components: {available_components}" ) if available_components is None or len(available_components) == 0: raise AuthorityException( f"Insufficient resources Component of type: {resource_type} not available " f"in graph node: {graph_node.node_id}") confirm_component = False for av in available_components: if node_map[1] == av.node_id: confirm_component = True break if not confirm_component: raise AuthorityException( f"Graph node: {graph_node.node_id} has no component: {node_map}" ) for reservation in existing_reservations: if reservation.get_reservation_id() == rid: continue # For Active or Ticketed or Ticketing reservations; reduce the counts from available allocated_sliver = None if reservation.is_redeeming( ) and reservation.get_approved_resources() is not None: allocated_sliver = reservation.get_approved_resources( ).get_sliver() if reservation.is_active() and reservation.get_resources( ) is not None: allocated_sliver = reservation.get_resources().get_sliver() if allocated_sliver is not None and allocated_sliver.attached_components_info is not None: allocated_components = allocated_sliver.attached_components_info.get_devices_by_type( resource_type=resource_type) self.logger.debug( f"Already allocated components {allocated_components} of resource_type " f"{resource_type} to reservation# {reservation.get_reservation_id()}" ) for ac in allocated_components: ac_node_map = ac.get_node_map() if ac_node_map[1] == node_map[1]: # For Shared NIC, make sure PCI devices are not same # For other components, having same node map is an error if (ac.get_type() == ComponentType.SharedNIC and ac.get_label_allocations().bdf == c.get_label_allocations()) or \ ac.get_type() != ComponentType.SharedNIC: raise AuthorityException( f"Component of type: {resource_type} BQM Node Id: {node_map[1]} " f"in graph {graph_node.node_id}" f"is already assigned to reservation# {reservation}" )
def extend(self, *, reservation: ABCReservationMixin, resources: ResourceSet, term: Term): raise AuthorityException(Constants.NOT_IMPLEMENTED)
def assign_reservation(self, *, reservation: ABCAuthorityReservation, node_id_to_reservations: dict): """ Assign resources for the given reservation @params reservation the request @params node_id_to_reservations node_id_to_reservations @returns a set of resources for the request @raises Exception in case of error """ requested = reservation.get_requested_resources() rtype = requested.get_type() rc = self.get_control_by_type(rtype=rtype) if rc is not None: try: ticketed_sliver = requested.get_sliver() node_id = ticketed_sliver.get_node_map()[1] self.logger.debug( f"node_id {node_id} serving reservation# {reservation}") if node_id is None: raise AuthorityException( f"Unable to find node_id {node_id} for reservation# {reservation}" ) graph_node = None if isinstance(ticketed_sliver, NodeSliver): graph_node = self.get_network_node_from_graph( node_id=node_id) elif isinstance(ticketed_sliver, NetworkServiceSliver): graph_node = self.get_network_service_from_graph( node_id=node_id) else: msg = f'Reservation {reservation} sliver type is neither Node, nor NetworkServiceSliver' self.logger.error(msg) raise AuthorityException(msg) self.logger.debug( f"Node {graph_node} serving reservation# {reservation}") existing_reservations = self.get_existing_reservations( node_id=node_id, node_id_to_reservations=node_id_to_reservations) delegation_name, broker_callback = self.get_delegation_name_and_callback( delegation_id=requested.get_resources().get_delegation_id( )) rset = rc.assign(reservation=reservation, delegation_name=delegation_name, graph_node=graph_node, existing_reservations=existing_reservations) if rset is None or rset.get_sliver( ) is None or rset.get_sliver().get_node_map() is None: raise AuthorityException( f"Could not assign resources to reservation# {reservation}" ) reservation.set_broker_callback( broker_callback=broker_callback) return rset except Exception as e: self.logger.error(traceback.format_exc()) self.logger.error(f"Could not assign {e}") return None else: raise AuthorityException( Constants.UNSUPPORTED_RESOURCE_TYPE.format( reservation.get_type()))
def remove(self, *, reservation: ABCReservationMixin): raise AuthorityException(Constants.NOT_IMPLEMENTED)