def run(self) -> None: self.validate() try: ReportScheduleDAO.bulk_delete(self._models) return None except DAODeleteFailedError as ex: logger.exception(ex.exception) raise ReportScheduleBulkDeleteFailedError() from ex
def validate(self) -> None: exceptions: List[ValidationError] = [] owner_ids: Optional[List[int]] = self._properties.get("owners") name = self._properties.get("name", "") report_type = self._properties.get("type") creation_method = self._properties.get("creation_method") chart_id = self._properties.get("chart") dashboard_id = self._properties.get("dashboard") user_id = self._actor.id # Validate type is required if not report_type: exceptions.append(ReportScheduleRequiredTypeValidationError()) # Validate name type uniqueness if report_type and not ReportScheduleDAO.validate_update_uniqueness( name, report_type ): exceptions.append(ReportScheduleNameUniquenessValidationError()) # validate relation by report type if report_type == ReportScheduleType.ALERT: database_id = self._properties.get("database") if not database_id: exceptions.append(ReportScheduleAlertRequiredDatabaseValidationError()) else: database = DatabaseDAO.find_by_id(database_id) if not database: exceptions.append(DatabaseNotFoundValidationError()) self._properties["database"] = database # Validate chart or dashboard relations self.validate_chart_dashboard(exceptions) # Validate that each chart or dashboard only has one report with # the respective creation method. if ( creation_method != ReportCreationMethodType.ALERTS_REPORTS and not ReportScheduleDAO.validate_unique_creation_method( user_id, dashboard_id, chart_id ) ): raise ReportScheduleCreationMethodUniquenessValidationError() if "validator_config_json" in self._properties: self._properties["validator_config_json"] = json.dumps( self._properties["validator_config_json"] ) try: owners = self.populate_owners(self._actor, owner_ids) self._properties["owners"] = owners except ValidationError as ex: exceptions.append(ex) if exceptions: exception = ReportScheduleInvalidError() exception.add_list(exceptions) raise exception
def run(self) -> None: with session_scope(nullpool=True) as session: self.validate() for report_schedule in session.query(ReportSchedule).all(): from_date = datetime.utcnow() - timedelta( days=report_schedule.log_retention) ReportScheduleDAO.bulk_delete_logs(report_schedule, from_date, session=session, commit=False)
def validate(self) -> None: exceptions: List[ValidationError] = list() owner_ids: Optional[List[int]] = self._properties.get("owners") report_type = self._properties.get("type", ReportScheduleType.ALERT) name = self._properties.get("name", "") self._model = ReportScheduleDAO.find_by_id(self._model_id) # Does the report exist? if not self._model: raise ReportScheduleNotFoundError() # Validate name uniqueness if not ReportScheduleDAO.validate_update_uniqueness( name, report_schedule_id=self._model_id): exceptions.append(ReportScheduleNameUniquenessValidationError()) # validate relation by report type if not report_type: report_type = self._model.type if report_type == ReportScheduleType.ALERT: database_id = self._properties.get("database") # If database_id was sent let's validate it exists if database_id: database = DatabaseDAO.find_by_id(database_id) if not database: exceptions.append(DatabaseNotFoundValidationError()) self._properties["database"] = database # Validate chart or dashboard relations self.validate_chart_dashboard(exceptions, update=True) if "validator_config_json" in self._properties: self._properties["validator_config_json"] = json.dumps( self._properties["validator_config_json"]) # Check ownership try: check_ownership(self._model) except SupersetSecurityException: raise ReportScheduleForbiddenError() # Validate/Populate owner if owner_ids is None: owner_ids = [owner.id for owner in self._model.owners] try: owners = populate_owners(self._actor, owner_ids) self._properties["owners"] = owners except ValidationError as ex: exceptions.append(ex) if exceptions: exception = ReportScheduleInvalidError() exception.add_list(exceptions) raise exception
def scheduler() -> None: """ Celery beat main scheduler for reports """ if not is_feature_enabled("ALERT_REPORTS"): return with session_scope(nullpool=True) as session: active_schedules = ReportScheduleDAO.find_active(session) for active_schedule in active_schedules: for schedule in cron_schedule_window( active_schedule.crontab, active_schedule.timezone ): logger.info( "Scheduling alert %s eta: %s", active_schedule.name, schedule ) async_options = {"eta": schedule} if ( active_schedule.working_timeout is not None and app.config["ALERT_REPORTS_WORKING_TIME_OUT_KILL"] ): async_options["time_limit"] = ( active_schedule.working_timeout + app.config["ALERT_REPORTS_WORKING_TIME_OUT_LAG"] ) async_options["soft_time_limit"] = ( active_schedule.working_timeout + app.config["ALERT_REPORTS_WORKING_SOFT_TIME_OUT_LAG"] ) execute.apply_async((active_schedule.id, schedule,), **async_options)
def validate( # pylint: disable=arguments-differ self, session: Session = None) -> None: # Validate/populate model exists self._model = ReportScheduleDAO.find_by_id(self._model_id, session=session) if not self._model: raise ReportScheduleNotFoundError()
def run(self) -> Model: self.validate() try: report_schedule = ReportScheduleDAO.create(self._properties) except DAOCreateFailedError as ex: logger.exception(ex.exception) raise ReportScheduleCreateFailedError() from ex return report_schedule
def run(self) -> Model: self.validate() try: report_schedule = ReportScheduleDAO.delete(self._model) except DAODeleteFailedError as ex: logger.exception(ex.exception) raise ReportScheduleDeleteFailedError() from ex return report_schedule
def run(self) -> Model: self.validate() try: report_schedule = ReportScheduleDAO.update(self._model, self._properties) except DAOUpdateFailedError as ex: logger.exception(ex.exception) raise ReportScheduleUpdateFailedError() return report_schedule
def is_in_grace_period(self) -> bool: """ Checks if an alert is on it's grace period """ last_success = ReportScheduleDAO.find_last_success_log( self._report_schedule, session=self._session) return (last_success is not None and self._report_schedule.grace_period and datetime.utcnow() - timedelta(seconds=self._report_schedule.grace_period) < last_success.end_dttm)
def validate(self) -> None: # Validate/populate model exists self._model = ReportScheduleDAO.find_by_id(self._model_id) if not self._model: raise ReportScheduleNotFoundError() # Check ownership try: security_manager.raise_for_ownership(self._model) except SupersetSecurityException as ex: raise ReportScheduleForbiddenError() from ex
def scheduler() -> None: """ Celery beat main scheduler for reports """ with session_scope(nullpool=True) as session: active_schedules = ReportScheduleDAO.find_active(session) for active_schedule in active_schedules: for schedule in cron_schedule_window(active_schedule.crontab): logger.info( "Scheduling alert %s eta: %s", active_schedule.name, schedule ) execute.apply_async((active_schedule.id, schedule,), eta=schedule)
def validate(self) -> None: # Validate/populate model exists self._models = ReportScheduleDAO.find_by_ids(self._model_ids) if not self._models or len(self._models) != len(self._model_ids): raise ReportScheduleNotFoundError() # Check ownership for model in self._models: try: check_ownership(model) except SupersetSecurityException as ex: raise ReportScheduleForbiddenError() from ex
def is_in_error_grace_period(self) -> bool: """ Checks if an alert/report on error is on it's notification grace period """ last_success = ReportScheduleDAO.find_last_error_notification( self._report_schedule, session=self._session) if not last_success: return False return (last_success is not None and self._report_schedule.grace_period and datetime.utcnow() - timedelta(seconds=self._report_schedule.grace_period) < last_success.end_dttm)
def validate( # pylint: disable=arguments-differ self, session: Session = None ) -> None: # Validate/populate model exists self._model = ReportScheduleDAO.find_by_id(self._model_id, session=session) if not self._model: raise ReportScheduleNotFoundError() # Avoid overlap processing if self._model.last_state == ReportLogState.WORKING: raise ReportSchedulePreviousWorkingError() # Check grace period if self._model.type == ReportScheduleType.ALERT: last_success = ReportScheduleDAO.find_last_success_log(session) if ( last_success and self._model.last_state in (ReportLogState.SUCCESS, ReportLogState.NOOP) and self._model.grace_period and datetime.utcnow() - timedelta(seconds=self._model.grace_period) < last_success.end_dttm ): raise ReportScheduleAlertGracePeriodError()
def is_on_working_timeout(self) -> bool: """ Checks if an alert is on a working timeout """ last_working = ReportScheduleDAO.find_last_entered_working_log( self._report_schedule, session=self._session) if not last_working: return False return (self._report_schedule.working_timeout is not None and self._report_schedule.last_eval_dttm is not None and datetime.utcnow() - timedelta(seconds=self._report_schedule.working_timeout) > last_working.end_dttm)
def validate(self) -> None: # Validate/populate model exists self._model = DatabaseDAO.find_by_id(self._model_id) if not self._model: raise DatabaseNotFoundError() # Check there are no associated ReportSchedules reports = ReportScheduleDAO.find_by_database_id(self._model_id) if reports: report_names = [report.name for report in reports] raise DatabaseDeleteFailedReportsExistError( _("There are associated alerts or reports: %s" % ",".join(report_names)) ) # Check if there are datasets for this database if self._model.tables: raise DatabaseDeleteDatasetsExistFailedError()
def validate(self) -> None: # Validate/populate model exists self._model = DashboardDAO.find_by_id(self._model_id) if not self._model: raise DashboardNotFoundError() # Check there are no associated ReportSchedules reports = ReportScheduleDAO.find_by_dashboard_id(self._model_id) if reports: report_names = [report.name for report in reports] raise DashboardDeleteFailedReportsExistError( _("There are associated alerts or reports: %s" % ",".join(report_names))) # Check ownership try: check_ownership(self._model) except SupersetSecurityException as ex: raise DashboardForbiddenError() from ex
def validate(self) -> None: # Validate/populate model exists self._models = DashboardDAO.find_by_ids(self._model_ids) if not self._models or len(self._models) != len(self._model_ids): raise DashboardNotFoundError() # Check there are no associated ReportSchedules reports = ReportScheduleDAO.find_by_dashboard_ids(self._model_ids) if reports: report_names = [report.name for report in reports] raise DashboardBulkDeleteFailedReportsExistError( _("There are associated alerts or reports: %s" % ",".join(report_names)) ) # Check ownership for model in self._models: try: security_manager.raise_for_ownership(model) except SupersetSecurityException as ex: raise DashboardForbiddenError() from ex
def validate(self) -> None: # Validate/populate model exists self._models = ChartDAO.find_by_ids(self._model_ids) if not self._models or len(self._models) != len(self._model_ids): raise ChartNotFoundError() # Check there are no associated ReportSchedules reports = ReportScheduleDAO.find_by_chart_ids(self._model_ids) if reports: report_names = [report.name for report in reports] raise ChartBulkDeleteFailedReportsExistError( _("There are associated alerts or reports: %s" % ",".join(report_names))) # Check ownership for model in self._models: try: check_ownership(model) except SupersetSecurityException: raise ChartForbiddenError()
def validate(self) -> None: exceptions: List[ValidationError] = list() owner_ids: Optional[List[int]] = self._properties.get("owners") name = self._properties.get("name", "") report_type = self._properties.get("type") # Validate type is required if not report_type: exceptions.append(ReportScheduleRequiredTypeValidationError()) # Validate name type uniqueness if report_type and not ReportScheduleDAO.validate_update_uniqueness( name, report_type ): exceptions.append(ReportScheduleNameUniquenessValidationError()) # validate relation by report type if report_type == ReportScheduleType.ALERT: database_id = self._properties.get("database") if not database_id: exceptions.append(ReportScheduleAlertRequiredDatabaseValidationError()) else: database = DatabaseDAO.find_by_id(database_id) if not database: exceptions.append(DatabaseNotFoundValidationError()) self._properties["database"] = database # Validate chart or dashboard relations self.validate_chart_dashboard(exceptions) if "validator_config_json" in self._properties: self._properties["validator_config_json"] = json.dumps( self._properties["validator_config_json"] ) try: owners = self.populate_owners(self._actor, owner_ids) self._properties["owners"] = owners except ValidationError as ex: exceptions.append(ex) if exceptions: exception = ReportScheduleInvalidError() exception.add_list(exceptions) raise exception
def run(self) -> None: with session_scope(nullpool=True) as session: self.validate() prune_errors = [] for report_schedule in session.query(ReportSchedule).all(): if report_schedule.log_retention is not None: from_date = datetime.utcnow() - timedelta( days=report_schedule.log_retention ) try: row_count = ReportScheduleDAO.bulk_delete_logs( report_schedule, from_date, session=session, commit=False ) logger.info( "Deleted %s logs for report schedule id: %s", str(row_count), str(report_schedule.id), ) except DAODeleteFailedError as ex: prune_errors.append(str(ex)) if prune_errors: raise ReportSchedulePruneLogError(";".join(prune_errors))
def validate(self) -> None: # Validate/populate model exists self._models = ReportScheduleDAO.find_by_ids(self._model_ids) if not self._models or len(self._models) != len(self._model_ids): raise ReportScheduleNotFoundError()
def validate(self) -> None: # Validate/populate model exists self._model = ReportScheduleDAO.find_by_id(self._model_id) if not self._model: raise ReportScheduleNotFoundError()
def validate(self) -> None: exceptions: List[ValidationError] = list() owner_ids: Optional[List[int]] = self._properties.get("owners") report_type = self._properties.get("type", ReportScheduleType.ALERT) name = self._properties.get("name", "") self._model = ReportScheduleDAO.find_by_id(self._model_id) # Does the report exist? if not self._model: raise ReportScheduleNotFoundError() # Change the state to not triggered when the user deactivates # A report that is currently in a working state. This prevents # an alert/report from being kept in a working state if activated back if (self._model.last_state == ReportState.WORKING and "active" in self._properties and not self._properties["active"]): self._properties["last_state"] = ReportState.NOOP # validate relation by report type if not report_type: report_type = self._model.type # Validate name type uniqueness if not ReportScheduleDAO.validate_update_uniqueness( name, report_type, report_schedule_id=self._model_id): exceptions.append(ReportScheduleNameUniquenessValidationError()) if report_type == ReportScheduleType.ALERT: database_id = self._properties.get("database") # If database_id was sent let's validate it exists if database_id: database = DatabaseDAO.find_by_id(database_id) if not database: exceptions.append(DatabaseNotFoundValidationError()) self._properties["database"] = database # Validate chart or dashboard relations self.validate_chart_dashboard(exceptions, update=True) if "validator_config_json" in self._properties: self._properties["validator_config_json"] = json.dumps( self._properties["validator_config_json"]) # Check ownership try: check_ownership(self._model) except SupersetSecurityException: raise ReportScheduleForbiddenError() # Validate/Populate owner if owner_ids is None: owner_ids = [owner.id for owner in self._model.owners] try: owners = populate_owners(self._actor, owner_ids) self._properties["owners"] = owners except ValidationError as ex: exceptions.append(ex) if exceptions: exception = ReportScheduleInvalidError() exception.add_list(exceptions) raise exception