Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[PR #1883/3b67513e backport][stable-6] cloudwatchevent_rule: Fix json input handling for input_template #1969

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading