Skip to content
This repository has been archived by the owner on Oct 30, 2018. It is now read-only.

New ec2_group_facts module to be able to get facts from EC2 security groups #2591

Merged
merged 7 commits into from
Nov 11, 2016
148 changes: 148 additions & 0 deletions cloud/amazon/ec2_group_facts.py
Original file line number Diff line number Diff line change
@@ -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 <http://www.gnu.org/licenses/>.

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"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to update this to 2.3

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's been updated to 2.3.

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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be really nice to be able to do underscore-separated tags as well, since that's typically how folks expect to do params. Do you think that'd be a useful addition?

diff --git a/cloud/amazon/ec2_group_facts.py b/cloud/amazon/ec2_group_facts.py
index 777fc59..bc9a75d 100644
--- a/cloud/amazon/ec2_group_facts.py
+++ b/cloud/amazon/ec2_group_facts.py
@@ -121,9 +121,11 @@ def main():
     else:
         module.fail_json(msg="region must be specified")

+    sanitized_filters = {k.replace('_', '-'): v for k, v in module.params.get("filters", {}).items() if 'tag:' not in k}
+    sanitized_filters.update({k: v for k, v in module.params.get("filters", {}).items() if 'tag:' in k})
     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)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's a good idea. I've implemented it a little bit different from you, but I think it's easier to read. I've also changed the documentation accordingly.


# 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:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On this example can you add a comment to the effect of "The quotes around tag:Name are important because of the colon in the value" because not everyone realizes the significance there.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your comment was spot on, so I just used it verbatim.

"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)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here can you add the exception to the failure, something like:

import traceback # do this with the other imports, not in the exception
module.fail_json(msg=e.message, exception=traceback.format_exc(e))

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's done. Let me know if you disagree with the location of the import. I really don't have others like that one and I wanted to keep the boto ones separate.


# 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()