diff --git a/integrations/pagerduty/.port/resources/blueprints.json b/integrations/pagerduty/.port/resources/blueprints.json index cf9391552c..39445a20fa 100644 --- a/integrations/pagerduty/.port/resources/blueprints.json +++ b/integrations/pagerduty/.port/resources/blueprints.json @@ -1,4 +1,69 @@ [ + { + "identifier": "pagerdutyUser", + "description": "This blueprint represents a PagerDuty user in our software catalog", + "title": "PagerDuty User", + "icon": "pagerduty", + "schema": { + "properties": { + "role": { + "icon": "DefaultProperty", + "title": "Role", + "type": "string", + "enum": [ + "admin", + "user", + "observer", + "limited_user", + "owner", + "read_only_user", + "restricted_access", + "read_only_limited_user" + ] + }, + "url": { + "icon": "DefaultProperty", + "type": "string", + "format": "url", + "title": "User URL" + }, + "job_title": { + "title": "Job Title", + "icon": "DefaultProperty", + "type": "string" + }, + "contact_methods": { + "title": "Contact Methods", + "icon": "DefaultProperty", + "type": "array" + }, + "description": { + "type": "string", + "title": "Description" + }, + "teams": { + "title": "Teams", + "icon": "DefaultProperty", + "type": "array" + }, + "time_zone": { + "icon": "DefaultProperty", + "type": "string", + "title": "Time Zone" + }, + "email": { + "type": "string", + "title": "Email", + "format": "user" + } + }, + "required": [] + }, + "mirrorProperties": {}, + "calculationProperties": {}, + "aggregationProperties": {}, + "relations": {} + }, { "identifier": "pagerdutyService", "description": "This blueprint represents a PagerDuty service in our software catalog", @@ -151,6 +216,10 @@ "title": "Updated At", "type": "string", "format": "date-time" + }, + "triggered_by": { + "type": "string", + "title": "Triggered By" } }, "required": [] diff --git a/integrations/pagerduty/.port/resources/port-app-config.yaml b/integrations/pagerduty/.port/resources/port-app-config.yaml index 1493a1690b..1715626d8e 100644 --- a/integrations/pagerduty/.port/resources/port-app-config.yaml +++ b/integrations/pagerduty/.port/resources/port-app-config.yaml @@ -25,6 +25,10 @@ resources: apiQueryParams: include: - assignees + - first_trigger_log_entries + statuses: + - triggered + - acknowledged port: entity: mappings: @@ -41,6 +45,34 @@ resources: updated_at: .updated_at priority: if .priority != null then .priority.summary else null end description: .description + triggered_by: .first_trigger_log_entry.agent.summary + relations: + pagerdutyService: .service.id + - kind: incidents + selector: + query: 'true' + apiQueryParams: + include: + - assignees + - first_trigger_log_entries + statuses: + - resolved + port: + entity: + mappings: + identifier: .id | tostring + title: .title + blueprint: '"pagerdutyIncident"' + properties: + status: .status + url: .html_url + urgency: .urgency + escalation_policy: .escalation_policy.summary + created_at: .created_at + updated_at: .updated_at + priority: if .priority != null then .priority.summary else null end + description: .description + triggered_by: .first_trigger_log_entry.agent.summary relations: pagerdutyService: .service.id - kind: schedules @@ -92,3 +124,21 @@ resources: description: .summary primaryOncall: .__oncall_users | sort_by(.escalation_level) | .[0].user.email escalationRules: .escalation_rules + - kind: users + selector: + query: "true" + port: + entity: + mappings: + identifier: .id + title: .name + blueprint: '"pagerdutyUser"' + properties: + url: .html_url + time_zone: .time_zone + email: .email + description: .description + role: .role + job_title: .job_title + teams: .teams + contact_methods: .contact_methods diff --git a/integrations/pagerduty/CHANGELOG.md b/integrations/pagerduty/CHANGELOG.md index 72159d2cba..58ef5076f7 100644 --- a/integrations/pagerduty/CHANGELOG.md +++ b/integrations/pagerduty/CHANGELOG.md @@ -7,6 +7,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 +## 0.1.121 (2024-11-25) + + +### Improvements + +- Improved on the integration default resources for PagerDuty incidents kind +- Added blueprint and mapping for PagerDuty users +- Added logs to track the HTTP requests made to PagerDuty API +- Added a generic resync event handler to allow the integration to bring any valid resource from PagerDuty + + ## 0.1.120 (2024-11-25) diff --git a/integrations/pagerduty/clients/pagerduty.py b/integrations/pagerduty/clients/pagerduty.py index 1f8d14a772..5ad0a1a9e8 100644 --- a/integrations/pagerduty/clients/pagerduty.py +++ b/integrations/pagerduty/clients/pagerduty.py @@ -11,6 +11,7 @@ USER_KEY = "users" MAX_CONCURRENT_REQUESTS = 10 +PAGE_SIZE = 100 class PagerDutyClient: @@ -77,9 +78,17 @@ async def paginate_request_to_pager_duty( has_more_data = True while has_more_data: + logger.debug( + f"Fetching data for {resource} with offset: {offset} limit: {PAGE_SIZE} and params: {params}" + ) try: data = await self.send_api_request( - endpoint=resource, query_params={"offset": offset, **(params or {})} + endpoint=resource, + query_params={ + "offset": offset, + "limit": PAGE_SIZE, + **(params or {}), + }, ) yield data[resource] @@ -91,6 +100,11 @@ async def paginate_request_to_pager_duty( f"Got {e.response.status_code} status code while fetching paginated data: {str(e)}" ) raise + except httpx.HTTPError as e: + logger.error( + f"Got an HTTP error while fetching paginated data for {resource}: {str(e)}" + ) + raise async def get_singular_from_pager_duty( self, object_type: str, identifier: str diff --git a/integrations/pagerduty/integration.py b/integrations/pagerduty/integration.py index c250bad68e..dce06565de 100644 --- a/integrations/pagerduty/integration.py +++ b/integrations/pagerduty/integration.py @@ -24,6 +24,15 @@ class ObjectKind: ESCALATION_POLICIES = "escalation_policies" +OBJECTS_WITH_SPECIAL_HANDLING = [ + ObjectKind.SERVICES, + ObjectKind.INCIDENTS, + ObjectKind.SCHEDULES, + ObjectKind.ONCALLS, + ObjectKind.ESCALATION_POLICIES, +] + + class PagerdutyServiceAPIQueryParams(BaseModel): include: ( list[ @@ -203,9 +212,8 @@ class PagerdutyPortAppConfig(PortAppConfig): | PagerdutyScheduleResourceConfig | PagerdutyOncallResourceConfig | PagerdutyEscalationPolicyResourceConfig - ] = Field( - default_factory=list - ) # type: ignore + | ResourceConfig + ] = Field(default_factory=list) class PagerdutyIntegration(BaseIntegration): diff --git a/integrations/pagerduty/main.py b/integrations/pagerduty/main.py index a7ddde9b29..97c7be4646 100644 --- a/integrations/pagerduty/main.py +++ b/integrations/pagerduty/main.py @@ -10,6 +10,7 @@ from clients.pagerduty import PagerDutyClient from integration import ( ObjectKind, + OBJECTS_WITH_SPECIAL_HANDLING, PagerdutyEscalationPolicyResourceConfig, PagerdutyIncidentResourceConfig, PagerdutyOncallResourceConfig, @@ -175,6 +176,28 @@ async def on_escalation_policies_resync(kind: str) -> ASYNC_GENERATOR_RESYNC_TYP yield escalation_policies +@ocean.on_resync() +async def on_global_resync(kind: str) -> ASYNC_GENERATOR_RESYNC_TYPE: + + if kind in OBJECTS_WITH_SPECIAL_HANDLING: + logger.info(f"Kind {kind} has a special handling. Skipping...") + return + else: + pager_duty_client = initialize_client() + + try: + async for ( + resource_batch + ) in pager_duty_client.paginate_request_to_pager_duty(resource=kind): + logger.info(f"Received batch with {len(resource_batch)} {kind}") + yield resource_batch + except Exception as e: + logger.error( + f"Failed to fetch {kind} from Pagerduty due to error: {e}. For information on supported resources, please refer to our documentation at https://docs.getport.io/build-your-software-catalog/sync-data-to-catalog/incident-management/pagerduty/#supported-resources" + ) + raise e + + @ocean.router.post("/webhook") async def upsert_incident_webhook_handler(data: dict[str, Any]) -> None: pager_duty_client = initialize_client() diff --git a/integrations/pagerduty/pyproject.toml b/integrations/pagerduty/pyproject.toml index 77b4e26068..d9fcb18ba2 100644 --- a/integrations/pagerduty/pyproject.toml +++ b/integrations/pagerduty/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "pagerduty" -version = "0.1.120" +version = "0.1.121" description = "Pagerduty Integration" authors = ["Port Team "]