Beispiel #1
0
    def at_lease_done(self, lease):
        """See AccountingProbe.at_lease_done"""        
        if lease.get_state() == Lease.STATE_DONE:
            self.accounting.incr_counter(PriceProbe.COUNTER_REVENUE, lease.id, lease.price)
            self.accounting.set_lease_stat(PriceProbe.LEASE_STAT_PRICE, lease.id, lease.price)

        if lease.extras.has_key("simul_userrate"):
            user_rate = float(lease.extras["simul_userrate"])
            user_price = get_policy().pricing.get_base_price(lease, user_rate)
            
            if lease.get_state() == Lease.STATE_DONE and lease.extras.has_key("rate"):
                surcharge = lease.price - get_policy().pricing.get_base_price(lease, lease.extras["rate"])
                self.accounting.incr_counter(PriceProbe.COUNTER_MISSED_REVENUE_UNDERCHARGE, lease.id, user_price - lease.price)
                self.accounting.incr_counter(PriceProbe.COUNTER_SURCHARGE, lease.id, surcharge)
            elif lease.get_state() == Lease.STATE_REJECTED:
                self.accounting.incr_counter(PriceProbe.COUNTER_MISSED_REVENUE_REJECT, lease.id, user_price)
            elif lease.get_state() == Lease.STATE_REJECTED_BY_USER:
                self.accounting.incr_counter(PriceProbe.COUNTER_MISSED_REVENUE_REJECT_BY_USER, lease.id, user_price)
    def request_lease(self, lease):
        """Requests a leases. This is the entry point of leases into the scheduler.
        
        Request a lease. The decision on whether to accept or reject a
        lease is deferred to the policy manager (through its admission
        control policy). 
        
        If the policy determines the lease can be
        accepted, it is marked as "Pending". This still doesn't
        guarantee that the lease will be scheduled (e.g., an AR lease
        could still be rejected if the scheduler determines there are no
        resources for it; but that is a *scheduling* decision, not a admission
        control policy decision). The ultimate fate of the lease is determined
        the next time the scheduling function is called.
        
        If the policy determines the lease cannot be accepted, it is marked
        as rejected.

        Arguments:
        lease -- Lease object. Its state must be STATE_NEW.
        """
        self.logger.info("Lease #%i has been requested." % lease.id)
        if lease.submit_time == None:
            lease.submit_time = round_datetime(get_clock().get_time())
        lease.print_contents()
        lease.set_state(Lease.STATE_PENDING)
        if get_policy().accept_lease(lease):
            self.logger.info("Lease #%i has been marked as pending." %
                             lease.id)
            self.leases.add(lease)
        else:
            self.logger.info("Lease #%i has not been accepted" % lease.id)
            lease.set_state(Lease.STATE_REJECTED)
            self.completed_leases.add(lease)

        self.accounting.at_lease_request(lease)
        get_persistence().persist_lease(lease)
Beispiel #3
0
    def request_lease(self, lease):
        """Requests a leases. This is the entry point of leases into the scheduler.
        
        Request a lease. The decision on whether to accept or reject a
        lease is deferred to the policy manager (through its admission
        control policy). 
        
        If the policy determines the lease can be
        accepted, it is marked as "Pending". This still doesn't
        guarantee that the lease will be scheduled (e.g., an AR lease
        could still be rejected if the scheduler determines there are no
        resources for it; but that is a *scheduling* decision, not a admission
        control policy decision). The ultimate fate of the lease is determined
        the next time the scheduling function is called.
        
        If the policy determines the lease cannot be accepted, it is marked
        as rejected.

        Arguments:
        lease -- Lease object. Its state must be STATE_NEW.
        """
        self.logger.info("Lease #%i has been requested." % lease.id)
        if lease.submit_time == None:
            lease.submit_time = round_datetime(get_clock().get_time())
        lease.print_contents()
        lease.set_state(Lease.STATE_PENDING)
        if get_policy().accept_lease(lease):
            self.logger.info("Lease #%i has been marked as pending." % lease.id)
            self.leases.add(lease)
        else:
            self.logger.info("Lease #%i has not been accepted" % lease.id)
            lease.set_state(Lease.STATE_REJECTED)
            self.completed_leases.add(lease)
        
        self.accounting.at_lease_request(lease)
        get_persistence().persist_lease(lease)
