def __call__(self) -> None: """Provision reservation request. The reservation will be provisioned and a ProvisionConfirmed message will be sent to the NSA/AG. If the provision state machine is not in the correct state for a Provision an NSI exception is returned leaving the state machine unchanged. """ self.log.info("Provisioning reservation") from supa.db.session import db_session with db_session() as session: reservation = (session.query(Reservation).filter( Reservation.connection_id == self.connection_id).one_or_none()) psm = ProvisionStateMachine(reservation, state_field="provision_state") dpsm = DataPlaneStateMachine(reservation, state_field="data_plane_state") try: # # TODO: If there is a Network Resource Manager that needs to be contacted # to provision the reservation request then this is the place. # If this is a recovered job then try to recover the reservation state # from the NRM. # pass except NsiException as nsi_exc: self.log.info("Provision failed.", reason=nsi_exc.text) send_error( to_header(reservation), nsi_exc, self.connection_id, ) except Exception as exc: self.log.exception("Unexpected error occurred.", reason=str(exc)) send_error( to_header(reservation), NsiException( GenericInternalError, str(exc), { Variable.PROVISION_STATE: reservation.provsion_state, Variable.CONNECTION_ID: str(self.connection_id), }, ), self.connection_id, ) else: from supa import scheduler psm.provision_confirmed() dpsm.data_plane_up() scheduler.add_job(job := ActivateJob(self.connection_id), trigger=job.trigger()) self._send_provision_confirmed(session)
def __call__(self) -> None: """Abort reservation request. The reservation will be aborted and a ReserveAbortConfirmed message will be sent to the NSA/AG. If the reservation state machine is not in the correct state for a ReserveCommit an NSI error is returned leaving the state machine unchanged. """ self.log.info("Aborting reservation") from supa.db.session import db_session with db_session() as session: reservation = (session.query(Reservation).filter( Reservation.connection_id == self.connection_id).one_or_none()) rsm = ReservationStateMachine(reservation, state_field="reservation_state") try: # # TODO: If there is a Network Resource Manager that needs to be contacted # to abort the reservation request then this is the place. # If this is a recovered job then try to recover the reservation state # from the NRM. # pass except NsiException as nsi_exc: self.log.info("Reserve abort failed.", reason=nsi_exc.text) send_error( to_header(reservation), nsi_exc, self.connection_id, ) except Exception as exc: self.log.exception("Unexpected error occurred.", reason=str(exc)) send_error( to_header(reservation), NsiException( GenericInternalError, str(exc), { Variable.RESERVATION_STATE: reservation.reservation_state, Variable.CONNECTION_ID: str(self.connection_id), }, ), self.connection_id, ) else: rsm.reserve_abort_confirmed() self._send_reserve_abort_confirmed(session)
def __call__(self) -> None: """Activate data plane request. Activate the data plane according to the reservation criteria and send a data plane status notitication to the NSA/AG. If the data plane state machine is not in the correct state for a Activate an NSI exception is returned leaving the state machine unchanged. """ self.log.info("Activating data plane") from supa.db.session import db_session with db_session() as session: reservation = (session.query(Reservation).filter( Reservation.connection_id == self.connection_id).one_or_none()) dpsm = DataPlaneStateMachine(reservation, state_field="data_plane_state") try: # # TODO: Call the Network Resource Manager to activate the data plane. # If this is a recovered job then try to recover the data plane state # from the NRM. # pass except NsiException as nsi_exc: self.log.info("Data plane activation failed", reason=nsi_exc.text) send_error( to_header(reservation), nsi_exc, self.connection_id, ) except Exception as exc: self.log.exception("Unexpected error occurred", reason=str(exc)) send_error( to_header(reservation), NsiException( GenericInternalError, str(exc), { Variable.CONNECTION_ID: str(self.connection_id), }, ), self.connection_id, ) else: dpsm.data_plane_activated() send_data_plane_state_change(session, self.connection_id)
def send_data_plane_state_change(session: orm.Session, connection_id: UUID) -> None: """Send a NSI dataPlaneStateChange notification. The dataPlaneStateChange is an autonomous notification sent from a PA to an RA to inform about a change in status of the data plane. """ reservation: Reservation = session.query(Reservation).get(connection_id) dpsm = DataPlaneStateMachine(reservation, state_field="data_plane_state") pb_dpsc_req = DataPlaneStateChangeRequest() pb_dpsc_req.header.CopyFrom(to_header( reservation, add_path_segment=True)) # Yes, add our segment! pb_dpsc_req.connection_id = str(reservation.connection_id) pb_dpsc_req.notification_id = 1 # TODO Add Column to database for unique notification ID for this reservation. pb_dpsc_req.time_stamp.FromDatetime(current_timestamp()) pb_dpsc_req.data_plane_status.version = reservation.version pb_dpsc_req.data_plane_status.version_consistent = True # always True for an uPA pb_dpsc_req.data_plane_status.active = dpsm.current_state == DataPlaneStateMachine.Active logger.debug("Sending message", method="DataPlaneStateChange", connection_id=connection_id, request_message=pb_dpsc_req) stub = get_stub() stub.DataPlaneStateChange(pb_dpsc_req)
def _send_provision_confirmed(self, session: orm.Session) -> None: # the reservation is still in the session, hence no actual query will be performed reservation: Reservation = session.query(Reservation).get( self.connection_id) pb_pc_req = ProvisionConfirmedRequest() pb_pc_req.header.CopyFrom(to_header( reservation, add_path_segment=True)) # Yes, add our segment! pb_pc_req.connection_id = str(reservation.connection_id) self.log.debug("Sending message.", method="ProvisionConfirmed", request_message=pb_pc_req) stub = requester.get_stub() stub.ProvisionConfirmed(pb_pc_req)
def _send_reserve_confirmed(self, session: orm.Session) -> None: # the reservation is still in the session, hence no actual query will be performed reservation: Reservation = session.query(Reservation).get( self.connection_id) pb_rc_req = ReserveConfirmedRequest() # Confirming the reservation means we have a Path. hence we should add it to the Header. pb_rc_req.header.CopyFrom(to_header(reservation, add_path_segment=True)) pb_rc_req.connection_id = str(reservation.connection_id) pb_rc_req.global_reservation_id = reservation.global_reservation_id # We skip setting the description, cause we have nothing specific to set it to (suggestions?) pb_rc_req.criteria.CopyFrom(to_confirm_criteria(reservation)) self.log.info("Sending message.", method="ReserveConfirmed", request_message=pb_rc_req) stub = requester.get_stub() stub.ReserveConfirmed(pb_rc_req)
def _send_reserve_commit_failed(self, session: orm.Session, nsi_exc: NsiException) -> None: # the reservation is still in the session, hence no actual query will be performed reservation: Reservation = session.query(Reservation).get( self.connection_id) pb_rcf_req = ReserveCommitFailedRequest() pb_rcf_req.header.CopyFrom( to_header(reservation, add_path_segment=False)) pb_rcf_req.connection_id = str(reservation.connection_id) pb_rcf_req.connection_states.CopyFrom( to_connection_states(reservation, data_plane_active=False)) pb_rcf_req.service_exception.CopyFrom( to_service_exception(nsi_exc, reservation.connection_id)) self.log.info("Sending message.", method="ReserveCommitFailed", request_message=pb_rcf_req) stub = requester.get_stub() stub.ReserveCommitFailed(pb_rcf_req)
def __call__(self) -> None: """Timeout reservation request. The reservation will be timed out if the ReservationStateMachine is still in the ReserveHeld state and a ReserveTimeoutNotification message will be sent to the NSA/AG. If another transition already moved the state beyond ReserveHeld then this is practically a no-op. """ self.log.info("Timeout reservation") from supa.db.session import db_session with db_session() as session: reservation = (session.query(Reservation).filter( Reservation.connection_id == self.connection_id).one_or_none()) rsm = ReservationStateMachine(reservation, state_field="reservation_state") try: rsm.reserve_timeout_notification() # # TODO: If there is a Network Resource Manager that needs to be contacted # to timeout the reservation request then this is the place. # If this is a recovered job then try to recover the reservation state # from the NRM. # except TransitionNotAllowed: # Reservation is already in another state turning this into a no-op. self.log.info( "Reservation not timed out", state=rsm.current_state.identifier, connection_id=str(self.connection_id), ) except NsiException as nsi_exc: self.log.info("Reserve timeout failed.", reason=nsi_exc.text) send_error( to_header(reservation), nsi_exc, self.connection_id, ) except Exception as exc: self.log.exception("Unexpected error occurred.", reason=str(exc)) send_error( to_header(reservation), NsiException( GenericInternalError, str(exc), { Variable.RESERVATION_STATE: reservation.reservation_state, Variable.CONNECTION_ID: str(self.connection_id), }, ), self.connection_id, ) else: # # TODO: release reserved resources(?) # self.log.debug( "setting reservation.reservation_timeout to true in db") reservation.reservation_timeout = True self._send_reserve_timeout_notification(session)