Skip to content

Commit

Permalink
Added integration testcase
Browse files Browse the repository at this point in the history
  • Loading branch information
GomathiselviS committed Oct 17, 2022
1 parent 863f0d0 commit 7b182f7
Show file tree
Hide file tree
Showing 2 changed files with 142 additions and 26 deletions.
99 changes: 73 additions & 26 deletions plugins/modules/cloudwatch_metric_alarm.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,34 +51,40 @@
aliases: ['metric']
metrics:
description:
- An array of MetricDataQuery structures that enable
- An array of MetricDataQuery structures that enable
you to create an alarm based on the result of a metric math expression.
type: list
required: false
elements: dict
suboptions:
id:
description:
- A short name used to tie this object to the results in the response.
- A short name used to tie this object to the results in the response.
type: str
required: true
metric_stat:
description: The metric to be returned, along with statistics, period, and units.
description: The metric to be returned, along with statistics, period, and units.
type: dict
required: false
suboptions:
metric:
description: The metric to return, including the metric name, namespace, and dimensions.
type: dict
required: false
suboptions:
namespace:
description: The namespace of the metric.
type: str
required: false
metric_name:
description: The name of the metric.
description: The name of the metric.
type: str
required: True
dimensions:
description: a name/value pair that is part of the identity of a metric.
type: list
elements: dict
required: false
suboptions:
name:
description: The name of the dimension.
Expand All @@ -89,7 +95,7 @@
type: str
required: True
period:
description: The granularity, in seconds, of the returned data points.
description: The granularity, in seconds, of the returned data points.
type: int
required: True
stat:
Expand All @@ -99,23 +105,29 @@
unit:
description: Unit to use when storing the metric.
type: str
required: false
expression:
description:
description:
- This field can contain either a Metrics Insights query,
or a metric math expression to be performed on the returned data.
type: str
required: false
label:
description: A human-readable label for this metric or expression.
description: A human-readable label for this metric or expression.
type: str
required: false
return_data:
description: This option indicates whether to return the timestamps and raw data values of this metric.
type: bool
required: false
period:
description: The granularity, in seconds, of the returned data points.
description: The granularity, in seconds, of the returned data points.
type: int
required: false
account_id:
description: The ID of the account where the metrics are located, if this is a cross-account alarm.
type: str
required: false
namespace:
description:
- Name of the appropriate namespace (C(AWS/EC2), C(System/Linux), etc.), which determines the category it will appear under in CloudWatch.
Expand All @@ -130,7 +142,8 @@
type: str
extended_statistic:
description: The percentile statistic for the metric specified in the metric name.
type: string
type: str
required: false
comparison:
description:
- Determines how the threshold value is compared
Expand Down Expand Up @@ -273,7 +286,7 @@
unit: "Percent"
return_data: False
alarm_actions: ["action1","action2"]
- name: Create an alarm to recover a failed instance
amazon.aws.cloudwatch_metric_alarm:
state: present
Expand All @@ -296,18 +309,18 @@
from botocore.exceptions import ClientError
except ImportError:
pass # protected by AnsibleAWSModule

from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule

from ansible_collections.amazon.aws.plugins.module_utils.ec2 import snake_dict_to_camel_dict

def create_metric_alarm(connection, module, params):
alarms = connection.describe_alarms(AlarmNames=[params['AlarmName']])

if not isinstance(params['Dimensions'], list):
fixed_dimensions = []
for key, value in params['Dimensions'].items():
fixed_dimensions.append({'Name': key, 'Value': value})
params['Dimensions'] = fixed_dimensions
if params.get('Dimensions'):
if not isinstance(params['Dimensions'], list):
fixed_dimensions = []
for key, value in params['Dimensions'].items():
fixed_dimensions.append({'Name': key, 'Value': value})
params['Dimensions'] = fixed_dimensions

if not alarms['MetricAlarms']:
try:
Expand All @@ -327,7 +340,7 @@ def create_metric_alarm(connection, module, params):

for key in ['ActionsEnabled', 'StateValue', 'StateReason',
'StateReasonData', 'StateUpdatedTimestamp',
'AlarmArn', 'AlarmConfigurationUpdatedTimestamp']:
'AlarmArn', 'AlarmConfigurationUpdatedTimestamp', 'Metrics']:
alarm.pop(key, None)
if alarm != params:
changed = True
Expand Down Expand Up @@ -361,6 +374,8 @@ def create_metric_alarm(connection, module, params):
insufficient_data_actions=result.get('InsufficientDataActions'),
last_updated=result.get('AlarmConfigurationUpdatedTimestamp'),
metric=result.get('MetricName'),
metric_name=result.get('MetricName'),
metrics=result.get('Metrics'),
namespace=result.get('Namespace'),
ok_actions=result.get('OKActions'),
period=result.get('Period'),
Expand All @@ -384,12 +399,25 @@ def delete_metric_alarm(connection, module, params):
module.fail_json_aws(e)
else:
module.exit_json(changed=False)

def delete_none_values(params):
"""Delete None values recursively from params"""
if isinstance(params, dict):
for key, value in list(params.items()):
if isinstance(value, (list, dict, tuple, set)):
params[key] = delete_none_values(value)
elif value is None or key is None:
del params[key]
elif isinstance(params, list):
params = [(delete_none_values(item) for item in params if item is not None)]

return params


def main():
argument_spec = dict(
name=dict(required=True, type='str'),
metric=dict(type='str'),
metric_name=dict(type='str', aliases=['metric']),
namespace=dict(type='str'),
statistic=dict(type='str', choices=['SampleCount', 'Average', 'Sum', 'Minimum', 'Maximum']),
comparison=dict(type='str', choices=['LessThanOrEqualToThreshold', 'LessThanThreshold', 'GreaterThanThreshold',
Expand All @@ -402,28 +430,34 @@ def main():
'Terabytes/Second', 'Bits/Second', 'Kilobits/Second', 'Megabits/Second', 'Gigabits/Second',
'Terabits/Second', 'Count/Second', 'None']),
evaluation_periods=dict(type='int'),
extended_statistic=dict(type='str'),
description=dict(type='str'),
dimensions=dict(type='dict', default={}),
dimensions=dict(type='dict'),
alarm_actions=dict(type='list', default=[], elements='str'),
insufficient_data_actions=dict(type='list', default=[], elements='str'),
ok_actions=dict(type='list', default=[], elements='str'),
treat_missing_data=dict(type='str', choices=['breaching', 'notBreaching', 'ignore', 'missing'], default='missing'),
state=dict(default='present', choices=['present', 'absent']),
metrics=dict(type='list', elements='dict'),
metrics=dict(type='list', elements='dict', default=[]),
)

mutually_exclusive = [
['metric_name', 'metrics', 'dimensions', 'period', 'namespace', 'statistic', 'extended_statistic'],
['metric_name', 'metrics'],
['dimensions', 'metrics'],
['period', 'metrics'],
['namespace', 'metrics'],
['statistic', 'metrics'],
['extended_statistic', 'metrics'],
['unit', 'metrics'],
['statistic', 'extended_statistic'],
]

#mutually_exclusive = []
module = AnsibleAWSModule(
argument_spec=argument_spec,
mutually_exclusive=mutually_exclusive,
supports_check_mode=True,
)


state = module.params.get('state')

params = dict()
Expand All @@ -443,7 +477,20 @@ def main():
params['InsufficientDataActions'] = module.params.get('insufficient_data_actions', [])
params['OKActions'] = module.params.get('ok_actions', [])
params['TreatMissingData'] = module.params.get('treat_missing_data')
params['Metrics'] = module.params.get('metrics')
if module.params.get('metrics'):
params['Metrics'] = []
for element in module.params.get('metrics'):
params['Metrics'].append(snake_dict_to_camel_dict(element, capitalize_first=True))
if module.params.get('extended_statistic'):
params['ExtendedStatistic'] = module.params.get('extended_statistic')

# Remove None value from params
#delete_none_values(params)
for key, value in list(params.items()):
if value is None:
del params[key]



