TechDebt: MyPy CloudWatch (#5623)
This commit is contained in:
parent
0f9a907af0
commit
15891efcef
@ -4,40 +4,40 @@ from moto.core.exceptions import RESTError
|
|||||||
class InvalidFormat(RESTError):
|
class InvalidFormat(RESTError):
|
||||||
code = 400
|
code = 400
|
||||||
|
|
||||||
def __init__(self, message):
|
def __init__(self, message: str):
|
||||||
super().__init__(__class__.__name__, message)
|
super().__init__(InvalidFormat.__name__, message)
|
||||||
|
|
||||||
|
|
||||||
class InvalidParameterValue(RESTError):
|
class InvalidParameterValue(RESTError):
|
||||||
code = 400
|
code = 400
|
||||||
|
|
||||||
def __init__(self, message):
|
def __init__(self, message: str):
|
||||||
super().__init__(__class__.__name__, message)
|
super().__init__(InvalidParameterValue.__name__, message)
|
||||||
|
|
||||||
|
|
||||||
class InvalidParameterCombination(RESTError):
|
class InvalidParameterCombination(RESTError):
|
||||||
code = 400
|
code = 400
|
||||||
|
|
||||||
def __init__(self, message):
|
def __init__(self, message: str):
|
||||||
super().__init__(__class__.__name__, message)
|
super().__init__(InvalidParameterCombination.__name__, message)
|
||||||
|
|
||||||
|
|
||||||
class ResourceNotFound(RESTError):
|
class ResourceNotFound(RESTError):
|
||||||
code = 404
|
code = 404
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self) -> None:
|
||||||
super().__init__(__class__.__name__, "Unknown")
|
super().__init__(ResourceNotFound.__name__, "Unknown")
|
||||||
|
|
||||||
|
|
||||||
class ResourceNotFoundException(RESTError):
|
class ResourceNotFoundException(RESTError):
|
||||||
code = 404
|
code = 404
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self) -> None:
|
||||||
super().__init__(__class__.__name__, "Unknown")
|
super().__init__(ResourceNotFoundException.__name__, "Unknown")
|
||||||
|
|
||||||
|
|
||||||
class ValidationError(RESTError):
|
class ValidationError(RESTError):
|
||||||
code = 400
|
code = 400
|
||||||
|
|
||||||
def __init__(self, message):
|
def __init__(self, message: str):
|
||||||
super().__init__(__class__.__name__, message)
|
super().__init__(ValidationError.__name__, message)
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import json
|
import json
|
||||||
|
import statistics
|
||||||
|
|
||||||
from moto.core import BaseBackend, BaseModel, CloudWatchMetricProvider
|
from moto.core import BaseBackend, BaseModel, CloudWatchMetricProvider
|
||||||
from moto.core.utils import (
|
from moto.core.utils import (
|
||||||
@ -19,37 +20,37 @@ from .exceptions import (
|
|||||||
)
|
)
|
||||||
from .utils import make_arn_for_dashboard, make_arn_for_alarm
|
from .utils import make_arn_for_dashboard, make_arn_for_alarm
|
||||||
from dateutil import parser
|
from dateutil import parser
|
||||||
|
from typing import Tuple, Optional, List, Iterable, Dict, Any, SupportsFloat
|
||||||
from ..utilities.tagging_service import TaggingService
|
from ..utilities.tagging_service import TaggingService
|
||||||
|
|
||||||
_EMPTY_LIST = tuple()
|
_EMPTY_LIST: Any = tuple()
|
||||||
|
|
||||||
|
|
||||||
class Dimension(object):
|
class Dimension(object):
|
||||||
def __init__(self, name, value):
|
def __init__(self, name: Optional[str], value: Optional[str]):
|
||||||
self.name = name
|
self.name = name
|
||||||
self.value = value
|
self.value = value
|
||||||
|
|
||||||
def __eq__(self, item):
|
def __eq__(self, item: Any) -> bool:
|
||||||
if isinstance(item, Dimension):
|
if isinstance(item, Dimension):
|
||||||
return self.name == item.name and (
|
return self.name == item.name and (
|
||||||
self.value is None or item.value is None or self.value == item.value
|
self.value is None or item.value is None or self.value == item.value
|
||||||
)
|
)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def __lt__(self, other):
|
def __lt__(self, other: "Dimension") -> bool:
|
||||||
return self.name < other.name and self.value < other.name
|
return self.name < other.name and self.value < other.name # type: ignore[operator]
|
||||||
|
|
||||||
|
|
||||||
class Metric(object):
|
class Metric(object):
|
||||||
def __init__(self, metric_name, namespace, dimensions):
|
def __init__(self, metric_name: str, namespace: str, dimensions: List[Dimension]):
|
||||||
self.metric_name = metric_name
|
self.metric_name = metric_name
|
||||||
self.namespace = namespace
|
self.namespace = namespace
|
||||||
self.dimensions = dimensions
|
self.dimensions = dimensions
|
||||||
|
|
||||||
|
|
||||||
class MetricStat(object):
|
class MetricStat(object):
|
||||||
def __init__(self, metric, period, stat, unit):
|
def __init__(self, metric: Metric, period: str, stat: str, unit: str):
|
||||||
self.metric = metric
|
self.metric = metric
|
||||||
self.period = period
|
self.period = period
|
||||||
self.stat = stat
|
self.stat = stat
|
||||||
@ -58,7 +59,13 @@ class MetricStat(object):
|
|||||||
|
|
||||||
class MetricDataQuery(object):
|
class MetricDataQuery(object):
|
||||||
def __init__(
|
def __init__(
|
||||||
self, query_id, label, period, return_data, expression=None, metric_stat=None
|
self,
|
||||||
|
query_id: str,
|
||||||
|
label: str,
|
||||||
|
period: str,
|
||||||
|
return_data: str,
|
||||||
|
expression: Optional[str] = None,
|
||||||
|
metric_stat: Optional[MetricStat] = None,
|
||||||
):
|
):
|
||||||
self.id = query_id
|
self.id = query_id
|
||||||
self.label = label
|
self.label = label
|
||||||
@ -68,7 +75,12 @@ class MetricDataQuery(object):
|
|||||||
self.metric_stat = metric_stat
|
self.metric_stat = metric_stat
|
||||||
|
|
||||||
|
|
||||||
def daterange(start, stop, step=timedelta(days=1), inclusive=False):
|
def daterange(
|
||||||
|
start: datetime,
|
||||||
|
stop: datetime,
|
||||||
|
step: timedelta = timedelta(days=1),
|
||||||
|
inclusive: bool = False,
|
||||||
|
) -> Iterable[datetime]:
|
||||||
"""
|
"""
|
||||||
This method will iterate from `start` to `stop` datetimes with a timedelta step of `step`
|
This method will iterate from `start` to `stop` datetimes with a timedelta step of `step`
|
||||||
(supports iteration forwards or backwards in time)
|
(supports iteration forwards or backwards in time)
|
||||||
@ -99,30 +111,30 @@ def daterange(start, stop, step=timedelta(days=1), inclusive=False):
|
|||||||
class FakeAlarm(BaseModel):
|
class FakeAlarm(BaseModel):
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
account_id,
|
account_id: str,
|
||||||
region_name,
|
region_name: str,
|
||||||
name,
|
name: str,
|
||||||
namespace,
|
namespace: str,
|
||||||
metric_name,
|
metric_name: str,
|
||||||
metric_data_queries,
|
metric_data_queries: List[MetricDataQuery],
|
||||||
comparison_operator,
|
comparison_operator: str,
|
||||||
evaluation_periods,
|
evaluation_periods: int,
|
||||||
datapoints_to_alarm,
|
datapoints_to_alarm: int,
|
||||||
period,
|
period: int,
|
||||||
threshold,
|
threshold: float,
|
||||||
statistic,
|
statistic: str,
|
||||||
extended_statistic,
|
extended_statistic: str,
|
||||||
description,
|
description: str,
|
||||||
dimensions,
|
dimensions: List[Dict[str, str]],
|
||||||
alarm_actions,
|
alarm_actions: List[str],
|
||||||
ok_actions,
|
ok_actions: List[str],
|
||||||
insufficient_data_actions,
|
insufficient_data_actions: List[str],
|
||||||
unit,
|
unit: str,
|
||||||
actions_enabled,
|
actions_enabled: bool,
|
||||||
treat_missing_data,
|
treat_missing_data: str,
|
||||||
evaluate_low_sample_count_percentile,
|
evaluate_low_sample_count_percentile: str,
|
||||||
threshold_metric_id,
|
threshold_metric_id: str,
|
||||||
rule=None,
|
rule: str,
|
||||||
):
|
):
|
||||||
self.region_name = region_name
|
self.region_name = region_name
|
||||||
self.name = name
|
self.name = name
|
||||||
@ -153,7 +165,7 @@ class FakeAlarm(BaseModel):
|
|||||||
self.evaluate_low_sample_count_percentile = evaluate_low_sample_count_percentile
|
self.evaluate_low_sample_count_percentile = evaluate_low_sample_count_percentile
|
||||||
self.threshold_metric_id = threshold_metric_id
|
self.threshold_metric_id = threshold_metric_id
|
||||||
|
|
||||||
self.history = []
|
self.history: List[Any] = []
|
||||||
|
|
||||||
self.state_reason = "Unchecked: Initial alarm creation"
|
self.state_reason = "Unchecked: Initial alarm creation"
|
||||||
self.state_reason_data = "{}"
|
self.state_reason_data = "{}"
|
||||||
@ -165,7 +177,7 @@ class FakeAlarm(BaseModel):
|
|||||||
# only used for composite alarms
|
# only used for composite alarms
|
||||||
self.rule = rule
|
self.rule = rule
|
||||||
|
|
||||||
def update_state(self, reason, reason_data, state_value):
|
def update_state(self, reason: str, reason_data: str, state_value: str) -> None:
|
||||||
# History type, that then decides what the rest of the items are, can be one of ConfigurationUpdate | StateUpdate | Action
|
# History type, that then decides what the rest of the items are, can be one of ConfigurationUpdate | StateUpdate | Action
|
||||||
self.history.append(
|
self.history.append(
|
||||||
(
|
(
|
||||||
@ -185,7 +197,9 @@ class FakeAlarm(BaseModel):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def are_dimensions_same(metric_dimensions, dimensions):
|
def are_dimensions_same(
|
||||||
|
metric_dimensions: List[Dimension], dimensions: List[Dimension]
|
||||||
|
) -> bool:
|
||||||
if len(metric_dimensions) != len(dimensions):
|
if len(metric_dimensions) != len(dimensions):
|
||||||
return False
|
return False
|
||||||
for dimension in metric_dimensions:
|
for dimension in metric_dimensions:
|
||||||
@ -199,7 +213,15 @@ def are_dimensions_same(metric_dimensions, dimensions):
|
|||||||
|
|
||||||
|
|
||||||
class MetricDatum(BaseModel):
|
class MetricDatum(BaseModel):
|
||||||
def __init__(self, namespace, name, value, dimensions, timestamp, unit=None):
|
def __init__(
|
||||||
|
self,
|
||||||
|
namespace: str,
|
||||||
|
name: str,
|
||||||
|
value: float,
|
||||||
|
dimensions: List[Dict[str, str]],
|
||||||
|
timestamp: datetime,
|
||||||
|
unit: Any = None,
|
||||||
|
):
|
||||||
self.namespace = namespace
|
self.namespace = namespace
|
||||||
self.name = name
|
self.name = name
|
||||||
self.value = value
|
self.value = value
|
||||||
@ -209,7 +231,13 @@ class MetricDatum(BaseModel):
|
|||||||
]
|
]
|
||||||
self.unit = unit
|
self.unit = unit
|
||||||
|
|
||||||
def filter(self, namespace, name, dimensions, already_present_metrics=None):
|
def filter(
|
||||||
|
self,
|
||||||
|
namespace: Optional[str],
|
||||||
|
name: Optional[str],
|
||||||
|
dimensions: List[Dict[str, str]],
|
||||||
|
already_present_metrics: Optional[List["MetricDatum"]] = None,
|
||||||
|
) -> bool:
|
||||||
if namespace and namespace != self.namespace:
|
if namespace and namespace != self.namespace:
|
||||||
return False
|
return False
|
||||||
if name and name != self.name:
|
if name and name != self.name:
|
||||||
@ -235,7 +263,7 @@ class MetricDatum(BaseModel):
|
|||||||
|
|
||||||
|
|
||||||
class Dashboard(BaseModel):
|
class Dashboard(BaseModel):
|
||||||
def __init__(self, account_id, name, body):
|
def __init__(self, account_id: str, name: str, body: str):
|
||||||
# Guaranteed to be unique for now as the name is also the key of a dictionary where they are stored
|
# Guaranteed to be unique for now as the name is also the key of a dictionary where they are stored
|
||||||
self.arn = make_arn_for_dashboard(account_id, name)
|
self.arn = make_arn_for_dashboard(account_id, name)
|
||||||
self.name = name
|
self.name = name
|
||||||
@ -243,75 +271,76 @@ class Dashboard(BaseModel):
|
|||||||
self.last_modified = datetime.now()
|
self.last_modified = datetime.now()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def last_modified_iso(self):
|
def last_modified_iso(self) -> str:
|
||||||
return self.last_modified.isoformat()
|
return self.last_modified.isoformat()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def size(self):
|
def size(self) -> int:
|
||||||
return len(self)
|
return len(self)
|
||||||
|
|
||||||
def __len__(self):
|
def __len__(self) -> int:
|
||||||
return len(self.body)
|
return len(self.body)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self) -> str:
|
||||||
return "<CloudWatchDashboard {0}>".format(self.name)
|
return "<CloudWatchDashboard {0}>".format(self.name)
|
||||||
|
|
||||||
|
|
||||||
class Statistics:
|
class Statistics:
|
||||||
def __init__(self, stats, dt):
|
def __init__(self, stats: List[str], dt: datetime):
|
||||||
self.timestamp = iso_8601_datetime_without_milliseconds(dt)
|
self.timestamp = iso_8601_datetime_without_milliseconds(dt)
|
||||||
self.values = []
|
self.values: List[float] = []
|
||||||
self.stats = stats
|
self.stats = stats
|
||||||
self.unit = None
|
self.unit = None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def sample_count(self):
|
def sample_count(self) -> Optional[SupportsFloat]:
|
||||||
if "SampleCount" not in self.stats:
|
if "SampleCount" not in self.stats:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
return len(self.values)
|
return len(self.values)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def sum(self):
|
def sum(self) -> Optional[SupportsFloat]:
|
||||||
if "Sum" not in self.stats:
|
if "Sum" not in self.stats:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
return sum(self.values)
|
return sum(self.values)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def minimum(self):
|
def minimum(self) -> Optional[SupportsFloat]:
|
||||||
if "Minimum" not in self.stats:
|
if "Minimum" not in self.stats:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
return min(self.values)
|
return min(self.values)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def maximum(self):
|
def maximum(self) -> Optional[SupportsFloat]:
|
||||||
if "Maximum" not in self.stats:
|
if "Maximum" not in self.stats:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
return max(self.values)
|
return max(self.values)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def average(self):
|
def average(self) -> Optional[SupportsFloat]:
|
||||||
if "Average" not in self.stats:
|
if "Average" not in self.stats:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# when moto is 3.4+ we can switch to the statistics module
|
return statistics.mean(self.values)
|
||||||
return sum(self.values) / len(self.values)
|
|
||||||
|
|
||||||
|
|
||||||
class CloudWatchBackend(BaseBackend):
|
class CloudWatchBackend(BaseBackend):
|
||||||
def __init__(self, region_name, account_id):
|
def __init__(self, region_name: str, account_id: str):
|
||||||
super().__init__(region_name, account_id)
|
super().__init__(region_name, account_id)
|
||||||
self.alarms = {}
|
self.alarms: Dict[str, FakeAlarm] = {}
|
||||||
self.dashboards = {}
|
self.dashboards: Dict[str, Dashboard] = {}
|
||||||
self.metric_data = []
|
self.metric_data: List[MetricDatum] = []
|
||||||
self.paged_metric_data = {}
|
self.paged_metric_data: Dict[str, List[MetricDatum]] = {}
|
||||||
self.tagger = TaggingService()
|
self.tagger = TaggingService()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def default_vpc_endpoint_service(service_region, zones):
|
def default_vpc_endpoint_service(
|
||||||
|
service_region: str, zones: List[str]
|
||||||
|
) -> List[Dict[str, str]]:
|
||||||
"""Default VPC endpoint service."""
|
"""Default VPC endpoint service."""
|
||||||
return BaseBackend.default_vpc_endpoint_service_factory(
|
return BaseBackend.default_vpc_endpoint_service_factory(
|
||||||
service_region, zones, "monitoring"
|
service_region, zones, "monitoring"
|
||||||
@ -320,7 +349,7 @@ class CloudWatchBackend(BaseBackend):
|
|||||||
@property
|
@property
|
||||||
# Retrieve a list of all OOTB metrics that are provided by metrics providers
|
# Retrieve a list of all OOTB metrics that are provided by metrics providers
|
||||||
# Computed on the fly
|
# Computed on the fly
|
||||||
def aws_metric_data(self):
|
def aws_metric_data(self) -> List[MetricDatum]:
|
||||||
providers = CloudWatchMetricProvider.__subclasses__()
|
providers = CloudWatchMetricProvider.__subclasses__()
|
||||||
md = []
|
md = []
|
||||||
for provider in providers:
|
for provider in providers:
|
||||||
@ -329,30 +358,30 @@ class CloudWatchBackend(BaseBackend):
|
|||||||
|
|
||||||
def put_metric_alarm(
|
def put_metric_alarm(
|
||||||
self,
|
self,
|
||||||
name,
|
name: str,
|
||||||
namespace,
|
namespace: str,
|
||||||
metric_name,
|
metric_name: str,
|
||||||
metric_data_queries,
|
metric_data_queries: List[MetricDataQuery],
|
||||||
comparison_operator,
|
comparison_operator: str,
|
||||||
evaluation_periods,
|
evaluation_periods: int,
|
||||||
datapoints_to_alarm,
|
datapoints_to_alarm: int,
|
||||||
period,
|
period: int,
|
||||||
threshold,
|
threshold: float,
|
||||||
statistic,
|
statistic: str,
|
||||||
extended_statistic,
|
extended_statistic: str,
|
||||||
description,
|
description: str,
|
||||||
dimensions,
|
dimensions: List[Dict[str, str]],
|
||||||
alarm_actions,
|
alarm_actions: List[str],
|
||||||
ok_actions,
|
ok_actions: List[str],
|
||||||
insufficient_data_actions,
|
insufficient_data_actions: List[str],
|
||||||
unit,
|
unit: str,
|
||||||
actions_enabled,
|
actions_enabled: bool,
|
||||||
treat_missing_data,
|
treat_missing_data: str,
|
||||||
evaluate_low_sample_count_percentile,
|
evaluate_low_sample_count_percentile: str,
|
||||||
threshold_metric_id,
|
threshold_metric_id: str,
|
||||||
rule=None,
|
rule: str,
|
||||||
tags=None,
|
tags: List[Dict[str, str]],
|
||||||
):
|
) -> FakeAlarm:
|
||||||
if extended_statistic and not extended_statistic.startswith("p"):
|
if extended_statistic and not extended_statistic.startswith("p"):
|
||||||
raise InvalidParameterValue(
|
raise InvalidParameterValue(
|
||||||
f"The value {extended_statistic} for parameter ExtendedStatistic is not supported."
|
f"The value {extended_statistic} for parameter ExtendedStatistic is not supported."
|
||||||
@ -398,18 +427,18 @@ class CloudWatchBackend(BaseBackend):
|
|||||||
|
|
||||||
return alarm
|
return alarm
|
||||||
|
|
||||||
def get_all_alarms(self):
|
def get_all_alarms(self) -> Iterable[FakeAlarm]:
|
||||||
return self.alarms.values()
|
return self.alarms.values()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _list_element_starts_with(items, needle):
|
def _list_element_starts_with(items: List[str], needle: str) -> bool:
|
||||||
"""True of any of the list elements starts with needle"""
|
"""True of any of the list elements starts with needle"""
|
||||||
for item in items:
|
for item in items:
|
||||||
if item.startswith(needle):
|
if item.startswith(needle):
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def get_alarms_by_action_prefix(self, action_prefix):
|
def get_alarms_by_action_prefix(self, action_prefix: str) -> Iterable[FakeAlarm]:
|
||||||
return [
|
return [
|
||||||
alarm
|
alarm
|
||||||
for alarm in self.alarms.values()
|
for alarm in self.alarms.values()
|
||||||
@ -418,26 +447,28 @@ class CloudWatchBackend(BaseBackend):
|
|||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
def get_alarms_by_alarm_name_prefix(self, name_prefix):
|
def get_alarms_by_alarm_name_prefix(self, name_prefix: str) -> Iterable[FakeAlarm]:
|
||||||
return [
|
return [
|
||||||
alarm
|
alarm
|
||||||
for alarm in self.alarms.values()
|
for alarm in self.alarms.values()
|
||||||
if alarm.name.startswith(name_prefix)
|
if alarm.name.startswith(name_prefix)
|
||||||
]
|
]
|
||||||
|
|
||||||
def get_alarms_by_alarm_names(self, alarm_names):
|
def get_alarms_by_alarm_names(self, alarm_names: List[str]) -> Iterable[FakeAlarm]:
|
||||||
return [alarm for alarm in self.alarms.values() if alarm.name in alarm_names]
|
return [alarm for alarm in self.alarms.values() if alarm.name in alarm_names]
|
||||||
|
|
||||||
def get_alarms_by_state_value(self, target_state):
|
def get_alarms_by_state_value(self, target_state: str) -> Iterable[FakeAlarm]:
|
||||||
return filter(
|
return filter(
|
||||||
lambda alarm: alarm.state_value == target_state, self.alarms.values()
|
lambda alarm: alarm.state_value == target_state, self.alarms.values()
|
||||||
)
|
)
|
||||||
|
|
||||||
def delete_alarms(self, alarm_names):
|
def delete_alarms(self, alarm_names: List[str]) -> None:
|
||||||
for alarm_name in alarm_names:
|
for alarm_name in alarm_names:
|
||||||
self.alarms.pop(alarm_name, None)
|
self.alarms.pop(alarm_name, None)
|
||||||
|
|
||||||
def put_metric_data(self, namespace, metric_data):
|
def put_metric_data(
|
||||||
|
self, namespace: str, metric_data: List[Dict[str, Any]]
|
||||||
|
) -> None:
|
||||||
for i, metric in enumerate(metric_data):
|
for i, metric in enumerate(metric_data):
|
||||||
if metric.get("Value") == "NaN":
|
if metric.get("Value") == "NaN":
|
||||||
raise InvalidParameterValue(
|
raise InvalidParameterValue(
|
||||||
@ -461,8 +492,12 @@ class CloudWatchBackend(BaseBackend):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def get_metric_data(
|
def get_metric_data(
|
||||||
self, queries, start_time, end_time, scan_by="TimestampAscending"
|
self,
|
||||||
):
|
queries: List[Dict[str, Any]],
|
||||||
|
start_time: datetime,
|
||||||
|
end_time: datetime,
|
||||||
|
scan_by: str = "TimestampAscending",
|
||||||
|
) -> List[Dict[str, Any]]:
|
||||||
|
|
||||||
period_data = [
|
period_data = [
|
||||||
md for md in self.metric_data if start_time <= md.timestamp <= end_time
|
md for md in self.metric_data if start_time <= md.timestamp <= end_time
|
||||||
@ -475,8 +510,8 @@ class CloudWatchBackend(BaseBackend):
|
|||||||
query_name = query["metric_stat._metric._metric_name"]
|
query_name = query["metric_stat._metric._metric_name"]
|
||||||
delta = timedelta(seconds=int(query["metric_stat._period"]))
|
delta = timedelta(seconds=int(query["metric_stat._period"]))
|
||||||
dimensions = self._extract_dimensions_from_get_metric_data_query(query)
|
dimensions = self._extract_dimensions_from_get_metric_data_query(query)
|
||||||
result_vals = []
|
result_vals: List[SupportsFloat] = []
|
||||||
timestamps = []
|
timestamps: List[str] = []
|
||||||
stat = query["metric_stat._stat"]
|
stat = query["metric_stat._stat"]
|
||||||
while period_start_time <= end_time:
|
while period_start_time <= end_time:
|
||||||
period_end_time = period_start_time + delta
|
period_end_time = period_start_time + delta
|
||||||
@ -513,7 +548,7 @@ class CloudWatchBackend(BaseBackend):
|
|||||||
elif stat == "Sum":
|
elif stat == "Sum":
|
||||||
result_vals.append(sum(metric_values))
|
result_vals.append(sum(metric_values))
|
||||||
timestamps.append(
|
timestamps.append(
|
||||||
iso_8601_datetime_without_milliseconds(period_start_time)
|
iso_8601_datetime_without_milliseconds(period_start_time) # type: ignore[arg-type]
|
||||||
)
|
)
|
||||||
period_start_time += delta
|
period_start_time += delta
|
||||||
if scan_by == "TimestampDescending" and len(timestamps) > 0:
|
if scan_by == "TimestampDescending" and len(timestamps) > 0:
|
||||||
@ -532,15 +567,15 @@ class CloudWatchBackend(BaseBackend):
|
|||||||
|
|
||||||
def get_metric_statistics(
|
def get_metric_statistics(
|
||||||
self,
|
self,
|
||||||
namespace,
|
namespace: str,
|
||||||
metric_name,
|
metric_name: str,
|
||||||
start_time,
|
start_time: datetime,
|
||||||
end_time,
|
end_time: datetime,
|
||||||
period,
|
period: int,
|
||||||
stats,
|
stats: List[str],
|
||||||
dimensions,
|
dimensions: List[Dict[str, str]],
|
||||||
unit=None,
|
unit: Optional[str] = None,
|
||||||
):
|
) -> List[Statistics]:
|
||||||
period_delta = timedelta(seconds=period)
|
period_delta = timedelta(seconds=period)
|
||||||
filtered_data = [
|
filtered_data = [
|
||||||
md
|
md
|
||||||
@ -563,7 +598,7 @@ class CloudWatchBackend(BaseBackend):
|
|||||||
return []
|
return []
|
||||||
|
|
||||||
idx = 0
|
idx = 0
|
||||||
data = list()
|
data: List[Statistics] = list()
|
||||||
for dt in daterange(
|
for dt in daterange(
|
||||||
filtered_data[0].timestamp,
|
filtered_data[0].timestamp,
|
||||||
filtered_data[-1].timestamp + period_delta,
|
filtered_data[-1].timestamp + period_delta,
|
||||||
@ -584,40 +619,38 @@ class CloudWatchBackend(BaseBackend):
|
|||||||
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def get_all_metrics(self):
|
def get_all_metrics(self) -> List[MetricDatum]:
|
||||||
return self.metric_data + self.aws_metric_data
|
return self.metric_data + self.aws_metric_data
|
||||||
|
|
||||||
def put_dashboard(self, name, body):
|
def put_dashboard(self, name: str, body: str) -> None:
|
||||||
self.dashboards[name] = Dashboard(self.account_id, name, body)
|
self.dashboards[name] = Dashboard(self.account_id, name, body)
|
||||||
|
|
||||||
def list_dashboards(self, prefix=""):
|
def list_dashboards(self, prefix: str = "") -> Iterable[Dashboard]:
|
||||||
for key, value in self.dashboards.items():
|
for key, value in self.dashboards.items():
|
||||||
if key.startswith(prefix):
|
if key.startswith(prefix):
|
||||||
yield value
|
yield value
|
||||||
|
|
||||||
def delete_dashboards(self, dashboards):
|
def delete_dashboards(self, dashboards: List[str]) -> Optional[str]:
|
||||||
to_delete = set(dashboards)
|
to_delete = set(dashboards)
|
||||||
all_dashboards = set(self.dashboards.keys())
|
all_dashboards = set(self.dashboards.keys())
|
||||||
|
|
||||||
left_over = to_delete - all_dashboards
|
left_over = to_delete - all_dashboards
|
||||||
if len(left_over) > 0:
|
if len(left_over) > 0:
|
||||||
# Some dashboards are not found
|
# Some dashboards are not found
|
||||||
return (
|
db_list = ", ".join(left_over)
|
||||||
False,
|
return f"The specified dashboard does not exist. [{db_list}]"
|
||||||
"The specified dashboard does not exist. [{0}]".format(
|
|
||||||
", ".join(left_over)
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
for dashboard in to_delete:
|
for dashboard in to_delete:
|
||||||
del self.dashboards[dashboard]
|
del self.dashboards[dashboard]
|
||||||
|
|
||||||
return True, None
|
return None
|
||||||
|
|
||||||
def get_dashboard(self, dashboard):
|
def get_dashboard(self, dashboard: str) -> Optional[Dashboard]:
|
||||||
return self.dashboards.get(dashboard)
|
return self.dashboards.get(dashboard)
|
||||||
|
|
||||||
def set_alarm_state(self, alarm_name, reason, reason_data, state_value):
|
def set_alarm_state(
|
||||||
|
self, alarm_name: str, reason: str, reason_data: str, state_value: str
|
||||||
|
) -> None:
|
||||||
try:
|
try:
|
||||||
if reason_data is not None:
|
if reason_data is not None:
|
||||||
json.loads(reason_data)
|
json.loads(reason_data)
|
||||||
@ -636,7 +669,13 @@ class CloudWatchBackend(BaseBackend):
|
|||||||
|
|
||||||
self.alarms[alarm_name].update_state(reason, reason_data, state_value)
|
self.alarms[alarm_name].update_state(reason, reason_data, state_value)
|
||||||
|
|
||||||
def list_metrics(self, next_token, namespace, metric_name, dimensions):
|
def list_metrics(
|
||||||
|
self,
|
||||||
|
next_token: Optional[str],
|
||||||
|
namespace: str,
|
||||||
|
metric_name: str,
|
||||||
|
dimensions: List[Dict[str, str]],
|
||||||
|
) -> Tuple[Optional[str], List[MetricDatum]]:
|
||||||
if next_token:
|
if next_token:
|
||||||
if next_token not in self.paged_metric_data:
|
if next_token not in self.paged_metric_data:
|
||||||
raise InvalidParameterValue("Request parameter NextToken is invalid")
|
raise InvalidParameterValue("Request parameter NextToken is invalid")
|
||||||
@ -648,9 +687,11 @@ class CloudWatchBackend(BaseBackend):
|
|||||||
metrics = self.get_filtered_metrics(metric_name, namespace, dimensions)
|
metrics = self.get_filtered_metrics(metric_name, namespace, dimensions)
|
||||||
return self._get_paginated(metrics)
|
return self._get_paginated(metrics)
|
||||||
|
|
||||||
def get_filtered_metrics(self, metric_name, namespace, dimensions):
|
def get_filtered_metrics(
|
||||||
|
self, metric_name: str, namespace: str, dimensions: List[Dict[str, str]]
|
||||||
|
) -> List[MetricDatum]:
|
||||||
metrics = self.get_all_metrics()
|
metrics = self.get_all_metrics()
|
||||||
new_metrics = []
|
new_metrics: List[MetricDatum] = []
|
||||||
for md in metrics:
|
for md in metrics:
|
||||||
if md.filter(
|
if md.filter(
|
||||||
namespace=namespace,
|
namespace=namespace,
|
||||||
@ -661,10 +702,10 @@ class CloudWatchBackend(BaseBackend):
|
|||||||
new_metrics.append(md)
|
new_metrics.append(md)
|
||||||
return new_metrics
|
return new_metrics
|
||||||
|
|
||||||
def list_tags_for_resource(self, arn):
|
def list_tags_for_resource(self, arn: str) -> Dict[str, str]:
|
||||||
return self.tagger.get_tag_dict_for_resource(arn)
|
return self.tagger.get_tag_dict_for_resource(arn)
|
||||||
|
|
||||||
def tag_resource(self, arn, tags):
|
def tag_resource(self, arn: str, tags: List[Dict[str, str]]) -> None:
|
||||||
# From boto3:
|
# From boto3:
|
||||||
# Currently, the only CloudWatch resources that can be tagged are alarms and Contributor Insights rules.
|
# Currently, the only CloudWatch resources that can be tagged are alarms and Contributor Insights rules.
|
||||||
all_arns = [alarm.alarm_arn for alarm in self.get_all_alarms()]
|
all_arns = [alarm.alarm_arn for alarm in self.get_all_alarms()]
|
||||||
@ -673,13 +714,15 @@ class CloudWatchBackend(BaseBackend):
|
|||||||
|
|
||||||
self.tagger.tag_resource(arn, tags)
|
self.tagger.tag_resource(arn, tags)
|
||||||
|
|
||||||
def untag_resource(self, arn, tag_keys):
|
def untag_resource(self, arn: str, tag_keys: List[str]) -> None:
|
||||||
if arn not in self.tagger.tags.keys():
|
if arn not in self.tagger.tags.keys():
|
||||||
raise ResourceNotFoundException
|
raise ResourceNotFoundException
|
||||||
|
|
||||||
self.tagger.untag_resource_using_names(arn, tag_keys)
|
self.tagger.untag_resource_using_names(arn, tag_keys)
|
||||||
|
|
||||||
def _get_paginated(self, metrics):
|
def _get_paginated(
|
||||||
|
self, metrics: List[MetricDatum]
|
||||||
|
) -> Tuple[Optional[str], List[MetricDatum]]:
|
||||||
if len(metrics) > 500:
|
if len(metrics) > 500:
|
||||||
next_token = str(mock_random.uuid4())
|
next_token = str(mock_random.uuid4())
|
||||||
self.paged_metric_data[next_token] = metrics[500:]
|
self.paged_metric_data[next_token] = metrics[500:]
|
||||||
@ -687,7 +730,9 @@ class CloudWatchBackend(BaseBackend):
|
|||||||
else:
|
else:
|
||||||
return None, metrics
|
return None, metrics
|
||||||
|
|
||||||
def _extract_dimensions_from_get_metric_data_query(self, query):
|
def _extract_dimensions_from_get_metric_data_query(
|
||||||
|
self, query: Dict[str, str]
|
||||||
|
) -> List[Dimension]:
|
||||||
dimensions = []
|
dimensions = []
|
||||||
prefix = "metric_stat._metric._dimensions.member."
|
prefix = "metric_stat._metric._dimensions.member."
|
||||||
suffix_name = "._name"
|
suffix_name = "._name"
|
||||||
|
@ -1,27 +1,38 @@
|
|||||||
import json
|
import json
|
||||||
|
|
||||||
from dateutil.parser import parse as dtparse
|
from dateutil.parser import parse as dtparse
|
||||||
|
from typing import Dict, List, Iterable, Tuple, Union
|
||||||
from moto.core.responses import BaseResponse
|
from moto.core.responses import BaseResponse
|
||||||
from moto.utilities.aws_headers import amzn_request_id
|
from moto.utilities.aws_headers import amzn_request_id
|
||||||
from .models import cloudwatch_backends, MetricDataQuery, MetricStat, Metric, Dimension
|
from .models import (
|
||||||
|
cloudwatch_backends,
|
||||||
|
CloudWatchBackend,
|
||||||
|
MetricDataQuery,
|
||||||
|
MetricStat,
|
||||||
|
Metric,
|
||||||
|
Dimension,
|
||||||
|
FakeAlarm,
|
||||||
|
)
|
||||||
from .exceptions import InvalidParameterCombination
|
from .exceptions import InvalidParameterCombination
|
||||||
|
|
||||||
|
|
||||||
|
ERROR_RESPONSE = Tuple[str, Dict[str, int]]
|
||||||
|
|
||||||
|
|
||||||
class CloudWatchResponse(BaseResponse):
|
class CloudWatchResponse(BaseResponse):
|
||||||
def __init__(self):
|
def __init__(self) -> None:
|
||||||
super().__init__(service_name="cloudwatch")
|
super().__init__(service_name="cloudwatch")
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def cloudwatch_backend(self):
|
def cloudwatch_backend(self) -> CloudWatchBackend:
|
||||||
return cloudwatch_backends[self.current_account][self.region]
|
return cloudwatch_backends[self.current_account][self.region]
|
||||||
|
|
||||||
def _error(self, code, message, status=400):
|
def _error(self, code: str, message: str, status: int = 400) -> ERROR_RESPONSE:
|
||||||
template = self.response_template(ERROR_RESPONSE_TEMPLATE)
|
template = self.response_template(ERROR_RESPONSE_TEMPLATE)
|
||||||
return template.render(code=code, message=message), dict(status=status)
|
return template.render(code=code, message=message), dict(status=status)
|
||||||
|
|
||||||
@amzn_request_id
|
@amzn_request_id
|
||||||
def put_metric_alarm(self):
|
def put_metric_alarm(self) -> str:
|
||||||
name = self._get_param("AlarmName")
|
name = self._get_param("AlarmName")
|
||||||
namespace = self._get_param("Namespace")
|
namespace = self._get_param("Namespace")
|
||||||
metric_name = self._get_param("MetricName")
|
metric_name = self._get_param("MetricName")
|
||||||
@ -30,14 +41,14 @@ class CloudWatchResponse(BaseResponse):
|
|||||||
if metrics:
|
if metrics:
|
||||||
metric_data_queries = []
|
metric_data_queries = []
|
||||||
for metric in metrics:
|
for metric in metrics:
|
||||||
dimensions = []
|
metric_dimensions = []
|
||||||
dims = (
|
dims = (
|
||||||
metric.get("MetricStat", {})
|
metric.get("MetricStat", {})
|
||||||
.get("Metric", {})
|
.get("Metric", {})
|
||||||
.get("Dimensions.member", [])
|
.get("Dimensions.member", [])
|
||||||
)
|
)
|
||||||
for dim in dims:
|
for dim in dims:
|
||||||
dimensions.append(
|
metric_dimensions.append(
|
||||||
Dimension(name=dim.get("Name"), value=dim.get("Value"))
|
Dimension(name=dim.get("Name"), value=dim.get("Value"))
|
||||||
)
|
)
|
||||||
metric_stat = None
|
metric_stat = None
|
||||||
@ -51,7 +62,7 @@ class CloudWatchResponse(BaseResponse):
|
|||||||
metric=Metric(
|
metric=Metric(
|
||||||
metric_name=stat_metric_name,
|
metric_name=stat_metric_name,
|
||||||
namespace=stat_metric_ns,
|
namespace=stat_metric_ns,
|
||||||
dimensions=dimensions,
|
dimensions=metric_dimensions,
|
||||||
),
|
),
|
||||||
period=stat_details.get("Period"),
|
period=stat_details.get("Period"),
|
||||||
stat=stat_details.get("Stat"),
|
stat=stat_details.get("Stat"),
|
||||||
@ -121,7 +132,7 @@ class CloudWatchResponse(BaseResponse):
|
|||||||
return template.render(alarm=alarm)
|
return template.render(alarm=alarm)
|
||||||
|
|
||||||
@amzn_request_id
|
@amzn_request_id
|
||||||
def describe_alarms(self):
|
def describe_alarms(self) -> str:
|
||||||
action_prefix = self._get_param("ActionPrefix")
|
action_prefix = self._get_param("ActionPrefix")
|
||||||
alarm_name_prefix = self._get_param("AlarmNamePrefix")
|
alarm_name_prefix = self._get_param("AlarmNamePrefix")
|
||||||
alarm_names = self._get_multi_param("AlarmNames.member")
|
alarm_names = self._get_multi_param("AlarmNames.member")
|
||||||
@ -149,14 +160,14 @@ class CloudWatchResponse(BaseResponse):
|
|||||||
)
|
)
|
||||||
|
|
||||||
@amzn_request_id
|
@amzn_request_id
|
||||||
def delete_alarms(self):
|
def delete_alarms(self) -> str:
|
||||||
alarm_names = self._get_multi_param("AlarmNames.member")
|
alarm_names = self._get_multi_param("AlarmNames.member")
|
||||||
self.cloudwatch_backend.delete_alarms(alarm_names)
|
self.cloudwatch_backend.delete_alarms(alarm_names)
|
||||||
template = self.response_template(DELETE_METRIC_ALARMS_TEMPLATE)
|
template = self.response_template(DELETE_METRIC_ALARMS_TEMPLATE)
|
||||||
return template.render()
|
return template.render()
|
||||||
|
|
||||||
@amzn_request_id
|
@amzn_request_id
|
||||||
def put_metric_data(self):
|
def put_metric_data(self) -> str:
|
||||||
namespace = self._get_param("Namespace")
|
namespace = self._get_param("Namespace")
|
||||||
metric_data = self._get_multi_param("MetricData.member")
|
metric_data = self._get_multi_param("MetricData.member")
|
||||||
self.cloudwatch_backend.put_metric_data(namespace, metric_data)
|
self.cloudwatch_backend.put_metric_data(namespace, metric_data)
|
||||||
@ -164,7 +175,7 @@ class CloudWatchResponse(BaseResponse):
|
|||||||
return template.render()
|
return template.render()
|
||||||
|
|
||||||
@amzn_request_id
|
@amzn_request_id
|
||||||
def get_metric_data(self):
|
def get_metric_data(self) -> str:
|
||||||
start = dtparse(self._get_param("StartTime"))
|
start = dtparse(self._get_param("StartTime"))
|
||||||
end = dtparse(self._get_param("EndTime"))
|
end = dtparse(self._get_param("EndTime"))
|
||||||
scan_by = self._get_param("ScanBy")
|
scan_by = self._get_param("ScanBy")
|
||||||
@ -178,7 +189,7 @@ class CloudWatchResponse(BaseResponse):
|
|||||||
return template.render(results=results)
|
return template.render(results=results)
|
||||||
|
|
||||||
@amzn_request_id
|
@amzn_request_id
|
||||||
def get_metric_statistics(self):
|
def get_metric_statistics(self) -> str:
|
||||||
namespace = self._get_param("Namespace")
|
namespace = self._get_param("Namespace")
|
||||||
metric_name = self._get_param("MetricName")
|
metric_name = self._get_param("MetricName")
|
||||||
start_time = dtparse(self._get_param("StartTime"))
|
start_time = dtparse(self._get_param("StartTime"))
|
||||||
@ -210,7 +221,7 @@ class CloudWatchResponse(BaseResponse):
|
|||||||
return template.render(label=metric_name, datapoints=datapoints)
|
return template.render(label=metric_name, datapoints=datapoints)
|
||||||
|
|
||||||
@amzn_request_id
|
@amzn_request_id
|
||||||
def list_metrics(self):
|
def list_metrics(self) -> str:
|
||||||
namespace = self._get_param("Namespace")
|
namespace = self._get_param("Namespace")
|
||||||
metric_name = self._get_param("MetricName")
|
metric_name = self._get_param("MetricName")
|
||||||
dimensions = self._get_params().get("Dimensions", [])
|
dimensions = self._get_params().get("Dimensions", [])
|
||||||
@ -222,24 +233,26 @@ class CloudWatchResponse(BaseResponse):
|
|||||||
return template.render(metrics=metrics, next_token=next_token)
|
return template.render(metrics=metrics, next_token=next_token)
|
||||||
|
|
||||||
@amzn_request_id
|
@amzn_request_id
|
||||||
def delete_dashboards(self):
|
def delete_dashboards(self) -> Union[str, ERROR_RESPONSE]:
|
||||||
dashboards = self._get_multi_param("DashboardNames.member")
|
dashboards = self._get_multi_param("DashboardNames.member")
|
||||||
if dashboards is None:
|
if dashboards is None:
|
||||||
return self._error("InvalidParameterValue", "Need at least 1 dashboard")
|
return self._error("InvalidParameterValue", "Need at least 1 dashboard")
|
||||||
|
|
||||||
status, error = self.cloudwatch_backend.delete_dashboards(dashboards)
|
error = self.cloudwatch_backend.delete_dashboards(dashboards)
|
||||||
if not status:
|
if error is not None:
|
||||||
return self._error("ResourceNotFound", error)
|
return self._error("ResourceNotFound", error)
|
||||||
|
|
||||||
template = self.response_template(DELETE_DASHBOARD_TEMPLATE)
|
template = self.response_template(DELETE_DASHBOARD_TEMPLATE)
|
||||||
return template.render()
|
return template.render()
|
||||||
|
|
||||||
@amzn_request_id
|
@amzn_request_id
|
||||||
def describe_alarm_history(self):
|
def describe_alarm_history(self) -> None:
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def filter_alarms(alarms, metric_name, namespace):
|
def filter_alarms(
|
||||||
|
alarms: Iterable[FakeAlarm], metric_name: str, namespace: str
|
||||||
|
) -> List[FakeAlarm]:
|
||||||
metric_filtered_alarms = []
|
metric_filtered_alarms = []
|
||||||
|
|
||||||
for alarm in alarms:
|
for alarm in alarms:
|
||||||
@ -248,7 +261,7 @@ class CloudWatchResponse(BaseResponse):
|
|||||||
return metric_filtered_alarms
|
return metric_filtered_alarms
|
||||||
|
|
||||||
@amzn_request_id
|
@amzn_request_id
|
||||||
def describe_alarms_for_metric(self):
|
def describe_alarms_for_metric(self) -> str:
|
||||||
alarms = self.cloudwatch_backend.get_all_alarms()
|
alarms = self.cloudwatch_backend.get_all_alarms()
|
||||||
namespace = self._get_param("Namespace")
|
namespace = self._get_param("Namespace")
|
||||||
metric_name = self._get_param("MetricName")
|
metric_name = self._get_param("MetricName")
|
||||||
@ -257,15 +270,15 @@ class CloudWatchResponse(BaseResponse):
|
|||||||
return template.render(alarms=filtered_alarms)
|
return template.render(alarms=filtered_alarms)
|
||||||
|
|
||||||
@amzn_request_id
|
@amzn_request_id
|
||||||
def disable_alarm_actions(self):
|
def disable_alarm_actions(self) -> str:
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
@amzn_request_id
|
@amzn_request_id
|
||||||
def enable_alarm_actions(self):
|
def enable_alarm_actions(self) -> str:
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
@amzn_request_id
|
@amzn_request_id
|
||||||
def get_dashboard(self):
|
def get_dashboard(self) -> Union[str, ERROR_RESPONSE]:
|
||||||
dashboard_name = self._get_param("DashboardName")
|
dashboard_name = self._get_param("DashboardName")
|
||||||
|
|
||||||
dashboard = self.cloudwatch_backend.get_dashboard(dashboard_name)
|
dashboard = self.cloudwatch_backend.get_dashboard(dashboard_name)
|
||||||
@ -276,7 +289,7 @@ class CloudWatchResponse(BaseResponse):
|
|||||||
return template.render(dashboard=dashboard)
|
return template.render(dashboard=dashboard)
|
||||||
|
|
||||||
@amzn_request_id
|
@amzn_request_id
|
||||||
def list_dashboards(self):
|
def list_dashboards(self) -> str:
|
||||||
prefix = self._get_param("DashboardNamePrefix", "")
|
prefix = self._get_param("DashboardNamePrefix", "")
|
||||||
|
|
||||||
dashboards = self.cloudwatch_backend.list_dashboards(prefix)
|
dashboards = self.cloudwatch_backend.list_dashboards(prefix)
|
||||||
@ -285,7 +298,7 @@ class CloudWatchResponse(BaseResponse):
|
|||||||
return template.render(dashboards=dashboards)
|
return template.render(dashboards=dashboards)
|
||||||
|
|
||||||
@amzn_request_id
|
@amzn_request_id
|
||||||
def put_dashboard(self):
|
def put_dashboard(self) -> Union[str, ERROR_RESPONSE]:
|
||||||
name = self._get_param("DashboardName")
|
name = self._get_param("DashboardName")
|
||||||
body = self._get_param("DashboardBody")
|
body = self._get_param("DashboardBody")
|
||||||
|
|
||||||
@ -300,7 +313,7 @@ class CloudWatchResponse(BaseResponse):
|
|||||||
return template.render()
|
return template.render()
|
||||||
|
|
||||||
@amzn_request_id
|
@amzn_request_id
|
||||||
def set_alarm_state(self):
|
def set_alarm_state(self) -> str:
|
||||||
alarm_name = self._get_param("AlarmName")
|
alarm_name = self._get_param("AlarmName")
|
||||||
reason = self._get_param("StateReason")
|
reason = self._get_param("StateReason")
|
||||||
reason_data = self._get_param("StateReasonData")
|
reason_data = self._get_param("StateReasonData")
|
||||||
@ -314,7 +327,7 @@ class CloudWatchResponse(BaseResponse):
|
|||||||
return template.render()
|
return template.render()
|
||||||
|
|
||||||
@amzn_request_id
|
@amzn_request_id
|
||||||
def list_tags_for_resource(self):
|
def list_tags_for_resource(self) -> str:
|
||||||
resource_arn = self._get_param("ResourceARN")
|
resource_arn = self._get_param("ResourceARN")
|
||||||
|
|
||||||
tags = self.cloudwatch_backend.list_tags_for_resource(resource_arn)
|
tags = self.cloudwatch_backend.list_tags_for_resource(resource_arn)
|
||||||
@ -323,7 +336,7 @@ class CloudWatchResponse(BaseResponse):
|
|||||||
return template.render(tags=tags)
|
return template.render(tags=tags)
|
||||||
|
|
||||||
@amzn_request_id
|
@amzn_request_id
|
||||||
def tag_resource(self):
|
def tag_resource(self) -> str:
|
||||||
resource_arn = self._get_param("ResourceARN")
|
resource_arn = self._get_param("ResourceARN")
|
||||||
tags = self._get_multi_param("Tags.member")
|
tags = self._get_multi_param("Tags.member")
|
||||||
|
|
||||||
@ -333,7 +346,7 @@ class CloudWatchResponse(BaseResponse):
|
|||||||
return template.render()
|
return template.render()
|
||||||
|
|
||||||
@amzn_request_id
|
@amzn_request_id
|
||||||
def untag_resource(self):
|
def untag_resource(self) -> str:
|
||||||
resource_arn = self._get_param("ResourceARN")
|
resource_arn = self._get_param("ResourceARN")
|
||||||
tag_keys = self._get_multi_param("TagKeys.member")
|
tag_keys = self._get_multi_param("TagKeys.member")
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
def make_arn_for_dashboard(account_id, name):
|
def make_arn_for_dashboard(account_id: str, name: str) -> str:
|
||||||
return "arn:aws:cloudwatch::{0}dashboard/{1}".format(account_id, name)
|
return "arn:aws:cloudwatch::{0}dashboard/{1}".format(account_id, name)
|
||||||
|
|
||||||
|
|
||||||
def make_arn_for_alarm(region, account_id, alarm_name):
|
def make_arn_for_alarm(region: str, account_id: str, alarm_name: str) -> str:
|
||||||
return "arn:aws:cloudwatch:{0}:{1}:alarm:{2}".format(region, account_id, alarm_name)
|
return "arn:aws:cloudwatch:{0}:{1}:alarm:{2}".format(region, account_id, alarm_name)
|
||||||
|
@ -195,5 +195,5 @@ class ConfigQueryModel:
|
|||||||
class CloudWatchMetricProvider(object):
|
class CloudWatchMetricProvider(object):
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def get_cloudwatch_metrics(account_id):
|
def get_cloudwatch_metrics(account_id: str) -> Any:
|
||||||
pass
|
pass
|
||||||
|
@ -18,7 +18,7 @@ disable = W,C,R,E
|
|||||||
enable = anomalous-backslash-in-string, arguments-renamed, dangerous-default-value, deprecated-module, function-redefined, import-self, redefined-builtin, redefined-outer-name, reimported, pointless-statement, super-with-arguments, unused-argument, unused-import, unused-variable, useless-else-on-loop, wildcard-import
|
enable = anomalous-backslash-in-string, arguments-renamed, dangerous-default-value, deprecated-module, function-redefined, import-self, redefined-builtin, redefined-outer-name, reimported, pointless-statement, super-with-arguments, unused-argument, unused-import, unused-variable, useless-else-on-loop, wildcard-import
|
||||||
|
|
||||||
[mypy]
|
[mypy]
|
||||||
files= moto/a*,moto/b*,moto/ce,moto/cloudformation,moto/cloudfront,moto/cloudtrail,moto/codebuild
|
files= moto/a*,moto/b*,moto/ce,moto/cloudformation,moto/cloudfront,moto/cloudtrail,moto/codebuild,moto/cloudwatch
|
||||||
show_column_numbers=True
|
show_column_numbers=True
|
||||||
show_error_codes = True
|
show_error_codes = True
|
||||||
disable_error_code=abstract
|
disable_error_code=abstract
|
||||||
|
Loading…
Reference in New Issue
Block a user