Exemplo n.º 1
0
 def _build_cbsd(self, session: Session, cbsd: DBCbsd) -> Cbsd:
     db_grants = session.query(DBGrant).join(DBGrantState).filter(
         DBGrant.cbsd_id == cbsd.id,
         DBGrantState.name != GrantStates.IDLE.value,
     )
     pending_requests_payloads = session.query(DBRequest.payload, ).join(
         DBRequestState, ).filter(
             DBRequestState.name == RequestStates.PENDING.value,
             DBRequest.cbsd_id == cbsd.id,
         )
     grants = [self._build_grant(x) for x in db_grants]
     channels = [self._build_channel(x) for x in cbsd.channels]
     pending_requests = [
         json.dumps(r.payload, separators=(',', ':'))
         for r in pending_requests_payloads
     ]
     last_seen = self._to_timestamp(cbsd.last_seen)
     eirp_capabilities = self._build_eirp_capabilities(cbsd)
     return Cbsd(
         id=cbsd.cbsd_id,
         user_id=cbsd.user_id,
         fcc_id=cbsd.fcc_id,
         serial_number=cbsd.cbsd_serial_number,
         state=cbsd_state_mapping[cbsd.state.name],
         grants=grants,
         channels=channels,
         pending_requests=pending_requests,
         last_seen_timestamp=last_seen,
         eirp_capabilities=eirp_capabilities,
     )
Exemplo n.º 2
0
    def _process_responses(
        self,
        requests: List[DBRequest],
        sas_response: Response,
        session: Session,
    ) -> None:

        response_json_list = sas_response.json().get(self.response_type, [])
        logger.debug(
            f"[{self.response_type}] requests json list: {response_json_list}",
        )

        no_of_requests = len(requests)
        no_of_responses = len(response_json_list)
        if no_of_responses != no_of_requests:
            logger.warning(
                f"[{self.response_type}] Got {no_of_requests=} and {no_of_responses=}",
            )
        for response_json, db_request in zip(response_json_list, requests):
            db_response = DBResponse(
                response_code=int(response_json["response"]["responseCode"]),
                payload=response_json,
                request=db_request,
            )
            logger.info(
                f"[{self.response_type}] Adding Response: {db_response} for Request {db_request}",
            )
            session.add(db_response)
            self._log_response(session, db_response)
            self._process_request(db_request)
            logger.debug(
                f'[{self.response_type}] About to process Response: {db_response}',
            )
            self._process_response(db_response, session)
Exemplo n.º 3
0
def _get_or_create_grant_from_response(
    obj: ResponseDBProcessor,
    response: DBResponse,
    session: Session,
) -> Optional[DBGrant]:
    cbsd_id = response.payload.get(
        CBSD_ID, ) or response.request.payload.get(CBSD_ID)
    grant_id = response.payload.get(
        GRANT_ID, ) or response.request.payload.get(GRANT_ID)
    cbsd = session.query(DBCbsd).filter(DBCbsd.cbsd_id == cbsd_id).scalar()
    grant = None
    if grant_id:
        logger.info(f'Getting grant by: {cbsd_id=} {grant_id=}')
        grant = session.query(DBGrant).filter(
            DBGrant.cbsd_id == cbsd.id,
            DBGrant.grant_id == grant_id,
        ).scalar()

    if grant_id and not grant:
        grant_idle_state = obj.grant_states_map[GrantStates.IDLE.value]
        grant = DBGrant(cbsd=cbsd, grant_id=grant_id, state=grant_idle_state)
        _update_grant_from_request(response, grant)
        session.add(grant)
        logger.info(f'Created new grant: {grant}')
    return grant
