class CloudwatchProvider(CloudwatchApi): def __init__(self): self.tags = TaggingService() def list_tags_for_resource( self, context: RequestContext, resource_arn: AmazonResourceName) -> ListTagsForResourceOutput: tags = self.tags.list_tags_for_resource(resource_arn) return ListTagsForResourceOutput(Tags=tags.get("Tags", [])) def untag_resource(self, context: RequestContext, resource_arn: AmazonResourceName, tag_keys: TagKeyList) -> UntagResourceOutput: self.tags.untag_resource(resource_arn, tag_keys) return UntagResourceOutput() def tag_resource(self, context: RequestContext, resource_arn: AmazonResourceName, tags: TagList) -> TagResourceOutput: self.tags.tag_resource(resource_arn, tags) return TagResourceOutput() @handler("PutMetricAlarm", expand=False) def put_metric_alarm( self, context: RequestContext, request: PutMetricAlarmInput, ) -> None: moto.call_moto(context) name = request.get("AlarmName") arn = aws_stack.cloudwatch_alarm_arn(name) self.tags.tag_resource(arn, request.get("Tags"))
class CloudwatchProvider(CloudwatchApi, ServiceLifecycleHook): """ Cloudwatch provider. LIMITATIONS: - no alarm rule evaluation """ def __init__(self): self.tags = TaggingService() def on_after_init(self): ROUTER.add(PATH_GET_RAW_METRICS, self.get_raw_metrics) def get_raw_metrics(self, request: Request): region = aws_stack.extract_region_from_auth_header(request.headers) backend = cloudwatch_backends.get(region) if backend: result = backend.metric_data else: result = [] result = [{ "ns": r.namespace, "n": r.name, "v": r.value, "t": r.timestamp, "d": [{ "n": d.name, "v": d.value } for d in r.dimensions], } for r in result] return {"metrics": result} def list_tags_for_resource( self, context: RequestContext, resource_arn: AmazonResourceName) -> ListTagsForResourceOutput: tags = self.tags.list_tags_for_resource(resource_arn) return ListTagsForResourceOutput(Tags=tags.get("Tags", [])) def untag_resource(self, context: RequestContext, resource_arn: AmazonResourceName, tag_keys: TagKeyList) -> UntagResourceOutput: self.tags.untag_resource(resource_arn, tag_keys) return UntagResourceOutput() def tag_resource(self, context: RequestContext, resource_arn: AmazonResourceName, tags: TagList) -> TagResourceOutput: self.tags.tag_resource(resource_arn, tags) return TagResourceOutput() @handler("PutMetricAlarm", expand=False) def put_metric_alarm( self, context: RequestContext, request: PutMetricAlarmInput, ) -> None: moto.call_moto(context) name = request.get("AlarmName") arn = aws_stack.cloudwatch_alarm_arn(name) self.tags.tag_resource(arn, request.get("Tags")) @handler("PutCompositeAlarm", expand=False) def put_composite_alarm( self, context: RequestContext, request: PutCompositeAlarmInput, ) -> None: pass backend = cloudwatch_backends[context.region] backend.put_metric_alarm( name=request.get("AlarmName"), namespace=None, metric_name=None, metric_data_queries=None, comparison_operator=None, evaluation_periods=None, datapoints_to_alarm=None, period=None, threshold=None, statistic=None, extended_statistic=None, description=request.get("AlarmDescription"), dimensions=[], alarm_actions=request.get("AlarmActions", []), ok_actions=request.get("OKActions", []), insufficient_data_actions=request.get("InsufficientDataActions", []), unit=None, actions_enabled=request.get("ActionsEnabled"), treat_missing_data=None, evaluate_low_sample_count_percentile=None, threshold_metric_id=None, rule=request.get("AlarmRule"), tags=request.get("Tags", []), )
class CloudwatchProvider(CloudwatchApi, ServiceLifecycleHook): """ Cloudwatch provider. LIMITATIONS: - no alarm rule evaluation """ def __init__(self): self.tags = TaggingService() self.alarm_scheduler = None def on_after_init(self): ROUTER.add(PATH_GET_RAW_METRICS, self.get_raw_metrics) self.alarm_scheduler = AlarmScheduler() def on_before_start(self): # re-schedule alarms for persistence use-case def restart_alarms(*args): poll_condition(lambda: SERVICE_PLUGINS.is_running("cloudwatch")) self.alarm_scheduler.restart_existing_alarms() start_worker_thread(restart_alarms) def on_before_stop(self): self.alarm_scheduler.shutdown_scheduler() def delete_alarms(self, context: RequestContext, alarm_names: AlarmNames) -> None: moto.call_moto(context) for alarm_name in alarm_names: arn = aws_stack.cloudwatch_alarm_arn(alarm_name) self.alarm_scheduler.delete_scheduler_for_alarm(arn) def get_raw_metrics(self, request: Request): region = aws_stack.extract_region_from_auth_header(request.headers) backend = cloudwatch_backends.get(region) if backend: result = backend.metric_data else: result = [] result = [{ "ns": r.namespace, "n": r.name, "v": r.value, "t": r.timestamp, "d": [{ "n": d.name, "v": d.value } for d in r.dimensions], } for r in result] return {"metrics": result} def list_tags_for_resource( self, context: RequestContext, resource_arn: AmazonResourceName) -> ListTagsForResourceOutput: tags = self.tags.list_tags_for_resource(resource_arn) return ListTagsForResourceOutput(Tags=tags.get("Tags", [])) def untag_resource(self, context: RequestContext, resource_arn: AmazonResourceName, tag_keys: TagKeyList) -> UntagResourceOutput: self.tags.untag_resource(resource_arn, tag_keys) return UntagResourceOutput() def tag_resource(self, context: RequestContext, resource_arn: AmazonResourceName, tags: TagList) -> TagResourceOutput: self.tags.tag_resource(resource_arn, tags) return TagResourceOutput() @handler("PutMetricAlarm", expand=False) def put_metric_alarm( self, context: RequestContext, request: PutMetricAlarmInput, ) -> None: # missing will be the default, when not set (but it will not explicitly be set) if not request.get("TreatMissingData", "missing") in [ "breaching", "notBreaching", "ignore", "missing", ]: raise ValidationError( f"The value {request['TreatMissingData']} is not supported for TreatMissingData parameter. Supported values are [breaching, notBreaching, ignore, missing]." ) # do some sanity checks: if request.get("Period"): # Valid values are 10, 30, and any multiple of 60. value = request.get("Period") if value not in (10, 30): if value % 60 != 0: raise ValidationError( "Period must be 10, 30 or a multiple of 60") if request.get("Statistic"): if not request.get("Statistic") in [ "SampleCount", "Average", "Sum", "Minimum", "Maximum", ]: raise ValidationError( f"Value '{request.get('Statistic')}' at 'statistic' failed to satisfy constraint: Member must satisfy enum value set: [Maximum, SampleCount, Sum, Minimum, Average]" ) moto.call_moto(context) name = request.get("AlarmName") arn = aws_stack.cloudwatch_alarm_arn(name) self.tags.tag_resource(arn, request.get("Tags")) self.alarm_scheduler.schedule_metric_alarm(arn) @handler("PutCompositeAlarm", expand=False) def put_composite_alarm( self, context: RequestContext, request: PutCompositeAlarmInput, ) -> None: backend = cloudwatch_backends[context.region] backend.put_metric_alarm( name=request.get("AlarmName"), namespace=None, metric_name=None, metric_data_queries=None, comparison_operator=None, evaluation_periods=None, datapoints_to_alarm=None, period=None, threshold=None, statistic=None, extended_statistic=None, description=request.get("AlarmDescription"), dimensions=[], alarm_actions=request.get("AlarmActions", []), ok_actions=request.get("OKActions", []), insufficient_data_actions=request.get("InsufficientDataActions", []), unit=None, actions_enabled=request.get("ActionsEnabled"), treat_missing_data=None, evaluate_low_sample_count_percentile=None, threshold_metric_id=None, rule=request.get("AlarmRule"), tags=request.get("Tags", []), ) LOG.warning( "Composite Alarms configuration is not yet supported, alarm state will not be evaluated" )