Beispiel #4
0
    def __schedule_lease(self, lease, nexttime):            
        """ Schedules a lease.
        
        This method orchestrates the preparation and VM scheduler to
        schedule a lease.
        
        Arguments:
        lease -- Lease to schedule.
        nexttime -- The next time at which the scheduler can allocate resources.
        """       
                
        lease_state = lease.get_state()
        migration = get_config().get("migration")
        
        # Determine earliest start time in each node
        if lease_state == Lease.STATE_PENDING or lease_state == Lease.STATE_QUEUED:
            # This lease might require preparation. Ask the preparation
            # scheduler for the earliest starting time.
            earliest = self.preparation_scheduler.find_earliest_starting_times(lease, nexttime)
        elif lease_state == Lease.STATE_SUSPENDED_PENDING or lease_state == Lease.STATE_SUSPENDED_QUEUED:
            # This lease may have to be migrated.
            # We have to ask both the preparation scheduler and the VM
            # scheduler what would be the earliest possible starting time
            # on each node, assuming we have to transfer files between
            # nodes.

            node_ids = self.slottable.nodes.keys()
            earliest = {}
            if migration == constants.MIGRATE_NO:
                # If migration is disabled, the earliest starting time
                # is simply nexttime.
                for node in node_ids:
                    earliest[node] = EarliestStartingTime(nexttime, EarliestStartingTime.EARLIEST_NOPREPARATION)
            else:
                # Otherwise, we ask the preparation scheduler and the VM
                # scheduler how long it would take them to migrate the
                # lease state.
                prep_migr_time = self.preparation_scheduler.estimate_migration_time(lease)            
                vm_migr_time = self.vm_scheduler.estimate_migration_time(lease)
                for node in node_ids:
                    earliest[node] = EarliestStartingTime(nexttime + prep_migr_time + vm_migr_time, EarliestStartingTime.EARLIEST_MIGRATION)
        else:
            raise InconsistentLeaseStateError(lease, doing = "scheduling a best-effort lease")

        # Now, we give the lease to the VM scheduler, along with the
        # earliest possible starting times. If the VM scheduler can
        # schedule VMs for this lease, it will return a resource reservation
        # that we can add to the slot table, along with a list of
        # leases that have to be preempted.
        # If the VM scheduler can't schedule the VMs, it will throw an
        # exception (we don't catch it here, and it is just thrown up
        # to the calling method.
        (vmrr, preemptions) = self.vm_scheduler.schedule(lease, lease.duration.get_remaining_duration(), nexttime, earliest)
        
        ## BEGIN NOT-FIT-FOR-PRODUCTION CODE
        ## Pricing shouldn't live here. Instead, it should happen before a lease is accepted
        ## It is being done here in the interest of developing a first prototype
        ## that incorporates pricing in simulations (but not interactively yet)
        
        # Call pricing policy
        lease_price = get_policy().price_lease(lease, preemptions)
        
        # Determine whether to accept price or not (this in particular
        # should happen in the lease admission step)
        if lease.extras.has_key("simul_userrate"):
            user_rate = float(lease.extras["simul_userrate"])
            if get_config().get("policy.pricing") != "free":
                user_price = get_policy().pricing.get_base_price(lease, user_rate)
                # We want to record the rate at which the lease was priced
                lease.extras["rate"] = get_policy().pricing.rate
                if lease_price > user_price:
                    lease.price = -1
                    lease.extras["rejected_price"] = lease_price
                    raise NotSchedulableException, "Lease priced at %.2f. User is only willing to pay %.2f" % (lease_price, user_price)
        
        lease.price = lease_price
        ## END NOT-FIT-FOR-PRODUCTION CODE
                                
        # Schedule lease preparation
        is_ready = False
        preparation_rrs = []
        if lease_state in (Lease.STATE_SUSPENDED_PENDING, Lease.STATE_SUSPENDED_QUEUED) and migration != constants.MIGRATE_NO:
            # The lease might require migration
            migr_rrs = self.preparation_scheduler.schedule_migration(lease, vmrr, nexttime)
            if len(migr_rrs) > 0:
                end_migr = migr_rrs[-1].end
            else:
                end_migr = nexttime
            migr_rrs += self.vm_scheduler.schedule_migration(lease, vmrr, end_migr)
            migr_rrs.reverse()
            for migr_rr in migr_rrs:
                vmrr.pre_rrs.insert(0, migr_rr)
            if len(migr_rrs) == 0:
                is_ready = True
        elif lease_state in (Lease.STATE_SUSPENDED_PENDING, Lease.STATE_SUSPENDED_QUEUED) and migration == constants.MIGRATE_NO:
            # No migration means the lease is ready
            is_ready = True
        elif lease_state in (Lease.STATE_PENDING, Lease.STATE_QUEUED):
            # The lease might require initial preparation
            preparation_rrs, is_ready = self.preparation_scheduler.schedule(lease, vmrr, earliest, nexttime)

        # If scheduling the lease involves preempting other leases,
        # go ahead and preempt them.
        if len(preemptions) > 0:
            self.logger.info("Must preempt leases %s to make room for lease #%i" % ([l.id for l in preemptions], lease.id))
            for l in preemptions:
                self.__preempt_lease(l, preemption_time=vmrr.start)

        # At this point, the lease is feasible.
        # Commit changes by adding RRs to lease and to slot table
        
        # Add preparation RRs (if any) to lease
        for rr in preparation_rrs:
            lease.append_preparationrr(rr)
        
        # Add VMRR to lease
        lease.append_vmrr(vmrr)
        

        # Add resource reservations to slottable
        
        # Preparation RRs (if any)
        for rr in preparation_rrs:
            self.slottable.add_reservation(rr)
        
        # Pre-VM RRs (if any)
        for rr in vmrr.pre_rrs:
            self.slottable.add_reservation(rr)
            
        # VM
        self.slottable.add_reservation(vmrr)
        
        # Post-VM RRs (if any)
        for rr in vmrr.post_rrs:
            self.slottable.add_reservation(rr)
          
        # Change lease state
        if lease_state == Lease.STATE_PENDING or lease_state == Lease.STATE_QUEUED:
            lease.set_state(Lease.STATE_SCHEDULED)
            if is_ready:
                lease.set_state(Lease.STATE_READY)
        elif lease_state == Lease.STATE_SUSPENDED_PENDING or lease_state == Lease.STATE_SUSPENDED_QUEUED:
            lease.set_state(Lease.STATE_SUSPENDED_SCHEDULED)

        get_persistence().persist_lease(lease)

        lease.print_contents()