Exemplo n.º 4
0
    def _build_state(self, session: Session) -> State:
        db_grant_idle_state_id = session.query(DBGrantState.id).filter(
            DBGrantState.name == GrantStates.IDLE.value,
        ).scalar()
        db_request_pending_state_id = session.query(DBRequestState.id).filter(
            DBRequestState.name == RequestStates.PENDING.value,
        ).scalar()

        # Selectively load sqlalchemy object relations using a single query to avoid commit races.
        # We want to have CBSD entity "grants" relation only contain grants in a Non-IDLE state.
        # We want to have CBSD entity "requests" relation only contain PENDING requests.
        db_configs = session.query(DBActiveModeConfig).join(DBCbsd).options(
            joinedload(DBActiveModeConfig.cbsd).options(
                joinedload(DBCbsd.channels),
                joinedload(
                    DBCbsd.grants.and_(
                        DBGrant.state_id != db_grant_idle_state_id,
                    ),
                ),
                joinedload(
                    DBCbsd.requests.and_(
                        DBRequest.state_id == db_request_pending_state_id,
                    ),
                ),
            ),
        ).filter(*self._get_filter()).populate_existing()
        configs = [self._build_config(db_config) for db_config in db_configs]
        session.commit()
        return State(active_mode_configs=configs)
Exemplo n.º 5
0
 def _log_response(self, session: Session, response: DBResponse):
     network_id = ''
     fcc_id = ''
     cbsd_serial_number = ''
     cbsd = response.request.cbsd
     if cbsd and cbsd.network_id:
         network_id = cbsd.network_id
     if cbsd and cbsd.fcc_id:
         fcc_id = cbsd.fcc_id
     if cbsd and cbsd.cbsd_serial_number:
         cbsd_serial_number = cbsd.cbsd_serial_number
     log_name = request_response[response.request.type.name]
     response_code = response.payload.get(
         'response',
         {},
     ).get('responseCode', None)
     log = DBLog(
         log_from='SAS',
         log_to='DP',
         log_name=f'{log_name}',
         log_message=f'{response.payload}',
         cbsd_serial_number=f'{cbsd_serial_number}',
         network_id=f'{network_id}',
         fcc_id=f'{fcc_id}',
         response_code=response_code,
     )
     session.add(log)
Exemplo n.º 6
0
 def _build_state(self, session: Session) -> State:
     db_configs = session.query(DBActiveModeConfig).join(DBCbsd).options(
         joinedload(DBActiveModeConfig.cbsd).options(
             joinedload(DBCbsd.channels),
             joinedload(DBCbsd.grants).options(joinedload(DBGrant.state)),
         ), ).filter(*self._get_filter())
     configs = [self._build_config(session, x) for x in db_configs]
     session.commit()
     return State(active_mode_configs=configs)
Exemplo n.º 7
0
def _find_cbsd_from_request(session: Session, payload: Dict) -> DBCbsd:
    if "cbsdSerialNumber" in payload:
        return session.query(DBCbsd).filter(
            DBCbsd.cbsd_serial_number == payload.get("cbsdSerialNumber"),
        ).scalar()
    if "cbsdId" in payload:
        return session.query(DBCbsd).filter(
            DBCbsd.cbsd_id == payload.get("cbsdId"), ).scalar()
    logger.warning(f'Could not find CBSD in Database matching {payload=}.')
Exemplo n.º 8
0
 def setUp(self):
     config = self.get_config()
     self.engine = create_engine(
         url=config.SQLALCHEMY_DB_URI,
         encoding=config.SQLALCHEMY_DB_ENCODING,
         echo=False,
         future=config.SQLALCHEMY_FUTURE,
     )
     Base.metadata.bind = self.engine
     Base.metadata.create_all()
     self.session = Session()
Exemplo n.º 9
0
 def _get_authorized_grant(self, session: Session, cbsd: DBCbsd) -> DBGrant:
     authorized_state = session.query(DBGrantState). \
         filter(DBGrantState.name == GrantStates.AUTHORIZED.value).first()
     grant = session.query(DBGrant).filter(
         DBGrant.cbsd_id == cbsd.id,
         DBGrant.state_id == authorized_state.id,
         (DBGrant.transmit_expire_time == None) | (  # noqa: WPS465,E711
             DBGrant.transmit_expire_time > now()),
         (DBGrant.grant_expire_time == None) | (  # noqa: WPS465,E711
             DBGrant.grant_expire_time > now()),
     ).first()
     return grant
