diff --git a/lib/ansible/modules/cloud/amazon/ec2_group.py b/lib/ansible/modules/cloud/amazon/ec2_group.py index 792ae6b021a..d3356589a7a 100644 --- a/lib/ansible/modules/cloud/amazon/ec2_group.py +++ b/lib/ansible/modules/cloud/amazon/ec2_group.py @@ -135,8 +135,47 @@ EXAMPLES = ''' group_name: example-other # description to use if example-other needs to be created group_desc: other example EC2 group + +- name: example2 ec2 group + ec2_group: + name: example2 + description: an example2 EC2 group + vpc_id: 12345 + region: eu-west-1a + rules: + # 'ports' rule keyword was introduced in version 2.3. It accepts a single port value or a list of values including ranges (from_port-to_port). + - proto: tcp + ports: 22 + group_name: example-vpn + - proto: tcp + ports: + - 80 + - 443 + - 8080-8099 + cidr_ip: 0.0.0.0/0 + # Rule sources list support was added in version 2.3. This allows to define multiple sources per source type as well as multiple source types per rule. + - proto: tcp + ports: + - 6379 + - 26379 + group_name: + - example-vpn + - example-redis + - proto: tcp + ports: 5665 + group_name: example-vpn + cidr_ip: + - 172.16.1.0/24 + - 172.16.17.0/24 + group_id: + - sg-edcd9784 ''' +import re +import time +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.ec2 import ec2_connect, ec2_argument_spec + try: import boto.ec2 from boto.ec2.securitygroup import SecurityGroup @@ -245,6 +284,80 @@ def get_target_from_rule(module, ec2, rule, name, group, groups, vpc_id): return group_id, ip, target_group_created +def ports_expand(ports): + # takes a list of ports and returns a list of (port_from, port_to) + ports_expanded = [] + for port in ports: + if not isinstance(port, str): + ports_expanded.append((port,) * 2) + elif '-' in port: + ports_expanded.append(tuple(p.strip() for p in + port.split('-', 1))) + else: + ports_expanded.append((port.strip(),) * 2) + + return ports_expanded + + +def rule_expand_ports(rule): + # takes a rule dict and returns a list of expanded rule dicts + if 'ports' not in rule: + return [rule] + + ports = rule['ports'] if isinstance(rule['ports'], list) else [rule['ports']] + + rule_expanded = [] + for from_to in ports_expand(ports): + temp_rule = rule.copy() + del temp_rule['ports'] + temp_rule['from_port'], temp_rule['to_port'] = from_to + rule_expanded.append(temp_rule) + + return rule_expanded + + +def rules_expand_ports(rules): + # takes a list of rules and expands it based on 'ports' + if not rules: + return rules + + return [rule for rule_complex in rules + for rule in rule_expand_ports(rule_complex)] + + +def rule_expand_source(rule, source_type): + # takes a rule dict and returns a list of expanded rule dicts for specified source_type + sources = rule[source_type] if isinstance(rule[source_type], list) else [rule[source_type]] + source_types_all = ('cidr_ip', 'group_id', 'group_name') + + rule_expanded = [] + for source in sources: + temp_rule = rule.copy() + for s in source_types_all: + temp_rule.pop(s, None) + temp_rule[source_type] = source + rule_expanded.append(temp_rule) + + return rule_expanded + + +def rule_expand_sources(rule): + # takes a rule dict and returns a list of expanded rule discts + source_types = (stype for stype in ('cidr_ip', 'group_id', 'group_name') if stype in rule) + + return [r for stype in source_types + for r in rule_expand_source(rule, stype)] + + +def rules_expand_sources(rules): + # takes a list of rules and expands it based on 'cidr_ip', 'group_id', 'group_name' + if not rules: + return rules + + return [rule for rule_complex in rules + for rule in rule_expand_sources(rule_complex)] + + def main(): argument_spec = ec2_argument_spec() argument_spec.update(dict( @@ -270,8 +383,8 @@ def main(): name = module.params['name'] description = module.params['description'] vpc_id = module.params['vpc_id'] - rules = module.params['rules'] - rules_egress = module.params['rules_egress'] + rules = rules_expand_sources(rules_expand_ports(module.params['rules'])) + rules_egress = rules_expand_sources(rules_expand_ports(module.params['rules_egress'])) state = module.params.get('state') purge_rules = module.params['purge_rules'] purge_rules_egress = module.params['purge_rules_egress'] @@ -484,9 +597,6 @@ def main(): else: module.exit_json(changed=changed, group_id=None) -# import module snippets -from ansible.module_utils.basic import * -from ansible.module_utils.ec2 import * if __name__ == '__main__': main()