Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion datadog_sync/model/dashboard_lists.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ def import_resource(self, resource: Dict) -> None:

self.resource_config.source_resources[_id] = resource

def pre_resource_action_hook(self, resource: Dict) -> None:
def pre_resource_action_hook(self, _id, resource: Dict) -> None:
pass

def pre_apply_hook(self, resources: Dict[str, Dict]) -> Optional[list]:
Expand Down
2 changes: 1 addition & 1 deletion datadog_sync/model/dashboards.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def import_resource(self, resource: Dict) -> None:

self.resource_config.source_resources[resource["id"]] = dashboard

def pre_resource_action_hook(self, resource: Dict) -> None:
def pre_resource_action_hook(self, _id, resource: Dict) -> None:
pass

def pre_apply_hook(self, resources: Dict[str, Dict]) -> Optional[list]:
Expand Down
38 changes: 34 additions & 4 deletions datadog_sync/model/downtimes.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,22 @@
# under the 3-clause BSD style license (see LICENSE).
# This product includes software developed at Datadog (https://www.datadoghq.com/).
# Copyright 2019 Datadog, Inc.

import math
from typing import Optional, List, Dict
from datetime import datetime

from datadog_sync.utils.base_resource import BaseResource, ResourceConfig
from datadog_sync.utils.custom_client import CustomClient


RECURRING_TIMES = {
"days": 86400,
"weeks": 604800,
"months": 2592000,
"years": 31536000,
}