Exemplo n.º 10
0
def _terminate_all_grants_from_response(response: DBResponse,
                                        session: Session) -> None:
    cbsd_id = response.payload.get(
        CBSD_ID, ) or response.request.payload.get(CBSD_ID)
    if not cbsd_id:
        return
    cbsd = session.query(DBCbsd).filter(DBCbsd.cbsd_id == cbsd_id).scalar()
    if cbsd:
        cbsd.grant_attempts = 0
    logger.info(f'Terminating all grants for {cbsd_id=}')
    session.query(DBGrant).filter(DBGrant.cbsd == cbsd).delete()
    logger.info(f"Deleting all channels for {cbsd_id=}")
    session.query(DBChannel).filter(DBChannel.cbsd == cbsd).delete()
Exemplo n.º 11
0
 def _create_or_update_active_mode_config(self, session: Session, cbsd: DBCbsd) -> DBActiveModeConfig:
     registered_state = session.query(DBCbsdState). \
         filter(DBCbsdState.name == CbsdStates.REGISTERED.value).first()
     active_mode_config = session.query(DBActiveModeConfig). \
         filter(DBActiveModeConfig.cbsd_id == cbsd.id).first()
     if active_mode_config:
         active_mode_config.desired_state = registered_state
         return None
     active_mode_config = DBActiveModeConfig(
         desired_state=registered_state,
         cbsd=cbsd,
     )
     session.add(active_mode_config)
     return active_mode_config
Exemplo n.º 12
0
def _remove_grant_from_response(
    response: DBResponse,
    session: Session,
    unset_freq: bool = False,
) -> None:
    grant = _get_grant_from_response(response, session)
    if not grant:
        return

    logger.info(f'Terminating grant {grant.grant_id}')

    if unset_freq:
        unset_frequency(grant)
    session.delete(grant)
Exemplo n.º 13
0
def _terminate_all_grants_from_response(response: DBResponse,
                                        session: Session) -> None:
    cbsd_id = response.payload.get(
        CBSD_ID, ) or response.request.payload.get(CBSD_ID)
    if not cbsd_id:
        return
    logger.info(f'Terminating all grants for {cbsd_id=}')
    with session.no_autoflush:
        session.query(DBGrant). \
            filter(DBGrant.cbsd_id == DBCbsd.id, DBCbsd.cbsd_id == cbsd_id). \
            delete(synchronize_session=False)
        logger.info(f"Deleting all channels for {cbsd_id=}")
        session.query(DBChannel). \
            filter(DBChannel.cbsd_id == DBCbsd.id, DBCbsd.cbsd_id == cbsd_id). \
            delete(synchronize_session=False)
Exemplo n.º 14
0
def _change_cbsd_state(cbsd: DBCbsd, session: Session, new_state: str) -> None:
    if not cbsd:
        return
    state = session.query(DBCbsdState).filter(
        DBCbsdState.name == new_state, ).scalar()
    print(f"Changing {cbsd=} {cbsd.state=} to {new_state=}")
    cbsd.state = state
Exemplo n.º 15
0
 def _get_or_create_cbsd(self, session: Session, request_type: str,
                         request_json: Dict) -> Optional[DBCbsd]:
     filters = self._get_cbsd_filters(request_type, request_json)
     cbsd = session.query(DBCbsd).filter(*filters).first()
     cbsd_id = request_json.get(CBSD_ID)
     return cbsd if cbsd else self._create_cbsd(session, request_json,
                                                cbsd_id)
