def send_notification(message, message_type, recipients, system_id): """ Create and sends a notification @param system_id: id of the system the notification is created from @type system_id:str @param message: a string of the content to be sent @type:str @param message_type: a string indicating the notification type @type: str @param recipients: a list containing either email or Phone_number dependent on message type @type:list @return: returns a dict of a code for success or failure @rtype: dict """ if not (recipients or message or message_type): return {"code": "800.400.002"} try: for recipient in recipients: data = NotificationService().create( message=message, notification_type=NotificationTypeService().get( name=message_type), recipient=recipient, system=SystemService().get(pk=system_id), state=StateService().get(name='Active')) if data is not None: message_data = { "destination": data.recipient, "message_type": data.notification_type.name, "lang": None, "corporate_id": None, "message_code": 'HPS0006', "replace_tags": { "code": None, 'corporate': None, 'date': datetime.now().strftime('%d/%m/%y'), 'time': datetime.now().time().strftime('%I:%M%p') } } # to do a call to notification API check if it returns a code for success if message_data: NotificationService().update( data.id, state=StateService().get(name='Sent')) else: data = NotificationService().update( data.id, state=StateService().get(name='Failed')) lgr.warn("Message sending failed: %s" % data) else: return {"code": "200.400.005"} return {"code": "800.200.001", "message": message} except Exception as e: lgr.exception("Notification logger exception %s" % e) return { "code": "800.400.001", "message": "error in sending notification interface" }
def get_look_up_data(): """ @return: a dictionary containing a success code and a list of dictionaries containing system recipient data @rtype:dict """ try: state = list(StateService().filter().values('id', 'name')) notification_type = list(NotificationTypeService().filter().values( 'id', 'name')) escalation_level = list(EscalationLevelService().filter().values( 'id', 'name')) event_type = list(EventTypeService().filter().values('id', 'name')) endpoint_type = list(EndpointTypeService().filter().values( 'id', 'name')) incident_type = list(IncidentTypeService().filter().values( 'id', 'name')) user = list(User.objects.all().values('id', 'username')) system = list(SystemService().filter().values('id', 'name')) endpoint_states = list(StateService().filter( Q(name='Operational') | Q(name='Minor Outage') | Q(name='Major Outage') | Q(name='Under Maintenance') | Q(name='Degraded Performance')).values('id', 'name')) realtime_incident_states = list(StateService().filter( Q(name='Investigating') | Q(name='Identified') | Q(name='Monitoring') | Q(name='Resolved')).values( 'id', 'name')) scheduled_incident_states = list(StateService().filter( Q(name='Scheduled') | Q(name='InProgress') | Q(name='Completed')).values('id', 'name')) lookups = { 'states': state, 'incident_types': incident_type, 'escalation_levels': escalation_level, 'notification_types': notification_type, 'endpoint_types': endpoint_type, 'event_types': event_type, 'users': user, 'systems': system, 'realtime_incident_states': realtime_incident_states, 'endpoint_states': endpoint_states, 'scheduled_incident_states': scheduled_incident_states } return {"code": "800.200.001", "data": lookups} except Exception as ex: lgr.exception("Look up interface Exception: %s" % ex) return { "code": "800.400.001", "message": "Error while fetching data %s" % str(ex) }
def create_rule(name, description, system, event_type, nth_event, escalation_level, duration, **kwargs): """ Creates an escalation rule for a selected system. @param name: Name of the escalation rule to be created @type name: str @param system: The system which the escalation rule will be applied in @type system: str @param description: Details on the Escalation Rule @type description: str @param event_type: Type of the event(s) to be affected by the rule @type event_type: str @param nth_event: Number of event of a certain type that need to be logged to raise an escalation @type nth_event: str @param duration: Time period within which certain events must occur to trigger an escalation. @type duration: int @param escalation_level: Level at which an escalation is configured with a set of recipients @type escalation_level: str @param kwargs: Extra key-value arguments to pass for incident logging @return: Response code dictionary to indicate if the incident was created or not @rtype: dict """ try: system = SystemService().get(pk=system, state__name="Active") escalation_level = EscalationLevelService().get( pk=escalation_level, state__name="Active") event_type = EventTypeService().get(pk=event_type, state__name='Active') if system is None or escalation_level is None or event_type is None: return {"code": "800.400.002"} escalation_rule = EscalationRuleService().create( name=name, description=description, system=system, nth_event=int(nth_event), duration=timedelta(seconds=duration), state=StateService().get(name='Active'), escalation_level=escalation_level, event_type=event_type) if escalation_rule is not None: rule = EscalationRuleService().filter( pk=escalation_rule.id, system=system).values( 'id', 'name', 'description', 'duration', 'date_created', 'date_modified', 'nth_event', system_id=F('system'), escalation_level_name=F('escalation_level__name'), state_name=F('state__name'), event_type_name=F('event_type__name')).first() rule.update( duration=timedelta.total_seconds(rule.get('duration'))) return {'code': '800.200.001', 'data': rule} except Exception as ex: lgr.exception("Escalation Rule Creation exception %s" % ex) return {"code": "800.400.001"}
def test_filter(self): """ Test State filter service """ mixer.cycle(3).blend('base.State') states = StateService().filter() assert len(states) == 3, 'Should have 3 State objects'
def get_access_token(request): """ Generates an access token for valid app users @param request: @type request: DJANGO WSGIRequest @return: An access token and its expiry time or a response code indicating invalid credentials supplied @rtype: dict """ try: data = get_request_data(request) app_user = AppUserService().get(user__username = data.get('username')) if app_user is not None: user = check_password(data.get('password'), app_user.user.password) if user: oauth = OauthService().filter( app_user = app_user, expires_at__gt = timezone.now(), state__name = 'Active').first() if oauth: oauth = OauthService().update(pk = oauth.id, expires_at = token_expiry()) else: oauth = OauthService().create( app_user = app_user, token = generate_access_token(), state = StateService().get(name = 'Active') ) if not oauth: return JsonResponse({'code': '800.400.001'}) return JsonResponse({ 'code': '800.200.001', 'data': { 'token': str(oauth.token), 'expires_at': calendar.timegm(oauth.expires_at.timetuple()) } }) return JsonResponse({'code': '800.403.001'}) except Exception as ex: lgr.exception("Get Access token Exception %s " % ex) return JsonResponse({'code': '800.400.001'})
def test_create(self): """ Test for the StateService create(**kwargs) method """ obj = StateService().create( name='Active', description='initializes all the ACTIVE state') assert obj is not None, 'Should create a new State with name ACTIVE'
def test_update(self): """ Test for the StateService update(pk, **kwargs) method """ state = mixer.blend('base.State', name='Active') new_state = StateService().update(state.id, name='In Transit') assert new_state is not None, 'Should update the State object with a new name'
def test_get(self): """ Test for the StateService get(*args, **kwargs) method """ mixer.blend('base.State', name='Active') obj = StateService().get(name='Active') assert obj is not None, 'Should return a State instance with name ACTIVE'
def test_update(self): """ Test State update service """ state = mixer.blend('base.State') state = StateService().update(state.id, name = "Active") assert state.name == "Active", 'Should have the same name'
def test_get(self): """ Test State get service """ mixer.blend('base.State', name="Active") state = StateService().get(name="Active") assert state is not None, 'Should have an State object'
def test_create(self): """ Test State create service """ state = StateService().create(name = "Active") assert state is not None, 'Should have a State object' assert state.name == "Active", "Created State name is equals to Active"
def update_system_recipient(recipient_id, escalations): """ @param recipient_id: The id of the recipient @type:str @param escalations:A list of dictionaries containing notification type id and escalation level_id @type:list @return:Response code dictionary to indicate if the recipient was updated or not @rtype:dict """ try: recipient = User.objects.get(id=recipient_id) if not (recipient and escalations): return { "code": "800.400.002", "message": "Error missing parameters" } for escalation in escalations: SystemRecipientService().update( pk=escalation.get('system_recipient_id'), notification_type=NotificationTypeService().get( id=escalation.get('notification_type_id')), state=StateService().get(id=escalation.get('state_id'))) return { "code": "800.200.001", "message": "Successfully updated system recipient" } except Exception as ex: lgr.exception("Recipient Administration Exception: %s" % ex) return { "code": "800.400.001", "message": "Error while updating recipient" }
def test_filter(self): """ Test for the StateService filter(*args, **kwargs) method """ mixer.cycle(3).blend('base.State', name='Active') obj = StateService().filter(name='Active') assert len( obj) == 3, 'Should return 3 State instances with name ACTIVE'
def create_endpoint(name, description, url, system_id, color, response_time, endpoint_type_id, state_id): """ @param color: color the line graph will use when plotting @type color: str @param name: name of endpoint to be created @type name:str @param description: description of endpoint to be created @type description: str @param url: url of endpoint to be created @type: str @param system_id: id of system the endpoint will belong to @type : int @param response_time: average response time the endpoint should take @type: int @param endpoint_type_id: id of endpoint type the endpoint will belong to @type endpoint_type_id: int @param state_id: the id of initial state of the created endpoint will have @type state_id: int @return: Response code dictionary to indicate if the endpoint was created or not @rtype:dict """ try: system = SystemService().get(id=system_id, state__name="Active") endpoint_type = EndpointTypeService().get(id=endpoint_type_id, state__name="Active") state = StateService().get(id=state_id) if not (system and endpoint_type and state and name and description and response_time and url): return {"code": "800.400.002", "message": "Missing parameters"} exist = True if EndpointService().filter(system = system, url = url) \ else EndpointService().filter(system = system, name = name) if exist: return { "code": "800.400.001", "message": "An endpoint with this url or name exists" } endpoint = EndpointService().create( name=name, description=description, url=url, system=system, endpoint_type=endpoint_type, color=color, optimal_response_time=datetime.timedelta( seconds=int(response_time)), state=state) return { "code": "800.200.001", "message": "successfully created endpoint: %s" % endpoint.name } except Exception as ex: lgr.exception("Endpoint Administration exception: %s" % ex) return { "code": "800.400.001", "message": "Error when creating an endpoint" }
def create_system_recipient(system_id, user_id, escalations): """ @param system_id: The id of the system the recipient will belong to @type:str @param user_id: The id of the recipient @type:str @param escalations:A list of dictionaries containing notification type id and escalation level_id @type:list @return:a dictionary containing response code and data indicating a success or failure in creation @rtype: dict """ try: system = SystemService().get(id=system_id) recipient = User.objects.get(id=user_id) if not (system and recipient and escalations): return { "code": "800.400.002", "message": "Invalid parameters given" } for escalation in escalations: if SystemRecipientService().filter( system=system, recipient=recipient, escalation_level=EscalationLevelService().get( id=escalation.get('EscalationLevel')), ): return { "code": "800.400.001", "message": "system recipient already exist consider updating the recipient" } SystemRecipientService().create( system=system, recipient=recipient, escalation_level=EscalationLevelService().get( id=escalation.get('EscalationLevel')), notification_type=NotificationTypeService().get( id=escalation.get('NotificationType')), state=StateService().get(name='Active')) return { "code": "800.200.001", "message": " successfully created a system recipient" } except Exception as ex: lgr.exception("Recipient Administration Exception: %s" % ex) return { "code": "800.400.001", "message": "Error while creating a system recipient" }
def update_endpoint(endpoint_id, state_id, description, color, url, response_time, name): """ @param color: color the line graph will use while plotting @type color: str @param endpoint_id: id of the endpoint to be edited @type endpoint_id: int @param name: name of endpoint to be created @type name: str @param description: description of endpoint to be created @type description: str @param url:url of endpoint to be created @type url: str @param response_time:average response time the endpoint should take @type response_time: int @param state_id:the id of initial state of the created endpoint will have @type state_id: int @return: Response code dictionary to indicate if the endpoint was updated or not @rtype: dict """ try: update_endpoint = EndpointService().get(pk=endpoint_id) state = StateService().get(id=state_id) if not (state and name and description and response_time and color and url and update_endpoint): return { "code": "800.400.002", "message": "Error missing parameters" } endpoint = EndpointService().update( pk=update_endpoint.id, description=description, state=state, name=name, color=color, optimal_response_time=datetime.timedelta( seconds=float(response_time)), url=url) return { "code": "800.200.001", "message": "successfully updated endpoint: %s" % endpoint.name } except Exception as ex: lgr.exception("Endpoint Administration exception: %s" % ex) return { "code": "800.400.001", "message": "Error when updating an endpoint" }
def create_user(username, password, email, first_name=None, last_name=None, phone_number=None, **kwargs): """ Creates a user. @param username: Username of the user to be created @type username: str @param email: Email of the user to be created @type email: str @param password: Password of the user to be created @type password: str @param first_name: First name of the user @type first_name: str | None @param last_name: Last name of the user @type last_name: str | None @param phone_number: Phone number of the user to be created @type email: str | None @param kwargs: Extra key-value arguments to pass for user creation @return: Response code dictionary to indicate if the user was created or not @rtype: dict """ try: if User.objects.filter(username=username).exists(): return { "code": "800.400.001", 'message': 'Username already in use' } if User.objects.filter(email=email).exists(): return { "code": "800.400.001", 'message': 'Email already in use' } user = User.objects.create_user(username, email, password, first_name=first_name, last_name=last_name, phone_number=phone_number) app = AppService().filter(system__name='Helaplan', state__name='Active').values().first() if not app: return { "code": "800.400.002", "message": 'No Authentication app tied to this system' } user = User.objects.filter(id=user.id).values().first() if user: app_user = AppUserService().create( app=AppService().get(system__name='Helaplan'), user=User.objects.get(email=user.get('email')), state=StateService().get(name='Active')) if not app_user: return { 'code': '800.400.003', "message": "Failed to create an app user %s %s" % (user.get('id'), app) } return {'code': '800.200.001', 'data': user} except Exception as ex: lgr.exception("UserCreation exception %s" % ex) return { "code": "800.400.001", 'message': 'User could not be created %s' % ex }
def perform_health_check(): """ This method formats system data and logs system status to system monitor model @return: Systems: a dictionary containing a success code and a list of dictionaries containing system status data @rtype:dict """ systems = [] try: for endpoint in EndpointService().filter( system__state__name="Active", endpoint_type__is_queried=True): try: health_state = requests.get(endpoint.url) monitor_data = { 'system': endpoint.system.name, 'endpoint': endpoint.name, 'response_body': health_state.content, 'response_code': health_state.status_code, 'state': StateService().get(name='Operational').name, } if health_state.status_code == 200: if health_state.elapsed > endpoint.optimal_response_time: monitor_data.update({ "response_time_speed": 'Slow', "event_type": EventTypeService().get(name='Warning'), "description": 'Response time is not within the expected time', "state": StateService().get( name='Degraded Performance'), "response_time": health_state.elapsed.total_seconds() }) else: monitor_data.update({ 'response_time_speed': 'Normal', "response_time": health_state.elapsed.total_seconds() }) else: monitor_data.update({ "response_time_speed": None, "event_type": EventTypeService().get(name='Critical'), "description": 'The system is not accessible', "state": StateService().get(name='Major Outage') }) system_status = SystemMonitorService().create( system=SystemService().get( name=monitor_data.get('system')), response_time=timedelta( seconds=int(monitor_data.get('response_time'))), response_time_speed=monitor_data.get( "response_time_speed"), state=StateService().get( name=monitor_data.get('state')), response_body=monitor_data.get("response_body"), endpoint=EndpointService().get( name=monitor_data.get("endpoint")), response_code=monitor_data.get("response_code")) if system_status is not None: systems.append({ "system": system_status.system.name, "status": system_status.state.name, "endpoint": endpoint.url }) else: systems.append({ "system": system_status.system, "status": "failed", "endpoint": endpoint }) if monitor_data.get("event_type") is not None: event = EventLog.log_event( event_type=monitor_data.get("event_type").name, system=monitor_data.get("system"), description=monitor_data.get("description"), response=monitor_data.get('response'), request=health_state.request) if event['code'] != "800.200.001": lgr.warning("Event creation failed %s" % event) except requests.ConnectionError as e: lgr.exception('Endpoint health check failed: %s' % e) return {"code": "800.200.001", "data": {"systems": systems}} except Exception as ex: lgr.exception("Health Status exception: %s" % ex) return { "code": "800.400.001", "message": "Error while performing health check" }
def log_incident(incident_type, system, escalation_level, name, description, priority_level, event_type=None, state="Investigating", escalated_events=None, scheduled_for=None, scheduled_until=None, **kwargs): """ Creates a realtime incident based on escalated events or scheduled incident based on user reports @param incident_type: Type of the incident to be created @type incident_type: str @param system: The system which the incident will be associated with @type system: str @param name: Title of the incident @type name: str @param description: Details on the incident @type description: str @param event_type: Type of the event(s) that triggered creation of the incident, if its event driven. @type event_type: str | None @param escalated_events: One or more events in the escalation if the incident is event driven. @type escalated_events: list | None @param state: Initial resolution state of the incident. Defaults to Investigating if left blank @type state: str @param priority_level: The level of importance to be assigned to the incident. @type priority_level: str @param escalation_level: Level at which an escalation is configured with a set of recipients @type escalation_level: str @param scheduled_for: Time the scheduled maintenance should begin if the incident is scheduled @type scheduled_for: str | None @param scheduled_until: Time the scheduled maintenance should end if the incident is scheduled @type scheduled_until: str | None @param kwargs: Extra key-value arguments to pass for incident logging @return: Response code dictionary to indicate if the incident was created or not @rtype: dict """ try: system = SystemService().get(pk=system, state__name="Active") incident_type = IncidentTypeService().get(name=incident_type, state__name="Active") try: state = StateService().get(pk=uuid.UUID(state)) except ValueError: state = StateService().get( name=state ) if incident_type.name == 'Realtime' else StateService().get( name='Scheduled') escalation_level = EscalationLevelService().get( pk=escalation_level, state__name="Active") if system is None or incident_type is None or escalation_level is None: return {"code": "800.400.002"} if incident_type.name == "Realtime" and event_type is not None: incident = IncidentService().filter( event_type__name=event_type, system=system).exclude( Q(state__name='Resolved'), Q(state__name='Completed')).order_by( '-date_created').first() if incident and int(priority_level) < 5: priority_level = incident.priority_level + 1 return IncidentAdministrator().update_incident( incident_id=incident.id, escalation_level=escalation_level.name, name=incident.name, state=incident.state.id, priority_level=str(priority_level), description= "Priority level of %s incident changed to %s" % (incident.name, priority_level)) if incident_type.name == 'Scheduled': scheduled_for = dateutil.parser.parse(scheduled_for) scheduled_until = dateutil.parser.parse(scheduled_until) incident = IncidentService().create( name=name, description=description, state=StateService().get(name=state), system=system, incident_type=incident_type, scheduled_for=scheduled_for, scheduled_until=scheduled_until, event_type=EventTypeService().get(name=event_type), priority_level=int(priority_level)) incident_log = IncidentLogService().create( description=description, incident=incident, priority_level=priority_level, state=StateService().get(name=state), escalation_level=escalation_level) if incident is not None and incident_log is not None: if escalated_events: for event in escalated_events: incident_event = IncidentEventService().create( event=event, incident=incident, state=StateService().get(name="Active")) if not incident_event: lgr.error("Error creating incident-events") email_system_recipients = SystemRecipientService().filter( escalation_level=escalation_level, system=incident.system, state__name='Active', notification_type__name='Email').values('recipient__id') sms_system_recipients = SystemRecipientService().filter( escalation_level=escalation_level, system=incident.system, state__name='Active', notification_type__name='Sms').values('recipient__id') sms_notification = NotificationLogger().send_notification( message=incident.description, message_type="Sms", system_id=incident.system.id, recipients=[ str(recipient["phone_number"]) for recipient in User.objects.filter( id__in=sms_system_recipients, is_active=True).values("phone_number") ]) email_notification = NotificationLogger().send_notification( message=incident.description, message_type="Email", system_id=incident.system.id, recipients=[ str(recipient['user__email']) for recipient in User.objects.filter(id__in=email_system_recipients, is_active=True).values('email') ]) if sms_notification.get( 'code') != '800.200.001' or email_notification.get( 'code') != '800.200.001': lgr.exception("Notification sending failed") return {'code': '800.200.001'} except Exception as ex: lgr.exception("Incident Logger exception %s" % ex) return {"code": "800.400.001"}
def update_incident(incident_id, name, escalation_level, state, description, user=None, priority_level=None): """ Logs incident updates e.g changes in resolution state or priority level of an incident @param incident_id: The id of the incident to be updated @type incident_id: str @param name: The name of the incident to be updated @type name: str @param escalation_level: Level at which to send notifications to configured users @type escalation_level: str @param state: New resolution state of the incident @type state: str @param description: Detailed information on the incident update @type description: str @param user: User assigned to the incident @type user: str | None @param priority_level: New priority level of the incident @type priority_level: str | None @return: Response code in a dictionary to indicate if the incident was updated or not @rtype: dict """ try: state = StateService().get(pk=state) incident = IncidentService().get(pk=incident_id) escalation_level = EscalationLevelService().get( pk=escalation_level, state__name="Active") user = User.objects.filter(id=user).first() if user else None if incident is None or escalation_level is None or state is None: return {'code': '800.400.002'} priority_level = int( priority_level ) if priority_level is not None else incident.priority_level incident_log = IncidentLogService().create( description=description, incident=incident, user=user, priority_level=priority_level, state=state, escalation_level=escalation_level) if state.name == 'Completed' or state.name == 'Resolved': IncidentService().update(pk=incident.id, priority_level=priority_level, state=state, name=name, description=description) else: IncidentService().update(pk=incident.id, priority_level=priority_level) if incident_log: email_system_recipients = SystemRecipientService().filter( escalation_level=escalation_level, system=incident.system, state__name='Active', notification_type__name='Email').values('recipient__id') sms_system_recipients = SystemRecipientService().filter( escalation_level=escalation_level, system=incident.system, state__name='Active', notification_type__name='Sms').values('recipient__id') sms_notification = NotificationLogger().send_notification( message=incident_log.description, message_type="Sms", system_id=incident.system.id, recipients=[ str(recipient["phone_number"]) for recipient in User.objects.filter( id__in=sms_system_recipients, is_active=True).values("phone_number") ]) email_notification = NotificationLogger().send_notification( message=incident_log.description, message_type="Email", system_id=incident.system.id, recipients=[ str(recipient['user__email']) for recipient in User.objects.filter(id__in=email_system_recipients, is_active=True).values('email') ]) if sms_notification.get( 'code') != '800.200.001' or email_notification.get( 'code') != '800.200.001': lgr.warning("Notification sending failed") return {'code': '800.200.001'} except Exception as ex: lgr.exception("Incident Administration exception %s" % ex) return {'code': '800.400.001'}
def log_event(event_type, system, interface=None, method=None, response=None, request=None, code=None, description=None, stack_trace=None, **kwargs): """ Logs an event that being reported from an external system or an health check @param event_type: Type of the event to be logged @type event_type: str @param system: The system where the event occurred @type system: str @param interface: Specific interface in a system where the event occurred @type interface: str | None @param method: Specific method within an interface where the event occurred @type method: str | None @param response: Response body, if any, of the reported event occurrence @type response: str | None @param request: Request body, if any, of the reported event occurrence @type request: str | None @param code: Response code of the event @type code: str | None @param description: Detailed information on the event occurrence @type description: str | None @param stack_trace: Stack trace from the on the event occurrence @type stack_trace: str | None @param kwargs: Extra key=>value arguments to be passed for the event logging @return: Response code in a dictionary indicating if the event is created successfully or not @rtype: dict """ try: system = SystemService().get(pk=system, state__name="Active") event_type = EventTypeService().get(name=event_type, state__name="Active") if system is None or event_type is None: return {"code": "800.400.002"} event = EventService().create( event_type=event_type, system=system, method=method, response=response, request=request, code=code, description=description, state=StateService().get(name="Active"), interface=InterfaceService().get(name=interface, state__name="Active", system=system), stack_trace=stack_trace) if event is not None: escalation = EventLog.escalate_event(event) if escalation.get('code') != '800.200.001': lgr.error('%s event escalation Failed' % event_type) created_event = EventService().filter(id=event.id).values( 'id', 'event_type', 'state__id', 'system__id', 'method', 'response', 'request', 'code', 'description', 'interface__id', 'stack_trace').first() return {'code': '800.200.001', 'data': created_event} except Exception as ex: lgr.exception('Event processor exception %s' % ex) return {'code': '800.400.001'}