Skip to content

Commit

Permalink
feat: add site24X7 provider (#1143)
Browse files Browse the repository at this point in the history
Signed-off-by: Jay Kumar <[email protected]>
Co-authored-by: Shahar Glazner <[email protected]>
  • Loading branch information
35C4n0r and shahargl authored Apr 27, 2024
1 parent 6851e45 commit 21d0d4b
Show file tree
Hide file tree
Showing 6 changed files with 325 additions and 0 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,8 @@ Workflow triggers can either be executed manually when an alert is activated or
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<img width=32 height=32 src="https://github.com/keephq/keep/blob/main/keep-ui/public/icons/pagertree-icon.png?raw=true"/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<img width=32 height=32 src="https://github.com/keephq/keep/blob/main/keep-ui/public/icons/site24x7-icon.png?raw=true"/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<img width=32 height=32 src="https://github.com/keephq/keep/blob/main/keep-ui/public/icons/opsgenie-icon.png?raw=true"/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<img width=32 height=32 src="https://github.com/keephq/keep/blob/main/keep-ui/public/icons/zenduty-icon.png?raw=true"/>
Expand Down
1 change: 1 addition & 0 deletions docs/mint.json
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@
"providers/documentation/sentry-provider",
"providers/documentation/signalfx-provider",
"providers/documentation/signl4-provider",
"providers/documentation/site24x7-provider",
"providers/documentation/slack-provider",
"providers/documentation/snowflake-provider",
"providers/documentation/splunk-provider",
Expand Down
88 changes: 88 additions & 0 deletions docs/providers/documentation/site24x7-provider.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
---
title: "Site24x7 Provider"
description: "The Site24x7 Provider allows you to install webhooks and receive alerts in Site24x7. It manages authentication, setup of webhooks, and retrieval of alert logs from Site24x7."
---

## Inputs

The `Site24x7Provider` class handles authentication and interacts with the Site24x7 API to install webhooks and fetch alerts. Here are the primary methods and their parameters:

### Main Class Methods

- **`setup_webhook(tenant_id, keep_api_url, api_key, setup_alerts)`**
- `tenant_id (str)`: Tenant identifier.
- `keep_api_url (str)`: URL to send alert data.
- `api_key (str)`: API key for authentication.
- `setup_alerts (bool)`: Whether to setup alerting capabilities (default is True).

- **`_get_alerts()`**
- Returns a list of `AlertDto` objects representing the alerts.

### Authentication Parameters

The `Site24x7ProviderAuthConfig` class is used for API authentication and includes:

- **`zohoRefreshToken (str)`**: Refresh token for Zoho authentication. *Required*
- **`zohoClientId (str)`**: Client ID for Zoho authentication. *Required*
- **`zohoClientSecret (str)`**: Client Secret for Zoho authentication. *Required*
- **`zohoAccountTLD (str)`**: Top-Level Domain for the Zoho account. Options include `.com`, `.eu`, `.com.cn`, `.in`, `.com.au`, `.jp`. *Required*

## Connecting with the Provider

To use the Site24x7 Provider, initialize it with the necessary authentication credentials and provider configuration. Ensure that your Zoho account credentials (Client ID, Client Secret, and Refresh Token) are correctly set up in the `Site24x7ProviderAuthConfig`.

## Steps to Obtain a Refresh Token

1. **Registration and Client Credentials:**
- Navigate to [Zoho API Console](https://api-console.zoho.com/).
- Sign in or sign up using the email associated with your Site24x7 account.
- Register your application using the "Self Client" option to get your Client ID and Client Secret.

2. **Generating Grant Token:**
- Go to the Zoho Developer Console and access your registered Self Client.
- In the "Generate Code" tab, input the required scopes (`Site24x7.Admin.Read, Site24x7.Admin.Create, Site24x7.Operations.Read`), description, and time duration.
- Click "Generate" and copy the provided code.

3. **Generating Access and Refresh Tokens:**
- Use the grant token to make a POST request to `https://accounts.zoho.com/oauth/v2/token` to obtain the access and refresh tokens.

```bash
curl -X POST 'https://accounts.zoho.com/oauth/v2/token' \
-d 'client_id=your_client_id' \
-d 'client_secret=your_client_secret' \
-d 'code=your_grant_token' \
-d 'grant_type=authorization_code'

```

OR

```python
import requests
response = requests.post(
'https://accounts.zoho.com/oauth/v2/token',
data={
'client_id': 'your_client_id',
'client_secret': 'your_client_secret',
'code': 'your_grant_token',
'grant_type': 'authorization_code'
}
)
refresh_token = response.json().get('refresh_token')
```

---
## Notes

- Ensure that the necessary scopes **Site24x7.Admin.Read, Site24x7.Admin.Create, Site24x7.Operations.Read** are included when generating the grant token, as they dictate the API functionalities accessible via the provider.
- Zoho API Console [Link](https://api-console.zoho.com)

---

## Useful Links

- [Site24x7 API Documentation](https://www.site24x7.com/help/api/)
- [Zoho OAuth Documentation](https://www.zoho.com/accounts/protocol/oauth/web-apps.html)
- [Site 24x7 Authentication Guide](https://www.site24x7.com/help/api/#authentication)
- [Third Party and Webhook Integrations](https://www.site24x7.com/help/api/#third-party-integrations)
Binary file added keep-ui/public/icons/site24x7-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file.
234 changes: 234 additions & 0 deletions keep/providers/site24x7_provider/site24x7_provider.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
"""
Site24x7Provider is a class that allows to install webhooks and get alerts in Site24x7.
"""

import dataclasses
from typing import List, Optional
from urllib.parse import urlencode, urljoin

import pydantic
import requests

from keep.api.models.alert import AlertDto, AlertSeverity
from keep.contextmanager.contextmanager import ContextManager
from keep.providers.base.base_provider import BaseProvider
from keep.providers.models.provider_config import ProviderConfig, ProviderScope


class ResourceAlreadyExists(Exception):
def __init__(self, *args):
super().__init__(*args)


@pydantic.dataclasses.dataclass
class Site24X7ProviderAuthConfig:
"""
Site24x7 authentication configuration.
"""
zohoRefreshToken: str = dataclasses.field(
metadata={
"required": True,
"description": "ZohoRefreshToken",
"hint": "Refresh token for Zoho authentication",
"sensitive": True,
},
)
zohoClientId: str = dataclasses.field(
metadata={
"required": True,
"description": "ZohoClientId",
"hint": "Client Secret for Zoho authentication.",
"sensitive": True,
},
)
zohoClientSecret: str = dataclasses.field(
metadata={
"required": True,
"description": "ZohoClientSecret",
"hint": "Password associated with yur account",
"sensitive": True,
},
)
zohoAccountTLD: str = dataclasses.field(
metadata={
"required": True,
"description": "Zoho Account's TLD (.com | .eu | .com.cn | .in | .au | .jp)",
"hint": "Possible: .com | .eu | .com.cn | .in | .com.au | .jp",
},
)


class Site24X7Provider(BaseProvider):
"""Install Webhooks and receive alerts from Site24x7."""

PROVIDER_SCOPES = [
ProviderScope(
name="authenticated",
description="User is Authenticated",
mandatory=True,
mandatory_for_webhook=True,
alias="Rules Reader",
),
ProviderScope(
name="valid_tld",
description="TLD is amongst the list [.com | .eu | .com.cn | .in | .com.au | .jp]",
mandatory=True,
mandatory_for_webhook=True,
alias="Valid TLD",
),
]

SEVERITIES_MAP = {
"DOWN": AlertSeverity.WARNING,
"TROUBLE": AlertSeverity.HIGH,
"UP": AlertSeverity.INFO,
"CRITICAL": AlertSeverity.CRITICAL
}

def __init__(
self, context_manager: ContextManager, provider_id: str, config: ProviderConfig
):
super().__init__(context_manager, provider_id, config)

def dispose(self):
"""
Dispose the provider.
"""
pass

def validate_config(self):
"""
Validates required configuration for Site24x7 provider.
"""
self.authentication_config = Site24X7ProviderAuthConfig(
**self.config.authentication
)

def __get_url(self, paths: List[str] = [], query_params: dict = None, **kwargs):
"""
Helper method to build the url for Site24x7 api requests.
Example:
paths = ["issue", "createmeta"]
query_params = {"projectKeys": "key1"}
url = __get_url("test", paths, query_params)
# url = https://site24x7.com/api/2/issue/createmeta?projectKeys=key1
"""

url = urljoin(
f"https://www.site24x7{self.authentication_config.zohoAccountTLD}/api/",
"/".join(str(path) for path in paths),
)

# add query params
if query_params:
url = f"{url}?{urlencode(query_params)}"

return url

def __get_headers(self):
"""
Getting the access token from Zoho API using the permanent refresh token.
"""
data = {
'client_id': self.authentication_config.zohoClientId,
'client_secret': self.authentication_config.zohoClientSecret,
'refresh_token': self.authentication_config.zohoRefreshToken,
'grant_type': 'refresh_token',
}
response = requests.post(f'https://accounts.zoho{self.authentication_config.zohoAccountTLD}/oauth/v2/token',
data=data).json()
return {
'Authorization': f'Bearer {response["access_token"]}',
}

def validate_scopes(self) -> dict[str, bool | str]:
valid_tlds = [".com", ".eu", ".com.cn", ".in", ".com.au", ".jp"]
valid_tld_scope = "TLD not in [.com | .eu | .com.cn | .in | .com.au | .jp]"
authentication_scope = "Validate TLD first"
if self.authentication_config.zohoAccountTLD in valid_tlds:
valid_tld_scope = True
response = requests.get(f'{self.__get_url(paths=["monitors"])}', headers=self.__get_headers())
if response.status_code == 401:
authentication_scope = response.json()
self.logger.error("Failed to authenticate user", extra=authentication_scope)
elif response.status_code == 200:
authentication_scope = True
self.logger.info("Authenticated user successfully")
else:
authentication_scope = f"Error while authenticating user, {response.status_code}"
self.logger.error("Error while authenticating user", extra={"status_code": response.status_code})
return {
'authenticated': authentication_scope,
'valid_tld': valid_tld_scope,
}

def setup_webhook(
self, tenant_id: str, keep_api_url: str, api_key: str, setup_alerts: bool = True
):
webhook_data = {
"method": "P",
"down_alert": True,
"is_poller_webhook": False,
"type": 8,
"alert_tags_id": [],
"custom_headers": [
{
"name": "X-API-KEY",
"value": api_key
}
],
"url": keep_api_url,
"timeout": 30,
"selection_type": 0,
"send_in_json_format": True,
"auth_method": "B",
"trouble_alert": True,
"critical_alert": True,
"send_incident_parameters": True,
"service_status": 0,
"name": "KeepWebhook",
"manage_tickets": False
}
response = requests.post(self.__get_url(paths=["integration/webhooks"]), json=webhook_data,
headers=self.__get_headers())
if not response.ok:
response_json = response.json()
self.logger.error("Error while creating webhook", extra=response_json)
raise Exception(response_json['message'])
else:
self.logger.info("Webhook created successfully")

@staticmethod
def _format_alert(
event: dict,
provider_instance: Optional["Site24X7Provider"] = None,
) -> AlertDto:
return AlertDto(
url=event.get("MONITORURL", ""),
lastReceived=event.get('INCIDENT_TIME', ""),
description=event.get("INCIDENT_REASON", ""),
name=event.get("MONITORNAME", ""),
id=event.get("MONITOR_ID", ""),
severity=Site24X7Provider.SEVERITIES_MAP.get(event.get("STATUS", "DOWN")),
)

def _get_alerts(self) -> list[AlertDto]:
response = requests.get(self.__get_url(paths=['alert_logs']), headers=self.__get_headers())
if response.status_code == 200:
alerts = []
response = response.json()
for alert in response['data']:
alerts.append(
AlertDto(
name=alert["display_name"],
title=alert["msg"],
startedAt=alert["sent_time"],
)
)
return alerts
else:
self.logger.error("Failed to get alerts", extra=response.json())
raise Exception("Could not get alerts")

0 comments on commit 21d0d4b

Please sign in to comment.