Assign AWS Cloudwatch Metric Filter via Ansible (#59925)
* #42292 first draft. * fix some documentation * use snake dict keynames * return metric filter variable * rework documentation * try to fix documentation. fix condition when defaultValue is 0. update version string * fix intenion, syntax and undefined * try solve state documentation * define type for state in doc * rework integration test and fix minor typos * add defaults for integration test * update documentation, integration tests, and return value * fix code formatting and documentation * irgnore errors in ignore block * Update lib/ansible/modules/cloud/amazon/cloudwatchlogs_log_group_metric_filter.py Co-Authored-By: Jill R <4121322+jillr@users.noreply.github.com> * add options to metric_transformation * fix pep-8 Co-authored-by: Jill R <4121322+jillr@users.noreply.github.com>
This commit is contained in:
parent
b0b00b555f
commit
193879d462
5 changed files with 386 additions and 0 deletions
|
@ -143,6 +143,8 @@ groupings:
|
||||||
- aws
|
- aws
|
||||||
cloudwatchlogs_log_group_info:
|
cloudwatchlogs_log_group_info:
|
||||||
- aws
|
- aws
|
||||||
|
cloudwatchlogs_log_group_metric_filter:
|
||||||
|
- aws
|
||||||
cpm_plugconfig:
|
cpm_plugconfig:
|
||||||
- cpm
|
- cpm
|
||||||
cpm_plugcontrol:
|
cpm_plugcontrol:
|
||||||
|
|
|
@ -0,0 +1,221 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
# Copyright: Ansible Project
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
from __future__ import absolute_import, division, print_function
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
|
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||||
|
'status': ['preview'],
|
||||||
|
'supported_by': 'community'}
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: cloudwatchlogs_log_group_metric_filter
|
||||||
|
version_added: "2.10"
|
||||||
|
author:
|
||||||
|
- "Markus Bergholz (@markuman)"
|
||||||
|
short_description: Manage CloudWatch log group metric filter
|
||||||
|
description:
|
||||||
|
- Create, modify and delete CloudWatch log group metric filter.
|
||||||
|
- CloudWatch log group metric filter can be use with M(ec2_metric_alarm).
|
||||||
|
requirements:
|
||||||
|
- boto3
|
||||||
|
- botocore
|
||||||
|
options:
|
||||||
|
state:
|
||||||
|
description:
|
||||||
|
- Whether the rule is present or absent.
|
||||||
|
choices: ["present", "absent"]
|
||||||
|
required: true
|
||||||
|
type: str
|
||||||
|
log_group_name:
|
||||||
|
description:
|
||||||
|
- The name of the log group where the metric filter is applied on.
|
||||||
|
required: true
|
||||||
|
type: str
|
||||||
|
filter_name:
|
||||||
|
description:
|
||||||
|
- A name for the metric filter you create.
|
||||||
|
required: true
|
||||||
|
type: str
|
||||||
|
filter_pattern:
|
||||||
|
description:
|
||||||
|
- A filter pattern for extracting metric data out of ingested log events. Required when I(state=present).
|
||||||
|
type: str
|
||||||
|
metric_transformation:
|
||||||
|
description:
|
||||||
|
- A collection of information that defines how metric data gets emitted. Required when I(state=present).
|
||||||
|
type: dict
|
||||||
|
suboptions:
|
||||||
|
metric_name:
|
||||||
|
description:
|
||||||
|
- The name of the cloudWatch metric.
|
||||||
|
type: str
|
||||||
|
metric_namespace:
|
||||||
|
description:
|
||||||
|
- The namespace of the cloudWatch metric.
|
||||||
|
type: str
|
||||||
|
metric_value:
|
||||||
|
description:
|
||||||
|
- The value to publish to the cloudWatch metric when a filter pattern matches a log event.
|
||||||
|
type: str
|
||||||
|
default_value:
|
||||||
|
description:
|
||||||
|
- The value to emit when a filter pattern does not match a log event.
|
||||||
|
type: float
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- aws
|
||||||
|
- ec2
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
- name: set metric filter on log group /fluentd/testcase
|
||||||
|
cloudwatchlogs_log_group_metric_filter:
|
||||||
|
log_group_name: /fluentd/testcase
|
||||||
|
filter_name: BoxFreeStorage
|
||||||
|
filter_pattern: '{($.value = *) && ($.hostname = "box")}'
|
||||||
|
state: present
|
||||||
|
metric_transformation:
|
||||||
|
metric_name: box_free_space
|
||||||
|
metric_namespace: fluentd_metrics
|
||||||
|
metric_value: "$.value"
|
||||||
|
|
||||||
|
- name: delete metric filter on log group /fluentd/testcase
|
||||||
|
cloudwatchlogs_log_group_metric_filter:
|
||||||
|
log_group_name: /fluentd/testcase
|
||||||
|
filter_name: BoxFreeStorage
|
||||||
|
state: absent
|
||||||
|
'''
|
||||||
|
|
||||||
|
RETURN = """
|
||||||
|
metric_filters:
|
||||||
|
description: Return the origin response value
|
||||||
|
returned: success
|
||||||
|
type: list
|
||||||
|
contains:
|
||||||
|
creation_time:
|
||||||
|
filter_name:
|
||||||
|
filter_pattern:
|
||||||
|
log_group_name:
|
||||||
|
metric_filter_count:
|
||||||
|
"""
|
||||||
|
from ansible.module_utils.aws.core import AnsibleAWSModule, is_boto3_error_code, get_boto3_client_method_parameters
|
||||||
|
from ansible.module_utils.ec2 import camel_dict_to_snake_dict
|
||||||
|
|
||||||
|
try:
|
||||||
|
from botocore.exceptions import ClientError, BotoCoreError, WaiterError
|
||||||
|
except ImportError:
|
||||||
|
pass # caught by AnsibleAWSModule
|
||||||
|
|
||||||
|
|
||||||
|
def metricTransformationHandler(metricTransformations, originMetricTransformations=None):
|
||||||
|
|
||||||
|
if originMetricTransformations:
|
||||||
|
change = False
|
||||||
|
originMetricTransformations = camel_dict_to_snake_dict(
|
||||||
|
originMetricTransformations)
|
||||||
|
for item in ["default_value", "metric_name", "metric_namespace", "metric_value"]:
|
||||||
|
if metricTransformations.get(item) != originMetricTransformations.get(item):
|
||||||
|
change = True
|
||||||
|
else:
|
||||||
|
change = True
|
||||||
|
|
||||||
|
defaultValue = metricTransformations.get("default_value")
|
||||||
|
if isinstance(defaultValue, int) or isinstance(defaultValue, float):
|
||||||
|
retval = [
|
||||||
|
{
|
||||||
|
'metricName': metricTransformations.get("metric_name"),
|
||||||
|
'metricNamespace': metricTransformations.get("metric_namespace"),
|
||||||
|
'metricValue': metricTransformations.get("metric_value"),
|
||||||
|
'defaultValue': defaultValue
|
||||||
|
}
|
||||||
|
]
|
||||||
|
else:
|
||||||
|
retval = [
|
||||||
|
{
|
||||||
|
'metricName': metricTransformations.get("metric_name"),
|
||||||
|
'metricNamespace': metricTransformations.get("metric_namespace"),
|
||||||
|
'metricValue': metricTransformations.get("metric_value"),
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
return retval, change
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
|
||||||
|
arg_spec = dict(
|
||||||
|
state=dict(type='str', required=True, choices=['present', 'absent']),
|
||||||
|
log_group_name=dict(type='str', required=True),
|
||||||
|
filter_name=dict(type='str', required=True),
|
||||||
|
filter_pattern=dict(type='str'),
|
||||||
|
metric_transformation=dict(type='dict', options=dict(
|
||||||
|
metric_name=dict(type='str'),
|
||||||
|
metric_namespace=dict(type='str'),
|
||||||
|
metric_value=dict(type='str'),
|
||||||
|
default_value=dict(type='float')
|
||||||
|
)),
|
||||||
|
)
|
||||||
|
|
||||||
|
module = AnsibleAWSModule(
|
||||||
|
argument_spec=arg_spec,
|
||||||
|
supports_check_mode=True,
|
||||||
|
required_if=[('state', 'present', ['metric_transformation', 'filter_pattern'])]
|
||||||
|
)
|
||||||
|
|
||||||
|
log_group_name = module.params.get("log_group_name")
|
||||||
|
filter_name = module.params.get("filter_name")
|
||||||
|
filter_pattern = module.params.get("filter_pattern")
|
||||||
|
metric_transformation = module.params.get("metric_transformation")
|
||||||
|
state = module.params.get("state")
|
||||||
|
|
||||||
|
cwl = module.client('logs')
|
||||||
|
|
||||||
|
# check if metric filter exists
|
||||||
|
response = cwl.describe_metric_filters(
|
||||||
|
logGroupName=log_group_name,
|
||||||
|
filterNamePrefix=filter_name
|
||||||
|
)
|
||||||
|
|
||||||
|
if len(response.get("metricFilters")) == 1:
|
||||||
|
originMetricTransformations = response.get(
|
||||||
|
"metricFilters")[0].get("metricTransformations")[0]
|
||||||
|
originFilterPattern = response.get("metricFilters")[
|
||||||
|
0].get("filterPattern")
|
||||||
|
else:
|
||||||
|
originMetricTransformations = None
|
||||||
|
originFilterPattern = None
|
||||||
|
change = False
|
||||||
|
metricTransformation = None
|
||||||
|
|
||||||
|
if state == "absent" and originMetricTransformations:
|
||||||
|
if not module.check_mode:
|
||||||
|
response = cwl.delete_metric_filter(
|
||||||
|
logGroupName=log_group_name,
|
||||||
|
filterName=filter_name
|
||||||
|
)
|
||||||
|
change = True
|
||||||
|
metricTransformation = [camel_dict_to_snake_dict(item) for item in [originMetricTransformations]]
|
||||||
|
|
||||||
|
elif state == "present":
|
||||||
|
metricTransformation, change = metricTransformationHandler(
|
||||||
|
metricTransformations=metric_transformation, originMetricTransformations=originMetricTransformations)
|
||||||
|
|
||||||
|
change = change or filter_pattern != originFilterPattern
|
||||||
|
|
||||||
|
if change:
|
||||||
|
if not module.check_mode:
|
||||||
|
response = cwl.put_metric_filter(
|
||||||
|
logGroupName=log_group_name,
|
||||||
|
filterName=filter_name,
|
||||||
|
filterPattern=filter_pattern,
|
||||||
|
metricTransformations=metricTransformation
|
||||||
|
)
|
||||||
|
|
||||||
|
metricTransformation = [camel_dict_to_snake_dict(item) for item in metricTransformation]
|
||||||
|
|
||||||
|
module.exit_json(changed=change, metric_filters=metricTransformation)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
3
test/integration/targets/cloudwatchlogs/aliases
Normal file
3
test/integration/targets/cloudwatchlogs/aliases
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
cloud/aws
|
||||||
|
shippable/aws/group1
|
||||||
|
cloudwatchlogs_log_group_metric_filter
|
|
@ -0,0 +1,3 @@
|
||||||
|
---
|
||||||
|
log_group_name: '{{ resource_prefix }}/integrationtest'
|
||||||
|
filter_name: '{{ resource_prefix }}/AnsibleTest'
|
157
test/integration/targets/cloudwatchlogs/tasks/main.yml
Normal file
157
test/integration/targets/cloudwatchlogs/tasks/main.yml
Normal file
|
@ -0,0 +1,157 @@
|
||||||
|
---
|
||||||
|
|
||||||
|
- module_defaults:
|
||||||
|
group/aws:
|
||||||
|
aws_access_key: "{{ aws_access_key }}"
|
||||||
|
aws_secret_key: "{{ aws_secret_key }}"
|
||||||
|
security_token: "{{ security_token | default(omit) }}"
|
||||||
|
region: "{{ aws_region }}"
|
||||||
|
|
||||||
|
block:
|
||||||
|
- name: create cloudwatch log group for integration test
|
||||||
|
cloudwatchlogs_log_group:
|
||||||
|
state: present
|
||||||
|
log_group_name: '{{ log_group_name }}'
|
||||||
|
retention: 1
|
||||||
|
|
||||||
|
- name: check_mode set metric filter on '{{ log_group_name }}'
|
||||||
|
cloudwatchlogs_log_group_metric_filter:
|
||||||
|
log_group_name: '{{ log_group_name }}'
|
||||||
|
filter_name: '{{ filter_name }}'
|
||||||
|
filter_pattern: '{ ($.value = *) && ($.hostname = "box")}'
|
||||||
|
state: present
|
||||||
|
metric_transformation:
|
||||||
|
metric_name: box_free_space
|
||||||
|
metric_namespace: fluentd_metrics
|
||||||
|
metric_value: "$.value"
|
||||||
|
check_mode: yes
|
||||||
|
register: out
|
||||||
|
|
||||||
|
- name: check_mode state must be changed
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- out is changed
|
||||||
|
- out.metric_filters | count == 1
|
||||||
|
|
||||||
|
- name: set metric filter on '{{ log_group_name }}'
|
||||||
|
cloudwatchlogs_log_group_metric_filter:
|
||||||
|
log_group_name: '{{ log_group_name }}'
|
||||||
|
filter_name: '{{ filter_name }}'
|
||||||
|
filter_pattern: '{ ($.value = *) && ($.hostname = "box")}'
|
||||||
|
state: present
|
||||||
|
metric_transformation:
|
||||||
|
metric_name: box_free_space
|
||||||
|
metric_namespace: fluentd_metrics
|
||||||
|
metric_value: "$.value"
|
||||||
|
register: out
|
||||||
|
|
||||||
|
- name: create metric filter
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- out is changed
|
||||||
|
- out.metric_filters | count == 1
|
||||||
|
|
||||||
|
- name: re-set metric filter on '{{ log_group_name }}'
|
||||||
|
cloudwatchlogs_log_group_metric_filter:
|
||||||
|
log_group_name: '{{ log_group_name }}'
|
||||||
|
filter_name: '{{ filter_name }}'
|
||||||
|
filter_pattern: '{ ($.value = *) && ($.hostname = "box")}'
|
||||||
|
state: present
|
||||||
|
metric_transformation:
|
||||||
|
metric_name: box_free_space
|
||||||
|
metric_namespace: fluentd_metrics
|
||||||
|
metric_value: "$.value"
|
||||||
|
register: out
|
||||||
|
|
||||||
|
- name: metric filter must not change
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- out is not changed
|
||||||
|
|
||||||
|
- name: update metric transformation on '{{ log_group_name }}'
|
||||||
|
cloudwatchlogs_log_group_metric_filter:
|
||||||
|
log_group_name: '{{ log_group_name }}'
|
||||||
|
filter_name: '{{ filter_name }}'
|
||||||
|
filter_pattern: '{ ($.value = *) && ($.hostname = "box")}'
|
||||||
|
state: present
|
||||||
|
metric_transformation:
|
||||||
|
metric_name: box_free_space
|
||||||
|
metric_namespace: made_with_ansible
|
||||||
|
metric_value: "$.value"
|
||||||
|
default_value: 3.1415
|
||||||
|
register: out
|
||||||
|
|
||||||
|
- name: update metric filter
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- out is changed
|
||||||
|
- out.metric_filters[0].metric_namespace == "made_with_ansible"
|
||||||
|
- out.metric_filters[0].default_value == 3.1415
|
||||||
|
|
||||||
|
- name: update filter_pattern on '{{ log_group_name }}'
|
||||||
|
cloudwatchlogs_log_group_metric_filter:
|
||||||
|
log_group_name: '{{ log_group_name }}'
|
||||||
|
filter_name: '{{ filter_name }}'
|
||||||
|
filter_pattern: '{ ($.value = *) && ($.hostname = "ansible")}'
|
||||||
|
state: present
|
||||||
|
metric_transformation:
|
||||||
|
metric_name: box_free_space
|
||||||
|
metric_namespace: made_with_ansible
|
||||||
|
metric_value: "$.value"
|
||||||
|
register: out
|
||||||
|
|
||||||
|
- name: update metric filter
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- out is changed
|
||||||
|
- out.metric_filters[0].metric_namespace == "made_with_ansible"
|
||||||
|
|
||||||
|
- name: checkmode delete metric filter on '{{ log_group_name }}'
|
||||||
|
cloudwatchlogs_log_group_metric_filter:
|
||||||
|
log_group_name: '{{ log_group_name }}'
|
||||||
|
filter_name: '{{ filter_name }}'
|
||||||
|
state: absent
|
||||||
|
check_mode: yes
|
||||||
|
register: out
|
||||||
|
|
||||||
|
- name: check_mode state must be changed
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- out is changed
|
||||||
|
|
||||||
|
- name: delete metric filter on '{{ log_group_name }}'
|
||||||
|
cloudwatchlogs_log_group_metric_filter:
|
||||||
|
log_group_name: '{{ log_group_name }}'
|
||||||
|
filter_name: '{{ filter_name }}'
|
||||||
|
state: absent
|
||||||
|
register: out
|
||||||
|
|
||||||
|
- name: delete metric filter
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- out is changed
|
||||||
|
|
||||||
|
- name: delete metric filter on '{{ log_group_name }}' which does not exist
|
||||||
|
cloudwatchlogs_log_group_metric_filter:
|
||||||
|
log_group_name: '{{ log_group_name }}'
|
||||||
|
filter_name: '{{ filter_name }}'
|
||||||
|
state: absent
|
||||||
|
register: out
|
||||||
|
|
||||||
|
- name: delete metric filter
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- out is not changed
|
||||||
|
|
||||||
|
always:
|
||||||
|
- name: delete metric filter
|
||||||
|
cloudwatchlogs_log_group_metric_filter:
|
||||||
|
log_group_name: '{{ log_group_name }}'
|
||||||
|
filter_name: '{{ filter_name }}'
|
||||||
|
state: absent
|
||||||
|
|
||||||
|
- name: delete cloudwatch log group for integration test
|
||||||
|
cloudwatchlogs_log_group:
|
||||||
|
state: absent
|
||||||
|
log_group_name: '{{ log_group_name }}'
|
||||||
|
ignore_errors: true
|
Loading…
Reference in a new issue