class Downtimes(BaseResource):
resource_type = "downtimes"
resource_config = ResourceConfig(
Expand All @@ -25,18 +34,39 @@ def get_resources(self, client: CustomClient) -> List[Dict]:
return resp

def import_resource(self, resource: Dict) -> None:
if resource["canceled"]:
return
# Dispose the recurring child downtimes and only retain the parent
if resource["recurrence"] and resource["parent_id"]:
return

self.resource_config.source_resources[str(resource["id"])] = resource

def pre_resource_action_hook(self, resource: Dict) -> None:
pass
def pre_resource_action_hook(self, _id, resource: Dict) -> None:
if _id not in self.resource_config.destination_resources:
current_time = round(datetime.now().timestamp())
if resource["recurrence"] is None:
# If the downtime start time is in the past, convert it to now + 1min
if resource["start"] and resource["start"] <= current_time:
resource["start"] = current_time + 60
else:
# Calculate the next recurrence `start` time by counting the number of recurrences
# that has occurred since `start` and round it up
r_time = RECURRING_TIMES[resource["recurrence"]["type"]]
r_period = resource["recurrence"]["period"]
r_interval = r_time * r_period
if resource["start"] and resource["start"] <= current_time:
num_of_recurrences_since_start = math.ceil((current_time - resource["start"]) / r_interval)
resource["start"] += r_interval * num_of_recurrences_since_start
resource["end"] += r_interval * num_of_recurrences_since_start

def pre_apply_hook(self, resources: Dict[str, Dict]) -> Optional[list]:
pass

def create_resource(self, _id: str, resource: Dict) -> None:
destination_client = self.config.destination_client
resp = destination_client.post(self.resource_config.base_path, resource).json()

resp = destination_client.post(self.resource_config.base_path, resource).json()
self.resource_config.destination_resources[_id] = resp

def update_resource(self, _id: str, resource: Dict) -> None:
Expand Down
2 changes: 1 addition & 1 deletion datadog_sync/model/integrations_aws.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def get_resources(self, client: CustomClient) -> List[Dict]:
def import_resource(self, resource: Dict) -> None:
self.resource_config.source_resources[resource["account_id"]] = resource

def pre_resource_action_hook(self, resource: Dict) -> None:
def pre_resource_action_hook(self, _id, resource: Dict) -> None:
pass

def pre_apply_hook(self, resources: Dict[str, Dict]) -> Optional[list]:
Expand Down
2 changes: 1 addition & 1 deletion datadog_sync/model/logs_custom_pipelines.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ def import_resource(self, resource: Dict) -> None:
return
self.resource_config.source_resources[resource["id"]] = resource

def pre_resource_action_hook(self, resource: Dict) -> None:
def pre_resource_action_hook(self, _id, resource: Dict) -> None:
pass

def pre_apply_hook(self, resources: Dict[str, Dict]) -> Optional[list]:
Expand Down
22 changes: 16 additions & 6 deletions datadog_sync/model/monitors.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
class Monitors(BaseResource):
resource_type = "monitors"
resource_config = ResourceConfig(
resource_connections={"monitors": ["query"], "roles": ["restricted_roles"]},
resource_connections={"monitors": ["query"], "roles": ["restricted_roles"], "synthetics_tests": []},
base_path="/api/v1/monitor",
excluded_attributes=[
"id",
Expand All @@ -37,12 +37,12 @@ def get_resources(self, client: CustomClient) -> List[Dict]:
return resp

def import_resource(self, resource: Dict) -> None:
if resource["type"] == "synthetics alert":
if resource["type"] in ("synthetics alert", "slo alert"):
return

self.resource_config.source_resources[str(resource["id"])] = resource

def pre_resource_action_hook(self, resource: Dict) -> None:
def pre_resource_action_hook(self, _id, resource: Dict) -> None:
pass

def pre_apply_hook(self, resources: Dict[str, Dict]) -> Optional[list]:
Expand Down Expand Up @@ -71,13 +71,23 @@ def update_resource(self, _id: str, resource: Dict) -> None:
self.resource_config.destination_resources[_id] = resp

def connect_id(self, key: str, r_obj: Dict, resource_to_connect: str) -> None:
resources = self.config.resources[resource_to_connect].resource_config.destination_resources
monitors = self.config.resources[resource_to_connect].resource_config.destination_resources
synthetics_tests = self.config.resources["synthetics_tests"].resource_config.destination_resources

if r_obj.get("type") == "composite" and key == "query":
ids = re.findall("[0-9]+", r_obj[key])
for _id in ids:
if _id in resources:
new_id = f"{resources[_id]['id']}"
found = False
if _id in monitors:
found = True
new_id = f"{monitors[_id]['id']}"
r_obj[key] = re.sub(_id + r"([^#]|$)", new_id + "# ", r_obj[key])
else:
# Check if it is a synthetics monitor
for k, v in synthetics_tests.items():
if k.endswith(_id):
found = True
r_obj[key] = re.sub(_id + r"([^#]|$)", str(v["monitor_id"]) + "# ", r_obj[key])
if not found:
raise ResourceConnectionError(resource_to_connect, _id=_id)
r_obj[key] = (r_obj[key].replace("#", "")).strip()
2 changes: 1 addition & 1 deletion datadog_sync/model/notebooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def get_resources(self, client: CustomClient) -> List[Dict]:
def import_resource(self, resource: Dict) -> None:
self.resource_config.source_resources[resource["id"]] = resource

def pre_resource_action_hook(self, resource: Dict) -> None:
def pre_resource_action_hook(self, _id, resource: Dict) -> None:
pass

def pre_apply_hook(self, resources: Dict[str, Dict]) -> Optional[list]:
Expand Down
2 changes: 1 addition & 1 deletion datadog_sync/model/roles.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def pre_apply_hook(self, resources: Dict[str, Dict]) -> Optional[list]:
self.destination_roles_mapping = self.get_destination_roles_mapping()
return None

def pre_resource_action_hook(self, resource: Dict) -> None:
def pre_resource_action_hook(self, _id, resource: Dict) -> None:
self.remap_permissions(resource)

def create_resource(self, _id, resource):
Expand Down
2 changes: 1 addition & 1 deletion datadog_sync/model/service_level_objectives.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def get_resources(self, client: CustomClient) -> List[Dict]:
def import_resource(self, resource: Dict) -> None:
self.resource_config.source_resources[resource["id"]] = resource

def pre_resource_action_hook(self, resource: Dict) -> None:
def pre_resource_action_hook(self, _id, resource: Dict) -> None:
pass

def pre_apply_hook(self, resources: Dict[str, Dict]) -> Optional[list]:
Expand Down
2 changes: 1 addition & 1 deletion datadog_sync/model/slo_corrections.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def get_resources(self, client: CustomClient) -> List[Dict]:
def import_resource(self, resource: Dict) -> None:
self.resource_config.source_resources[resource["id"]] = resource

def pre_resource_action_hook(self, resource: Dict) -> None:
def pre_resource_action_hook(self, _id, resource: Dict) -> None:
pass

def pre_apply_hook(self, resources: Dict[str, Dict]) -> Optional[list]:
Expand Down
2 changes: 1 addition & 1 deletion datadog_sync/model/synthetics_global_variables.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ def get_resources(self, client: CustomClient) -> List[Dict]:
def import_resource(self, resource: Dict) -> None:
self.resource_config.source_resources[resource["id"]] = resource

def pre_resource_action_hook(self, resource: Dict) -> None:
def pre_resource_action_hook(self, _id, resource: Dict) -> None:
pass

def pre_apply_hook(self, resources: Dict[str, Dict]) -> Optional[list]:
Expand Down
2 changes: 1 addition & 1 deletion datadog_sync/model/synthetics_private_locations.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def import_resource(self, resource: Dict) -> None:

self.resource_config.source_resources[resource["id"]] = pl

def pre_resource_action_hook(self, resource: Dict) -> None:
def pre_resource_action_hook(self, _id, resource: Dict) -> None:
pass

def pre_apply_hook(self, resources: Dict[str, Dict]) -> Optional[list]:
Expand Down
2 changes: 1 addition & 1 deletion datadog_sync/model/synthetics_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def get_resources(self, client: CustomClient) -> List[Dict]:
def import_resource(self, resource: Dict) -> None:
self.resource_config.source_resources[f"{resource['public_id']}#{resource['monitor_id']}"] = resource

def pre_resource_action_hook(self, resource: Dict) -> None:
def pre_resource_action_hook(self, _id, resource: Dict) -> None:
pass

def pre_apply_hook(self, resources: Dict[str, Dict]) -> Optional[list]:
Expand Down
2 changes: 1 addition & 1 deletion datadog_sync/model/users.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def import_resource(self, resource: Dict) -> None:

self.resource_config.source_resources[resource["id"]] = resource

def pre_resource_action_hook(self, resource: Dict) -> None:
def pre_resource_action_hook(self, _id, resource: Dict) -> None:
pass

def pre_apply_hook(self, resources: Dict[str, Dict]) -> Optional[list]:
Expand Down
40 changes: 27 additions & 13 deletions datadog_sync/utils/base_resource.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ def import_resource(self, resource: Dict) -> None:
pass

@abc.abstractmethod
def pre_resource_action_hook(self, resource: Dict) -> None:
def pre_resource_action_hook(self, _id, resource: Dict) -> None:
pass

@abc.abstractmethod
Expand All @@ -80,13 +80,23 @@ def update_resource(self, _id: str, resource: Dict) -> None:
@abc.abstractmethod
def connect_id(self, key: str, r_obj: Dict, resource_to_connect: str) -> None:
resources = self.config.resources[resource_to_connect].resource_config.destination_resources
_id = str(r_obj[key])
if _id in resources:
# Cast resource id to str on int based on source type
type_attr = type(r_obj[key])
r_obj[key] = type_attr(resources[_id]["id"])
if isinstance(r_obj[key], list):
for i, v in enumerate(r_obj[key]):
_id = str(v)
if _id in resources:
# Cast resource id to str or int based on source type
type_attr = type(v)
r_obj[key][i] = type_attr(resources[_id]["id"])
else:
raise ResourceConnectionError(resource_to_connect, _id=_id)
else:
raise ResourceConnectionError(resource_to_connect, _id=_id)
_id = str(r_obj[key])
if _id in resources:
# Cast resource id to str on int based on source type
type_attr = type(r_obj[key])
r_obj[key] = type_attr(resources[_id]["id"])
else:
raise ResourceConnectionError(resource_to_connect, _id=_id)

def import_resources(self) -> None:
# reset source resources obj
Expand Down Expand Up @@ -150,7 +160,7 @@ def check_diffs(self):
if not self.filter(resource):
continue

self.pre_resource_action_hook(resource)
self.pre_resource_action_hook(_id, resource)

try:
self.connect_resources(_id, resource)
Expand All @@ -160,12 +170,12 @@ def check_diffs(self):
if _id in self.resource_config.destination_resources:
diff = check_diff(self.resource_config, self.resource_config.destination_resources[_id], resource)
if diff:
print("{} resource ID {} diff: \n {}".format(self.resource_type, _id, pformat(diff)))
print("{} resource source ID {} diff: \n {}".format(self.resource_type, _id, pformat(diff)))
else:
print("Resource to be added {}: \n {}".format(self.resource_type, pformat(resource)))
print("Resource to be added {} source ID {}: \n {}".format(self.resource_type, _id, pformat(resource)))

def apply_resource(self, _id: str, resource: Dict) -> None:
self.pre_resource_action_hook(resource)
self.pre_resource_action_hook(_id, resource)
self.connect_resources(_id, resource)

if _id in self.resource_config.destination_resources:
Expand All @@ -175,13 +185,17 @@ def apply_resource(self, _id: str, resource: Dict) -> None:
try:
self.update_resource(_id, resource)
except Exception as e:
self.config.logger.error(f"error while updating resource {self.resource_type}. Error: {str(e)}")
self.config.logger.error(
f"error while updating resource {self.resource_type}. source ID: {_id} - Error: {str(e)}"
)
else:
prep_resource(self.resource_config, resource)
try:
self.create_resource(_id, resource)
except Exception as e:
self.config.logger.error(f"error while creating resource {self.resource_type}. Error: {str(e)}")
self.config.logger.error(
f"error while creating resource {self.resource_type}. source ID: {_id} - Error: {str(e)}"
)

def connect_resources(self, _id: str, resource: Dict) -> None:
if not self.resource_config.resource_connections:
Expand Down