예제 #1
0
    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)
예제 #2
0
    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)
예제 #3
0
 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 = {}
예제 #4
0
 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
예제 #5
0
    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()
예제 #6
0
 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
예제 #7
0
 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
예제 #8
0
    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
예제 #9
0
 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
예제 #11
0
    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))
예제 #12
0
    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
예제 #13
0
    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)
예제 #14
0
    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()
예제 #16
0
 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))
예제 #17
0
 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))
예제 #18
0
 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)
예제 #19
0
 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))
예제 #20
0
 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
예제 #21
0
    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)
예제 #22
0
 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))
예제 #23
0
 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
예제 #25
0
    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
예제 #27
0
    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
예제 #28
0
 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()
예제 #29
0
    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
예제 #30
0
    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)