def map_shrinking(self, *, bids: ReservationSet): """ Maps reservations that are shrinking or staying the same (extending with no flex) in this cycle, and removes them from the bid set. @param bids set of deferred operations for this cycle (non-null) @raises Exception in case of error """ # self.logger.debug("Processing shrinking requests") rids_to_remove = [] node_id_to_reservations = {} for reservation in bids.values(): adjust = reservation.get_deficit() if adjust > 0: continue if not reservation.is_terminal( ) and reservation.is_extending_lease(): if adjust < 0: self.logger.debug( f"**Shrinking reservation by {adjust}:{reservation}") else: self.logger.debug( f"**Extending reservation (no flex): {reservation}") node_id_to_reservations = self.map( reservation=reservation, node_id_to_reservations=node_id_to_reservations) rids_to_remove.append(reservation.get_reservation_id()) for rid in rids_to_remove: bids.remove_by_rid(rid=rid)
def map_growing(self, *, bids: ReservationSet): """ Maps reservations that are growing in this cycle (redeems or expanding extends), and removes them from the bid set. @param bids set of deferred operations for this cycle (non-null) @throws Exception in case of error """ # self.logger.debug("Processing growing requests") rids_to_remove = [] node_id_to_reservations = {} for reservation in bids.values(): if reservation.is_terminal(): continue adjust = reservation.get_deficit() if adjust > 0: if reservation.is_extending_lease(): self.logger.debug( f"**Growing reservation by {adjust}:{reservation}") else: self.logger.debug( f"**Redeeming reservation by {adjust}:{reservation}") node_id_to_reservations = self.map( reservation=reservation, node_id_to_reservations=node_id_to_reservations) rids_to_remove.append(reservation.get_reservation_id()) for rid in rids_to_remove: bids.remove_by_rid(rid=rid)
def __init__(self): # List of reservation wrappers sorted by increasing end time. self.list = [] # All reservations stored in this collection. self.reservation_set = ReservationSet() # Map of reservations to ReservationWrappers. Needed when removing a reservation. self.map = {}
def __init__(self, *, slice_id: ID = None, name: str = "unspecified"): # Globally unique identifier. self.guid = slice_id # Slice name. Not required to be globally or locally unique. self.name = name # Description string. Has only local meaning. self.description = "no description" # The slice type: inventory or client. self.type = SliceTypes.ClientSlice # The owner of the slice. self.owner = None # Resource type associated with this slice. Used when the slice is used to # represent an inventory pool. self.resource_type = None # The reservations in this slice. self.reservations = ReservationSet() self.delegations = {} # Neo4jGraph Id self.graph_id = None self.graph = None self.state_machine = SliceStateMachine(slice_id=slice_id) self.dirty = False self.config_properties = None self.lock = threading.Lock() self.lease_end = None self.lease_start = None
def __setstate__(self, state): self.__dict__.update(state) self.logger = None self.actor = None self.clock = None self.initialized = False self.pending_notify = ReservationSet() self.lazy_close = False self.pending_redeem = ReservationSet()
def __init__(self, *, identity: AuthToken = None, clock: ActorClock = None): super().__init__(auth=identity, clock=clock) # Recovered reservations that need to obtain tickets (both server and client roles). self.ticketing = ReservationSet() # Recovered reservations that need to extend tickets (both server and client roles). self.extending = ReservationSet() # The peer registry. self.registry = PeerRegistry() # Initialization status. self.initialized = False self.type = ActorType.Broker
def get_closing(self, *, cycle: int) -> ReservationSet: closing = self.calendar.get_closing(cycle=cycle) result = ReservationSet() for reservation in closing.values(): if not reservation.is_failed(): self.calendar.add_pending(reservation=reservation) result.add(reservation=reservation) else: self.logger.warning( "Removing failed reservation from the closing list: {}". format(reservation)) return result
def count(self, *, rvset: ReservationSet, when: datetime): """ Returns a counter for the passed set and the specified data. @param rvset the set of reservations being counted @param when the date when to count the resources @return counter """ rc = ResourceCount() rvset.count(rc=rc, when=when) return rc
def __init__(self): super().__init__() # calendar self.calendar = None # Contains reservations for which we may have completed performing # bookkeeping actions but may need to wait for some other event to take # place before we raise the corresponding event. self.pending_notify = ReservationSet() # If the actor is initialized self.initialized = False # If true, the orchestrator will close reservations lazily: it will not # issue a close and will wait until the site terminates the lease. The # major drawback is that leave actions will not be able to connect to the # resources, since the resources will not exist at this time. self.lazy_close = False
def get_all_reservations(self, *, cycle: int) -> ReservationSet: """ Returns all reservations associated with cycles up to and including the specified cycle @params cycle : cycle @returns a set of reservations associated with the cycles up to and including specified cycle. Note that removing from the set will not affect the ReservationList """ result = ReservationSet() for entry in self.rset_wrapper_list: if entry.cycle <= cycle: for reservation in entry.reservation_set.values(): result.add(reservation=reservation) else: break return result
def extend_lease(self, *, reservation: ABCControllerReservation = None, rset: ReservationSet = None): if reservation is not None and rset is not None: raise ControllerException( "Invalid Arguments: reservation and rset can not be both not None" ) if reservation is None and rset is None: raise ControllerException( "Invalid Arguments: reservation and rset can not be both None") if reservation is not None: self.extend_lease_reservation(reservation=reservation) if rset is not None: for r in rset.values(): try: if isinstance(r, ABCControllerReservation): self.extend_lease_reservation(reservation=r) else: self.logger.warning( "Reservation #{} cannot extendLease".format( r.get_reservation_id())) except Exception as e: self.logger.error( "Could not extend_lease for #{} e={}".format( r.get_reservation_id(), e))
def map(self, *, reservation: ABCAuthorityReservation, node_id_to_reservations: dict) -> dict: """ Maps a reservation. Indicates we will approve the request: update its expire time in the calendar, and issue a map probe. The map probe will result in a retry of the mapper request through bind or extend above, which will release the request to the associated mapper. @param reservation: the reservation @param node_id_to_reservations: node_id_to_reservations @throws Exception in case of error """ assigned = self.assign_reservation( reservation=reservation, node_id_to_reservations=node_id_to_reservations) if assigned is not None: approved = reservation.get_requested_term() reservation.set_approved(term=approved, approved_resources=assigned) reservation.set_bid_pending(value=False) node_id = assigned.get_sliver().get_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) else: if not reservation.is_terminal(): self.logger.debug( f"Deferring reservation {reservation} for the next cycle: " f"{self.actor.get_current_cycle() + 1}") self.reschedule(reservation=reservation) return node_id_to_reservations
def allocate_ticketing(self, *, requests: ReservationSet): if requests is not None: # Holds the Node Id to List of Reservation Ids allocated # This is used to check on the reservations allocated during this cycle to compute available resources # as the reservations are not updated in the database yet node_id_to_reservations = {} for reservation in requests.values(): if not reservation.is_ticketing(): continue status, node_id_to_reservations, error_msg = self.ticket( reservation=reservation, node_id_to_reservations=node_id_to_reservations) if status: continue if self.queue is None and not reservation.is_failed(): fail_message = "Insufficient resources" if error_msg is not None: fail_message = error_msg reservation.fail(message=fail_message) continue if not reservation.is_failed(): fail_message = f"Insufficient resources for specified start time, Failing reservation: " \ f"{reservation.get_reservation_id()}" if error_msg is not None: fail_message = error_msg reservation.fail(message=fail_message)
def __init__(self, *, auth: AuthToken = None, clock: ActorClock = None): # Globally unique identifier for this actor. self.guid = ID() # Actor name. self.name = None # Actor type code. self.type = ActorType.All # Actor description. self.description = self.DefaultDescription # Identity object representing this actor. self.identity = auth # Actor policy object. self.policy = None # Actor plugin self.plugin = None # True if this actor has completed the recovery phase. self.recovered = False # The kernel wrapper. self.wrapper = None # logger self.logger = None # Factory for term. self.clock = clock # current cycle self.current_cycle = -1 # True if the current tick is the first tick this actor has received. self.first_tick = True # Set to true when the actor is stopped. self.stopped = False # Initialization status. self.initialized = False # Contains a reference to the thread currently executing the timer handler. # This field is set at the entry to and clear at the exit. # The primary use of the field is to handle correctly stopping the actor. self.thread = None # A queue of timers that have fired and need to be processed. self.timer_queue = queue.Queue() self.event_queue = queue.Queue() self.reservation_tracker = None self.subscription_id = None # Reservations to close once recovery is complete. self.closing = ReservationSet() self.thread_lock = threading.Lock() self.actor_main_lock = threading.Condition() self.message_service = None
def __init__(self, *, clock: ActorClock): """ Constructor @params clock: clock factory """ super().__init__(clock=clock) # Set of reservations representing the current demand. Callers are # responsible for removing serviced reservations self.demand = ReservationSet() # Set of reservations for which a request has been issued but no # confirmation has been received. Callers are responsible for removing # acknowledged reservations. self.pending = ReservationSet() # Set of reservations grouped by renewing time. self.renewing = ReservationList() # Set of active reservations. self.holdings = ReservationHoldings() self.lock = threading.Lock()
def extend_lease_reservations(self, *, rset: ReservationSet): """ Extend all reservations: @param rset: reservation set """ for reservation in rset.values(): try: self.extend_lease(reservation=reservation) except Exception as e: self.logger.error("Could not redeem for # {} {}".format(reservation.get_reservation_id(), e))
def close_reservations(self, *, reservations: ReservationSet): for reservation in reservations.values(): try: self.logger.debug("Closing reservation: {}".format( reservation.get_reservation_id())) self.close(reservation=reservation) except Exception as e: self.logger.error(traceback.format_exc()) self.logger.error("Could not close for #{} {}".format( reservation.get_reservation_id(), e))
def __setstate__(self, state): self.__dict__.update(state) self.recovered = False self.wrapper = None self.logger = None self.clock = None self.current_cycle = -1 self.first_tick = True self.stopped = False self.initialized = False self.thread = None self.thread_lock = threading.Lock() self.timer_queue = queue.Queue() self.event_queue = queue.Queue() self.subscription_id = None self.actor_main_lock = threading.Condition() self.closing = ReservationSet() self.message_service = None self.policy.set_actor(actor=self)
def tickets_client(self, *, rset: ReservationSet): for reservation in rset.values(): try: if isinstance(reservation, ABCBrokerReservation): self.ticket_broker(reservation=reservation) elif isinstance(reservation, ABCClientReservation): self.ticket_client(reservation=reservation) else: self.logger.warning("Reservation #{} cannot be ticketed".format(reservation.get_reservation_id())) except Exception as e: self.logger.error("Could not ticket for #{} e: {}".format(reservation.get_reservation_id(), e))
def __init__(self, *, identity: AuthToken = None, clock: ActorClock = None): super().__init__(auth=identity, clock=clock) # Recovered reservations that need to obtain tickets. self.ticketing = ReservationSet() # Recovered reservations that need to extend tickets. self.extending_ticket = ReservationSet() # Recovered reservations that need to be redeemed. self.redeeming = ReservationSet() # Recovered reservations that need to extend leases. self.extending_lease = ReservationSet() # Recovered reservations that need to modify leases self.modifying_lease = ReservationSet() # Peer registry. self.registry = PeerRegistry() # initialization status self.initialized = False self.type = ActorType.Orchestrator
def test_demand(self): cal = self._get_calendar() rset = ReservationSet() for i in range(5): r = self._make_reservation(id=str(i)) # add to the list rset.add(reservation=r) cal.add_demand(reservation=r) # get the list and check it temp = cal.get_demand() self.check_set(rset=rset, check=temp) # remove from the returned set temp.remove(reservation=r) # make sure this did not affect the parent data structure temp = cal.get_demand() self.check_set(rset=rset, check=temp) for i in range(5): r = self._make_reservation(id=str(i)) # add to the list rset.remove(reservation=r) cal.remove_demand(reservation=r) # get the list and check it temp = cal.get_demand() self.check_set(rset=rset, check=temp)
def redeem_reservations(self, *, rset: ReservationSet): """ Redeem all reservations: @param rset: reservation set """ for reservation in rset.values(): try: if isinstance(reservation, ABCAuthorityReservation): self.redeem(reservation=reservation) else: self.logger.warning("Reservation # {} cannot be redeemed".format(reservation.get_reservation_id())) except Exception as e: self.logger.error("Could not redeem for # {} {}".format(reservation.get_reservation_id(), e))
def redeem_reservations(self, *, rset: ReservationSet): for reservation in rset.values(): try: if isinstance(reservation, ABCControllerReservation): self.redeem(reservation=reservation) else: self.logger.warning( "Reservation #{} cannot be redeemed".format( reservation.get_reservation_id())) except Exception as e: self.logger.error(traceback.format_exc()) self.logger.error("Could not redeem for #{} {}".format( reservation.get_reservation_id(), e))
def get_reservations(self, *, cycle: int) -> ReservationSet: """ Returns all reservations associated with the specified cycle. @params cycle : cycle @return a set of reservations associated with the specified cycle. Note that removing from the set will not affect the ReservationList """ result = ReservationSet() if cycle in self.cycle_to_rset: result = self.cycle_to_rset[cycle].clone() return result
def process_renewing(self, *, renewing: ReservationSet) -> ReservationSet: """ Performs checks on renewing reservations. Updates the terms to suggest new terms, stores the extend on the pending list. Returns a fresh ReservationSet of expiring reservations to try to renew in this bidding cycle. @param renewing collection of the renewing reservations @return non-null set of renewals """ result = ReservationSet() if renewing is None: return None #self.logger.debug("Expiring = {}".format(renewing.size())) for reservation in renewing.values(): self.logger.debug("Expiring res: {}".format(reservation)) if reservation.is_renewable(): self.logger.debug("This is a renewable expiring reservation") term = reservation.get_term() term = term.extend() reservation.set_approved(term=term, approved_resources=reservation. get_resources().abstract_clone()) result.add(reservation=reservation) self.calendar.add_pending(reservation=reservation) else: self.logger.debug( "This is not a renewable expiring reservation") return result
def add_reservation(self, *, reservation: ABCReservationMixin, cycle: int): """ Adds a reservation associated with a given cycle. @params reservation: the reservation @params cycle: the cycle with which to associate the reservation """ if reservation is None or cycle < 0 or reservation.get_reservation_id( ) is None: raise FrameworkException(Constants.INVALID_ARGUMENT) if reservation.get_reservation_id() in self.reservation_id_to_cycle: existing_cycle = self.reservation_id_to_cycle[ reservation.get_reservation_id()] if existing_cycle == cycle: return else: raise RuntimeError( "Reservation: #{} is already in the list at a different cycle. Please remove it first, " "before adding to a different cycle".format( reservation.get_reservation_id())) reservation_set = None if cycle in self.cycle_to_rset: reservation_set = self.cycle_to_rset[cycle] else: reservation_set = ReservationSet() if reservation_set.contains(reservation=reservation) is False: reservation_set.add(reservation=reservation) self.count += 1 if cycle not in self.cycle_to_rset: self.add_to_list(reservation_set=reservation_set, cycle=cycle) self.cycle_to_rset[cycle] = reservation_set self.reservation_id_to_cycle[reservation.get_reservation_id()] = cycle
def all_failed(*, reservations: ReservationSet) -> bool: """ We don't introduce a special state to flag when a slice is ALL FAILED, however this helper function helps decide when to GC a slice @return true or false """ bins = StateBins() for r in reservations.values(): bins.add(s=r.get_state()) if not bins.has_state_other_than(ReservationStates.Failed): return True return False
def __init__(self, *, identity: AuthToken = None, clock: ActorClock = None): super().__init__(auth=identity, clock=clock) self.type = ActorType.Authority # Initialization status. self.initialized = False # Reservations to redeem once the actor recovers. self.redeeming = ReservationSet() # Reservations to extendLease for once the actor recovers. self.extending_lease = ReservationSet() # Reservations to modifyLease for once the actor recovers self.modifying_lease = ReservationSet()
def get_reservations(self, *, time: int = None, rtype: ResourceType = None) -> ReservationSet: """ Performs an intersection query: returns all reservations from the specified resource type present in the collection that are active at the specified time instance. @params time : time instance @params rtype : resource type @returns reservations set containing active reservations """ if time is None and rtype is None: return self.reservation_set result = ReservationSet() key = ReservationWrapper(reservation=None, start=time, end=time) # Find the location of key in the list. index = binary_search(a=self.list, x=key) if index < 0: index = -index - 1 # Scan the upper part of the list. We need to scan the whole list. i = index count = self.size() while i < count: entry = self.list[i] if rtype is None or rtype == entry.reservation.getType(): if entry.start <= time <= entry.end: result.add(reservation=entry.reservation) i += 1 # Scan the lower part of the list until no further intersections are possible i = index - 1 while i >= 0: entry = self.list[i] if entry.end < time: break if entry.start <= time and rtype is None or entry.reservation.getType( ) == rtype: result.add(reservation=entry.reservation) i -= 1 return result
def allocate_extending_reservation_set(self, *, requests: ReservationSet): if requests is not None: for reservation in requests.values(): if reservation.is_extending_ticket( ) and not reservation.is_closed(): start = reservation.get_requested_term( ).get_new_start_time() end = self.align_end( when=reservation.get_requested_term().get_end_time()) resource_type = reservation.get_resources().get_type() inv = self.inventory.get(resource_type=resource_type) if inv is not None: ext_term = Term( start=reservation.get_term().get_start_time(), end=end, new_start=start) self.extend_private(reservation=reservation, inv=inv, term=ext_term) else: reservation.fail(message=Constants.NO_POOL)