From 512fe4452e207b5666a0ac009363da2e920b3470 Mon Sep 17 00:00:00 2001 From: "patchback[bot]" <45432694+patchback[bot]@users.noreply.github.com> Date: Tue, 13 Feb 2024 18:28:01 +0000 Subject: [PATCH] cloudwatchevent_rule: Fix json input handling for input_template (#1883) (#1969) [PR #1883/3b67513e backport][stable-6] cloudwatchevent_rule: Fix json input handling for input_template This is a backport of PR #1883 as merged into main (3b67513). 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: Alina Buzachis --- ...json-input-handling-for-input_template.yml | 3 + plugins/modules/cloudwatchevent_rule.py | 29 ++++--- .../cloudwatchevent_rule/tasks/main.yml | 4 + .../tasks/test_json_input_template.yml | 76 +++++++++++++++++++ 4 files changed, 103 insertions(+), 9 deletions(-) create mode 100644 changelogs/fragments/1883-cloudwatchevent_rule-fix-json-input-handling-for-input_template.yml create mode 100644 tests/integration/targets/cloudwatchevent_rule/tasks/test_json_input_template.yml diff --git a/changelogs/fragments/1883-cloudwatchevent_rule-fix-json-input-handling-for-input_template.yml b/changelogs/fragments/1883-cloudwatchevent_rule-fix-json-input-handling-for-input_template.yml new file mode 100644 index 00000000000..13c9ea1191f --- /dev/null +++ b/changelogs/fragments/1883-cloudwatchevent_rule-fix-json-input-handling-for-input_template.yml @@ -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). diff --git a/plugins/modules/cloudwatchevent_rule.py b/plugins/modules/cloudwatchevent_rule.py index 8f6f1fe5734..e5ca55331fe 100644 --- a/plugins/modules/cloudwatchevent_rule.py +++ b/plugins/modules/cloudwatchevent_rule.py @@ -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 @@ -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""" @@ -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""" @@ -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"] @@ -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 " is in state ", it returns '" is in state "' + # if existing value is , it returns '' + # 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""" diff --git a/tests/integration/targets/cloudwatchevent_rule/tasks/main.yml b/tests/integration/targets/cloudwatchevent_rule/tasks/main.yml index c92723e29b8..376bc7c612c 100644 --- a/tests/integration/targets/cloudwatchevent_rule/tasks/main.yml +++ b/tests/integration/targets/cloudwatchevent_rule/tasks/main.yml @@ -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" diff --git a/tests/integration/targets/cloudwatchevent_rule/tasks/test_json_input_template.yml b/tests/integration/targets/cloudwatchevent_rule/tasks/test_json_input_template.yml new file mode 100644 index 00000000000..d72fa3c8e6e --- /dev/null +++ b/tests/integration/targets/cloudwatchevent_rule/tasks/test_json_input_template.yml @@ -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" : "", + "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 \ No newline at end of file