Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 32 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@

**Webhook plugin for AWS SNS**

> SpaceONE's [plugin-aws-sns-monitoring-webhook](https://github.com/spaceone-dev/plugin-aws-sns-mon-webhook)
is a tool that can integrate and manage events of various patterns from various AWS alert services.
> SpaceONE's [plugin-aws-sns-monitoring-webhook](https://github.com/spaceone-dev/plugin-aws-sns-mon-webhook)
> is a tool that can integrate and manage events of various patterns from various AWS alert services.
> SpaceONE already supports various external monitoring ecosystems in the form of plug-ins
> (Prometheus, Grafana, Zabbix, etc), and SNS webhook is one of them, which more reliably supports events of AWS alert services.
> (Prometheus, Grafana, Zabbix, etc), and SNS webhook is one of them, which more reliably supports events of AWS alert
> services.

Find us also at [Dockerhub](https://hub.docker.com/repository/docker/spaceone/plugin-aws-sns-mon-webhook)
> Latest stable version : 1.2.1
Expand All @@ -27,66 +28,83 @@ Please contact us if you need any further information. (support@spaceone.dev)
## Supported Alert Services

Currently, you can receive the following events using AWS SNS webhook.

* AWS Cloudwatch
* AWS Health

If you need detailed AWS SNS settings to use the sns webhook.
Please refer to the [SpaceONE Documentations](https://spaceone.org/docs/guides/alert_manager/webhook_settings/aws_sns_webhook/).
Please refer to
the [SpaceONE Documentations](https://spaceone.org/docs/guides/alert_manager/webhook_settings/aws_sns_webhook/).

---

## Release note

### Ver 1.2.7

---

Enhancement

- add statusCode in the PHD event for auto-resolve alert.

### Ver 1.2.3

---

Enhancement
- add MetricName and Namespace field in additional_info of cloudwatch ([#1](https://github.com/cloudforet-io/plugin-aws-sns-mon-webhook/issues/1))

- add MetricName and Namespace field in additional_info of
cloudwatch ([#1](https://github.com/cloudforet-io/plugin-aws-sns-mon-webhook/issues/1))

Bugfix
- fix title and rule field in event of cloudwatch ([#1](https://github.com/cloudforet-io/plugin-aws-sns-mon-webhook/issues/1))

- fix title and rule field in event of
cloudwatch ([#1](https://github.com/cloudforet-io/plugin-aws-sns-mon-webhook/issues/1))

### Ver 1.2.2

---

Enhancement
- Apply regardless of primitive type about phd events ([#50](https://github.com/spaceone-dev/plugin-aws-sns-mon-webhook/issues/50))
- change to receive paragraph-delimited scription ([#48](https://github.com/spaceone-dev/plugin-aws-sns-mon-webhook/issues/48))

- Apply regardless of primitive type about phd
events ([#50](https://github.com/spaceone-dev/plugin-aws-sns-mon-webhook/issues/50))
- change to receive paragraph-delimited
scription ([#48](https://github.com/spaceone-dev/plugin-aws-sns-mon-webhook/issues/48))

### Ver 1.2.1

---

Enhancement

- Add provider field and account field (#47)
- Add affected entities in discription (#46)

Test
- Add test code about Event Service (#46)



- Add test code about Event Service (#46)

### Ver 1.2

---

Enhancement

- Apply PersonalHealthDashboard Event (#39, #41)

Refactoring

- Modify affectedEntities type (#44)
- Add account info in discription(#41)


### Ver 1.1

---

Refactoring
Refactoring

- Add remove_code_in_title method (#37)
- Update get_namespace (#35)
- Modify severity_flag (#27)
Expand All @@ -96,4 +114,5 @@ Refactoring
---

Enhancement

- Update for cloud_metrics for aws cloudwatch type (#29)
135 changes: 89 additions & 46 deletions src/spaceone/monitoring/manager/phd_event_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ def _generate_events(self, message):
"service": "ELASTICLOADBALANCING",
"eventTypeCode": "AWS_ELASTICLOADBALANCING_API_ISSUE",
"eventTypeCategory": "issue",
"statusCode": "open|closed|upcoming",
"startTime": "Sat, 04 Jun 2016 05:01:10 GMT",
"endTime": "Sat, 04 Jun 2016 05:30:57 GMT",
"eventDescription": [{
Expand All @@ -59,6 +60,7 @@ def _generate_events(self, message):
"service": "EC2",
"eventTypeCode": "AWS_EC2_INSTANCE_STORE_DRIVE_PERFORMANCE_DEGRADED",
"eventTypeCategory": "issue",
"statusCode": "open|closed|upcoming",
"startTime": "Sat, 05 Jun 2016 15:10:09 GMT",
"eventDescription": [{
"language": "en_US",
Expand Down Expand Up @@ -90,6 +92,7 @@ def _generate_events(self, message):
"service": "ABUSE",
"eventTypeCode": "AWS_ABUSE_DOS_REPORT",
"eventTypeCategory": "issue",
"statusCode": "open|closed|upcoming",
"startTime": "Wed, 01 Aug 2018 06:27:57 GMT",
"eventDescription": [{
"language": "en_US",
Expand Down Expand Up @@ -119,6 +122,7 @@ def _generate_events(self, message):
"service": "ABUSE",
"eventTypeCode": "AWS_ABUSE_DOS_REPORT",
"eventTypeCategory": "issue",
"statusCode": "open|closed|upcoming",
"startTime": "Wed, 01 Aug 2018 06:27:57 GMT",
"eventDescription": [{
"language": "en_US",
Expand All @@ -132,74 +136,109 @@ def _generate_events(self, message):
}
}
"""
resource_type = message.get('source', 'aws.health')
account_id = message.get('account', '')
detail_event = message.get('detail', {})
resource_type = message.get("source", "aws.health")
account_id = message.get("account", "")
detail_event = message.get("detail", {})

event_arn = detail_event.get('eventArn', '')
event_type_code = detail_event.get('eventTypeCode', '')
event_type_category = detail_event.get('eventTypeCategory', '')
event_arn = detail_event.get("eventArn", "")
event_type = detail_event.get("statusCode", "open").lower()
event_type_code = detail_event.get("eventTypeCode", "")
event_type_category = detail_event.get("eventTypeCategory", "")
occurred_at = self._get_occurred_at(detail_event)
event_description = self._generate_description(detail_event, account_id)
event_dict = self._generate_event_dict(event_arn, event_type_category, resource_type, event_description,
event_type_code, occurred_at, message, account_id)
event_dict = self._generate_event_dict(
event_arn,
event_type,
event_type_category,
resource_type,
event_description,
event_type_code,
occurred_at,
message,
account_id,
)
events.append(self._evaluate_parsing_data(event_dict))

return events

def _generate_event_dict(self, event_arn, event_type_category, resource_type, event_description, event_type_code,
occurred_at, message, account_id):
def _generate_event_dict(
self,
event_arn,
event_type,
event_type_category,
resource_type,
event_description,
event_type_code,
occurred_at,
message,
account_id,
):
return {
'event_key': event_arn,
'event_type': self._get_event_type(),
'severity': self._get_severity(event_type_category),
'resource': self._get_resource_for_event(event_arn, resource_type),
'description': event_description,
'title': self._change_string_format(event_type_code),
'rule': event_type_category,
'occurred_at': occurred_at,
'account': account_id,
'additional_info': self._get_additional_info(message)
"event_key": event_arn,
"event_type": self._get_event_type(event_type),
"severity": self._get_severity(event_type_category),
"resource": self._get_resource_for_event(event_arn, resource_type),
"description": event_description,
"title": self._change_string_format(event_type_code),
"rule": event_type_category,
"occurred_at": occurred_at,
"account": account_id,
"additional_info": self._get_additional_info(message),
}

@staticmethod
def _change_string_format(event_type_code):
title = event_type_code.replace('_', ' ').title()
title = event_type_code.replace("_", " ").title()
return title

@staticmethod
def _generate_description(detail_event, account_id):
text = [description.get('latestDescription', '').replace('\\\\n', '\n').replace('\\n', '\n')
for description in detail_event.get('eventDescription', '')]
full_text = ' '.join(text)
text = [
description.get("latestDescription", "")
.replace("\\\\n", "\n")
.replace("\\n", "\n")
for description in detail_event.get("eventDescription", "")
]
full_text = " ".join(text)

affected_entities = [affected_entity.get("entityValue", "")
for affected_entity in detail_event.get("affectedEntities", [])]
affected_entities = [
affected_entity.get("entityValue", "")
for affected_entity in detail_event.get("affectedEntities", [])
]
if affected_entities:
affected_entities_names_str = '\n - '.join(affected_entities)
description = f'{full_text} (Account:{account_id})\n\nAffected Entities:\n - {affected_entities_names_str}'
affected_entities_names_str = "\n - ".join(affected_entities)
description = f"{full_text} (Account:{account_id})\n\nAffected Entities:\n - {affected_entities_names_str}"
else:
description = f'{full_text} (Account:{account_id})\n\nAffected Entities: None'
description = (
f"{full_text} (Account:{account_id})\n\nAffected Entities: None"
)

return description

@staticmethod
def request_subscription_confirm(confirm_url):
r = requests.get(confirm_url)
_LOGGER.debug(f'[Confirm_URL: SubscribeURL] {confirm_url}')
_LOGGER.debug(f'[AWS SNS: Status]: {r.status_code}, {r.content}')
_LOGGER.debug(f"[Confirm_URL: SubscribeURL] {confirm_url}")
_LOGGER.debug(f"[AWS SNS: Status]: {r.status_code}, {r.content}")

@staticmethod
def _get_occurred_at(detail_event):
if t := detail_event.get('startTime'):
return datetime.strptime(t, '%a, %d %b %Y %H:%M:%S %Z')
if t := detail_event.get("startTime"):
return datetime.strptime(t, "%a, %d %b %Y %H:%M:%S %Z")
else:
return datetime.now()

@staticmethod
def _get_additional_info(message):
additional_info = {}
additional_info_key = ['id', 'account', 'region', 'service', 'eventTypeCode', 'affectedEntities']
additional_info_key = [
"id",
"account",
"region",
"service",
"eventTypeCode",
"affectedEntities",
]
for _key in message:
if _key in additional_info_key and message.get(_key):
additional_info.update({_key: message.get(_key)})
Expand All @@ -208,11 +247,15 @@ def _get_additional_info(message):
for detail_key in detail_event:
if detail_key in additional_info_key:
if detail_key == "affectedEntities":
affected_entities = [affected_entity.get("entityValue", "")
for affected_entity in detail_event.get(detail_key)]
affected_entities = [
affected_entity.get("entityValue", "")
for affected_entity in detail_event.get(detail_key)
]
additional_info.update({detail_key: affected_entities})
else:
additional_info.update({detail_key: detail_event.get(detail_key)})
additional_info.update(
{detail_key: detail_event.get(detail_key)}
)

return additional_info

Expand All @@ -224,23 +267,23 @@ def _get_severity(event_type_category):
- accountNotification -> INFO
"""

if event_type_category in ['issue', 'scheduledChange']:
severity_flag = 'ERROR'
if event_type_category in ["issue", "scheduledChange"]:
severity_flag = "ERROR"
else:
severity_flag = 'INFO'
severity_flag = "INFO"

return severity_flag

@staticmethod
def _get_resource_for_event(event_arn, resource_type):
return {
'resouce_id': event_arn,
'resource_type': resource_type
}
return {"resouce_id": event_arn, "resource_type": resource_type}

@staticmethod
def _get_event_type():
return 'ALERT'
def _get_event_type(event_type: str) -> str:
if event_type == "close":
return "RECOVERY"
else:
return "ALERT"

@staticmethod
def _get_json_message(json_raw_data):
Expand Down
Loading