oncall-engine/tools/migrators/lib/network.py
Joey Orlando c46dff09d9
Splunk OnCall migration tool (#4267)
# What this PR does

Refactors the PagerDuty migration script to be a bit more generic + adds
a migration script to migrate from Splunk OnCall (VictorOps)

tldr;
```bash
❯ docker build -t oncall-migrator .
[+] Building 0.4s (10/10) FINISHED
❯ docker run --rm \
-e MIGRATING_FROM="pagerduty" \
-e MODE="plan" \
-e ONCALL_API_URL="http://localhost:8080" \
-e ONCALL_API_TOKEN="<ONCALL_API_TOKEN>" \
-e PAGERDUTY_API_TOKEN="<PAGERDUTY_API_TOKEN>" \
oncall-migrator
running pagerduty migration script...

❯ docker run --rm \
-e MIGRATING_FROM="splunk" \
-e MODE="plan" \
-e ONCALL_API_URL="http://localhost:8080" \
-e ONCALL_API_TOKEN="<ONCALL_API_TOKEN>" \
-e SPLUNK_API_ID="<SPLUNK_API_ID>" \
-e SPLUNK_API_KEY="<SPLUNK_API_KEY>" \
oncall-migrator
migrating from splunk oncall...
```

https://www.loom.com/share/a855062d436a4ef79f030e22528d8c71

## Checklist

- [x] Unit, integration, and e2e (if applicable) tests updated
- [x] Documentation added (or `pr:no public docs` PR label added if not
required)
- [x] Added the relevant release notes label (see labels prefixed w/
`release:`). These labels dictate how your PR will
    show up in the autogenerated release notes.
2024-05-14 13:53:59 +00:00

48 lines
1.6 KiB
Python

from contextlib import suppress
from time import sleep
from urllib.parse import urljoin
import requests
from requests import HTTPError
from requests.adapters import HTTPAdapter, Retry
def api_call(method: str, base_url: str, path: str, **kwargs) -> requests.Response:
url = urljoin(base_url, path)
# Retry on network errors
session = requests.Session()
retries = Retry(total=5, backoff_factor=0.1)
session.mount("http://", HTTPAdapter(max_retries=retries))
session.mount("https://", HTTPAdapter(max_retries=retries))
response = session.request(method, url, **kwargs)
try:
response.raise_for_status()
except HTTPError as e:
if e.response.status_code == 429:
cooldown_seconds = int(e.response.headers["Retry-After"])
sleep(cooldown_seconds)
return api_call(method, path, **kwargs)
elif e.response.status_code == 400:
resp_json = None
with suppress(requests.exceptions.JSONDecodeError):
resp_json = response.json()
# if no JSON payload is available, just raise the original exception
if not resp_json:
raise
# this is mostly taken from requests.models.Response.raise_for_status, but with additional JSON payload
http_error_msg = (
"%s Client Error: %s for url: %s, response payload JSON: %s"
% (response.status_code, e.response.reason, response.url, resp_json)
)
raise requests.exceptions.HTTPError(
http_error_msg, response=e.response
) from e
else:
raise
return response