Skip to content

Commit

Permalink
cloudwatchevent_rule: Fix json input handling for input_template (#1883)
Browse files Browse the repository at this point in the history
cloudwatchevent_rule: Fix json input handling for input_template

SUMMARY

Fixes #1842
This PR

Moves _snakify() out of class CloudWatchEventRule https://github.com/ansible-collections/amazon.aws/pull/1883/files#diff-3a2f223edc4e34ea28b9859827a830844d92a8cd97f1300a2d16b1703a083bc8R213-R215

Fixes conditional in function _targets_to_put() to avoid wrong results due to _snakify() https://github.com/ansible-collections/amazon.aws/pull/1883/files#diff-3a2f223edc4e34ea28b9859827a830844d92a8cd97f1300a2d16b1703a083bc8R461-R463

Updates code to add quotes " to input_template only when the given input is not JSON to avoid quotes being added to provided JSON input https://github.com/ansible-collections/amazon.aws/pull/1883/files#diff-3a2f223edc4e34ea28b9859827a830844d92a8cd97f1300a2d16b1703a083bc8R452-R458

ISSUE TYPE

Bugfix Pull Request

COMPONENT NAME

cloudwatchevent_rule
ADDITIONAL INFORMATION

Reviewed-by: Bikouo Aubin
Reviewed-by: Helen Bailey <[email protected]>
Reviewed-by: Alina Buzachis
Reviewed-by: Mandar Kulkarni <[email protected]>
(cherry picked from commit 3b67513)
  • Loading branch information
mandar242 authored and patchback[bot] committed Feb 8, 2024
1 parent 962c093 commit 54f91b0
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 9 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
---
bugfixes:
- cloudwatchevent_rule - Fix to avoid adding quotes to JSON input for provided input_template (https://github.com/ansible-collections/amazon.aws/pull/1883).
29 changes: 20 additions & 9 deletions plugins/modules/cloudwatchevent_rule.py
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,14 @@ def _format_json(json_string):
return str(json.dumps(json_string))


def _validate_json(s):
try:
json.loads(s)
return True
except json.JSONDecodeError:
return False


class CloudWatchEventRule:
def __init__(
self, module, name, client, schedule_expression=None, event_pattern=None, description=None, role_arn=None
Expand All @@ -228,7 +236,7 @@ def describe(self):
botocore.exceptions.ClientError,
) as e: # pylint: disable=duplicate-except
self.module.fail_json_aws(e, msg=f"Could not describe rule {self.name}")
return self._snakify(rule_info)
return camel_dict_to_snake_dict(rule_info)

def put(self, enabled=True):
"""Creates or updates the rule in AWS"""
Expand Down Expand Up @@ -291,7 +299,7 @@ def list_targets(self):
botocore.exceptions.ClientError,
) as e: # pylint: disable=duplicate-except
self.module.fail_json_aws(e, msg=f"Could not find target for rule {self.name}")
return self._snakify(targets)["targets"]
return camel_dict_to_snake_dict(targets)["targets"]

def put_targets(self, targets):
"""Creates or updates the provided targets on the rule in AWS"""
Expand Down Expand Up @@ -342,10 +350,6 @@ def _targets_request(self, targets):
targets_request.append(target_request)
return targets_request

def _snakify(self, dict):
"""Converts camel case to snake case"""
return camel_dict_to_snake_dict(dict)


class CloudWatchEventRuleManager:
RULE_FIELDS = ["name", "event_pattern", "schedule_expression", "description", "role_arn"]
Expand Down Expand Up @@ -441,11 +445,18 @@ def _targets_to_put(self):
# The remote_targets contain quotes, so add
# quotes to temp
val = t["input_transformer"]["input_template"]
t["input_transformer"]["input_template"] = '"' + val + '"'
# list_targets_by_rule return input_template as string
# if existing value is string "<instance> is in state <state>", it returns '"<instance> is in state <state>"'
# if existing value is <JSON>, it returns '<JSON>'
# therefore add quotes to provided input_template value only if it is not a JSON
valid_json = _validate_json(val)
if not valid_json:
t["input_transformer"]["input_template"] = '"' + val + '"'
temp.append(scrub_none_parameters(t))
self.targets = temp

return [t for t in self.targets if t not in remote_targets]
# remote_targets is snakified output of client.list_targets_by_rule()
# therefore snakified version of t should be compared to avoid wrong result of below conditional
return [t for t in self.targets if camel_dict_to_snake_dict(t) not in remote_targets]

def _remote_target_ids_to_remove(self):
"""Returns a list of targets that need to be removed remotely"""
Expand Down
4 changes: 4 additions & 0 deletions tests/integration/targets/cloudwatchevent_rule/tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
region: "{{ aws_region }}"

block:

- name: Run tests for testing json input_template
ansible.builtin.import_tasks: test_json_input_template.yml

- name: Create SNS topic
sns_topic:
name: "TestSNSTopic"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
---
- name: Run tests for json input_template
block:

- name: Create SNS topic
community.aws.sns_topic:
name: TestSNSTopic-Json
state: present
display_name: Test SNS Topic
register: sns_topic_output

- name: Define JSON input_template
ansible.builtin.set_fact:
json_input_template: |
{
"instance" : "<instance>",
"state": "<state>"
}
- name: Create cloudwatch event rule with input transformer
amazon.aws.cloudwatchevent_rule:
name: "{{ input_transformer_event_name }}-Json"
description: Event rule with input transformer configuration
state: present
event_pattern: '{"source":["aws.ec2"],"detail-type":["EC2 Instance State-change Notification"],"detail":{"state":["pending"]}}'
targets:
- id: "{{ sns_topic_output.sns_topic.name }}"
arn: "{{ sns_topic_output.sns_topic.topic_arn }}"
input_transformer:
input_paths_map:
instance: $.detail.instance-id
state: $.detail.state
input_template: "{{ json_input_template }}"
register: event_rule_input_transformer_output

- name: Assert that input transformer event rule was created
ansible.builtin.assert:
that:
- event_rule_input_transformer_output.changed

- name: Assert that event rule is created with a valid json value for input_template
ansible.builtin.assert:
that:
- event_rule_input_transformer_output.targets[0].input_transformer.input_template | from_json

- name: Create cloudwatch event rule with input transformer (idempotent)
amazon.aws.cloudwatchevent_rule:
name: "{{ input_transformer_event_name }}-Json"
description: Event rule with input transformer configuration
state: present
event_pattern: '{"source":["aws.ec2"],"detail-type":["EC2 Instance State-change Notification"],"detail":{"state":["pending"]}}'
targets:
- id: "{{ sns_topic_output.sns_topic.name }}"
arn: "{{ sns_topic_output.sns_topic.topic_arn }}"
input_transformer:
input_paths_map:
instance: $.detail.instance-id
state: $.detail.state
input_template: "{{ json_input_template }}"
register: event_rule_input_transformer_output

always:
- name: Assert that no changes were made to the rule
ansible.builtin.assert:
that:
- event_rule_input_transformer_output is not changed

- name: Delete input transformer CloudWatch event rules
amazon.aws.cloudwatchevent_rule:
name: "{{ input_transformer_event_name }}-Json"
state: absent

- name: Delete SNS topic
community.aws.sns_topic:
name: TestSNSTopic-Json
state: absent

0 comments on commit 54f91b0

Please sign in to comment.