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

[2.6] ec2_group: fix regression for targets that are a list containing strings and lists #45748

Merged
merged 3 commits into from
Sep 25, 2018
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
bugfixes:
- ec2_group - Sanitize the ingress and egress rules before operating on them by flattening any lists
within lists describing the target CIDR(s) into a list of strings. Prior to Ansible 2.6 the ec2_group
module accepted a list of strings, a list of lists, or a combination of strings and lists within a list.
https://github.com/ansible/ansible/pull/45594
28 changes: 26 additions & 2 deletions lib/ansible/modules/cloud/amazon/ec2_group.py
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,7 @@

import json
import re
from copy import deepcopy
from time import sleep
from collections import namedtuple
from ansible.module_utils.aws.core import AnsibleAWSModule
Expand Down Expand Up @@ -847,6 +848,27 @@ def verify_rules_with_descriptions_permitted(client, module, rules, rules_egress
module.fail_json(msg="Using rule descriptions requires botocore version >= 1.7.2.")


def flatten_nested_targets(module, rules):
def _flatten(targets):
for target in targets:
if isinstance(target, list):
for t in _flatten(target):
yield t
elif isinstance(target, string_types):
yield target

if rules is not None:
for rule in rules:
target_list_type = None
if isinstance(rule.get('cidr_ip'), list):
target_list_type = 'cidr_ip'
elif isinstance(rule.get('cidr_ipv6'), list):
target_list_type = 'cidr_ipv6'
if target_list_type is not None:
rule[target_list_type] = list(_flatten(rule[target_list_type]))
return rules


def main():
argument_spec = dict(
name=dict(),
Expand All @@ -872,8 +894,10 @@ def main():
group_id = module.params['group_id']
description = module.params['description']
vpc_id = module.params['vpc_id']
rules = deduplicate_rules_args(rules_expand_sources(rules_expand_ports(module.params['rules'])))
rules_egress = deduplicate_rules_args(rules_expand_sources(rules_expand_ports(module.params['rules_egress'])))
rules = flatten_nested_targets(module, deepcopy(module.params['rules']))
rules_egress = flatten_nested_targets(module, deepcopy(module.params['rules_egress']))
rules = deduplicate_rules_args(rules_expand_sources(rules_expand_ports(rules)))
rules_egress = deduplicate_rules_args(rules_expand_sources(rules_expand_ports(rules_egress)))
state = module.params.get('state')
purge_rules = module.params['purge_rules']
purge_rules_egress = module.params['purge_rules_egress']
Expand Down
1 change: 1 addition & 0 deletions test/integration/targets/ec2_group/tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
- include: ./rule_group_create.yml
- include: ./egress_tests.yml
- include: ./data_validation.yml
- include: ./multi_target.yml

# ============================================================
- name: test state=absent (CHECK MODE)
Expand Down
230 changes: 230 additions & 0 deletions test/integration/targets/ec2_group/tasks/multi_target.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,230 @@
---
- name: set up aws connection info
set_fact:
aws_connection_info: &aws_connection_info
aws_access_key: "{{ aws_access_key }}"
aws_secret_key: "{{ aws_secret_key }}"
security_token: "{{ security_token }}"
region: "{{ aws_region }}"
no_log: yes

# ============================================================

- name: test state=present for multiple ipv6 and ipv4 targets (expected changed=true) (CHECK MODE)
ec2_group:
name: '{{ ec2_group_name }}'
description: '{{ ec2_group_description }}'
state: present
rules:
- proto: "tcp"
from_port: 8182
to_port: 8182
cidr_ipv6:
- "64:ff9b::/96"
- ["2620::/32"]
- proto: "tcp"
ports: 5665
cidr_ip:
- 172.16.1.0/24
- 172.16.17.0/24
- ["10.0.0.0/24", "20.0.0.0/24"]
<<: *aws_connection_info
check_mode: true
register: result

- name: assert state=present (expected changed=true)
assert:
that:
- 'result.changed'

- name: test state=present for multiple ipv6 and ipv4 targets (expected changed=true)
ec2_group:
name: '{{ ec2_group_name }}'
description: '{{ ec2_group_description }}'
state: present
rules:
- proto: "tcp"
from_port: 8182
to_port: 8182
cidr_ipv6:
- "64:ff9b::/96"
- ["2620::/32"]
- proto: "tcp"
ports: 5665
cidr_ip:
- 172.16.1.0/24
- 172.16.17.0/24
- ["10.0.0.0/24", "20.0.0.0/24"]
<<: *aws_connection_info
register: result

- name: assert state=present (expected changed=true)
assert:
that:
- 'result.changed'
- 'result.ip_permissions | length == 2'
- 'result.ip_permissions[0].ip_ranges | length == 4 or result.ip_permissions[1].ip_ranges | length == 4'
- 'result.ip_permissions[0].ipv6_ranges | length == 2 or result.ip_permissions[1].ipv6_ranges | length == 2'

- name: test state=present for multiple ipv6 and ipv4 targets (expected changed=false) (CHECK MODE)
ec2_group:
name: '{{ ec2_group_name }}'
description: '{{ ec2_group_description }}'
state: present
rules:
- proto: "tcp"
from_port: 8182
to_port: 8182
cidr_ipv6:
- "64:ff9b::/96"
- ["2620::/32"]
- proto: "tcp"
ports: 5665
cidr_ip:
- 172.16.1.0/24
- 172.16.17.0/24
- ["10.0.0.0/24", "20.0.0.0/24"]
<<: *aws_connection_info
check_mode: true
register: result

- name: assert state=present (expected changed=true)
assert:
that:
- 'not result.changed'

- name: test state=present for multiple ipv6 and ipv4 targets (expected changed=false)
ec2_group:
name: '{{ ec2_group_name }}'
description: '{{ ec2_group_description }}'
state: present
rules:
- proto: "tcp"
from_port: 8182
to_port: 8182
cidr_ipv6:
- "64:ff9b::/96"
- ["2620::/32"]
- proto: "tcp"
ports: 5665
cidr_ip:
- 172.16.1.0/24
- 172.16.17.0/24
- ["10.0.0.0/24", "20.0.0.0/24"]
<<: *aws_connection_info
register: result

- name: assert state=present (expected changed=true)
assert:
that:
- 'not result.changed'

- name: test state=present purging a nested ipv4 target (expected changed=true) (CHECK MODE)
ec2_group:
name: '{{ ec2_group_name }}'
description: '{{ ec2_group_description }}'
state: present
rules:
- proto: "tcp"
from_port: 8182
to_port: 8182
cidr_ipv6:
- "64:ff9b::/96"
- ["2620::/32"]
- proto: "tcp"
ports: 5665
cidr_ip:
- 172.16.1.0/24
- 172.16.17.0/24
- ["10.0.0.0/24"]
<<: *aws_connection_info
check_mode: true
register: result

- assert:
that:
- result.changed

- name: test state=present purging a nested ipv4 target (expected changed=true)
ec2_group:
name: '{{ ec2_group_name }}'
description: '{{ ec2_group_description }}'
state: present
rules:
- proto: "tcp"
from_port: 8182
to_port: 8182
cidr_ipv6:
- "64:ff9b::/96"
- ["2620::/32"]
- proto: "tcp"
ports: 5665
cidr_ip:
- 172.16.1.0/24
- 172.16.17.0/24
- ["10.0.0.0/24"]
<<: *aws_connection_info
register: result

- assert:
that:
- result.changed
- 'result.ip_permissions[0].ip_ranges | length == 3 or result.ip_permissions[1].ip_ranges | length == 3'
- 'result.ip_permissions[0].ipv6_ranges | length == 2 or result.ip_permissions[1].ipv6_ranges | length == 2'

- name: test state=present with both associated ipv6 targets nested (expected changed=false)
ec2_group:
name: '{{ ec2_group_name }}'
description: '{{ ec2_group_description }}'
state: present
rules:
- proto: "tcp"
from_port: 8182
to_port: 8182
cidr_ipv6:
- ["2620::/32", "64:ff9b::/96"]
- proto: "tcp"
ports: 5665
cidr_ip:
- 172.16.1.0/24
- 172.16.17.0/24
- ["10.0.0.0/24"]
<<: *aws_connection_info
register: result

- assert:
that:
- not result.changed

- name: test state=present add another nested ipv6 target (expected changed=true)
ec2_group:
name: '{{ ec2_group_name }}'
description: '{{ ec2_group_description }}'
state: present
rules:
- proto: "tcp"
from_port: 8182
to_port: 8182
cidr_ipv6:
- ["2620::/32", "64:ff9b::/96"]
- ["2001:DB8:A0B:12F0::1/64"]
- proto: "tcp"
ports: 5665
cidr_ip:
- 172.16.1.0/24
- 172.16.17.0/24
- ["10.0.0.0/24"]
<<: *aws_connection_info
register: result

- assert:
that:
- result.changed
- 'result.ip_permissions[0].ip_ranges | length == 3 or result.ip_permissions[1].ip_ranges | length == 3'
- 'result.ip_permissions[0].ipv6_ranges | length == 3 or result.ip_permissions[1].ipv6_ranges | length == 3'

- name: delete it
ec2_group:
name: '{{ ec2_group_name }}'
state: absent
<<: *aws_connection_info