connection = module.client('cloudwatch')

Expand Down
69 changes: 69 additions & 0 deletions tests/integration/targets/cloudwatch_metric_alarm/tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,75 @@
- 'ec2_instance_metric_alarm_no_unit.description == alarm_info_no_unit.metric_alarms[0].alarm_description'
- 'ec2_instance_metric_alarm_no_unit.treat_missing_data == alarm_info_no_unit.metric_alarms[0].treat_missing_data'

- name: try to remove the alarm
ec2_metric_alarm:
state: absent
name: '{{ alarm_full_name }}'
register: ec2_instance_metric_alarm_deletion

- name: Verify that the alarm reports deleted/changed
assert:
that:
- ec2_instance_metric_alarm_deletion.changed

- name: get info on alarms
amazon.aws.cloudwatch_metric_alarm_info:
alarm_names:
- "{{ alarm_full_name }}"
register: alarm_info

- name: Verify that the alarm was deleted using cli
assert:
that:
- 'alarm_info.metric_alarms | length == 0'

- name: create ec2 metric alarm with metrics
ec2_metric_alarm:
state: present
name: '{{ alarm_full_name }}'
treat_missing_data: missing
comparison: LessThanOrEqualToThreshold
threshold: 5.0
evaluation_periods: 3
description: This will alarm when an instance's cpu usage average is lower than
5% for 15 minutes
metrics:
- id: cpu
metric_stat:
metric:
dimensions:
- name: "InstanceId"
value: "{{ ec2_instance_results.instances[0].instance_id }}"
metric_name: "CPUUtilization"
namespace: "AWS/EC2"
period: 300
stat: "Average"
unit: "Percent"
return_data: true
register: ec2_instance_metric_alarm_metrics

- name: get info on alarms
amazon.aws.cloudwatch_metric_alarm_info:
alarm_names:
- "{{ alarm_full_name }}"
register: alarm_info_metrics

- name: verify that an alarm was created
assert:
that:
- ec2_instance_metric_alarm_metrics.changed
- ec2_instance_metric_alarm_metrics.alarm_arn
- 'ec2_instance_metric_alarm_metrics.metrics[0].metric_stat.stat == alarm_info_metrics.metric_alarms[0].metrics[0].metric_stat.stat'
- 'ec2_instance_metric_alarm_metrics.metrics[0].metric_stat.metric.namespace == alarm_info_metrics.metric_alarms[0].nmetrics[0].metric_stat.metric.namespace'
- 'ec2_instance_metric_alarm_metrics.metrics[0].metric_stat.metric.metric_name == alarm_info_metrics.metric_alarms[0].nmetrics[0].metric_stat.metric.metric_name'
- 'ec2_instance_metric_alarm_metrics.metrics[0].metric_stat.metric.dimensions[0].name == alarm_info_metrics.metric_alarms[0].nmetrics[0].metric_stat.metric.dimensions[0].name'
- 'ec2_instance_metric_alarm_metrics.metrics[0].metric_stat.metric.dimensions[0].value == alarm_info_metrics.metric_alarms[0].nmetrics[0].metric_stat.metric.dimensions[0].value'
- 'ec2_instance_metric_alarm_metrics.metrics[0].metric_stat.id == alarm_info_metrics.metric_alarms[0].metrics[0].metric_stat.id'
- 'ec2_instance_metric_alarm_metrics.metrics[0].metric_stat.period == alarm_info_metrics.metric_alarms[0].metrics[0].metric_stat.period'
- 'ec2_instance_metric_alarm_metrics.metrics[0].metric_stat.unit == alarm_info_metrics.metric_alarms[0].metrics[0].metric_stat.unit'
- 'ec2_instance_metric_alarm_metrics.metrics[0].metric_stat.return_data == alarm_info_metrics.metric_alarms[0].metrics[0].metric_stat.return_data'


- name: try to remove the alarm
ec2_metric_alarm:
state: absent
Expand Down

0 comments on commit 7b182f7

Please sign in to comment.