From 9e7b6506b95c820b0af94869012e506fb2256ab8 Mon Sep 17 00:00:00 2001 From: Henrique Rodrigues Date: Wed, 20 Jul 2016 11:57:17 +0100 Subject: [PATCH 1/7] Add ec2_group_facts module to be able to get facts from EC2 security groups --- cloud/amazon/ec2_group_facts.py | 148 ++++++++++++++++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100644 cloud/amazon/ec2_group_facts.py diff --git a/cloud/amazon/ec2_group_facts.py b/cloud/amazon/ec2_group_facts.py new file mode 100644 index 00000000000..777fc5903aa --- /dev/null +++ b/cloud/amazon/ec2_group_facts.py @@ -0,0 +1,148 @@ +#!/usr/bin/python +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see . + +DOCUMENTATION = ''' +--- +module: ec2_group_facts +short_description: Gather facts about ec2 security groups in AWS. +description: + - Gather facts about ec2 security groups in AWS. +version_added: "2.2" +author: "Henrique Rodrigues (github.com/Sodki)" +options: + filters: + description: + - A dict of filters to apply. Each dict item consists of a filter key and a filter value. See \ + U(https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeSecurityGroups.html) for \ + possible filters. Filter names and values are case sensitive. + required: false + default: {} +notes: + - By default, the module will return all security groups. To limit results use the appropriate filters. + +extends_documentation_fragment: + - aws + - ec2 +''' + +EXAMPLES = ''' +# Note: These examples do not set authentication details, see the AWS Guide for details. + +# Gather facts about all security groups +- ec2_group_facts: + +# Gather facts about all security groups in a specific VPC +- ec2_group_facts: + filters: + vpc-id: vpc-12345678 + +# Gather facts about all security groups in a specific VPC +- ec2_group_facts: + filters: + vpc-id: vpc-12345678 + +# Gather facts about a security group +- ec2_group_facts: + filters: + group-name: example-1 + +# Gather facts about a security group by id +- ec2_group_facts: + filters: + group-id: sg-12345678 + +# Gather facts about various security groups +- ec2_group_facts: + filters: + group-name: + - example-1 + - example-2 + - example-3 + +# Gather facts about any security group with a tag key Name and value Example +- ec2_group_facts: + filters: + "tag:Name": Example +''' + +RETURN = ''' +security_groups: + description: Security groups that match the provided filters. Each element consists of a dict with all the information related to that security group. + type: list + sample: +''' + + +try: + import boto3 + from botocore.exceptions import ClientError + HAS_BOTO3 = True +except ImportError: + HAS_BOTO3 = Falsentry + + +def main(): + argument_spec = ec2_argument_spec() + argument_spec.update( + dict( + filters=dict(default={}, type='dict') + ) + ) + + module = AnsibleModule(argument_spec=argument_spec) + + if not HAS_BOTO3: + module.fail_json(msg='boto3 required for this module') + + region, ec2_url, aws_connect_params = get_aws_connection_info(module, boto3=True) + + if region: + connection = boto3_conn( + module, + conn_type='client', + resource='ec2', + region=region, + endpoint=ec2_url, + **aws_connect_params + ) + else: + module.fail_json(msg="region must be specified") + + try: + security_groups = connection.describe_security_groups( + Filters=ansible_dict_to_boto3_filter_list(module.params.get("filters")) + ) + except ClientError as e: + module.fail_json(msg=e.message) + + # Turn the boto3 result in to ansible_friendly_snaked_names + snaked_security_groups = [] + for security_group in security_groups['SecurityGroups']: + snaked_security_groups.append(camel_dict_to_snake_dict(security_group)) + + # Turn the boto3 result in to ansible friendly tag dictionary + for security_group in snaked_security_groups: + if 'tags' in security_group: + security_group['tags'] = boto3_tag_list_to_ansible_dict(security_group['tags']) + + module.exit_json(security_groups=snaked_security_groups) + + +from ansible.module_utils.basic import * +from ansible.module_utils.ec2 import * + +if __name__ == '__main__': + main() From 095a39873d253127e38d586560fba093db74e19b Mon Sep 17 00:00:00 2001 From: Henrique Rodrigues Date: Fri, 11 Nov 2016 11:14:10 +0000 Subject: [PATCH 2/7] Update to Ansible 2.3 --- cloud/amazon/ec2_group_facts.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cloud/amazon/ec2_group_facts.py b/cloud/amazon/ec2_group_facts.py index 777fc5903aa..1ef4eee7df9 100644 --- a/cloud/amazon/ec2_group_facts.py +++ b/cloud/amazon/ec2_group_facts.py @@ -20,7 +20,7 @@ short_description: Gather facts about ec2 security groups in AWS. description: - Gather facts about ec2 security groups in AWS. -version_added: "2.2" +version_added: "2.3" author: "Henrique Rodrigues (github.com/Sodki)" options: filters: From 75f6364c34b5989fe4d38f8b910c41e5955cf2ab Mon Sep 17 00:00:00 2001 From: Henrique Rodrigues Date: Fri, 11 Nov 2016 11:23:25 +0000 Subject: [PATCH 3/7] Add more information regarding the use of quotes on a value in the examples --- cloud/amazon/ec2_group_facts.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cloud/amazon/ec2_group_facts.py b/cloud/amazon/ec2_group_facts.py index 1ef4eee7df9..7901c0f7319 100644 --- a/cloud/amazon/ec2_group_facts.py +++ b/cloud/amazon/ec2_group_facts.py @@ -72,7 +72,7 @@ - example-2 - example-3 -# Gather facts about any security group with a tag key Name and value Example +# Gather facts about any security group with a tag key Name and value Example. The quotes around 'tag:name' are important because of the colon in the value - ec2_group_facts: filters: "tag:Name": Example From cdd6281dfddb022a5f2f167c61c9982930155741 Mon Sep 17 00:00:00 2001 From: Henrique Rodrigues Date: Fri, 11 Nov 2016 11:32:40 +0000 Subject: [PATCH 4/7] Add traceback to the main boto3 operation exception --- cloud/amazon/ec2_group_facts.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cloud/amazon/ec2_group_facts.py b/cloud/amazon/ec2_group_facts.py index 7901c0f7319..deae5d87d4a 100644 --- a/cloud/amazon/ec2_group_facts.py +++ b/cloud/amazon/ec2_group_facts.py @@ -93,6 +93,8 @@ except ImportError: HAS_BOTO3 = Falsentry +import traceback + def main(): argument_spec = ec2_argument_spec() @@ -126,7 +128,7 @@ def main(): Filters=ansible_dict_to_boto3_filter_list(module.params.get("filters")) ) except ClientError as e: - module.fail_json(msg=e.message) + module.fail_json(msg=e.message, exception=traceback.format_exc(e)) # Turn the boto3 result in to ansible_friendly_snaked_names snaked_security_groups = [] From 2f9d91ac590883aec6e2bd7a0bba4007c73e8b5f Mon Sep 17 00:00:00 2001 From: Henrique Rodrigues Date: Fri, 11 Nov 2016 12:11:34 +0000 Subject: [PATCH 5/7] Allow using underscores instead of dashes as filter keys --- cloud/amazon/ec2_group_facts.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/cloud/amazon/ec2_group_facts.py b/cloud/amazon/ec2_group_facts.py index deae5d87d4a..f4384864b96 100644 --- a/cloud/amazon/ec2_group_facts.py +++ b/cloud/amazon/ec2_group_facts.py @@ -27,7 +27,8 @@ description: - A dict of filters to apply. Each dict item consists of a filter key and a filter value. See \ U(https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeSecurityGroups.html) for \ - possible filters. Filter names and values are case sensitive. + possible filters. Filter names and values are case sensitive. You can also use underscores (_) \ + instead of dashes (-) in the filter keys, which will take precedence in case of conflict. required: false default: {} notes: @@ -123,9 +124,13 @@ def main(): else: module.fail_json(msg="region must be specified") + sanitized_filters = module.params.get("filters") + for key in sanitized_filters: + sanitized_filters[key.replace("_", "-")] = sanitized_filters.pop(key) + try: security_groups = connection.describe_security_groups( - Filters=ansible_dict_to_boto3_filter_list(module.params.get("filters")) + Filters=ansible_dict_to_boto3_filter_list(sanitized_filters) ) except ClientError as e: module.fail_json(msg=e.message, exception=traceback.format_exc(e)) From bf0fd65ee71877eb2db8e5cd0fb4d185befcf1ac Mon Sep 17 00:00:00 2001 From: Henrique Rodrigues Date: Fri, 11 Nov 2016 13:38:56 +0000 Subject: [PATCH 6/7] Add examples for alternative filter key, using underscores --- cloud/amazon/ec2_group_facts.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cloud/amazon/ec2_group_facts.py b/cloud/amazon/ec2_group_facts.py index f4384864b96..6b2ca3b2341 100644 --- a/cloud/amazon/ec2_group_facts.py +++ b/cloud/amazon/ec2_group_facts.py @@ -65,6 +65,12 @@ filters: group-id: sg-12345678 +# Gather facts about a security group with multiple filters, also mixing the use of underscores as filter keys +- ec2_group_facts: + filters: + group_id: sg-12345678 + vpc-id: vpc-12345678 + # Gather facts about various security groups - ec2_group_facts: filters: From 9429a79f6b24764f8d30f35c7e2567efa4172215 Mon Sep 17 00:00:00 2001 From: Henrique Rodrigues Date: Fri, 11 Nov 2016 13:59:14 +0000 Subject: [PATCH 7/7] Don't replace underscores with dashes when dealing with tags --- cloud/amazon/ec2_group_facts.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cloud/amazon/ec2_group_facts.py b/cloud/amazon/ec2_group_facts.py index 6b2ca3b2341..6e4039f8b55 100644 --- a/cloud/amazon/ec2_group_facts.py +++ b/cloud/amazon/ec2_group_facts.py @@ -130,9 +130,11 @@ def main(): else: module.fail_json(msg="region must be specified") + # Replace filter key underscores with dashes, for compatibility, except if we're dealing with tags sanitized_filters = module.params.get("filters") for key in sanitized_filters: - sanitized_filters[key.replace("_", "-")] = sanitized_filters.pop(key) + if not key.startswith("tag:"): + sanitized_filters[key.replace("_", "-")] = sanitized_filters.pop(key) try: security_groups = connection.describe_security_groups(