Exemplo n.º 16
0
 def _get_or_create_cbsd(self, session: Session,
                         request: CBSDRequest) -> DBCbsd:
     cbsd = session.query(DBCbsd).filter(
         DBCbsd.cbsd_serial_number == request.serial_number, ).first()
     if cbsd:
         self._update_fields_from_request(cbsd, request)
         return cbsd
     unregistered_state = session.query(DBCbsdState). \
         filter(DBCbsdState.name == CbsdStates.UNREGISTERED.value).first()
     cbsd = DBCbsd(
         cbsd_serial_number=request.serial_number,
         state=unregistered_state,
     )
     self._update_fields_from_request(cbsd, request)
     session.add(cbsd)
     return cbsd
Exemplo n.º 17
0
 def _log_result(self, session: Session, method_name: str, result: CBSDStateResult, cbsd: DBCbsd, serial_number: str):
     network_id = ''
     fcc_id = ''
     if cbsd:
         network_id = cbsd.network_id or ''
         fcc_id = cbsd.fcc_id or ''
     log = DBLog(
         log_from='DP',
         log_to='CBSD',
         log_name=method_name + 'Response',
         log_message=f'{result}',
         cbsd_serial_number=f'{serial_number}',
         network_id=f'{network_id}',
         fcc_id=f'{fcc_id}',
     )
     session.add(log)
Exemplo n.º 18
0
def _list_cbsds(session: Session) -> State:
    # It might be possible to use join instead of nested queries
    # however it requires some serious investigation on how to use it
    # with eager_contains and filter (aliases)
    db_grant_idle_state_id = session.query(DBGrantState.id).filter(
        DBGrantState.name == GrantStates.IDLE.value,
    ).scalar_subquery()
    db_request_pending_state_id = session.query(DBRequestState.id).filter(
        DBRequestState.name == RequestStates.PENDING.value,
    ).scalar_subquery()

    not_null = [
        DBCbsd.fcc_id, DBCbsd.user_id, DBCbsd.number_of_ports,
        DBCbsd.antenna_gain, DBCbsd.min_power, DBCbsd.max_power,
    ]
    query_filter = [field != None for field in not_null] + [DBRequest.id == None]  # noqa: E711

    # Selectively load sqlalchemy object relations using a single query to avoid commit races.
    # We want to have CBSD entity "grants" relation only contain grants in a Non-IDLE state.
    # We want to have CBSD entity "requests" relation only contain PENDING requests.
    return (
        session.query(DBCbsd).
        join(DBActiveModeConfig).
        outerjoin(
            DBGrant, and_(
                DBGrant.cbsd_id == DBCbsd.id,
                DBGrant.state_id != db_grant_idle_state_id,
            ),
        ).
        outerjoin(
            DBRequest, and_(
                DBRequest.cbsd_id == DBCbsd.id,
                DBRequest.state_id == db_request_pending_state_id,
            ),
        ).
        options(
            joinedload(DBCbsd.state),
            joinedload(DBCbsd.channels),
            contains_eager(DBCbsd.active_mode_config).
            joinedload(DBActiveModeConfig.desired_state),
            contains_eager(DBCbsd.grants).
            joinedload(DBGrant.state),
        ).
        filter(*query_filter).
        populate_existing()
    )
Exemplo n.º 19
0
def _create_grant_from_response(
    response: DBResponse,
    state: DBGrantState,
    session: Session,
    grant_id: str = None,
) -> Optional[DBGrant]:
    grant_id = grant_id or response.grant_id
    if not grant_id:
        return None
    cbsd_id = session.query(
        DBCbsd.id).filter(DBCbsd.cbsd_id == response.cbsd_id)
    grant = DBGrant(cbsd_id=cbsd_id.subquery(), grant_id=grant_id, state=state)
    _update_grant_from_request(response, grant)
    session.add(grant)

    logger.info(f'Created new grant {grant}')
    return grant
