def delete_handler( session: Optional[SessionProxy], request: ResourceHandlerRequest, callback_context: MutableMapping[str, Any], ) -> ProgressEvent: model = request.desiredResourceState progress: ProgressEvent = ProgressEvent( status=OperationStatus.IN_PROGRESS, resourceModel=model, ) LOG.info(f"Starting the {TYPE_NAME} Delete Handler") with v1_client( model.DatadogCredentials.ApiKey, model.DatadogCredentials.ApplicationKey, model.DatadogCredentials.ApiURL or "https://api.datadoghq.com", TELEMETRY_TYPE_NAME, __version__, ) as api_client: api_instance = users_api.UsersApi(api_client) user_handle = model.Handle try: api_instance.disable_user(user_handle) except ApiException as e: LOG.error("Exception when calling UsersApi->disable_user: %s\n" % e) return ProgressEvent(status=OperationStatus.FAILED, resourceModel=model, message=e.body) return ProgressEvent( status=OperationStatus.SUCCESS, resourceModel=None, )
def delete_handler( session: Optional[SessionProxy], request: ResourceHandlerRequest, callback_context: MutableMapping[str, Any], ) -> ProgressEvent: LOG.info("Starting %s Delete Handler", TYPE_NAME) model = request.desiredResourceState type_configuration = request.typeConfiguration with v1_client( type_configuration.DatadogCredentials.ApiKey, type_configuration.DatadogCredentials.ApplicationKey, type_configuration.DatadogCredentials.ApiURL, TELEMETRY_TYPE_NAME, __version__, ) as api_client: api_instance = MonitorsApi(api_client) try: api_instance.delete_monitor(model.Id) except ApiException as e: LOG.exception( "Exception when calling MonitorsApi->delete_monitor: %s\n", e) return ProgressEvent( status=OperationStatus.FAILED, resourceModel=model, message=f"Error deleting monitor: {e}", errorCode=http_to_handler_error_code(e.status), ) return ProgressEvent( status=OperationStatus.SUCCESS, resourceModel=None, )
def delete_handler( session: Optional[SessionProxy], request: ResourceHandlerRequest, callback_context: MutableMapping[str, Any], ) -> ProgressEvent: model = request.desiredResourceState aws_account = build_aws_account_from_model(model) with v1_client( model.DatadogCredentials.ApiKey, model.DatadogCredentials.ApplicationKey, model.DatadogCredentials.ApiURL, TELEMETRY_TYPE_NAME, __version__, ) as api_client: api_instance = AWSIntegrationApi(api_client) try: api_instance.delete_aws_account(aws_account) except ApiException as e: LOG.error( "Exception when calling AWSIntegrationApi->delete_aws_account: %s\n", e) return ProgressEvent(status=OperationStatus.FAILED, resourceModel=model, message=f"Error deleting AWS account: {e}") return ProgressEvent( status=OperationStatus.SUCCESS, resourceModel=None, )
def update_handler( session: Optional[SessionProxy], request: ResourceHandlerRequest, callback_context: MutableMapping[str, Any], ) -> ProgressEvent: model = request.desiredResourceState progress: ProgressEvent = ProgressEvent( status=OperationStatus.IN_PROGRESS, resourceModel=model, ) LOG.info(f"Starting the {TYPE_NAME} Update Handler") with v1_client( model.DatadogCredentials.ApiKey, model.DatadogCredentials.ApplicationKey, model.DatadogCredentials.ApiURL or "https://api.datadoghq.com", TELEMETRY_TYPE_NAME, __version__, ) as api_client: api_instance = users_api.UsersApi(api_client) body = User( access_role=AccessRole(model.AccessRole), email=model.Email, disabled=model.Disabled or False, name=model.Name, ) try: api_instance.update_user(model.Handle, body) except ApiException as e: LOG.error("Exception when calling UsersApi->update_user: %s\n" % e) return ProgressEvent(status=OperationStatus.FAILED, resourceModel=model, message=e.body) return read_handler(session, request, callback_context)
def read_handler( session: Optional[SessionProxy], request: ResourceHandlerRequest, callback_context: MutableMapping[str, Any], ) -> ProgressEvent: model = request.desiredResourceState LOG.info(f"Starting the {TYPE_NAME} Delete Handler") with v1_client( model.DatadogCredentials.ApiKey, model.DatadogCredentials.ApplicationKey, model.DatadogCredentials.ApiURL or "https://api.datadoghq.com", TELEMETRY_TYPE_NAME, __version__, ) as api_client: api_instance = users_api.UsersApi(api_client) user_handle = model.Handle try: api_response = api_instance.get_user(user_handle) except ApiException as e: LOG.error("Exception when calling UsersApi->get_user: %s\n" % e) return ProgressEvent(status=OperationStatus.FAILED, resourceModel=model, message=e.body) model.AccessRole = api_response.user.access_role.value model.Name = api_response.user.name model.Disabled = api_response.user.disabled model.Verified = api_response.user.verified model.Email = api_response.user.email return ProgressEvent( status=OperationStatus.SUCCESS, resourceModel=model, )
def update_handler( session: Optional[SessionProxy], request: ResourceHandlerRequest, callback_context: MutableMapping[str, Any], ) -> ProgressEvent: model = request.desiredResourceState type_configuration = request.typeConfiguration LOG.info(f"Starting the {TYPE_NAME} Update Handler") downtime_body = build_downtime_struct(model) with v1_client( type_configuration.DatadogCredentials.ApiKey, type_configuration.DatadogCredentials.ApplicationKey, type_configuration.DatadogCredentials.ApiURL, TELEMETRY_TYPE_NAME, __version__, ) as api_client: api_instance = downtimes_api.DowntimesApi(api_client) try: api_instance.update_downtime(model.Id, downtime_body) except ApiException as e: LOG.exception( "Exception when calling DowntimeApi->update_downtime: %s\n" % e) return ProgressEvent(status=OperationStatus.FAILED, resourceModel=model, message=e.body, errorCode=http_to_handler_error_code( e.status)) return read_handler(session, request, callback_context)
def delete_handler( session: Optional[SessionProxy], request: ResourceHandlerRequest, callback_context: MutableMapping[str, Any], ) -> ProgressEvent: LOG.info("Starting %s Delete Handler", TYPE_NAME) model = request.desiredResourceState dashboard_id = model.Id with v1_client( model.DatadogCredentials.ApiKey, model.DatadogCredentials.ApplicationKey, model.DatadogCredentials.ApiURL, TELEMETRY_TYPE_NAME, __version__, ) as api_client: api_instance = DashboardsApi(api_client) try: api_instance.delete_dashboard(dashboard_id) except ApiException as e: LOG.error( "Exception when calling DashboardsApi->delete_dashboard: %s\n", e) return ProgressEvent(status=OperationStatus.FAILED, resourceModel=model, message=f"Error deleting dashboard: {e}") return ProgressEvent( status=OperationStatus.SUCCESS, resourceModel=None, )
def read_handler( session: Optional[SessionProxy], request: ResourceHandlerRequest, callback_context: MutableMapping[str, Any], ) -> ProgressEvent: LOG.info("Starting %s Read Handler", TYPE_NAME) model = request.desiredResourceState dashboard_id = model.Id with v1_client( model.DatadogCredentials.ApiKey, model.DatadogCredentials.ApplicationKey, model.DatadogCredentials.ApiURL, TELEMETRY_TYPE_NAME, __version__, ) as api_client: api_instance = DashboardsApi(api_client) try: dash = api_instance.get_dashboard(dashboard_id) json_dict = ApiClient.sanitize_for_serialization(dash) model.DashboardDefinition = json.dumps(json_dict) except ApiException as e: LOG.error( "Exception when calling DashboardsApi->get_dashboard: %s\n", e) return ProgressEvent(status=OperationStatus.FAILED, resourceModel=model, message=f"Error getting dashboard: {e}") return ProgressEvent( status=OperationStatus.SUCCESS, resourceModel=model, )
def create_handler( session: Optional[SessionProxy], request: ResourceHandlerRequest, callback_context: MutableMapping[str, Any], ) -> ProgressEvent: LOG.info("Starting %s Create Handler", TYPE_NAME) model = request.desiredResourceState aws_account = build_aws_account_from_model(model) with v1_client( model.DatadogCredentials.ApiKey, model.DatadogCredentials.ApplicationKey, model.DatadogCredentials.ApiURL, TELEMETRY_TYPE_NAME, __version__, ) as api_client: api_instance = AWSIntegrationApi(api_client) try: api_instance.create_aws_account(aws_account) except ApiException as e: LOG.error( "Exception when calling AWSIntegrationApi->create_aws_account: %s\n", e) return ProgressEvent(status=OperationStatus.FAILED, resourceModel=model, message=f"Error creating AWS account: {e}") model.IntegrationID = get_integration_id(model.AccountID, model.RoleName, model.AccessKeyID) return read_handler(session, request, callback_context)
def create_handler( session: Optional[SessionProxy], request: ResourceHandlerRequest, callback_context: MutableMapping[str, Any], ) -> ProgressEvent: model = request.desiredResourceState progress: ProgressEvent = ProgressEvent( status=OperationStatus.IN_PROGRESS, resourceModel=model, ) LOG.info(f"Starting the {TYPE_NAME} Create Handler") downtime_body = build_downtime_struct(model) with v1_client( model.DatadogCredentials.ApiKey, model.DatadogCredentials.ApplicationKey, model.DatadogCredentials.ApiURL, TELEMETRY_TYPE_NAME, __version__, ) as api_client: api_instance = downtimes_api.DowntimesApi(api_client) try: api_resp = api_instance.create_downtime(downtime_body) model.Id = api_resp.id except ApiException as e: LOG.error( "Exception when calling DowntimeApi->create_downtime: %s\n" % e) return ProgressEvent(status=OperationStatus.FAILED, resourceModel=model, message=e.body) return read_handler(session, request, callback_context)
def update_handler( session: Optional[SessionProxy], request: ResourceHandlerRequest, callback_context: MutableMapping[str, Any], ) -> ProgressEvent: LOG.info("Starting %s Update Handler", TYPE_NAME) model = request.desiredResourceState type_configuration = request.typeConfiguration try: json_payload = json.loads(model.DashboardDefinition) except ValueError as e: LOG.exception("Exception parsing dashboard payload: %s\n", e) return ProgressEvent( status=OperationStatus.FAILED, resourceModel=model, message=f"Error parsing dashboard payload: {e}", errorCode=HandlerErrorCode.InternalFailure, ) dashboard_id = model.Id with v1_client( type_configuration.DatadogCredentials.ApiKey, type_configuration.DatadogCredentials.ApplicationKey, type_configuration.DatadogCredentials.ApiURL, TELEMETRY_TYPE_NAME, __version__, ) as api_client: api_instance = DashboardsApi(api_client) try: # Get raw http response with _preload_content False api_instance.update_dashboard(dashboard_id, json_payload, _check_input_type=False, _preload_content=False) except TypeError as e: LOG.exception( "Exception when deserializing the Dashboard payload definition: %s\n", e) return ProgressEvent( status=OperationStatus.FAILED, resourceModel=model, message=f"Error deserializing dashboard: {e}", errorCode=HandlerErrorCode.InternalFailure, ) except ApiException as e: LOG.exception( "Exception when calling DashboardsApi->update_dashboard: %s\n", e) return ProgressEvent(status=OperationStatus.FAILED, resourceModel=model, message=f"Error updating dashboard: {e}", errorCode=http_to_handler_error_code( e.status)) return read_handler(session, request, callback_context)
def create_handler( session: Optional[SessionProxy], request: ResourceHandlerRequest, callback_context: MutableMapping[str, Any], ) -> ProgressEvent: LOG.info("Starting %s Create Handler", TYPE_NAME) model = request.desiredResourceState try: json_payload = json.loads(model.DashboardDefinition) except json.JSONDecodeError as e: LOG.error("Exception when loading the Dashboard JSON definition: %s\n", e) return ProgressEvent( status=OperationStatus.FAILED, resourceModel=model, message=f"Error loading Dashboard JSON definition: {e}") with v1_client( model.DatadogCredentials.ApiKey, model.DatadogCredentials.ApplicationKey, model.DatadogCredentials.ApiURL, TELEMETRY_TYPE_NAME, __version__, ) as api_client: api_instance = DashboardsApi(api_client) try: # Call the deserialization function of the python client. # It expects the loaded JSON payload, the python client type of the model, # some path to the data (not sure what this one does), # whether or not the payload is a server payload, so true in our case, # whether or not to do type conversion, true in our case too # and importantly the api_client configuration, needed to perform the type conversions dashboard = validate_and_convert_types( json_payload, (Dashboard, ), ["resource_data"], True, True, configuration=api_client.configuration) res = api_instance.create_dashboard(dashboard) model.Id = res.id except TypeError as e: LOG.error( "Exception when deserializing the Dashboard payload definition: %s\n", e) return ProgressEvent(status=OperationStatus.FAILED, resourceModel=model, message=f"Error deserializing dashboard: {e}") except ApiException as e: LOG.error( "Exception when calling DashboardsApi->create_dashboard: %s\n", e) return ProgressEvent(status=OperationStatus.FAILED, resourceModel=model, message=f"Error creating dashboard: {e}") return read_handler(session, request, callback_context)
def read_handler( session: Optional[SessionProxy], request: ResourceHandlerRequest, callback_context: MutableMapping[str, Any], ) -> ProgressEvent: model = request.desiredResourceState LOG.info(f"Starting the {TYPE_NAME} Read Handler") with v1_client( model.DatadogCredentials.ApiKey, model.DatadogCredentials.ApplicationKey, model.DatadogCredentials.ApiURL, TELEMETRY_TYPE_NAME, __version__, ) as api_client: api_instance = downtimes_api.DowntimesApi(api_client) try: api_resp = api_instance.get_downtime(model.Id) except ApiException as e: LOG.error( "Exception when calling DowntimeApi->get_downtime: %s\n" % e) return ProgressEvent(status=OperationStatus.FAILED, resourceModel=model, message=e.body) LOG.info(f"Success retrieving downtime {api_resp}") # Add hasattr checks for non-nullable fields to ensure they're available to be set # Currently in datadog-api-client-python, accessing fields that don't exist return an AttributeError if hasattr(api_resp, 'message'): model.Message = api_resp.message if hasattr(api_resp, 'monitor_tags'): model.MonitorTags = api_resp.monitor_tags if hasattr(api_resp, 'scope'): model.Scope = api_resp.scope if hasattr(api_resp, 'timezone'): model.Timezone = api_resp.timezone if hasattr(api_resp, 'start'): model.Start = api_resp.start # Nullable fields, these should be None or set as a value if api_resp.end: model.End = api_resp.end if api_resp.monitor_id: model.MonitorId = api_resp.monitor_id return ProgressEvent( status=OperationStatus.SUCCESS, resourceModel=model, )
def delete_handler( session: Optional[SessionProxy], request: ResourceHandlerRequest, callback_context: MutableMapping[str, Any], ) -> ProgressEvent: model = request.desiredResourceState type_configuration = request.typeConfiguration LOG.info(f"Starting the {TYPE_NAME} Delete Handler") with v1_client( type_configuration.DatadogCredentials.ApiKey, type_configuration.DatadogCredentials.ApplicationKey, type_configuration.DatadogCredentials.ApiURL, TELEMETRY_TYPE_NAME, __version__, ) as api_client: api_instance = downtimes_api.DowntimesApi(api_client) # First get the downtime to check if it's disabled (mostly a hack to make a contract_delete_delete test pass) try: api_resp = api_instance.get_downtime(model.Id) if api_resp.disabled: # Return a 404 to indicate the downtime was already deleted return ProgressEvent( status=OperationStatus.FAILED, resourceModel=None, message="Downtime {model.Id} already disabled", errorCode=HandlerErrorCode.NotFound) except ApiException as e: # Log error but continue in case of failure to get, this should not prevent the next call to delete LOG.exception( "Exception when calling DowntimeApi->get_downtime: %s\n" % e) try: api_instance.cancel_downtime(model.Id) except ApiException as e: LOG.exception( "Exception when calling DowntimeApi->cancel_downtime: %s\n" % e) return ProgressEvent(status=OperationStatus.FAILED, resourceModel=model, message=e.body, errorCode=http_to_handler_error_code( e.status)) return ProgressEvent( status=OperationStatus.SUCCESS, resourceModel=None, )
def read_handler( session: Optional[SessionProxy], request: ResourceHandlerRequest, callback_context: MutableMapping[str, Any], ) -> ProgressEvent: LOG.info("Starting %s Read Handler", TYPE_NAME) model = request.desiredResourceState type_configuration = request.typeConfiguration dashboard_id = model.Id with v1_client( type_configuration.DatadogCredentials.ApiKey, type_configuration.DatadogCredentials.ApplicationKey, type_configuration.DatadogCredentials.ApiURL, TELEMETRY_TYPE_NAME, __version__, ) as api_client: api_instance = DashboardsApi(api_client) try: # Get raw http response with _preload_content set to False resp = api_instance.get_dashboard(dashboard_id, _preload_content=False) json_dict = json.loads(resp.data) model.Url = json_dict["url"] for k in [ "author_handle", "id", "created_at", "modified_at", "url", "author_name" ]: try: del json_dict[k] except KeyError: pass model.DashboardDefinition = json.dumps(json_dict, sort_keys=True) except ApiException as e: LOG.exception( "Exception when calling DashboardsApi->get_dashboard: %s\n", e) return ProgressEvent(status=OperationStatus.FAILED, resourceModel=model, message=f"Error getting dashboard: {e}", errorCode=http_to_handler_error_code( e.status)) return ProgressEvent( status=OperationStatus.SUCCESS, resourceModel=model, )
def read_handler( session: Optional[SessionProxy], request: ResourceHandlerRequest, callback_context: MutableMapping[str, Any], ) -> ProgressEvent: model = request.desiredResourceState with v1_client( model.DatadogCredentials.ApiKey, model.DatadogCredentials.ApplicationKey, model.DatadogCredentials.ApiURL, TELEMETRY_TYPE_NAME, __version__, ) as api_client: api_instance = AWSIntegrationApi(api_client) try: aws_account = api_instance.list_aws_accounts( account_id=model.AccountID, role_name=model.RoleName, access_key_id=model.AccessKeyID).accounts[0] except ApiException as e: LOG.error( "Exception when calling AWSIntegrationApi->list_aws_accounts: %s\n", e) return ProgressEvent(status=OperationStatus.FAILED, resourceModel=model, message=f"Error getting AWS account: {e}") except IndexError: LOG.error( f"Account with integration ID '{model.IntegrationID}' not found. " f"Was it updated outside of AWS CloudFormation ?") return ProgressEvent( status=OperationStatus.FAILED, resourceModel=model, message= f"Account with integration ID '{model.IntegrationID}' not found. " f"Was it updated outside of AWS CloudFormation ?") model.HostTags = aws_account.host_tags model.FilterTags = aws_account.filter_tags model.AccountSpecificNamespaceRules = aws_account.account_specific_namespace_rules return ProgressEvent( status=OperationStatus.SUCCESS, resourceModel=model, )
def create_handler( session: Optional[SessionProxy], request: ResourceHandlerRequest, callback_context: MutableMapping[str, Any], ) -> ProgressEvent: LOG.info("Starting %s Create Handler", TYPE_NAME) model = request.desiredResourceState type_configuration = request.typeConfiguration aws_account = build_aws_account_from_model(model) with v1_client( type_configuration.DatadogCredentials.ApiKey, type_configuration.DatadogCredentials.ApplicationKey, type_configuration.DatadogCredentials.ApiURL, TELEMETRY_TYPE_NAME, __version__, ) as api_client: api_instance = AWSIntegrationApi(api_client) try: response = api_instance.create_aws_account(aws_account) except ApiException as e: LOG.exception( "Exception when calling AWSIntegrationApi->create_aws_account: %s\n", e) return ProgressEvent(status=OperationStatus.FAILED, resourceModel=model, message=f"Error creating AWS account: {e}", errorCode=http_to_handler_error_code( e.status)) if model.ExternalIDSecretName is not None: secret_name = model.ExternalIDSecretName else: secret_name = DEFAULT_SECRET_NAME boto_client = session.client("secretsmanager") boto_client.create_secret( Description= 'The external_id associated with your Datadog AWS Integration.', Name=secret_name, SecretString='{"external_id":"%s"}' % response.external_id, ) model.IntegrationID = get_integration_id(model.AccountID, model.RoleName, model.AccessKeyID) return read_handler(session, request, callback_context)
def create_handler( session: Optional[SessionProxy], request: ResourceHandlerRequest, callback_context: MutableMapping[str, Any], ) -> ProgressEvent: LOG.info("Starting %s Create Handler", TYPE_NAME) model = request.desiredResourceState type_configuration = request.typeConfiguration thresholds = build_slo_thresholds_from_model(model) slo = ApiSLORequest(name=model.Name, type=ApiSLOType(model.Type), thresholds=thresholds) if model.Description is not None: slo.description = model.Description if model.Groups is not None: slo.groups = model.Groups if model.MonitorIds is not None: slo.monitor_ids = model.MonitorIds if model.Query is not None: slo.query = ApiSLOQuery(numerator=model.Query.Numerator, denominator=model.Query.Denominator) if model.Tags is not None: slo.tags = model.Tags with v1_client( type_configuration.DatadogCredentials.ApiKey, type_configuration.DatadogCredentials.ApplicationKey, type_configuration.DatadogCredentials.ApiURL, TELEMETRY_TYPE_NAME, __version__, ) as api_client: api_instance = ServiceLevelObjectivesApi(api_client) try: slo_resp = api_instance.create_slo(slo) except ApiException as e: LOG.error("Exception when calling SLOApi->create_slo: %s\n", e) return ProgressEvent(status=OperationStatus.FAILED, resourceModel=model, message=f"Error creating slo: {e}", errorCode=http_to_handler_error_code( e.status)) model.Id = slo_resp.data[0].id return read_handler(session, request, callback_context)
def update_handler( session: Optional[SessionProxy], request: ResourceHandlerRequest, callback_context: MutableMapping[str, Any], ) -> ProgressEvent: LOG.info("Starting %s Update Handler", TYPE_NAME) model = request.desiredResourceState type_configuration = request.typeConfiguration monitor = ApiMonitorUpdateRequest() monitor.query = model.Query monitor.type = ApiMonitorType(model.Type) if model.Message is not None: monitor.message = model.Message if model.Name is not None: monitor.name = model.Name if model.Tags is not None: monitor.tags = model.Tags if model.Priority is not None: monitor.priority = model.Priority options = build_monitor_options_from_model(model) if options: monitor.options = options with v1_client( type_configuration.DatadogCredentials.ApiKey, type_configuration.DatadogCredentials.ApplicationKey, type_configuration.DatadogCredentials.ApiURL, TELEMETRY_TYPE_NAME, __version__, ) as api_client: api_instance = MonitorsApi(api_client) try: api_instance.update_monitor(model.Id, monitor) except ApiException as e: LOG.exception( "Exception when calling MonitorsApi->update_monitor: %s\n", e) return ProgressEvent( status=OperationStatus.FAILED, resourceModel=model, message=f"Error updating monitor: {e}", errorCode=http_to_handler_error_code(e.status), ) return read_handler(session, request, callback_context)
def update_handler( session: Optional[SessionProxy], request: ResourceHandlerRequest, callback_context: MutableMapping[str, Any], ) -> ProgressEvent: LOG.info("Starting %s Update Handler", TYPE_NAME) model = request.desiredResourceState aws_account = build_aws_account_from_model(model) if get_integration_id(model.AccountID, model.RoleName, model.AccessKeyID) != model.IntegrationID: LOG.error( f"Cannot update `account_id`, `role_name` or `access_key_id` using this resource. " f"Please delete it and create a new one instead.") return ProgressEvent( status=OperationStatus.FAILED, resourceModel=model, message= f"Cannot update `account_id`, `role_name` or `access_key_id` using this resource. " f"Please delete it and create a new one instead.") with v1_client( model.DatadogCredentials.ApiKey, model.DatadogCredentials.ApplicationKey, model.DatadogCredentials.ApiURL, TELEMETRY_TYPE_NAME, __version__, ) as api_client: api_instance = AWSIntegrationApi(api_client) try: api_instance.update_aws_account( aws_account, account_id=model.AccountID, role_name=model.RoleName, access_key_id=model.AccessKeyID, ) except ApiException as e: LOG.error( "Exception when calling AWSIntegrationApi->update_aws_account: %s\n", e) return ProgressEvent(status=OperationStatus.FAILED, resourceModel=model, message=f"Error updating AWS account: {e}") return read_handler(session, request, callback_context)
def create_handler( session: Optional[SessionProxy], request: ResourceHandlerRequest, callback_context: MutableMapping[str, Any], ) -> ProgressEvent: LOG.info("Starting %s Create Handler", TYPE_NAME) model = request.desiredResourceState monitor = ApiMonitor() monitor.query = model.Query monitor.type = ApiMonitorType(model.Type) if model.Message is not None: monitor.message = model.Message if model.Name is not None: monitor.name = model.Name if model.Tags is not None: monitor.tags = model.Tags options = build_monitor_options_from_model(model) if options: monitor.options = options with v1_client( model.DatadogCredentials.ApiKey, model.DatadogCredentials.ApplicationKey, model.DatadogCredentials.ApiURL or "https://api.datadoghq.com", TELEMETRY_TYPE_NAME, __version__, ) as api_client: api_instance = MonitorsApi(api_client) try: monitor_resp = api_instance.create_monitor(monitor) except ApiException as e: LOG.error( "Exception when calling MonitorsApi->create_monitor: %s\n", e) return ProgressEvent(status=OperationStatus.FAILED, resourceModel=model, message=f"Error creating monitor: {e}") model.Id = monitor_resp.id return read_handler(session, request, callback_context)
def update_handler( session: Optional[SessionProxy], request: ResourceHandlerRequest, callback_context: MutableMapping[str, Any], ) -> ProgressEvent: LOG.info("Starting %s Update Handler", TYPE_NAME) model = request.desiredResourceState type_configuration = request.typeConfiguration aws_account = build_aws_account_from_model(model) if not model.IntegrationID: LOG.error("Cannot update non existent resource") return ProgressEvent( status=OperationStatus.FAILED, resourceModel=model, message="Cannot update non existent resource", errorCode=HandlerErrorCode.NotFound, ) if get_integration_id(model.AccountID, model.RoleName, model.AccessKeyID) != model.IntegrationID: LOG.error( "Cannot update `account_id`, `role_name` or `access_key_id` using this resource. " "Please delete it and create a new one instead.") return ProgressEvent( status=OperationStatus.FAILED, resourceModel=model, message= "Cannot update `account_id`, `role_name` or `access_key_id` using this resource. " "Please delete it and create a new one instead.", errorCode=HandlerErrorCode.NotUpdatable) with v1_client( type_configuration.DatadogCredentials.ApiKey, type_configuration.DatadogCredentials.ApplicationKey, type_configuration.DatadogCredentials.ApiURL, TELEMETRY_TYPE_NAME, __version__, ) as api_client: api_instance = AWSIntegrationApi(api_client) try: kwargs = {} if model.AccountID is not None: kwargs["account_id"] = model.AccountID if model.RoleName is not None: kwargs["role_name"] = model.RoleName if model.AccessKeyID is not None: kwargs["access_key_id"] = model.AccessKeyID api_instance.update_aws_account(aws_account, **kwargs) except ApiException as e: LOG.exception( "Exception when calling AWSIntegrationApi->update_aws_account: %s\n", e) error_code = http_to_handler_error_code(e.status) if e.status == 400 and "errors" in e.body and any( "does not exist" in s for s in e.body['errors']): error_code = HandlerErrorCode.NotFound return ProgressEvent( status=OperationStatus.FAILED, resourceModel=model, message=f"Error updating AWS account: {e}", errorCode=error_code, ) return read_handler(session, request, callback_context)
def read_handler( session: Optional[SessionProxy], request: ResourceHandlerRequest, callback_context: MutableMapping[str, Any], ) -> ProgressEvent: model = request.desiredResourceState type_configuration = request.typeConfiguration with v1_client( type_configuration.DatadogCredentials.ApiKey, type_configuration.DatadogCredentials.ApplicationKey, type_configuration.DatadogCredentials.ApiURL, TELEMETRY_TYPE_NAME, __version__, ) as api_client: api_instance = AWSIntegrationApi(api_client) try: if model.IntegrationID is None: return ProgressEvent( status=OperationStatus.FAILED, resourceModel=model, message="No IntegrationID set, resource never created", errorCode=HandlerErrorCode.NotFound, ) account_id, role_name, access_key_id = parse_integration_id( model.IntegrationID) kwargs = {} if account_id is not None: kwargs["account_id"] = account_id if role_name is not None: kwargs["role_name"] = role_name if access_key_id is not None: kwargs["access_key_id"] = access_key_id aws_account = api_instance.list_aws_accounts(**kwargs).accounts[0] except ApiException as e: LOG.exception( "Exception when calling AWSIntegrationApi->list_aws_accounts: %s\n", e) error_code = http_to_handler_error_code(e.status) if e.status == 400 and "errors" in e.body and any( "does not exist" in s for s in e.body['errors']): error_code = HandlerErrorCode.NotFound return ProgressEvent( status=OperationStatus.FAILED, resourceModel=model, message=f"Error getting AWS account: {e}", errorCode=error_code, ) except IndexError: LOG.error( f"Account with integration ID '{model.IntegrationID}' not found. " f"Was it updated outside of AWS CloudFormation ?") return ProgressEvent( status=OperationStatus.FAILED, resourceModel=model, message= f"Account with integration ID '{model.IntegrationID}' not found. " f"Was it updated outside of AWS CloudFormation ?", errorCode=HandlerErrorCode.NotFound, ) model.HostTags = aws_account.host_tags model.FilterTags = aws_account.filter_tags model.AccountSpecificNamespaceRules = aws_account.account_specific_namespace_rules return ProgressEvent( status=OperationStatus.SUCCESS, resourceModel=model, )
def read_handler( session: Optional[SessionProxy], request: ResourceHandlerRequest, callback_context: MutableMapping[str, Any], ) -> ProgressEvent: LOG.info("Starting %s Read Handler", TYPE_NAME) model = request.desiredResourceState type_configuration = request.typeConfiguration with v1_client( type_configuration.DatadogCredentials.ApiKey, type_configuration.DatadogCredentials.ApplicationKey, type_configuration.DatadogCredentials.ApiURL, TELEMETRY_TYPE_NAME, __version__, ) as api_client: api_instance = ServiceLevelObjectivesApi(api_client) slo_id = model.Id if slo_id is None: return ProgressEvent( status=OperationStatus.FAILED, resourceModel=model, message="Error getting SLO: SLO does not exist", errorCode=HandlerErrorCode.NotFound, ) try: slo = api_instance.get_slo(slo_id) except ApiException as e: LOG.error("Exception when calling SLOApi->get_slo: %s\n", e) return ProgressEvent(status=OperationStatus.FAILED, resourceModel=model, message=f"Error getting SLO: {e}", errorCode=http_to_handler_error_code( e.status)) model.Created = slo.data.created_at model.Modified = slo.data.modified_at model.Description = slo.data.description model.Name = slo.data.name model.Tags = slo.data.tags model.Type = slo.data.type.value if slo.data.creator: model.Creator = Creator(Name=slo.data.creator.name, Email=slo.data.creator.email, Handle=slo.data.creator.handle) if slo.data.type.value == "monitor": if hasattr(slo.data, 'groups'): model.Groups = slo.data.groups model.MonitorIds = slo.data.monitor_ids elif slo.data.type.value == "metric": model.Query = Query(Denominator=slo.data.query.denominator, Numerator=slo.data.query.numerator) thresholds = [] for th in slo.data.thresholds: thresholds.append( Threshold(Target=th.target if hasattr(th, "target") else None, TargetDisplay=th.target_display if hasattr( th, "target_display") else None, Timeframe=th.timeframe.value if hasattr(th, "timeframe") else None, Warning=th.warning if hasattr(th, "warning") else None, WarningDisplay=th.warning_display if hasattr( th, "warning_display") else None)) model.Thresholds = thresholds model.Id = slo.data.id return ProgressEvent(status=OperationStatus.SUCCESS, resourceModel=model)
def read_handler( session: Optional[SessionProxy], request: ResourceHandlerRequest, callback_context: MutableMapping[str, Any], ) -> ProgressEvent: LOG.info("Starting %s Read Handler", TYPE_NAME) model = request.desiredResourceState with v1_client( model.DatadogCredentials.ApiKey, model.DatadogCredentials.ApplicationKey, model.DatadogCredentials.ApiURL or "https://api.datadoghq.com", TELEMETRY_TYPE_NAME, __version__, ) as api_client: api_instance = MonitorsApi(api_client) monitor_id = model.Id try: monitor = api_instance.get_monitor(monitor_id) except ApiException as e: LOG.error("Exception when calling MonitorsApi->get_monitor: %s\n", e) return ProgressEvent(status=OperationStatus.FAILED, resourceModel=model, message=f"Error getting monitor: {e}") model.Created = monitor.created.isoformat() model.Modified = monitor.modified.isoformat() model.Message = monitor.message model.Name = monitor.name model.Tags = monitor.tags model.Query = monitor.query model.Multi = monitor.multi if monitor.deleted: model.Deleted = monitor.deleted.isoformat() if not ((model.Type == "query alert" and monitor.type.value == "metric alert") or (model.Type == "metric alert" and monitor.type.value == "query alert")): # metric alert and query alert are interchangeable, so don't update from one to the other model.Type = monitor.type.value if monitor.creator: model.Creator = Creator(Name=monitor.creator.name, Email=monitor.creator.email, Handle=monitor.creator.handle) # Add hasattr checks for options since not all of them are applicable to all monitor types, so some attributes # might not always be present options = monitor.options if hasattr(monitor, "options") else None if options: model.Options = MonitorOptions( EnableLogsSample=options.enable_logs_sample if hasattr( options, "enable_logs_sample") else None, EscalationMessage=options.escalation_message if hasattr( options, "escalation_message") else None, EvaluationDelay=options.evaluation_delay if hasattr( options, "evaluation_delay") else None, IncludeTags=options.include_tags if hasattr( options, "include_tags") else None, Locked=options.locked if hasattr(options, "locked") else None, MinLocationFailed=options.min_location_failed if hasattr( options, "min_location_failed") else None, NewHostDelay=options.new_host_delay if hasattr( options, "new_host_delay") else None, NoDataTimeframe=options.no_data_timeframe if hasattr( options, "no_data_timeframe") else None, NotifyAudit=options.notify_audit if hasattr( options, "notify_audit") else None, NotifyNoData=options.notify_no_data if hasattr( options, "notify_no_data") else None, RenotifyInterval=options.renotify_interval if hasattr( options, "renotify_interval") else None, RequireFullWindow=options.require_full_window if hasattr( options, "require_full_window") else None, SyntheticsCheckID=options.synthetics_check_id if hasattr( options, "synthetics_check_id") else None, Thresholds=None, ThresholdWindows=None, TimeoutH=options.timeout_h if hasattr(options, "timeout_h") else None, ) thresholds = options.thresholds if hasattr(options, "thresholds") else None if thresholds: model.Options.Thresholds = MonitorThresholds( Critical=thresholds.critical if hasattr( thresholds, "critical") else None, CriticalRecovery=thresholds.critical_recovery if hasattr( thresholds, "critical_recovery") else None, Warning=thresholds.warning if hasattr(thresholds, "warning") else None, WarningRecovery=thresholds.warning_recovery if hasattr( thresholds, "warning_recovery") else None, OK=thresholds.ok if hasattr(thresholds, "ok") else None, ) tw = options.threshold_windows if hasattr( options, "threshold_windows") else None if tw: model.Options.ThresholdWindows = MonitorThresholdWindows( TriggerWindow=tw.trigger_window if hasattr( tw, "trigger_window") else None, RecoveryWindow=tw.recovery_window if hasattr( tw, "recovery_window") else None, ) model.Id = monitor.id return ProgressEvent( status=OperationStatus.SUCCESS, resourceModel=model, )
def delete_handler( session: Optional[SessionProxy], request: ResourceHandlerRequest, callback_context: MutableMapping[str, Any], ) -> ProgressEvent: model = request.desiredResourceState type_configuration = request.typeConfiguration if model.ExternalIDSecretName is not None: secret_name = model.ExternalIDSecretName else: secret_name = DEFAULT_SECRET_NAME boto_client = session.client("secretsmanager") callback_count = callback_context.get("callback_count", 0) if 0 < callback_count <= MAX_DELETE_SECRET_RETRIES: LOG.info(f"Checking deletion of secret {secret_name}") try: boto_client.describe_secret(SecretId=secret_name) except boto_client.exceptions.ResourceNotFoundException: return ProgressEvent( status=OperationStatus.SUCCESS, resourceModel=None, ) elif callback_count > MAX_DELETE_SECRET_RETRIES: return ProgressEvent( status=OperationStatus.FAILED, message= f"Error deleting AWS Account: failed to delete secret {secret_name}" ) else: kwargs = {} if model.AccountID is not None: kwargs["account_id"] = model.AccountID if model.RoleName is not None: kwargs["role_name"] = model.RoleName if model.AccessKeyID is not None: kwargs["access_key_id"] = model.AccessKeyID delete_request = AWSAccountDeleteRequest(**kwargs) with v1_client( type_configuration.DatadogCredentials.ApiKey, type_configuration.DatadogCredentials.ApplicationKey, type_configuration.DatadogCredentials.ApiURL, TELEMETRY_TYPE_NAME, __version__, ) as api_client: api_instance = AWSIntegrationApi(api_client) try: api_instance.delete_aws_account(delete_request) except ApiException as e: LOG.exception( "Exception when calling AWSIntegrationApi->delete_aws_account: %s\n", e) error_code = http_to_handler_error_code(e.status) if e.status == 400 and "errors" in e.body and any( "does not exist" in s for s in e.body['errors']): error_code = HandlerErrorCode.NotFound return ProgressEvent( status=OperationStatus.FAILED, resourceModel=model, message=f"Error deleting AWS account: {e}", errorCode=error_code) boto_client.delete_secret( SecretId=secret_name, ForceDeleteWithoutRecovery=True, ) return ProgressEvent( status=OperationStatus.IN_PROGRESS, resourceModel=model, callbackContext={"callback_count": callback_count + 1}, callbackDelaySeconds=DELETE_SECRET_CALLBACK_INTERVAL, )