def reclaim_delegation_client(self, *, delegation_id: str = None, slice_object: ABCSlice = None, broker: ABCBrokerProxy = None, id_token: str = None) -> ABCDelegation: if delegation_id is None: raise BrokerException(error_code=ExceptionErrorCode.INVALID_ARGUMENT, msg="delegation_id") if broker is None: broker = self.get_default_broker() if slice_object is None: slice_object = self.get_default_slice() if slice_object is None: slice_object = SliceFactory.create(slice_id=ID(), name=self.identity.get_name()) slice_object.set_owner(owner=self.identity) slice_object.set_inventory(value=True) delegation = BrokerDelegationFactory.create(did=delegation_id, slice_id=slice_object.get_slice_id(), broker=broker) delegation.set_slice_object(slice_object=slice_object) delegation.set_exported(value=True) callback = ActorRegistrySingleton.get().get_callback(protocol=Constants.PROTOCOL_KAFKA, actor_name=self.get_name()) if callback is None: raise BrokerException(error_code=ExceptionErrorCode.NOT_SUPPORTED, msg="callback is None") delegation.prepare(callback=callback, logger=self.logger) delegation.validate_outgoing() self.wrapper.reclaim_delegation_request(delegation=delegation, caller=broker, callback=callback, id_token=id_token) return delegation
def __update_smart_nic_labels_and_capacities( self, *, available_component: ComponentSliver, requested_component: ComponentSliver) -> ComponentSliver: """ Update the IFS for the Smart NIC with VLAN, MAC and IP Address information This is to enable AM handler to configure network interfaces at VM creation. This is only done for Layer 2 services :param available_component: Available Component :param requested_component: Requested Component :return updated requested component with VLAN, MAC and IP information """ # Find the VLAN from the BQM Component if available_component.network_service_info is None or \ len(available_component.network_service_info.network_services) != 1: message = "Smart NIC Card must have at one Network Service" self.logger.error(message) raise BrokerException(error_code=ExceptionErrorCode.FAILURE, msg=f"{message}") ns_name = next( iter(available_component.network_service_info.network_services)) ns = available_component.network_service_info.network_services[ns_name] if ns.interface_info is None or len(ns.interface_info.interfaces) < 0: message = "Smart NIC Card must have at least one Connection Point" self.logger.error(message) raise BrokerException(error_code=ExceptionErrorCode.FAILURE, msg=f"{message}") for ifs in ns.interface_info.interfaces.values(): delegation_id, ifs_delegated_labels = self._get_delegations( lab_cap_delegations=ifs.get_label_delegations()) for requested_ns in requested_component.network_service_info.network_services.values( ): if requested_ns.interface_info is not None and requested_ns.interface_info.interfaces is not None: for requested_ifs in requested_ns.interface_info.interfaces.values( ): if requested_ifs.labels.local_name == ifs_delegated_labels.local_name: lab = Labels() lab.mac = ifs_delegated_labels.mac lab.local_name = ifs_delegated_labels.local_name # Update the VLAN and IP address to be used for configuration at AM only for L2 services # Information for L3 services is updated later after NetworkService has been ticketed if requested_ns.layer == NSLayer.L2: if requested_ifs.labels is not None and requested_ifs.labels.vlan is not None: lab.vlan = requested_ifs.labels.vlan if requested_ifs.labels.ipv4 is not None: lab.ipv4 = requested_ifs.labels.ipv4 if requested_ifs.labels.ipv6 is not None: lab.ipv6 = requested_ifs.labels.ipv6 requested_ifs.set_label_allocations(lab=lab) self.logger.info( f"Assigned Interface Sliver: {requested_ifs}") return requested_component
def demand(self, *, rid: ID): if rid is None: raise BrokerException(error_code=ExceptionErrorCode.INVALID_ARGUMENT, msg="rid") reservation = self.get_reservation(rid=rid) if reservation is None: raise BrokerException(error_code=ExceptionErrorCode.NOT_FOUND, msg=f"rid={rid}") self.policy.demand(reservation=reservation) reservation.set_policy(policy=self.policy)
def query(self, *, p: dict) -> dict: """ Returns the Broker Query Model @params p : dictionary containing filters (not used currently) """ result = {} self.logger.debug("Processing Query with properties: {}".format(p)) query_action = self.get_query_action(properties=p) query_level = p.get(Constants.QUERY_DETAIL_LEVEL, None) if query_level is not None: query_level = int(query_level) if query_action is None: raise BrokerException( error_code=ExceptionErrorCode.INVALID_ARGUMENT, msg=f"query_action {query_action}") if query_action != Constants.QUERY_ACTION_DISCOVER_BQM: raise BrokerException( error_code=ExceptionErrorCode.INVALID_ARGUMENT, msg=f"query_action {query_action}") bqm_format = p.get(Constants.BROKER_QUERY_MODEL_FORMAT, None) if bqm_format is not None: bqm_format = GraphFormat(int(bqm_format)) else: bqm_format = GraphFormat.GRAPHML try: self.lock.acquire() if self.combined_broker_model is not None: graph = self.combined_broker_model.get_bqm( query_level=query_level) graph_string = None if graph is not None: graph_string = graph.serialize_graph(format=bqm_format) if graph_string is not None: result[Constants.BROKER_QUERY_MODEL] = graph_string result[Constants.QUERY_RESPONSE_STATUS] = "True" else: result[Constants.BROKER_QUERY_MODEL] = "" result[Constants.QUERY_RESPONSE_STATUS] = "False" result[Constants. QUERY_RESPONSE_MESSAGE] = "Resource(s) not found" graph.delete_graph() except Exception as e: self.logger.error(traceback.format_exc()) self.logger.error(e) result[Constants.BROKER_QUERY_MODEL] = "" result[Constants.QUERY_RESPONSE_STATUS] = "False" result[Constants.QUERY_RESPONSE_MESSAGE] = str(e) finally: self.lock.release() self.logger.debug("Returning Query Result: {}".format(result)) return result
def unregister_client(self, *, guid: ID): database = self.plugin.get_database() try: database.get_client(guid=guid) except Exception as e: raise BrokerException(error_code=ExceptionErrorCode.NOT_FOUND, msg=f"client: {guid} e: {e}") try: database.remove_client(guid=guid) except Exception as e: raise BrokerException(error_code=ExceptionErrorCode.FAILURE, msg=f"client: {guid} e: {e}")
def register_client(self, *, client: Client): database = self.plugin.get_database() try: database.get_client(guid=client.get_guid()) except Exception as e: raise BrokerException(error_code=ExceptionErrorCode.NOT_FOUND, msg=f"client: {client.get_guid()} e: {e}") try: database.add_client(client=client) except Exception as e: raise BrokerException(error_code=ExceptionErrorCode.FAILURE, msg=f"client: {client.get_guid()} e: {e}")
def revisit_server(self, *, reservation: ABCBrokerReservation): """ Recovers a client reservation. @param reservation reservation to recover @throws Exception in case of error """ if reservation.get_state() == ReservationStates.Ticketed and \ (reservation.get_pending_state() == ReservationPendingStates.None_ or reservation.get_pending_state() == ReservationPendingStates.Priming): source = reservation.get_source() if source is None: raise BrokerException( msg=f"source delegation is None for res# {reservation}") self.calendar.add_outlay( source=source, client=reservation, start=reservation.get_term().get_new_start_time(), end=reservation.get_term().get_end_time()) self.calendar.add_closing( reservation=reservation, cycle=self.clock.cycle( when=reservation.get_term().get_end_time()))
def get_net_interface_sliver(self, *, site_ifs_id: str, itype: InterfaceType) -> InterfaceSliver: """ Get Peer Interface Sliver (child of Network Service Sliver) provided node id of Interface Sliver (child of Component Sliver) E.g: Provided Connection Point which is a child of Component i.e. renc-w3-nic2-p1, return Peer Connection Point i.e. HundredGigE 0/0/0/25.3 renc-w3-nic2-p1 => l10 <= HundredGigE 0/0/0/25.3 [Connection Point] Link [Connection Point] @param site_ifs_id Interface Sliver Id @param itype Interface Type @return Interface sliver """ try: self.lock.acquire() result = FimHelper.get_interface_sliver_by_id( ifs_node_id=site_ifs_id, graph=self.combined_broker_model, itype=itype) if len(result) != 1: raise BrokerException( msg= f"More than one Peer Interface Sliver of type {itype} found for " f"IFS: {site_ifs_id}") return next(iter(result)) finally: self.lock.release()
def __allocate_nodes( self, *, reservation: ABCBrokerReservation, inv: NetworkNodeInventory, sliver: NodeSliver, node_id_to_reservations: dict ) -> Tuple[str or None, BaseSliver, Any]: """ Allocate Network Node Slivers @param reservation Reservation @param inv Inventory @param sliver Requested sliver @param node_id_to_reservations @return tuple containing delegation id, sliver, error message if any """ delegation_id = None node_id_list = self.__candidate_nodes(sliver=sliver) # no candidate nodes found if len(node_id_list) == 0: error_msg = f'Insufficient resources: No candidates nodes found to serve {reservation}' self.logger.error(error_msg) return delegation_id, sliver, error_msg if self.get_algorithm_type().lower( ) == BrokerAllocationAlgorithm.FirstFit.name.lower(): return self.__find_first_fit( node_id_list=node_id_list, node_id_to_reservations=node_id_to_reservations, inv=inv, reservation=reservation) else: raise BrokerException( error_code=ExceptionErrorCode.NOT_SUPPORTED, msg=f"Broker currently only supports First Fit")
def issue_ticket(self, *, reservation: ABCBrokerReservation, units: int, rtype: ResourceType, term: Term, source: ABCDelegation, sliver: BaseSliver) -> ABCBrokerReservation: # make the new delegation resource_delegation = ResourceTicketFactory.create( issuer=self.actor.get_identity().get_guid(), units=units, term=term, rtype=rtype) # extract a new resource set mine = self.extract(source=source, delegation=resource_delegation) # attach the current request properties so that we can look at them in the future mine.set_sliver(sliver=sliver) if mine is not None and not reservation.is_failed(): reservation.set_approved(term=term, approved_resources=mine) reservation.set_source(source=source) self.logger.debug( f"allocated: {mine.get_units()} for term: {term}") self.logger.debug( f"resourceshare= {units} mine= {mine.get_units()}") self.add_to_calendar(reservation=reservation) reservation.set_bid_pending(value=False) else: if mine is None: raise BrokerException( msg= "There was an error extracting a ticket from the source delegation" ) return reservation
def get_client(self, *, guid: ID) -> Client: database = self.plugin.get_database() ret_val = None try: ret_val = database.get_client(guid=guid) except Exception as e: raise BrokerException(error_code=ExceptionErrorCode.NOT_FOUND, msg=f"client: {guid} e: {e}") return ret_val
def get_renew(self, *, reservation: ABCClientReservation) -> int: """ Returns the cycle when the reservation must be renewed. @param reservation reservation for which to calculate renew time @return renew cycle @throws Exception in case of error """ raise BrokerException(error_code=ExceptionErrorCode.NOT_IMPLEMENTED)
def __exclude_allocated_pci_device_from_shared_nic( self, shared_nic: ComponentSliver, allocated_nic: ComponentSliver) -> Tuple[ComponentSliver, bool]: """ For Shared NIC cards, exclude the already assigned PCI addresses from the available PCI addresses in BQM Component Sliver for the NIC Card @param shared_nic: Available Shared NIC @param allocated_nic: Allocated NIC @return Available NIC updated to exclude the Allocated PCI addresses and True/False indicating if Available Shared NIC has any available PCI addresses """ if shared_nic.get_type( ) != ComponentType.SharedNIC and allocated_nic.get_type( ) != ComponentType.SharedNIC: raise BrokerException( error_code=ExceptionErrorCode.INVALID_ARGUMENT, msg=f"shared_nic: {shared_nic} allocated_nic: {allocated_nic}") # Reduce capacity for component delegation_id, delegated_capacity = self._get_delegations( lab_cap_delegations=shared_nic.get_capacity_delegations()) self.logger.debug( f"Allocated NIC: {allocated_nic} labels: {allocated_nic.get_label_allocations()}" ) # Get the Allocated PCI address allocated_labels = allocated_nic.get_label_allocations() delegation_id, delegated_label = self._get_delegations( lab_cap_delegations=shared_nic.get_label_delegations()) # Remove allocated PCI address from delegations excluded_labels = [] if isinstance(allocated_labels.bdf, list): excluded_labels = allocated_labels.bdf else: excluded_labels = [allocated_labels.bdf] exists = False for e in excluded_labels: if e in delegated_label.bdf: self.logger.debug(f"Excluding PCI device {e}") delegated_label.bdf.remove(e) exists = True # Exclude already allocated Shared NIC cards if exists: delegated_capacity -= allocated_nic.get_capacity_allocations() return shared_nic, (delegated_capacity.unit < 1)
def __check_capacities( self, *, rid: ID, requested_capacities: Capacities, delegated_capacities: Delegations, existing_reservations: List[ABCReservationMixin]) -> str or None: """ Check if the requested capacities can be satisfied with the available capacities :param rid: reservation id of the reservation being served :param requested_capacities: Requested Capacities :param delegated_capacities: Delegated Capacities :param existing_reservations: Existing Reservations served by the same BQM node :return: Delegation Id of the delegation which satisfies the request :raises: BrokerException in case the request cannot be satisfied """ self.logger.debug( f"requested_capacities: {requested_capacities} for reservation# {rid}" ) delegation_id, delegated_capacity = self._get_delegations( lab_cap_delegations=delegated_capacities) # Remove allocated capacities to the reservations if existing_reservations is not None: for reservation in existing_reservations: if rid == reservation.get_reservation_id(): continue # For Active or Ticketed or Ticketing reservations; reduce the counts from available resource_sliver = None if reservation.is_ticketing( ) and reservation.get_approved_resources() is not None: resource_sliver = reservation.get_approved_resources( ).get_sliver() if (reservation.is_active() or reservation.is_ticketed()) and \ reservation.get_resources() is not None: resource_sliver = reservation.get_resources().get_sliver() if resource_sliver is not None and isinstance( resource_sliver, NodeSliver): self.logger.debug( f"Excluding already assigned resources {resource_sliver.get_capacity_allocations()} to " f"reservation# {reservation.get_reservation_id()}") delegated_capacity = delegated_capacity - resource_sliver.get_capacity_allocations( ) # Compare the requested against available delegated_capacity = delegated_capacity - requested_capacities negative_fields = delegated_capacity.negative_fields() if len(negative_fields) > 0: raise BrokerException( error_code=ExceptionErrorCode.INSUFFICIENT_RESOURCES, msg=f"{negative_fields}") return delegation_id
def __check_component_labels_and_capacities( self, *, available_component: ComponentSliver, graph_id: str, requested_component: ComponentSliver) -> ComponentSliver: """ Check if available component capacities, labels to match requested component :param available_component: available component :param graph_id: BQM graph id :param requested_component: requested component :return: requested component annotated with properties in case of success, None otherwise """ if requested_component.get_model() is not None and \ requested_component.get_model() != available_component.get_model(): return requested_component # Checking capacity for component delegation_id, delegated_capacity = self._get_delegations( lab_cap_delegations=available_component.get_capacity_delegations()) # Delegated capacity would have been decremented already to exclude allocated shared NICs if delegated_capacity.unit < 1: message = f"Insufficient Capacities for component: {requested_component}" self.logger.error(message) raise BrokerException( error_code=ExceptionErrorCode.INSUFFICIENT_RESOURCES, msg=f"{message}") requested_component.capacity_allocations = Capacities(unit=1) # Check labels delegation_id, delegated_label = self._get_delegations( lab_cap_delegations=available_component.get_label_delegations()) if requested_component.get_type() == ComponentType.SharedNIC: requested_component = self.__update_shared_nic_labels_and_capacities( available_component=available_component, requested_component=requested_component) else: requested_component.label_allocations = delegated_label if requested_component.get_type() == ComponentType.SmartNIC: requested_component = self.__update_smart_nic_labels_and_capacities( available_component=available_component, requested_component=requested_component) node_map = tuple([graph_id, available_component.node_id]) requested_component.set_node_map(node_map=node_map) return requested_component
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.RequestTicket: if self.pending_state == ReservationPendingStates.None_ and self.state != ReservationStates.Nascent and \ not self.pending_recover: self.generate_update() elif operation == RequestTypes.RequestExtendTicket: if self.pending_state == ReservationPendingStates.None_ and not self.pending_recover: self.generate_update() elif operation == RequestTypes.RequestRelinquish: self.logger.debug("no op") else: raise BrokerException( error_code=ExceptionErrorCode.NOT_SUPPORTED, msg=f"operation {RequestTypes(operation).name}")
def claim_delegation_client(self, *, delegation_id: str = None, slice_object: ABCSlice = None, broker: ABCBrokerProxy = None, id_token: str = None) -> ABCDelegation: if delegation_id is None: raise BrokerException(error_code=ExceptionErrorCode.INVALID_ARGUMENT, msg="delegation_id") if broker is None: broker = self.get_default_broker() if slice_object is None: slice_object = self.get_default_slice() if slice_object is None: slice_object = SliceFactory.create(slice_id=ID(), name=self.identity.get_name()) slice_object.set_owner(owner=self.identity) slice_object.set_inventory(value=True) delegation = BrokerDelegationFactory.create(did=delegation_id, slice_id=slice_object.get_slice_id(), broker=broker) delegation.set_exported(value=True) delegation.set_slice_object(slice_object=slice_object) self.wrapper.delegate(delegation=delegation, destination=self, id_token=id_token) return delegation
def extend_ticket(self, *, reservation: ABCReservationMixin, caller: AuthToken): if not self.recovered or self.is_stopped(): raise BrokerException(error_code=ExceptionErrorCode.UNEXPECTED_STATE, msg="of actor") self.wrapper.extend_ticket_request(reservation=reservation, caller=caller, compare_sequence_numbers=True)
def recover(self): """ Recover the reservation post stateful restart """ if isinstance(self.policy, ABCAuthorityPolicy): self.logger.debug( "No recovery necessary for reservation #{}".format( self.get_reservation_id())) return if not isinstance(self.policy, ABCBrokerPolicyMixin): raise BrokerException( msg=f"Do not know how to recover: policy={self.policy}") if self.state == ReservationStates.Nascent: if self.pending_state == ReservationPendingStates.None_: self.actor.ticket(self) self.logger.info( "Added reservation #{} to the ticketing list. State={}". format(self.get_reservation_id(), self.print_state())) elif self.pending_state == ReservationPendingStates.Ticketing: self.set_pending_recover(pending_recover=True) self.transition(prefix="[recovery]", state=self.state, pending=ReservationPendingStates.None_) self.actor.ticket(self) self.logger.info( "Added reservation #{} to the ticketing list. State={}". format(self.get_reservation_id(), self.print_state())) else: raise BrokerException( error_code=ExceptionErrorCode.UNEXPECTED_STATE, msg=f"pending_state={self.pending_state}") elif self.state == ReservationStates.Ticketed: if self.pending_state == ReservationPendingStates.None_ or \ self.pending_state == ReservationPendingStates.Priming: self.set_service_pending(code=ReservationPendingStates.None_) self.logger.debug( "No recovery necessary for reservation #{}".format( self.get_reservation_id())) elif self.pending_state == ReservationPendingStates.ExtendingTicket: self.set_pending_recover(pending_recover=True) self.transition(prefix="[recovery]", state=self.state, pending=ReservationPendingStates.None_) self.actor.extend_ticket(reservation=self) self.logger.info( "Added reservation #{} to the extending list. State={}". format(self.get_reservation_id(), self.print_state())) else: raise BrokerException( error_code=ExceptionErrorCode.UNEXPECTED_STATE, msg=f"pending_state={self.pending_state}") elif self.state == ReservationStates.Failed: self.logger.warning("Reservation #{} has failed".format( self.get_reservation_id())) else: raise BrokerException( error_code=ExceptionErrorCode.UNEXPECTED_STATE, msg=f"state={self.state}")
def __allocate_services( self, *, rid: ID, inv: NetworkServiceInventory, sliver: NetworkServiceSliver, node_id_to_reservations: dict) -> Tuple[str, BaseSliver, Any]: """ Allocate Network Service Slivers @param rid Reservation Id @param inv Inventory @param sliver Requested sliver @param node_id_to_reservations @return tuple containing delegation id, sliver, error message if any """ self.logger.debug(f"Processing Network Service sliver: {sliver}") delegation_id = None error_msg = None owner_switch = None owner_mpls_ns = None # For each Interface Sliver; for ifs in sliver.interface_info.interfaces.values(): # Fetch Network Node Id and BQM Component Id node_id, bqm_component_id = ifs.get_node_map() bqm_component = self.get_component_sliver(node_id=bqm_component_id) # Get BQM Connection Point in Site Delegation (c) site_cp = FimHelper.get_site_interface_sliver( component=bqm_component, local_name=ifs.get_labels().local_name) self.logger.debug( f"Interface Sliver [Site Delegation] (C): {site_cp}") # Get BQM Peer Connection Point in Site Delegation (a) net_cp = self.get_net_interface_sliver( site_ifs_id=site_cp.node_id, itype=InterfaceType.TrunkPort) if net_cp is None: error_msg = "Peer Connection Point not found from Network AM" raise BrokerException(msg=error_msg) self.logger.debug( f"Peer Interface Sliver [Network Delegation] (A): {site_cp}") # need to find the owner switch of the network service in CBM and take it's name or labels.local_name owner_switch, owner_mpls_ns = self.get_owners( node_id=net_cp.node_id) if bqm_component.get_type() == ComponentType.SharedNIC: # VLAN is already set by the Orchestrator using the information from the Node Sliver Parent Reservation if ifs.get_labels().vlan is None: message = "Shared NIC VLAN cannot be None" self.logger.error(message) raise BrokerException( error_code=ExceptionErrorCode.FAILURE, msg=f"{message}") else: existing_reservations = self.get_existing_reservations( node_id=owner_mpls_ns.node_id, node_id_to_reservations=node_id_to_reservations) # Set vlan - source: (c) - only for dedicated NICs ifs = inv.allocate_ifs( requested_ns=sliver, requested_ifs=ifs, owner_switch=owner_switch, mpls_ns=owner_mpls_ns, bqm_ifs_id=net_cp.node_id, existing_reservations=existing_reservations) # local_name source: (a) ifs_labels = ifs.get_labels() ifs_labels = Labels.update(ifs_labels, local_name=net_cp.get_name()) # NSO device name source: (a) - need to find the owner switch of the network service in CBM # and take its name or labels.local_name # Set the NSO device-name ifs_labels = Labels.update(ifs_labels, device_name=owner_switch.get_name()) adm_ids = owner_switch.get_structural_info().adm_graph_ids site_adm_ids = bqm_component.get_structural_info().adm_graph_ids self.logger.debug(f"Owner MPLS Network Service: {owner_mpls_ns}") self.logger.debug(f"Owner Switch: {owner_switch}") self.logger.debug( f"Owner Switch: {owner_switch.network_service_info}") net_adm_ids = [ x for x in adm_ids if not x in site_adm_ids or site_adm_ids.remove(x) ] if len(net_adm_ids) != 1: error_msg = f"More than 1 or 0 Network Delegations found! net_adm_ids: {net_adm_ids}" self.logger.error(error_msg) raise BrokerException(msg=error_msg) # Update the Interface Sliver Node Map to map to (a) ifs.set_node_map(node_map=(self.combined_broker_model_graph_id, net_cp.node_id)) delegation_id = net_adm_ids[0] ifs.labels = ifs_labels self.logger.debug( f"Allocated Interface Sliver: {ifs} delegation: {delegation_id}" ) # Update the Network Service Sliver Node Map to map to parent of (a) sliver.set_node_map(node_map=(self.combined_broker_model_graph_id, owner_mpls_ns.node_id)) # Set the Subnet and gateway from the Owner Switch (a) if sliver.get_type() == ServiceType.FABNetv6 or sliver.get_type( ) == ServiceType.FABNetv4: existing_reservations = self.get_existing_reservations( node_id=owner_mpls_ns.node_id, node_id_to_reservations=node_id_to_reservations) sliver = inv.allocate(rid=rid, requested_ns=sliver, owner_switch=owner_switch, existing_reservations=existing_reservations) return delegation_id, sliver, error_msg
def ticket_inventory( self, *, reservation: ABCBrokerReservation, inv: InventoryForType, term: Term, node_id_to_reservations: dict) -> Tuple[bool, dict, Any]: error_msg = None try: rset = reservation.get_requested_resources() needed = rset.get_units() # for network node slivers # find a list of candidate worker nodes that satisfy the requirements based on delegated # capacities within the site # for network link slivers # orchestrator needs to provide a map to CBM guid of the node representing the # intended link (and possibly interfaces connected to it) res_sliver = rset.get_sliver() delegation_id = None sliver = None if isinstance(res_sliver, NodeSliver): delegation_id, sliver, error_msg = self.__allocate_nodes( reservation=reservation, inv=inv, sliver=res_sliver, node_id_to_reservations=node_id_to_reservations) elif isinstance(res_sliver, NetworkServiceSliver): delegation_id, sliver, error_msg = self.__allocate_services( rid=reservation.get_reservation_id(), inv=inv, sliver=res_sliver, node_id_to_reservations=node_id_to_reservations) else: self.logger.error( f'Reservation {reservation} sliver type is neither Node, nor NetworkServiceSliver' ) raise BrokerException( msg=f"Reservation sliver type is neither Node " f"nor NetworkLink for reservation# {reservation}") if delegation_id is not None: delegation = self.actor.get_delegation(did=delegation_id) reservation = self.issue_ticket(reservation=reservation, units=needed, rtype=rset.get_type(), term=term, source=delegation, sliver=sliver) node_map = sliver.get_node_map() node_id = node_map[1] if node_id_to_reservations.get(node_id, None) is None: node_id_to_reservations[node_id] = ReservationSet() node_id_to_reservations[node_id].add(reservation=reservation) return True, node_id_to_reservations, error_msg except Exception as e: self.logger.error(traceback.format_exc()) self.logger.error(e) reservation.fail(message=str(e)) return False, node_id_to_reservations, error_msg
def relinquish(self, *, reservation: ABCReservationMixin, caller: AuthToken): if not self.is_recovered() or self.is_stopped(): raise BrokerException(error_code=ExceptionErrorCode.UNEXPECTED_STATE, msg="of actor") self.wrapper.relinquish_request(reservation=reservation, caller=caller)
def ticket(self, *, reservation: ABCReservationMixin, callback: ABCClientCallbackProxy, caller: AuthToken): if not self.is_recovered() or self.is_stopped(): raise BrokerException(error_code=ExceptionErrorCode.UNEXPECTED_STATE, msg="of actor") self.wrapper.ticket_request(reservation=reservation, caller=caller, callback=callback, compare_seq_numbers=True)
def allocate( self, *, rid: ID, requested_sliver: BaseSliver, graph_id: str, graph_node: BaseSliver, existing_reservations: List[ABCReservationMixin] ) -> Tuple[str, BaseSliver]: """ Allocate an extending or ticketing reservation :param rid: reservation id of the reservation to be allocated :param requested_sliver: requested sliver :param graph_id: BQM graph id :param graph_node: BQM graph node identified to serve the reservation :param existing_reservations: Existing Reservations served by the same BQM node :return: Tuple of Delegation Id and the Requested Sliver annotated with BQM Node Id and other properties :raises: BrokerException in case the request cannot be satisfied """ if graph_node.get_capacity_delegations() is None or rid is None: raise BrokerException( error_code=Constants.INVALID_ARGUMENT, msg=f"capacity_delegations is missing or reservation is None") if not isinstance(requested_sliver, NodeSliver): raise BrokerException( error_code=Constants.INVALID_ARGUMENT, msg=f"resource type: {requested_sliver.get_type()}") if not isinstance(graph_node, NodeSliver): raise BrokerException( error_code=Constants.INVALID_ARGUMENT, msg=f"resource type: {graph_node.get_type()}") # Always use requested capacities to be mapped from flavor i.e. capacity hints requested_capacity_hints = requested_sliver.get_capacity_hints() catalog = InstanceCatalog() requested_capacities = catalog.get_instance_capacities( instance_type=requested_capacity_hints.instance_type) # Check if Capacities can be satisfied delegation_id = self.__check_capacities( rid=rid, requested_capacities=requested_capacities, delegated_capacities=graph_node.get_capacity_delegations(), existing_reservations=existing_reservations) # Check if Components can be allocated if requested_sliver.attached_components_info is not None: requested_sliver.attached_components_info = self.__check_components( rid=rid, requested_components=requested_sliver.attached_components_info, graph_id=graph_id, graph_node=graph_node, existing_reservations=existing_reservations) requested_sliver.capacity_allocations = Capacities() requested_sliver.capacity_allocations = Labels.update( lab=requested_capacities) requested_sliver.label_allocations = Labels( instance_parent=graph_node.get_name()) requested_sliver.set_node_map(node_map=(graph_id, graph_node.node_id)) self.logger.info( f"Reservation# {rid} is being served by delegation# {delegation_id} " f"node# [{graph_id}/{graph_node.node_id}]") return delegation_id, requested_sliver
def __update_shared_nic_labels_and_capacities( self, *, available_component: ComponentSliver, requested_component: ComponentSliver) -> ComponentSliver: """ Update the shared NIC Labels and Capacities. Assign the 1st available PCI address/bdf to the requested component Traverse the available component's labels to find the index for bdf assigned Using the found labels, assign BDF, MAC and VLAN address to the IFS on the Requested component In case of L2 service, also copy the requested IP address so it can be used by the AMHandler to configure the interface post VM creation :param available_component: Available Component :param requested_component: Requested Component :return updated requested component with VLAN, MAC and IP information """ # Check labels delegation_id, delegated_label = self._get_delegations( lab_cap_delegations=available_component.get_label_delegations()) if delegated_label.bdf is None or len(delegated_label.bdf) < 1: message = "No PCI devices available in the delegation" self.logger.error(message) raise BrokerException( error_code=ExceptionErrorCode.INSUFFICIENT_RESOURCES, msg=f"{message}") # Assign the first PCI Id from the list of available PCI slots requested_component.label_allocations = Labels( bdf=delegated_label.bdf[0]) # Find the VLAN from the BQM Component if available_component.network_service_info is None or \ len(available_component.network_service_info.network_services) != 1: message = "Shared NIC Card must have one Network Service" self.logger.error(message) raise BrokerException(error_code=ExceptionErrorCode.FAILURE, msg=f"{message}") ns_name = next( iter(available_component.network_service_info.network_services)) ns = available_component.network_service_info.network_services[ns_name] if ns.interface_info is None or len(ns.interface_info.interfaces) != 1: message = "Shared NIC Card must have one Connection Point" self.logger.error(message) raise BrokerException(error_code=ExceptionErrorCode.FAILURE, msg=f"{message}") ifs_name = next(iter(ns.interface_info.interfaces)) ifs = ns.interface_info.interfaces[ifs_name] delegation_id, ifs_delegated_labels = self._get_delegations( lab_cap_delegations=ifs.get_label_delegations()) # Determine the index which points to the same PCI id as assigned above # This index points to the other relevant information such as MAC Address, # VLAN tag for that PCI device i = 0 for pci_id in ifs_delegated_labels.bdf: if pci_id == delegated_label.bdf[0]: break i += 1 # Updated the Requested component with VLAN, BDF, MAC req_ns_name = next( iter(requested_component.network_service_info.network_services)) req_ns = requested_component.network_service_info.network_services[ req_ns_name] req_ifs_name = next(iter(req_ns.interface_info.interfaces)) req_ifs = req_ns.interface_info.interfaces[req_ifs_name] lab = Labels(bdf=ifs_delegated_labels.bdf[i], mac=ifs_delegated_labels.mac[i], vlan=ifs_delegated_labels.vlan[i], local_name=ifs_delegated_labels.local_name[i]) # For the Layer 2 copying the IP address to the label allocations # This is to be used by AM Handler to configure Network Interface if req_ns.layer == NSLayer.L2: if req_ifs.labels is not None and req_ifs.labels.ipv4 is not None: lab.ipv4 = req_ifs.labels.ipv4 if req_ifs.labels is not None and req_ifs.labels.ipv6 is not None: lab.ipv6 = req_ifs.labels.ipv6 req_ifs.set_label_allocations(lab=lab) self.logger.info(f"Assigned Interface Sliver: {req_ifs}") return requested_component
def update_lease(self, *, reservation: ABCReservationMixin, update_data, caller: AuthToken): if not self.is_recovered() or self.is_stopped(): raise BrokerException("This actor cannot receive calls") self.wrapper.update_lease(reservation=reservation, update_data=update_data, caller=caller)
def __check_components( self, *, rid: ID, requested_components: AttachedComponentsInfo, graph_id: str, graph_node: NodeSliver, existing_reservations: List[ABCReservationMixin] ) -> AttachedComponentsInfo: """ Check if the requested capacities can be satisfied with the available capacities :param rid: reservation id of the reservation being served :param requested_components: Requested components :param graph_id: BQM graph id :param graph_node: BQM graph node identified to serve the reservation :param existing_reservations: Existing Reservations served by the same BQM node :return: Components updated with the corresponding BQM node ids :raises: BrokerException in case the request cannot be satisfied """ self.__exclude_components_for_existing_reservations( rid=rid, graph_node=graph_node, existing_reservations=existing_reservations) self.logger.debug( f"requested_components: {requested_components.devices.values()} for reservation# {rid}" ) for name, requested_component in requested_components.devices.items(): self.logger.debug( f"==========Allocating component: {requested_component}") resource_type = requested_component.get_type() available_components = graph_node.attached_components_info.get_devices_by_type( resource_type=resource_type) self.logger.debug( f"available_components after excluding allocated components: {available_components}" ) if available_components is None or len(available_components) == 0: raise BrokerException( error_code=ExceptionErrorCode.INSUFFICIENT_RESOURCES, msg=f"Component of type: {resource_type} not available in " f"graph node: {graph_node.node_id}") for component in available_components: # check model matches the requested model requested_component = self.__check_component_labels_and_capacities( available_component=component, graph_id=graph_id, requested_component=requested_component) if requested_component.get_node_map() is not None: self.logger.info( f"Assigning {component.node_id} to component# " f"{requested_component} in reservation# {rid} ") # Remove the component from available components as it is assigned self.__exclude_allocated_component( graph_node=graph_node, available_component=component, allocated_component=requested_component) break if requested_component.get_node_map() is None: raise BrokerException( error_code=ExceptionErrorCode.INSUFFICIENT_RESOURCES, msg=f"Component of type: {resource_type} not available in " f"graph node: {graph_node.node_id}") return requested_components
def update_ticket(self, *, reservation: ABCReservationMixin, update_data, caller: AuthToken): if not self.is_recovered() or self.is_stopped(): raise BrokerException(error_code=ExceptionErrorCode.UNEXPECTED_STATE, msg="of actor") self.wrapper.update_ticket(reservation=reservation, update_data=update_data, caller=caller)
def update_delegation(self, *, delegation: ABCDelegation, update_data, caller: AuthToken): if not self.is_recovered() or self.is_stopped(): raise BrokerException(error_code=ExceptionErrorCode.UNEXPECTED_STATE, msg="of actor") self.wrapper.update_delegation(delegation=delegation, update_data=update_data, caller=caller)
def __init__(self): if self.__instance is not None: raise BrokerException(msg="Singleton can't be created twice !")