Skip to content

Commit

Permalink
chore(provider): PagerDuty scopes added and fix: mongodb connection c…
Browse files Browse the repository at this point in the history
…heck (#1183)
  • Loading branch information
KanvaBhatia authored May 17, 2024
1 parent 2bb36cb commit 687f208
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 20 deletions.
46 changes: 30 additions & 16 deletions docs/providers/documentation/pagerduty-provider.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,19 @@ description: "Pagerduty Provider is a provider that allows to create incidents o

## Inputs

The `notify` function in the `PagerdutyProvider` class takes the following parameters:

```python
kwargs (dict):
title (str): Title of the alert or incident. *Required*
alert_body (str): UTF-8 string of custom message for alert. Shown in incident body for events, and in the body for incidents. *Required for events, optional for incidents*
dedup (str | None): Any string, max 255 characters, used to deduplicate alerts for events. *Required for events, optional for incidents*
service_id (str): ID of the service for incidents. *Required for incidents, optional for events*
body (dict): Body of the incident. *Required for incidents, optional for events*
requester (str): Requester of the incident. *Required for incidents, optional for events*
incident_key (str | None): Key to identify the incident. If not given, a UUID will be generated. *Required for incidents, optional for events*
```
- `title`: str: Title of the alert or incident.
- `alert_body`: str: UTF-8 string of custom message for alert. Shown in incident body for events, and in the body for incidents.
- `dedup`: str | None: Any string, max 255 characters, used to deduplicate alerts for events.
- `service_id`: str: ID of the service for incidents.
- `body`: dict: Body of the incident.
- `requester`: str: Requester of the incident.
- `incident_key`: str | None: Key to identify the incident. If not given, a UUID will be generated.

## Authentication Parameters

The PagerdutyProviderAuthConfig class takes the following parameters:
python
routing*key (str | None): Routing key, which is an integration or ruleset key. Optional, default is `None`. \_Required for events, optional for incidents*_No
api*key (str | None): API key, which is a user or team API key. Optional, default is `None`. \_Required for incidents, optional for events*_
The `api_key` or `routing_key` are required for connecting to the Pagerduty provider. You can obtain them as described in the "Connecting with the Provider" section.

Routing key, which is an integration or ruleset key. API key, which is a user or team API key.

## Connecting with the Provider

Expand All @@ -35,6 +29,26 @@ You can find your API key in the PagerDuty web app under **Configuration** > **A
The routing_key is used to post events to Pagerduty using the events API.
The api_key is used to create incidents using the incidents API.

## Scopes

Certain scopes may be required to perform specific actions or queries via the Pagerduty Provider. Below is a summary of relevant scopes and their use cases:

- incidents_read (Incidents Read)
Required: True
Description: View incidents.
- incidents_write (Incidents Write)
Required: False
Description: Write incidents.
- webhook_subscriptions_read (Webhook Subscriptions Read)
Required: False
Description: View webhook subscriptions.
(*Required for auto-webhook integration)
- webhook_subscriptions_write (Webhook Subscriptions Write)
Required: False
Description: Write webhook subscriptions.
(*Required for auto-webhook integration)


## Notes

The provider uses either the events API or the incidents API to create an alert or an incident. The choice of API to use is determined by the presence of either a routing_key or an api_key.
Expand Down
7 changes: 4 additions & 3 deletions keep/providers/mongodb_provider/mongodb_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,14 +77,15 @@ def validate_scopes(self):
"""
try:
client = self.__generate_client()
client.admin.command('ping') # will raise an exception if the server is not available
client.close()
scopes = {
"connect_to_server": True,
}
except Exception as e:
except Exception:
self.logger.exception("Error validating scopes")
scopes = {
"connect_to_server": str(e),
"connect_to_server": "Unable to connect to server. Please check the connection details.",
}
return scopes

Expand Down Expand Up @@ -117,7 +118,7 @@ def __generate_client(self):
and k != "additional_options" # additional_options will go seperately
and k != "database"
} # database is not a valid mongo option
client = MongoClient(**client_conf, **additional_options)
client = MongoClient(**client_conf, **additional_options, serverSelectionTimeoutMS=10000) # 10 seconds timeout
return client

def dispose(self):
Expand Down
61 changes: 60 additions & 1 deletion keep/providers/pagerduty_provider/pagerduty_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from keep.contextmanager.contextmanager import ContextManager
from keep.exceptions.provider_config_exception import ProviderConfigException
from keep.providers.base.base_provider import BaseProvider
from keep.providers.models.provider_config import ProviderConfig
from keep.providers.models.provider_config import ProviderConfig, ProviderScope
from keep.providers.providers_factory import ProvidersFactory

# Todo: think about splitting in to PagerdutyIncidentsProvider and PagerdutyAlertsProvider
Expand Down Expand Up @@ -40,6 +40,34 @@ class PagerdutyProviderAuthConfig:
class PagerdutyProvider(BaseProvider):
"""Pull alerts and query incidents from PagerDuty."""

PROVIDER_SCOPES = [
ProviderScope(
name="incidents_read",
description="Read incidents data.",
mandatory=True,
alias="Incidents Data Read",
),
ProviderScope(
name="incidents_write",
description="Write incidents.",
mandatory=False,
alias="Incidents Write",
),
ProviderScope(
name="webhook_subscriptions_read",
description="Read webhook data.",
mandatory=False,
mandatory_for_webhook=True,
alias="Webhooks Data Read",
),
ProviderScope(
name="webhook_subscriptions_write",
description="Write webhooks.",
mandatory=False,
mandatory_for_webhook=True,
alias="Webhooks Write",
),
]
SUBSCRIPTION_API_URL = "https://api.pagerduty.com/webhook_subscriptions"
PROVIDER_DISPLAY_NAME = "PagerDuty"
SEVERITIES_MAP = {
Expand Down Expand Up @@ -71,6 +99,37 @@ def validate_config(self):
"PagerdutyProvider requires either routing_key or api_key",
provider_id=self.provider_id,
)

def validate_scopes(self):
"""
Validate that the provider has the required scopes.
"""
headers = {
"Accept": "application/json",
"Authorization": f"Token token={self.authentication_config.api_key}",
}
scopes = {}
for scope in self.PROVIDER_SCOPES:
try:
# Todo: how to check validity for write scopes?
if scope.name.startswith("incidents"):
response = requests.get(
"https://api.pagerduty.com/incidents",
headers=headers,
)
elif scope.name.startswith("webhook_subscriptions"):
response = requests.get(
self.SUBSCRIPTION_API_URL,
headers=headers,
)
if response.ok:
scopes[scope.name] = True
else:
scopes[scope.name] = response.reason
except Exception as e:
self.logger.exception("Error validating scopes")
scopes[scope.name] = str(e)
return scopes

def _build_alert(
self, title: str, alert_body: str, dedup: str
Expand Down

0 comments on commit 687f208

Please sign in to comment.