Exemplo n.º 20
0
 def _create_cbsd(self, session: Session, request_payload: Dict, cbsd_id: Optional[str]):
     cbsd_state = session.query(DBCbsdState).filter(
         DBCbsdState.name == CbsdStates.UNREGISTERED.value,
     ).scalar()
     user_id = request_payload.get("userId", None)
     fcc_id = request_payload.get("fccId", None)
     cbsd_serial_number = request_payload.get("cbsdSerialNumber", None)
     cbsd = DBCbsd(
         cbsd_id=cbsd_id,
         state=cbsd_state,
         user_id=user_id,
         fcc_id=fcc_id,
         cbsd_serial_number=cbsd_serial_number,
     )
     session.add(cbsd)
     logging.info(f"New CBSD {cbsd=} created.")
     return cbsd
Exemplo n.º 21
0
 def _log_request(self, session: Session, method_name: str, request: CBSDRequest, cbsd: DBCbsd):
     cbsd_serial_number = request.serial_number
     network_id = ''
     fcc_id = ''
     if cbsd:
         network_id = cbsd.network_id or ''
         fcc_id = cbsd.fcc_id or ''
     log = DBLog(
         log_from='CBSD',
         log_to='DP',
         log_name=method_name + 'Request',
         log_message=f'{request}',
         cbsd_serial_number=f'{cbsd_serial_number}',
         network_id=f'{network_id}',
         fcc_id=f'{fcc_id}',
     )
     session.add(log)
Exemplo n.º 22
0
 def _create_cbsd(self, session: Session, request_payload: Dict,
                  cbsd_id: Optional[str]):
     cbsd_state_id = self.cbsd_states_map[CbsdStates.UNREGISTERED.value]
     user_id = request_payload.get("userId", None)
     fcc_id = request_payload.get("fccId", None)
     cbsd_serial_number = request_payload.get("cbsdSerialNumber", None)
     cbsd = DBCbsd(
         cbsd_id=cbsd_id,
         state_id=cbsd_state_id,
         desired_state_id=cbsd_state_id,
         user_id=user_id,
         fcc_id=fcc_id,
         cbsd_serial_number=cbsd_serial_number,
     )
     session.add(cbsd)
     logging.info(f"New CBSD {cbsd=} created.")
     return cbsd
Exemplo n.º 23
0
 def _add_relinquish_requests(self, session: Session, cbsd: DBCbsd) -> None:
     deregister_request_type = session.query(DBRequestType).filter(
         DBRequestType.name == RequestTypes.RELINQUISHMENT.value,
     ).scalar()
     grants = session.query(DBGrant).join(DBGrantState).filter(
         DBGrant.cbsd_id == cbsd.id,
         DBGrantState.name != GrantStates.IDLE.value,
     )
     for grant in grants:
         request_dict = {"cbsdId": cbsd.cbsd_id, "grantId": grant.grant_id}
         db_request = DBRequest(
             type=deregister_request_type,
             cbsd=cbsd,
             payload=request_dict,
         )
         session.add(db_request)
         logger.debug(f"Added {db_request=}.")
     pass
Exemplo n.º 24
0
def _unregister_cbsd(response: DBResponse, session: Session) -> None:
    payload = response.request.payload
    where = _get_cbsd_filter(payload)
    if not where:
        return
    state_id = session.query(DBCbsdState.id). \
        filter(DBCbsdState.name == CbsdStates.UNREGISTERED.value)
    _terminate_all_grants_from_response(response, session)
    _update_cbsd(session, where, {"state_id": state_id.subquery()})
Exemplo n.º 25
0
def _get_channel_related_to_grant(response: DBResponse,
                                  session: Session) -> DBChannel:
    payload = response.request.payload
    operation_param = payload[OPERATION_PARAM]
    frequency_range = operation_param["operationFrequencyRange"]
    channel = session.query(DBChannel).join(DBCbsd).filter(
        DBCbsd.cbsd_id == payload["cbsdId"],
        DBChannel.low_frequency == frequency_range["lowFrequency"],
        DBChannel.high_frequency == frequency_range["highFrequency"],
    ).scalar()
    return channel
