# What this PR does Adds Service and Business Service migration to the Pager Duty Migrator. To test, in addition to the OnCall configs, you need to crate a Grafana Service Account with `Admin` permission and generate a token. You will set `GRAFANA_SERVICE_ACCOUNT_URL`, per the README, to `https://<namespace>:<token>@<server>` The namespace is the stack id, in the format of `stacks-<stack id>` Service migration is configurable, filterable, and idempotent. ## Which issue(s) this PR closes Related to [issue link here] <!-- *Note*: If you want the issue to be auto-closed once the PR is merged, change "Related to" to "Closes" in the line above. If you have more than one GitHub issue that this PR closes, be sure to preface each issue link with a [closing keyword](https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/using-keywords-in-issues-and-pull-requests#linking-a-pull-request-to-an-issue). This ensures that the issue(s) are auto-closed once the PR has been merged. --> ## Checklist - [x] Unit, integration, and e2e (if applicable) tests updated - [x] Documentation added (or `pr:no public docs` PR label added if not required) - [ ] 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. --------- Co-authored-by: Joey Orlando <joey.orlando@grafana.com> Co-authored-by: GitHub Actions <actions@github.com> Co-authored-by: grafana-irm-app[bot] <165293418+grafana-irm-app[bot]@users.noreply.github.com> Co-authored-by: Joey Orlando <joseph.t.orlando@gmail.com>
75 lines
2.4 KiB
Python
75 lines
2.4 KiB
Python
"""
|
|
Common service filtering functionality.
|
|
"""
|
|
|
|
import re
|
|
from typing import Any, Dict, List
|
|
|
|
from lib.pagerduty.config import (
|
|
PAGERDUTY_FILTER_SERVICE_REGEX,
|
|
PAGERDUTY_FILTER_TEAM,
|
|
PAGERDUTY_FILTER_USERS,
|
|
)
|
|
|
|
|
|
def filter_services(
|
|
services: List[Dict[str, Any]], tab: str = ""
|
|
) -> List[Dict[str, Any]]:
|
|
"""
|
|
Filter services based on configured filters.
|
|
|
|
Args:
|
|
services: List of service dictionaries to filter
|
|
tab: Optional indentation prefix for logging
|
|
|
|
Returns:
|
|
List of filtered services
|
|
"""
|
|
filtered_services = []
|
|
filtered_out = 0
|
|
|
|
for service in services:
|
|
should_include = True
|
|
reason = None
|
|
|
|
# Filter by team
|
|
if PAGERDUTY_FILTER_TEAM:
|
|
teams = service.get("teams", [])
|
|
if not any(team["summary"] == PAGERDUTY_FILTER_TEAM for team in teams):
|
|
should_include = False
|
|
reason = f"No teams found for team filter: {PAGERDUTY_FILTER_TEAM}"
|
|
|
|
# Filter by users (for technical services)
|
|
if (
|
|
should_include
|
|
and PAGERDUTY_FILTER_USERS
|
|
and service.get("type") != "business_service"
|
|
):
|
|
service_users = set()
|
|
# Get users from escalation policy if present
|
|
if service.get("escalation_policy"):
|
|
for rule in service["escalation_policy"].get("escalation_rules", []):
|
|
for target in rule.get("targets", []):
|
|
if target["type"] == "user":
|
|
service_users.add(target["id"])
|
|
|
|
if not any(user_id in service_users for user_id in PAGERDUTY_FILTER_USERS):
|
|
should_include = False
|
|
reason = f"No users found for user filter: {','.join(PAGERDUTY_FILTER_USERS)}"
|
|
|
|
# Filter by name regex
|
|
if should_include and PAGERDUTY_FILTER_SERVICE_REGEX:
|
|
if not re.match(PAGERDUTY_FILTER_SERVICE_REGEX, service["name"]):
|
|
should_include = False
|
|
reason = f"Service name does not match regex: {PAGERDUTY_FILTER_SERVICE_REGEX}"
|
|
|
|
if should_include:
|
|
filtered_services.append(service)
|
|
else:
|
|
filtered_out += 1
|
|
print(f"{tab}Service {service['id']}: {reason}")
|
|
|
|
if filtered_out > 0:
|
|
print(f"Filtered out {filtered_out} services")
|
|
|
|
return filtered_services
|