def _get_network_running_observations(self, tels, ends_after,
                                          starts_before):
        n_running_total = 0
        running_at_tel = {}
        for full_tel_name in tels:
            tel_name, obs_name, site_name = full_tel_name.split('.')
            log.debug(
                "Acquiring running observations and first availability at %s",
                full_tel_name)

            running = self._get_running_observations(ends_after, starts_before,
                                                     site_name, obs_name,
                                                     tel_name)

            running_at_tel[full_tel_name] = running

            n_running = len(running)
            _, observation_str = pl(n_running, 'observation')
            log.debug("Found %d running %s at %s", n_running, observation_str,
                      full_tel_name)
            n_running_total += n_running

        _, observation_str = pl(n_running_total, 'observation')
        log.info("Network-wide, found %d running %s", n_running_total,
                 observation_str)

        return running_at_tel
    def _send_schedule_to_observation_portal(self,
                                             schedule,
                                             semester_start,
                                             configdb_interface,
                                             dry_run=False):
        ''' Convert a kernel schedule into Observation Portal observations and submit them '''

        # TODO: Update this code to send Observations and ConfigStatuses to observation portal
        observations_by_resource = defaultdict(list)
        for resource_name, reservations in schedule.items():
            for reservation in reservations:
                try:
                    observation = build_observation(reservation,
                                                    semester_start,
                                                    configdb_interface)
                except Exception:
                    log.exception(
                        'Unable to build observation from reservation for request number {}'
                        .format(reservation.request.id))
                    continue
                observations_by_resource[resource_name].append(observation)
            _, observation_str = pl(
                len(observations_by_resource[resource_name]), 'observation')
            msg = 'Will send {} {} to {}'.format(
                len(observations_by_resource[resource_name]), observation_str,
                resource_name)
            log_info_dry_run(msg, dry_run)
        n_submitted_total = self._send_observations_to_observation_portal(
            observations_by_resource, dry_run)

        return n_submitted_total
Ejemplo n.º 3
0
def filter_on_scheduling_horizon(request_groups, scheduling_horizon):
    '''Filter out windows in user requests that extend beyond the scheduling
       horizon for types (single, many)
    '''
    rgs_by_type = filter_compounds_by_type(request_groups)
    log.info("Identified %s, %s, %s, %s" % (pl(len(rgs_by_type['single']), 'single'),
                                            pl(len(rgs_by_type['many']), 'many'),
                                            pl(len(rgs_by_type['and']), 'and'),
                                            pl(len(rgs_by_type['oneof']), 'oneof')))

    # Filter windows that are beyond the short-term scheduling horizon
    log.info("Filtering RGs of type 'single' and 'many' based on scheduling horizon (%s)" % scheduling_horizon)
    horizon_limited_rgs = rgs_by_type['single'] + rgs_by_type['many']
    horizon_limited_rgs = truncate_upper_crossing_windows(horizon_limited_rgs, horizon=scheduling_horizon)
    horizon_limited_rgs = filter_out_future_windows(horizon_limited_rgs, horizon=scheduling_horizon)
    # TODO: Add the duration filter here?
    # Clean up Requests without any windows
    horizon_limited_rgs = filter_on_type(horizon_limited_rgs)
    # Many's may have children with no windows that should be removed from consideration
    drop_empty_requests(horizon_limited_rgs)
    log.info("After filtering, %d horizon-limited rgs remain" % len(horizon_limited_rgs))

    # Compounds (and/oneof) are not constrained to the short-term scheduling horizon
    # TODO: Remove this block after review
    log.info("Filtering compound RGs of type 'and' and 'oneof', not constrained by scheduling horizon")
    unlimited_rgs = rgs_by_type['and'] + rgs_by_type['oneof']
    unlimited_rgs = truncate_upper_crossing_windows(unlimited_rgs)
    unlimited_rgs = filter_out_future_windows(unlimited_rgs)

    # TODO: it's possible that one-ofs and ands may have these windowless 
    # children at this point from requests that crossed the semester boundary
    # might need to drop empty requests before filtering on type   

    # Clean up Requests without any windows
    unlimited_rgs = filter_on_type(unlimited_rgs)
    log.info("After filtering, %d unlimited RGs remain" % len(unlimited_rgs))

    remaining_rgs = horizon_limited_rgs + unlimited_rgs

    return remaining_rgs
Ejemplo n.º 4
0
    def build_request_group(self,
                            rg_dict,
                            scheduled_requests=None,
                            ignore_ipp=False):
        if scheduled_requests is None:
            scheduled_requests = {}
        rg_id = int(rg_dict['id'])
        operator = rg_dict['operator'].lower()
        ipp_value = rg_dict.get('ipp_value', 1.0)
        submitter = rg_dict.get('submitter', '')
        if ignore_ipp:
            # if we want to ignore ipp in the scheduler, then set it to 1.0 here and it will not modify the priority
            ipp_value = 1.0

        requests, invalid_requests = self.build_requests(rg_dict,
                                                         scheduled_requests,
                                                         is_staff=rg_dict.get(
                                                             'is_staff',
                                                             False))
        if invalid_requests:
            msg = "Found %s." % pl(len(invalid_requests), 'invalid Request')
            log.warn(msg)
            for _, error_msg in invalid_requests:
                tag = "InvalidRequest"
                RequestGroup.emit_request_group_feedback(rg_id, error_msg, tag)
            if operator.lower() == 'and':
                msg = "Invalid request found within 'AND' RG %s making RG invalid" % rg_id
                tag = "InvalidRequestGroup"
                RequestGroup.emit_request_group_feedback(rg_id, msg, tag)
                raise RequestError(msg)

        if not requests:
            msg = "No valid Requests for RG %s" % rg_id
            tag = "InvalidRequestGroup"
            RequestGroup.emit_request_group_feedback(rg_id, msg, tag)
            raise RequestError(msg)

        proposal = self.get_proposal_details(rg_dict['proposal'])

        # Validate we are an allowed type of UR
        valid_observation_types = ['NORMAL', 'RAPID_RESPONSE', 'TIME_CRITICAL']
        observation_type = rg_dict['observation_type']
        if observation_type not in valid_observation_types:
            msg = "RequestGroup observation_type must be one of %s" % valid_observation_types
            raise RequestError(msg)

        # Calculate the maximum window time as the expire time
        max_window_time = datetime(1000, 1, 1)
        for req in requests:
            for windows in req.windows.windows_for_resource.values():
                for window in windows:
                    max_window_time = max(max_window_time, window.end)

        # Truncate the expire time by the current semester's end
        semester_details = self.get_semester_details(datetime.utcnow())
        if semester_details:
            max_window_time = min(max_window_time, semester_details['end'])

        request_group = RequestGroup(
            operator=operator,
            requests=requests,
            proposal=proposal,
            rg_id=rg_id,
            is_staff=rg_dict.get('is_staff', False),
            observation_type=observation_type,
            ipp_value=ipp_value,
            name=rg_dict['name'],
            expires=max_window_time,
            submitter=safe_unidecode(submitter, 50),
        )

        # Return only the invalid request and not the error message
        invalid_requests = [ir[0] for ir in invalid_requests]
        return request_group, invalid_requests