Exemplo n.º 26
0
def _create_channels(response: DBResponse, session: Session):
    _terminate_all_grants_from_response(response, session)
    cbsd_id = response.request.payload["cbsdId"]
    cbsd = session.query(DBCbsd).filter(DBCbsd.cbsd_id == cbsd_id).scalar()
    available_channels = response.payload.get("availableChannel")
    if not available_channels:
        logger.warning(
            "Could not create channel from spectrumInquiryResponse. Response missing 'availableChannel' object",
        )
        return
    for ac in available_channels:
        frequency_range = ac["frequencyRange"]
        channel = DBChannel(
            cbsd=cbsd,
            low_frequency=frequency_range["lowFrequency"],
            high_frequency=frequency_range["highFrequency"],
            channel_type=ac["channelType"],
            rule_applied=ac["ruleApplied"],
            max_eirp=ac.get("maxEirp"),
        )
        logger.info(f"Creating channel for {cbsd=}")
        session.add(channel)
Exemplo n.º 27
0
def _list_cbsds(session: Session) -> State:
    # It might be possible to use join instead of nested queries
    # however it requires some serious investigation on how to use it
    # with eager_contains and filter (aliases)
    db_grant_idle_state_id = session.query(DBGrantState.id).filter(
        DBGrantState.name == GrantStates.IDLE.value, ).scalar_subquery()

    # Selectively load sqlalchemy object relations using a single query to avoid commit races.
    # We want to have CBSD entity "grants" relation only contain grants in a Non-IDLE state.
    # We want to have CBSD entity "requests" relation only contain PENDING requests.
    return (session.query(DBCbsd).outerjoin(
        DBGrant,
        and_(
            DBGrant.cbsd_id == DBCbsd.id,
            DBGrant.state_id != db_grant_idle_state_id,
        ),
    ).outerjoin(DBRequest).options(
        joinedload(DBCbsd.state),
        joinedload(DBCbsd.desired_state),
        joinedload(DBCbsd.channels),
        contains_eager(DBCbsd.grants).joinedload(DBGrant.state),
    ).filter(_build_filter()).populate_existing())
Exemplo n.º 28
0
def _get_grant_from_response(
    response: DBResponse,
    session: Session,
) -> Optional[DBGrant]:
    cbsd_id = response.cbsd_id
    grant_id = response.grant_id
    if not grant_id:
        return None

    grant = session.query(DBGrant). \
        join(DBCbsd). \
        filter(DBCbsd.cbsd_id == cbsd_id, DBGrant.grant_id == grant_id). \
        scalar()
    return grant
Exemplo n.º 29
0
def _process_registration_response(cbsd_id: str, response: DBResponse,
                                   session: Session):
    payload = response.request.payload

    where = _get_cbsd_filter(payload)
    if not where:
        return

    state_id = session.query(DBCbsdState.id). \
        filter(DBCbsdState.name == CbsdStates.REGISTERED.value)
    _update_cbsd(session, where, {
        "state_id": state_id.subquery(),
        "cbsd_id": cbsd_id
    })
Exemplo n.º 30
0
class DBTestCase(unittest.TestCase):
    def get_config(self):
        return TestConfig()

    def setUp(self):
        config = self.get_config()
        self.engine = create_engine(
            url=config.SQLALCHEMY_DB_URI,
            encoding=config.SQLALCHEMY_DB_ENCODING,
            echo=False,
            future=config.SQLALCHEMY_FUTURE,
        )
        Base.metadata.bind = self.engine
        Base.metadata.create_all()
        self.session = Session()

    def tearDown(self):
        self.session.rollback()
        self.session.close()
        self.drop_all()

    @staticmethod
    def drop_all():
        Base.metadata.drop_all()