diff --git a/datadog_sync/model/powerpacks.py b/datadog_sync/model/powerpacks.py index 12a45883..de82ae4c 100644 --- a/datadog_sync/model/powerpacks.py +++ b/datadog_sync/model/powerpacks.py @@ -14,8 +14,20 @@ class Powerpacks(BaseResource): base_path="/api/v2/powerpacks", excluded_attributes=["id", "relationships"], resource_connections={ - "monitors": ["widgets.definition.alert_id", "widgets.definition.widgets.definition.alert_id"], - "service_level_objectives": ["widgets.definition.slo_id", "widgets.definition.widgets.definition.slo_id"], + "monitors": [ + "widgets.definition.alert_id", + "widgets.definition.widgets.definition.alert_id", + "attributes.group_widget.definition.alert_id", + "attributes.group_widget.definition.widgets.definition.alert_id", + "attributes.group_widget.definition.widgets.definition.widgets.definition.alert_id", + ], + "service_level_objectives": [ + "widgets.definition.slo_id", + "widgets.definition.widgets.definition.slo_id", + "attributes.group_widget.definition.slo_id", + "attributes.group_widget.definition.widgets.definition.slo_id", + "attributes.group_widget.definition.widgets.definition.widgets.definition.slo_id", + ], }, skip_resource_mapping=True, ) @@ -36,10 +48,14 @@ async def get_resources(self, client: CustomClient) -> List[Dict]: return resp - async def import_resource(self, _id: Optional[str] = None, resource: Optional[Dict] = None) -> Tuple[str, Dict]: + async def import_resource( + self, _id: Optional[str] = None, resource: Optional[Dict] = None + ) -> Tuple[str, Dict]: if _id: source_client = self.config.source_client - resource = (await source_client.get(self.resource_config.base_path + f"/{_id}"))["data"] + resource = ( + await source_client.get(self.resource_config.base_path + f"/{_id}") + )["data"] return resource["id"], resource @@ -60,7 +76,8 @@ async def update_resource(self, _id: str, resource: Dict) -> Tuple[str, Dict]: destination_client = self.config.destination_client payload = {"data": resource} resp = await destination_client.patch( - self.resource_config.base_path + f"/{self.config.state.destination[self.resource_type][_id]['id']}", + self.resource_config.base_path + + f"/{self.config.state.destination[self.resource_type][_id]['id']}", payload, ) @@ -69,8 +86,11 @@ async def update_resource(self, _id: str, resource: Dict) -> Tuple[str, Dict]: async def delete_resource(self, _id: str) -> None: destination_client = self.config.destination_client await destination_client.delete( - self.resource_config.base_path + f"/{self.config.state.destination[self.resource_type][_id]['id']}" + self.resource_config.base_path + + f"/{self.config.state.destination[self.resource_type][_id]['id']}" ) - def connect_id(self, key: str, r_obj: Dict, resource_to_connect: str) -> Optional[List[str]]: + def connect_id( + self, key: str, r_obj: Dict, resource_to_connect: str + ) -> Optional[List[str]]: return super(Powerpacks, self).connect_id(key, r_obj, resource_to_connect) diff --git a/tests/unit/test_powerpacks.py b/tests/unit/test_powerpacks.py new file mode 100644 index 00000000..115b5f72 --- /dev/null +++ b/tests/unit/test_powerpacks.py @@ -0,0 +1,120 @@ +# Unless explicitly stated otherwise all files in this repository are licensed +# under the 3-clause BSD style license (see LICENSE). +# This product includes software developed at Datadog (https://www.datadoghq.com/). +# Copyright 2019 Datadog, Inc. + +from collections import defaultdict +from unittest.mock import MagicMock + +from datadog_sync.model.powerpacks import Powerpacks +from datadog_sync.utils.resource_utils import prep_resource + + +def _make_powerpacks(): + config = MagicMock() + config.state = MagicMock() + config.state.source = defaultdict(dict) + config.state.destination = defaultdict(dict) + config.skip_failed_resource_connections = False + config.logger = MagicMock() + return Powerpacks(config) + + +def test_group_widget_monitor_and_slo_ids_are_remapped(): + powerpacks = _make_powerpacks() + powerpacks.config.state.destination["monitors"]["src-monitor"] = { + "id": "dst-monitor" + } + powerpacks.config.state.destination["monitors"]["src-nested-monitor"] = { + "id": "dst-nested-monitor" + } + powerpacks.config.state.destination["monitors"]["src-direct-monitor"] = { + "id": "dst-direct-monitor" + } + powerpacks.config.state.destination["service_level_objectives"]["src-slo"] = { + "id": "dst-slo" + } + powerpacks.config.state.destination["service_level_objectives"][ + "src-nested-slo" + ] = {"id": "dst-nested-slo"} + powerpacks.config.state.destination["service_level_objectives"][ + "src-direct-slo" + ] = {"id": "dst-direct-slo"} + resource = { + "id": "src-powerpack", + "type": "powerpack", + "attributes": { + "group_widget": { + "definition": { + "alert_id": "src-direct-monitor", + "slo_id": "src-direct-slo", + "widgets": [ + { + "definition": { + "type": "alert_graph", + "alert_id": "src-monitor", + } + }, + {"definition": {"type": "slo", "slo_id": "src-slo"}}, + { + "definition": { + "type": "group", + "widgets": [ + { + "definition": { + "type": "alert_graph", + "alert_id": "src-nested-monitor", + } + }, + { + "definition": { + "type": "slo", + "slo_id": "src-nested-slo", + } + }, + ], + } + }, + ], + } + } + }, + } + + powerpacks.connect_resources("src-powerpack", resource) + + definition = resource["attributes"]["group_widget"]["definition"] + assert definition["alert_id"] == "dst-direct-monitor" + assert definition["slo_id"] == "dst-direct-slo" + widgets = definition["widgets"] + assert widgets[0]["definition"]["alert_id"] == "dst-monitor" + assert widgets[1]["definition"]["slo_id"] == "dst-slo" + nested_widgets = widgets[2]["definition"]["widgets"] + assert nested_widgets[0]["definition"]["alert_id"] == "dst-nested-monitor" + assert nested_widgets[1]["definition"]["slo_id"] == "dst-nested-slo" + + +def test_top_level_id_and_relationships_are_removed_but_widget_ids_remain(): + resource = { + "id": "src-powerpack", + "type": "powerpack", + "attributes": { + "group_widget": { + "definition": { + "widgets": [ + {"id": 12345, "definition": {"type": "timeseries"}}, + ], + } + } + }, + "relationships": {"author": {"data": {"type": "users", "id": "src-user"}}}, + } + + prep_resource(Powerpacks.resource_config, resource) + + assert "id" not in resource + assert "relationships" not in resource + assert ( + resource["attributes"]["group_widget"]["definition"]["widgets"][0]["id"] + == 12345 + )