From 58adf1750ede4d73d8442692a7de5672db75f0b1 Mon Sep 17 00:00:00 2001 From: Sloane Hertel Date: Tue, 19 Dec 2017 12:20:19 -0500 Subject: [PATCH] [cloud] New a lookup plugin for AWS account attributes (#33025) * Add a lookup plugin for AWS account attributes * PEP8 * Use config system instead of hard coding logic for environment variables * simplify logic * Return a flattened dict to make using easier * Reformat return example --- .../plugins/lookup/aws_account_attribute.py | 165 ++++++++++++++++++ 1 file changed, 165 insertions(+) create mode 100644 lib/ansible/plugins/lookup/aws_account_attribute.py diff --git a/lib/ansible/plugins/lookup/aws_account_attribute.py b/lib/ansible/plugins/lookup/aws_account_attribute.py new file mode 100644 index 00000000000..00b4b943fd5 --- /dev/null +++ b/lib/ansible/plugins/lookup/aws_account_attribute.py @@ -0,0 +1,165 @@ +# (c) 2017 Ansible Project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +DOCUMENTATION = """ +lookup: aws_account_attribute +author: + - Sloane Hertel +version_added: "2.5" +requirements: + - boto3 + - botocore +short_description: Look up AWS account attributes. +description: + - Describes attributes of your AWS account. You can specify one of the listed + attribute choices or omit it to see all attributes. +options: + attribute: + description: The attribute for which to get the value(s). + default: null + choices: + - supported-platforms + - default-vpc + - max-instances + - vpc-max-security-groups-per-interface + - max-elastic-ips + - vpc-max-elastic-ips + - has-ec2-classic + boto_profile: + description: The boto profile to use to create the connection. + default: null + env: + - name: AWS_PROFILE + - name: AWS_DEFAULT_PROFILE + aws_access_key: + description: The AWS access key to use. + default: null + env: + - name: AWS_ACCESS_KEY_ID + - name: AWS_ACCESS_KEY + - name: EC2_ACCESS_KEY + aws_secret_key: + description: The AWS secret key that corresponds to the access key. + default: null + env: + - name: AWS_SECRET_ACCESS_KEY + - name: AWS_SECRET_KEY + - name: EC2_SECRET_KEY + aws_security_token: + description: The AWS security token if using temporary access and secret keys. + default: null + env: + - name: AWS_SECURITY_TOKEN + - name: AWS_SESSION_TOKEN + - name: EC2_SECURITY_TOKEN + region: + description: The region for which to create the connection. + default: null + env: + - name: AWS_REGION + - name: EC2_REGION +""" + +EXAMPLES = """ +vars: + has_ec2_classic: "{{ lookup('aws_account_attribute', attribute='has-ec2-classic') }}" + # true | false + + default_vpc_id: "{{ lookup('aws_account_attribute', attribute='default-vpc') }}" + # vpc-xxxxxxxx | none + + account_details: "{{ lookup('aws_account_attribute', wantlist='true') }}" + # {'default-vpc': ['vpc-xxxxxxxx'], 'max-elastic-ips': ['5'], 'max-instances': ['20'], + # 'supported-platforms': ['VPC', 'EC2'], 'vpc-max-elastic-ips': ['5'], 'vpc-max-security-groups-per-interface': ['5']} + +""" + +RETURN = """ +_raw: + description: + Returns a boolean when I(attribute) is check_ec2_classic. Otherwise returns the value(s) of the attribute + (or all attributes if one is not specified). +""" + +from ansible.errors import AnsibleError + +try: + import boto3 + import botocore +except ImportError: + raise AnsibleError("The lookup aws_account_attribute requires boto3 and botocore.") + +from ansible.plugins import AnsiblePlugin +from ansible.plugins.lookup import LookupBase +from ansible.module_utils.ec2 import boto3_conn, get_aws_connection_info +from ansible.module_utils._text import to_native +from ansible.module_utils.six import string_types +import os + + +def _boto3_conn(region, credentials): + if 'boto_profile' in credentials: + boto_profile = credentials.pop('boto_profile') + else: + boto_profile = None + + try: + connection = boto3.session.Session(profile_name=boto_profile).client('ec2', region, **credentials) + except (botocore.exceptions.ProfileNotFound, botocore.exceptions.PartialCredentialsError) as e: + if boto_profile: + try: + connection = boto3.session.Session(profile_name=boto_profile).client('ec2', region) + except (botocore.exceptions.ProfileNotFound, botocore.exceptions.PartialCredentialsError) as e: + raise AnsibleError("Insufficient credentials found.") + else: + raise AnsibleError("Insufficient credentials found.") + return connection + + +def _get_credentials(options): + credentials = {} + credentials['boto_profile'] = options['boto_profile'] + credentials['aws_secret_access_key'] = options['aws_access_key'] + credentials['aws_access_key_id'] = options['aws_secret_key'] + credentials['aws_session_token'] = options['aws_security_token'] + + return credentials + + +class LookupModule(LookupBase): + def run(self, terms, variables, **kwargs): + + self.set_options(var_options=variables, direct=kwargs) + boto_credentials = _get_credentials(self._options) + + region = self._options['region'] + client = _boto3_conn(region, boto_credentials) + + attribute = kwargs.get('attribute') + params = {'AttributeNames': []} + check_ec2_classic = False + if 'has-ec2-classic' == attribute: + check_ec2_classic = True + params['AttributeNames'] = ['supported-platforms'] + elif attribute: + params['AttributeNames'] = [attribute] + + try: + response = client.describe_account_attributes(**params)['AccountAttributes'] + except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: + raise AnsibleError("Failed to describe account attributes: %s" % to_native(e)) + + if check_ec2_classic: + attr = response[0] + return any(value['AttributeValue'] == 'EC2' for value in attr['AttributeValues']) + + if attribute: + attr = response[0] + return [value['AttributeValue'] for value in attr['AttributeValues']] + + flattened = {} + for k_v_dict in response: + flattened[k_v_dict['AttributeName']] = [value['AttributeValue'] for value in k_v_dict['AttributeValues']] + return flattened