Beispiel #5
0
    def schedule(self, nexttime):
        """ The main scheduling function
        
        The scheduling function looks at all pending requests and schedules them.
        Note that most of the actual scheduling code is contained in the
        __schedule_lease method and in the VMScheduler and PreparationScheduler classes.
        
        Arguments:
        nexttime -- The next time at which the scheduler can allocate resources.
        """
        
        # Get pending leases
        pending_leases = self.leases.get_leases_by_state(Lease.STATE_PENDING)  

        # we process all the leases at one time, without notion of queued leases
        # and now leases
        for choice in generate_combination(pending_leases):
            # we first check if IM leases are feasible
            im_leases = [l for l in choice if l.get_type() == Lease.IMMEDIATE]
        
        # Process leases that have to be queued. Right now, only best-effort leases get queued.
        queue_leases = [req for req in pending_leases if req.get_type() == Lease.BEST_EFFORT]

        # Queue leases
        for lease in queue_leases:
            self.__enqueue(lease)
            lease.set_state(Lease.STATE_QUEUED)
            self.logger.info("Queued lease request #%i, %i nodes for %s." % (lease.id, lease.numnodes, lease.duration.requested))
            get_persistence().persist_lease(lease)


        # Process leases that have to be scheduled right away. Right now, this is any
        # lease that is not a best-effort lease (ARs, immediate, and deadlined leases)
        now_leases = [req for req in pending_leases if req.get_type() != Lease.BEST_EFFORT]
        
        # Schedule leases
        for lease in now_leases:
            lease_type = Lease.type_str[lease.get_type()]
            self.logger.info("Scheduling lease #%i (%i nodes) -- %s" % (lease.id, lease.numnodes, lease_type))
            if lease.get_type() == Lease.ADVANCE_RESERVATION:
                self.logger.info("From %s to %s" % (lease.start.requested, lease.start.requested + lease.duration.requested))
            elif lease.get_type() == Lease.DEADLINE:
                self.logger.info("Starting at %s. Deadline: %s" % (lease.start.requested, lease.deadline))
                
            lease.print_contents()
       
            try:
                self.__schedule_lease(lease, nexttime=nexttime)
                self.logger.info("Lease #%i has been scheduled." % lease.id)
                ## BEGIN NOT-FIT-FOR-PRODUCTION CODE
                ## This should happen when the lease is requested.
                get_policy().pricing.feedback(lease)
                ## END NOT-FIT-FOR-PRODUCTION CODE
                lease.print_contents()
            except NotSchedulableException, exc:
                self.logger.info("Lease request #%i cannot be scheduled: %s" % (lease.id, exc.reason))
                ## BEGIN NOT-FIT-FOR-PRODUCTION CODE
                ## This should happen when the lease is requested.
                if lease.price == -1:
                    lease.set_state(Lease.STATE_REJECTED_BY_USER)
                else:
                    lease.set_state(Lease.STATE_REJECTED)                    
                self.completed_leases.add(lease)
                self.accounting.at_lease_done(lease)
                ## BEGIN NOT-FIT-FOR-PRODUCTION CODE
                ## This should happen when the lease is requested.
                get_policy().pricing.feedback(lease)
                ## END NOT-FIT-FOR-PRODUCTION CODE
                self.leases.remove(lease)            
            get_persistence().persist_lease(lease)