def get_info(self): info = { 'name': self.name, 'state': self.state, 'subscriptions_new': self.subscriptions, 'subscriptions_existing': self.subscriptions_existing, 'subscriptions_deleted': self.subscriptions_deleted, 'subscriptions_added': self.subscriptions_added, 'subscriptions_purge': self.purge_subscriptions, 'check_mode': self.check_mode, 'topic_created': self.topic_created, 'topic_deleted': self.topic_deleted, 'attributes_set': self.attributes_set, } if self.state != 'absent': if self.topic_arn in self._list_topics(): info.update( camel_dict_to_snake_dict( self.connection.get_topic_attributes( TopicArn=self.topic_arn)['Attributes'])) info['delivery_policy'] = info.pop('effective_delivery_policy') info['subscriptions'] = [ camel_dict_to_snake_dict(sub) for sub in self._list_topic_subscriptions() ] return info
def describe_subnets(connection, module): """ Describe Subnets. module : AnsibleModule object connection : boto3 client connection object """ # collect parameters filters = ansible_dict_to_boto3_filter_list(module.params.get('filters')) subnet_ids = module.params.get('subnet_ids') if subnet_ids is None: # Set subnet_ids to empty list if it is None subnet_ids = [] # init empty list for return vars subnet_info = list() # Get the basic VPC info try: response = describe_subnets_with_backoff(connection, subnet_ids, filters) except botocore.exceptions.ClientError as e: module.fail_json(msg=to_native(e), exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response)) for subnet in response['Subnets']: # for backwards compatibility subnet['id'] = subnet['SubnetId'] subnet_info.append(camel_dict_to_snake_dict(subnet)) # convert tag list to ansible dict subnet_info[-1]['tags'] = boto3_tag_list_to_ansible_dict(subnet.get('Tags', [])) module.exit_json(subnets=subnet_info)
def create_instance(module, client, instance_name): inst = find_instance_info(module, client, instance_name) if inst: module.exit_json(changed=False, instance=camel_dict_to_snake_dict(inst)) else: create_params = { 'instanceNames': [instance_name], 'availabilityZone': module.params.get('zone'), 'blueprintId': module.params.get('blueprint_id'), 'bundleId': module.params.get('bundle_id'), 'userData': module.params.get('user_data') } key_pair_name = module.params.get('key_pair_name') if key_pair_name: create_params['keyPairName'] = key_pair_name try: client.create_instances(**create_params) except botocore.exceptions.ClientError as e: module.fail_json_aws(e) wait = module.params.get('wait') if wait: desired_states = ['running'] wait_for_instance_state(module, client, instance_name, desired_states) inst = find_instance_info(module, client, instance_name, fail_if_not_found=True) module.exit_json(changed=True, instance=camel_dict_to_snake_dict(inst))
def set_logging(module, client, name, action): """ Starts or stops logging based on given state module : AnsibleModule object client : boto3 client connection object name : The name or ARN of the CloudTrail to operate on action : start or stop """ if action == 'start': try: client.start_logging(Name=name) return client.get_trail_status(Name=name) except ClientError as err: module.fail_json(msg=err.message, exception=traceback.format_exc(), **camel_dict_to_snake_dict(err.response)) elif action == 'stop': try: client.stop_logging(Name=name) return client.get_trail_status(Name=name) except ClientError as err: module.fail_json(msg=err.message, exception=traceback.format_exc(), **camel_dict_to_snake_dict(err.response)) else: module.fail_json(msg="Unsupported logging action")
def create_vpc_endpoint(client, module): params = dict() changed = False token_provided = False params['VpcId'] = module.params.get('vpc_id') params['ServiceName'] = module.params.get('service') params['DryRun'] = module.check_mode if module.params.get('route_table_ids'): params['RouteTableIds'] = module.params.get('route_table_ids') if module.params.get('client_token'): token_provided = True request_time = datetime.datetime.utcnow() params['ClientToken'] = module.params.get('client_token') policy = None if module.params.get('policy'): try: policy = json.loads(module.params.get('policy')) except ValueError as e: module.fail_json(msg=str(e), exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response)) elif module.params.get('policy_file'): try: with open(module.params.get('policy_file'), 'r') as json_data: policy = json.load(json_data) except Exception as e: module.fail_json(msg=str(e), exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response)) if policy: params['PolicyDocument'] = json.dumps(policy) try: changed = True result = camel_dict_to_snake_dict(client.create_vpc_endpoint(**params)['VpcEndpoint']) if token_provided and (request_time > result['creation_timestamp'].replace(tzinfo=None)): changed = False elif module.params.get('wait') and not module.check_mode: status_achieved, result = wait_for_status(client, module, result['vpc_endpoint_id'], 'available') if not status_achieved: module.fail_json(msg='Error waiting for vpc endpoint to become available - please check the AWS console') except botocore.exceptions.ClientError as e: if "DryRunOperation" in e.message: changed = True result = 'Would have created VPC Endpoint if not in check mode' elif "IdempotentParameterMismatch" in e.message: module.fail_json(msg="IdempotentParameterMismatch - updates of endpoints are not allowed by the API") elif "RouteAlreadyExists" in e.message: module.fail_json(msg="RouteAlreadyExists for one of the route tables - update is not allowed by the API") else: module.fail_json(msg=str(e), exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response)) except Exception as e: module.fail_json(msg=str(e), exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response)) return changed, result
def find_clusters(conn, module, identifier=None, tags=None): try: cluster_paginator = conn.get_paginator('describe_clusters') clusters = cluster_paginator.paginate().build_full_result() except ClientError as e: module.fail_json(msg=e.message, exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response)) matched_clusters = [] if identifier is not None: identifier_prog = re.compile('^' + identifier) for cluster in clusters['Clusters']: matched_identifier = True if identifier: matched_identifier = identifier_prog.search( cluster['ClusterIdentifier']) matched_tags = True if tags: matched_tags = match_tags(tags, cluster) if matched_identifier and matched_tags: matched_clusters.append(camel_dict_to_snake_dict(cluster)) return matched_clusters
def get_subnet_info(subnet): if 'Subnets' in subnet: return [get_subnet_info(s) for s in subnet['Subnets']] elif 'Subnet' in subnet: subnet = camel_dict_to_snake_dict(subnet['Subnet']) else: subnet = camel_dict_to_snake_dict(subnet) if 'tags' in subnet: subnet['tags'] = boto3_tag_list_to_ansible_dict(subnet['tags']) else: subnet['tags'] = dict() if 'subnet_id' in subnet: subnet['id'] = subnet['subnet_id'] del subnet['subnet_id'] subnet['ipv6_cidr_block'] = '' subnet['ipv6_association_id'] = '' ipv6set = subnet.get('ipv6_cidr_block_association_set') if ipv6set: for item in ipv6set: if item.get('ipv6_cidr_block_state', {}).get('state') in ('associated', 'associating'): subnet['ipv6_cidr_block'] = item['ipv6_cidr_block'] subnet['ipv6_association_id'] = item['association_id'] return subnet
def update_tags(module, connection, group, tags): changed = False existing_tags = connection.list_tags_for_resource(ResourceName=group['DBParameterGroupArn'])['TagList'] to_update, to_delete = compare_aws_tags(boto3_tag_list_to_ansible_dict(existing_tags), tags, module.params['purge_tags']) if to_update: try: connection.add_tags_to_resource(ResourceName=group['DBParameterGroupArn'], Tags=ansible_dict_to_boto3_tag_list(to_update)) changed = True except botocore.exceptions.ClientError as e: module.fail_json(msg="Couldn't add tags to parameter group: %s" % str(e), exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response)) except botocore.exceptions.ParamValidationError as e: # Usually a tag value has been passed as an int or bool, needs to be a string # The AWS exception message is reasonably ok for this purpose module.fail_json(msg="Couldn't add tags to parameter group: %s." % str(e), exception=traceback.format_exc()) if to_delete: try: connection.remove_tags_from_resource(ResourceName=group['DBParameterGroupArn'], TagKeys=to_delete) changed = True except botocore.exceptions.ClientError as e: module.fail_json(msg="Couldn't remove tags from parameter group: %s" % str(e), exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response)) return changed
def main(): argument_spec = ec2_argument_spec() argument_spec.update( dict( vpc_id=dict(), service=dict(), policy=dict(type='json'), policy_file=dict(type='path', aliases=['policy_path']), state=dict(default='present', choices=['present', 'absent']), wait=dict(type='bool', default=False), wait_timeout=dict(type='int', default=320, required=False), route_table_ids=dict(type='list'), vpc_endpoint_id=dict(), client_token=dict(), ) ) module = AnsibleModule( argument_spec=argument_spec, supports_check_mode=True, mutually_exclusive=[['policy', 'policy_file']], required_if=[ ['state', 'present', ['vpc_id', 'service']], ['state', 'absent', ['vpc_endpoint_id']], ] ) # Validate Requirements if not HAS_BOTO3: module.fail_json(msg='botocore and boto3 are required for this module') state = module.params.get('state') try: region, ec2_url, aws_connect_kwargs = get_aws_connection_info(module, boto3=True) except NameError as e: # Getting around the get_aws_connection_info boto reliance for region if "global name 'boto' is not defined" in e.message: module.params['region'] = botocore.session.get_session().get_config_variable('region') if not module.params['region']: module.fail_json(msg="Error - no region provided") else: module.fail_json(msg="Can't retrieve connection information - " + str(e), exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response)) try: region, ec2_url, aws_connect_kwargs = get_aws_connection_info(module, boto3=True) ec2 = boto3_conn(module, conn_type='client', resource='ec2', region=region, endpoint=ec2_url, **aws_connect_kwargs) except botocore.exceptions.NoCredentialsError as e: module.fail_json(msg="Failed to connect to AWS due to wrong or missing credentials: %s" % str(e), exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response)) # Ensure resource is present if state == 'present': (changed, results) = setup_creation(ec2, module) else: (changed, results) = setup_removal(ec2, module) module.exit_json(changed=changed, result=results)
def deregister_target(connection, module): """ Deregisters a target to a target group :param module: ansible module object :param connection: boto3 connection :return: """ deregister_unused = module.params.get("deregister_unused") target_group_arn = module.params.get("target_group_arn") target_id = module.params.get("target_id") target_port = module.params.get("target_port") target_status = module.params.get("target_status") target_status_timeout = module.params.get("target_status_timeout") changed = False if not target_group_arn: target_group_arn = convert_tg_name_to_arn(connection, module, module.params.get("target_group_name")) target = dict(Id=target_id) if target_port: target['Port'] = target_port target_description = describe_targets(connection, module, target_group_arn, target) current_target_state = target_description['TargetHealth']['State'] current_target_reason = target_description['TargetHealth'].get('Reason') needs_deregister = False if deregister_unused and current_target_state == 'unused': if current_target_reason != 'Target.NotRegistered': needs_deregister = True elif current_target_state not in ['unused', 'draining']: needs_deregister = True if needs_deregister: try: deregister_target_with_backoff(connection, target_group_arn, target) changed = True except ClientError as e: module.fail_json(msg="Unable to deregister target {0}: {1}".format(target, to_native(e)), exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response)) except BotoCoreError as e: module.fail_json(msg="Unable to deregister target {0}: {1}".format(target, to_native(e)), exception=traceback.format_exc()) else: if current_target_reason != 'Target.NotRegistered' and current_target_state != 'draining': module.warn(warning="Your specified target has an 'unused' state but is still registered to the target group. " + "To force deregistration use the 'deregister_unused' option.") if target_status: target_status_check(connection, module, target_group_arn, target, target_status, target_status_timeout) # Get all targets for the target group target_descriptions = describe_targets(connection, module, target_group_arn) module.exit_json(changed=changed, target_health_descriptions=camel_dict_to_snake_dict(target_descriptions), target_group_arn=target_group_arn)
def list_ec2_images(ec2_client, module): image_ids = module.params.get("image_ids") owners = module.params.get("owners") executable_users = module.params.get("executable_users") filters = module.params.get("filters") owner_param = [] # describe_images is *very* slow if you pass the `Owners` # param (unless it's self), for some reason. # Converting the owners to filters and removing from the # owners param greatly speeds things up. # Implementation based on aioue's suggestion in #24886 for owner in owners: if owner.isdigit(): if 'owner-id' not in filters: filters['owner-id'] = list() filters['owner-id'].append(owner) elif owner == 'self': # self not a valid owner-alias filter (https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeImages.html) owner_param.append(owner) else: if 'owner-alias' not in filters: filters['owner-alias'] = list() filters['owner-alias'].append(owner) filters = ansible_dict_to_boto3_filter_list(filters) try: images = ec2_client.describe_images(ImageIds=image_ids, Filters=filters, Owners=owner_param, ExecutableUsers=executable_users) images = [ camel_dict_to_snake_dict(image) for image in images["Images"] ] except (ClientError, BotoCoreError) as err: module.fail_json_aws(err, msg="error describing images") for image in images: try: image['tags'] = boto3_tag_list_to_ansible_dict( image.get('tags', [])) if module.params.get("describe_image_attributes"): launch_permissions = ec2_client.describe_image_attribute( Attribute='launchPermission', ImageId=image['image_id'])['LaunchPermissions'] image['launch_permissions'] = [ camel_dict_to_snake_dict(perm) for perm in launch_permissions ] except (ClientError, BotoCoreError) as err: # describing launch permissions of images owned by others is not permitted, but shouldn't cause failures pass images.sort( key=lambda e: e.get('creation_date', '') ) # it may be possible that creation_date does not always exist module.exit_json(images=images)
def tag_trail(module, client, tags, trail_arn, curr_tags=None, dry_run=False): """ Creates, updates, removes tags on a CloudTrail resource module : AnsibleModule object client : boto3 client connection object tags : Dict of tags converted from ansible_dict to boto3 list of dicts trail_arn : The ARN of the CloudTrail to operate on curr_tags : Dict of the current tags on resource, if any dry_run : true/false to determine if changes will be made if needed """ adds = [] removes = [] updates = [] changed = False if curr_tags is None: # No current tags so just convert all to a tag list adds = ansible_dict_to_boto3_tag_list(tags) else: curr_keys = set(curr_tags.keys()) new_keys = set(tags.keys()) add_keys = new_keys - curr_keys remove_keys = curr_keys - new_keys update_keys = dict() for k in curr_keys.intersection(new_keys): if curr_tags[k] != tags[k]: update_keys.update({k: tags[k]}) adds = get_tag_list(add_keys, tags) removes = get_tag_list(remove_keys, curr_tags) updates = get_tag_list(update_keys, tags) if removes or updates: changed = True if not dry_run: try: client.remove_tags(ResourceId=trail_arn, TagsList=removes + updates) except ClientError as err: module.fail_json(msg=err.message, exception=traceback.format_exc(), **camel_dict_to_snake_dict(err.response)) if updates or adds: changed = True if not dry_run: try: client.add_tags(ResourceId=trail_arn, TagsList=updates + adds) except ClientError as err: module.fail_json(msg=err.message, exception=traceback.format_exc(), **camel_dict_to_snake_dict(err.response)) return changed
def main(): argument_spec = dict( api_id=dict(type='str', required=False), state=dict(type='str', default='present', choices=['present', 'absent']), swagger_file=dict(type='path', default=None, aliases=['src', 'api_file']), swagger_dict=dict(type='json', default=None), swagger_text=dict(type='str', default=None), stage=dict(type='str', default=None), deploy_desc=dict(type='str', default="Automatic deployment by Ansible."), ) mutually_exclusive = [['swagger_file', 'swagger_dict', 'swagger_text']] # noqa: F841 module = AnsibleAWSModule( argument_spec=argument_spec, supports_check_mode=False, mutually_exclusive=mutually_exclusive, ) api_id = module.params.get('api_id') state = module.params.get('state') # noqa: F841 swagger_file = module.params.get('swagger_file') swagger_dict = module.params.get('swagger_dict') swagger_text = module.params.get('swagger_text') stage = module.params.get('stage') deploy_desc = module.params.get('deploy_desc') client = module.client('apigateway') changed = True # for now it will stay that way until we can sometimes avoid change conf_res = None dep_res = None del_res = None if state == "present": if api_id is None: api_id = create_empty_api(module, client) api_data = get_api_definitions(module, swagger_file=swagger_file, swagger_dict=swagger_dict, swagger_text=swagger_text) conf_res, dep_res = ensure_api_in_correct_state(module, client, api_id=api_id, api_data=api_data, stage=stage, deploy_desc=deploy_desc) if state == "absent": del_res = delete_rest_api(module, client, api_id) exit_args = {"changed": changed, "api_id": api_id} if conf_res is not None: exit_args['configure_response'] = camel_dict_to_snake_dict(conf_res) if dep_res is not None: exit_args['deploy_response'] = camel_dict_to_snake_dict(dep_res) if del_res is not None: exit_args['delete_response'] = camel_dict_to_snake_dict(del_res) module.exit_json(**exit_args)
def ensure_present(client, module): name = module.params.get('name') subnets = module.params['subnets'] groups = module.params['security_groups'] wait = module.params.get('wait') cluster = get_cluster(client, module) try: ec2 = module.client('ec2') vpc_id = ec2.describe_subnets(SubnetIds=[subnets[0]])['Subnets'][0]['VpcId'] groups = get_ec2_security_group_ids_from_names(groups, ec2, vpc_id) except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e: module.fail_json_aws(e, msg="Couldn't lookup security groups") if cluster: if set(cluster['resourcesVpcConfig']['subnetIds']) != set(subnets): module.fail_json(msg="Cannot modify subnets of existing cluster") if set(cluster['resourcesVpcConfig']['securityGroupIds']) != set(groups): module.fail_json(msg="Cannot modify security groups of existing cluster") if module.params.get('version') and module.params.get('version') != cluster['version']: module.fail_json(msg="Cannot modify version of existing cluster") if wait: wait_until(client, module, 'cluster_active') # Ensure that fields that are only available for active clusters are # included in the returned value cluster = get_cluster(client, module) module.exit_json(changed=False, **camel_dict_to_snake_dict(cluster)) if module.check_mode: module.exit_json(changed=True) try: params = dict(name=name, roleArn=module.params['role_arn'], resourcesVpcConfig=dict( subnetIds=subnets, securityGroupIds=groups), clientRequestToken='ansible-create-%s' % name) if module.params['version']: params['version'] = module.params['version'] cluster = client.create_cluster(**params)['cluster'] except botocore.exceptions.EndpointConnectionError as e: module.fail_json(msg="Region %s is not supported by EKS" % client.meta.region_name) except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e: module.fail_json_aws(e, msg="Couldn't create cluster %s" % name) if wait: wait_until(client, module, 'cluster_active') # Ensure that fields that are only available for active clusters are # included in the returned value cluster = get_cluster(client, module) module.exit_json(changed=True, **camel_dict_to_snake_dict(cluster))
def ensure_present(module, connection): groupname = module.params['name'] tags = module.params.get('tags') changed = False errors = [] try: response = connection.describe_db_parameter_groups(DBParameterGroupName=groupname) except botocore.exceptions.ClientError as e: if e.response['Error']['Code'] == 'DBParameterGroupNotFound': response = None else: module.fail_json(msg="Couldn't access parameter group information: %s" % str(e), exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response)) if not response: params = dict(DBParameterGroupName=groupname, DBParameterGroupFamily=module.params['engine'], Description=module.params['description']) if tags: params['Tags'] = ansible_dict_to_boto3_tag_list(tags) try: response = connection.create_db_parameter_group(**params) changed = True except botocore.exceptions.ClientError as e: module.fail_json(msg="Couldn't create parameter group: %s" % str(e), exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response)) else: group = response['DBParameterGroups'][0] if tags: changed = update_tags(module, connection, group, tags) if module.params.get('params'): params_changed, errors = update_parameters(module, connection) changed = changed or params_changed try: response = connection.describe_db_parameter_groups(DBParameterGroupName=groupname) group = camel_dict_to_snake_dict(response['DBParameterGroups'][0]) except botocore.exceptions.ClientError as e: module.fail_json(msg="Couldn't obtain parameter group information: %s" % str(e), exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response)) try: tags = connection.list_tags_for_resource(ResourceName=group['db_parameter_group_arn'])['TagList'] except botocore.exceptions.ClientError as e: module.fail_json(msg="Couldn't obtain parameter group tags: %s" % str(e), exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response)) group['tags'] = boto3_tag_list_to_ansible_dict(tags) module.exit_json(changed=changed, errors=errors, **group)
def list_mfa_devices(connection, module): user_name = module.params.get('user_name') changed = False args = {} if user_name is not None: args['UserName'] = user_name try: response = connection.list_mfa_devices(**args) except ClientError as e: module.fail_json(msg=e.message, **camel_dict_to_snake_dict(e.response)) module.exit_json(changed=changed, **camel_dict_to_snake_dict(response))
def main(): argument_spec = dict(state=dict(required=True, choices=['present', 'absent']), name=dict(), location=dict(), bandwidth=dict(choices=['1Gbps', '10Gbps']), link_aggregation_group=dict(), connection_id=dict(), forced_update=dict(type='bool', default=False)) module = AnsibleAWSModule(argument_spec=argument_spec, required_one_of=[('connection_id', 'name')], required_if=[('state', 'present', ('location', 'bandwidth'))]) connection = module.client('directconnect') state = module.params.get('state') try: connection_id = connection_exists( connection, connection_id=module.params.get('connection_id'), connection_name=module.params.get('name')) if not connection_id and module.params.get('connection_id'): module.fail_json( msg="The Direct Connect connection {0} does not exist.".format( module.params.get('connection_id'))) if state == 'present': changed, connection_id = ensure_present( connection, connection_id=connection_id, connection_name=module.params.get('name'), location=module.params.get('location'), bandwidth=module.params.get('bandwidth'), lag_id=module.params.get('link_aggregation_group'), forced_update=module.params.get('forced_update')) response = connection_status(connection, connection_id) elif state == 'absent': changed = ensure_absent(connection, connection_id) response = {} except DirectConnectError as e: if e.last_traceback: module.fail_json(msg=e.msg, exception=e.last_traceback, **camel_dict_to_snake_dict(e.exception.response)) else: module.fail_json(msg=e.msg) module.exit_json(changed=changed, **camel_dict_to_snake_dict(response))
def get_or_create_policy_version(module, iam, policy, policy_document): try: versions = iam.list_policy_versions( PolicyArn=policy['Arn'])['Versions'] except botocore.exceptions.ClientError as e: module.fail_json(msg="Couldn't list policy versions: %s" % str(e), exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response)) for v in versions: try: document = iam.get_policy_version( PolicyArn=policy['Arn'], VersionId=v['VersionId'])['PolicyVersion']['Document'] except botocore.exceptions.ClientError as e: module.fail_json(msg="Couldn't get policy version %s: %s" % (v['VersionId'], str(e)), exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response)) # If the current policy matches the existing one if not compare_policies(document, json.loads( to_native(policy_document))): return v, False # No existing version so create one # There is a service limit (typically 5) of policy versions. # # Rather than assume that it is 5, we'll try to create the policy # and if that doesn't work, delete the oldest non default policy version # and try again. try: version = iam.create_policy_version( PolicyArn=policy['Arn'], PolicyDocument=policy_document)['PolicyVersion'] return version, True except botocore.exceptions.ClientError as e: if e.response['Error']['Code'] == 'LimitExceeded': delete_oldest_non_default_version(module, iam, policy) try: version = iam.create_policy_version( PolicyArn=policy['Arn'], PolicyDocument=policy_document)['PolicyVersion'] return version, True except botocore.exceptions.ClientError as second_e: e = second_e # Handle both when the exception isn't LimitExceeded or # the second attempt still failed module.fail_json(msg="Couldn't create policy version: %s" % str(e), exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response))
def create_or_update_role(connection, module): params = generate_create_params(module) role_name = params['RoleName'] create_instance_profile = module.params.get('create_instance_profile') purge_policies = module.params.get('purge_policies') if purge_policies is None: purge_policies = True managed_policies = module.params.get('managed_policies') if managed_policies: # Attempt to list the policies early so we don't leave things behind if we can't find them. managed_policies = convert_friendly_names_to_arns( connection, module, managed_policies) changed = False # Get role role = get_role(connection, module, role_name) # If role is None, create it if role is None: role = create_basic_role(connection, module, params) changed = True else: changed |= update_role_tags(connection, module, params, role) changed |= update_role_assumed_policy(connection, module, params, role) changed |= update_role_description(connection, module, params, role) changed |= update_role_max_session_duration(connection, module, params, role) changed |= update_role_permissions_boundary(connection, module, params, role) if create_instance_profile: changed |= create_instance_profiles(connection, module, params, role) changed |= update_managed_policies(connection, module, params, role, managed_policies, purge_policies) # Get the role again if not role.get('MadeInCheckMode', False): role = get_role(connection, module, params['RoleName']) role['AttachedPolicies'] = get_attached_policy_list( connection, module, params['RoleName']) role['tags'] = get_role_tags(connection, module) module.exit_json(changed=changed, iam_role=camel_dict_to_snake_dict(role, ignore_list=['tags']), **camel_dict_to_snake_dict(role, ignore_list=['tags']))
def policy_details(client, module): """ Returns policy attached to a lambda function. :param client: AWS API client reference (boto3) :param module: Ansible module reference :return dict: """ if module.params.get('max_items') or module.params.get('next_marker'): module.fail_json( msg='Cannot specify max_items nor next_marker for query=policy.') lambda_info = dict() function_name = module.params.get('function_name') if function_name: try: # get_policy returns a JSON string so must convert to dict before reassigning to its key lambda_info.update(policy=json.loads( client.get_policy(FunctionName=function_name)['Policy'])) except ClientError as e: if e.response['Error']['Code'] == 'ResourceNotFoundException': lambda_info.update(policy={}) else: module.fail_json_aws( e, msg="Trying to get {0} policy".format(function_name)) else: module.fail_json( msg='Parameter function_name required for query=policy.') return {function_name: camel_dict_to_snake_dict(lambda_info)}
def list_eni(connection, module): if module.params.get("filters") is None: filters = [] else: filters = ansible_dict_to_boto3_filter_list( module.params.get("filters")) try: network_interfaces_result = connection.describe_network_interfaces( Filters=filters)['NetworkInterfaces'] except (ClientError, NoCredentialsError) as e: module.fail_json(msg=e.message) # Modify boto3 tags list to be ansible friendly dict and then camel_case camel_network_interfaces = [] for network_interface in network_interfaces_result: network_interface['TagSet'] = boto3_tag_list_to_ansible_dict( network_interface['TagSet']) # Added id to interface info to be compatible with return values of ec2_eni module: network_interface['Id'] = network_interface['NetworkInterfaceId'] camel_network_interfaces.append( camel_dict_to_snake_dict(network_interface)) module.exit_json(network_interfaces=camel_network_interfaces)
def list_customer_gateways(connection, module): params = dict() params['Filters'] = ansible_dict_to_boto3_filter_list( module.params.get('filters')) params['CustomerGatewayIds'] = module.params.get('customer_gateway_ids') try: result = json.loads( json.dumps(connection.describe_customer_gateways(**params), default=date_handler)) except (ClientError, BotoCoreError) as e: module.fail_json_aws(e, msg="Could not describe customer gateways") snaked_customer_gateways = [ camel_dict_to_snake_dict(gateway) for gateway in result['CustomerGateways'] ] if snaked_customer_gateways: for customer_gateway in snaked_customer_gateways: customer_gateway['tags'] = boto3_tag_list_to_ansible_dict( customer_gateway.get('tags', [])) customer_gateway_name = customer_gateway['tags'].get('Name') if customer_gateway_name: customer_gateway[ 'customer_gateway_name'] = customer_gateway_name module.exit_json(changed=False, customer_gateways=snaked_customer_gateways)
def create_or_update_bucket_cors(connection, module): name = module.params.get("name") rules = module.params.get("rules", []) changed = False try: current_camel_rules = connection.get_bucket_cors( Bucket=name)['CORSRules'] except ClientError: current_camel_rules = [] new_camel_rules = snake_dict_to_camel_dict(rules, capitalize_first=True) # compare_policies() takes two dicts and makes them hashable for comparison if compare_policies(new_camel_rules, current_camel_rules): changed = True if changed: try: cors = connection.put_bucket_cors( Bucket=name, CORSConfiguration={'CORSRules': new_camel_rules}) except ClientError as e: module.fail_json( msg="Unable to update CORS for bucket {0}: {1}".format( name, to_native(e)), exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response)) except BotoCoreError as e: module.fail_json(msg=to_native(e), exception=traceback.format_exc()) module.exit_json(changed=changed, name=name, rules=rules)
def main(): argument_spec = ec2_argument_spec() argument_spec.update(dict(log_group_name=dict(), )) module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) if module._name == 'cloudwatchlogs_log_group_facts': module.deprecate( "The 'cloudwatchlogs_log_group_facts' module has been renamed to 'cloudwatchlogs_log_group_info'", version='2.13') if not HAS_BOTO3: module.fail_json(msg='boto3 is required.') region, ec2_url, aws_connect_kwargs = get_aws_connection_info(module, boto3=True) logs = boto3_conn(module, conn_type='client', resource='logs', region=region, endpoint=ec2_url, **aws_connect_kwargs) desc_log_group = describe_log_group( client=logs, log_group_name=module.params['log_group_name'], module=module) final_log_group_snake = [] for log_group in desc_log_group['logGroups']: final_log_group_snake.append(camel_dict_to_snake_dict(log_group)) desc_log_group_result = dict(changed=False, log_groups=final_log_group_snake) module.exit_json(**desc_log_group_result)
def describe_iam_roles(module, client): name = module.params['name'] path_prefix = module.params['path_prefix'] if name: try: roles = [client.get_role(RoleName=name)['Role']] except botocore.exceptions.ClientError as e: if e.response['Error']['Code'] == 'NoSuchEntity': return [] else: module.fail_json_aws(e, msg="Couldn't get IAM role %s" % name) except botocore.exceptions.BotoCoreError as e: module.fail_json_aws(e, msg="Couldn't get IAM role %s" % name) else: params = dict() if path_prefix: if not path_prefix.startswith('/'): path_prefix = '/' + path_prefix if not path_prefix.endswith('/'): path_prefix = path_prefix + '/' params['PathPrefix'] = path_prefix try: roles = list_iam_roles_with_backoff(client, **params)['Roles'] except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: module.fail_json_aws(e, msg="Couldn't list IAM roles") return [ camel_dict_to_snake_dict(describe_iam_role(module, client, role), ignore_list=['tags']) for role in roles ]
def common_snapshot_info(module, conn, method, prefix, params): paginator = conn.get_paginator(method) try: results = paginator.paginate(**params).build_full_result()['%ss' % prefix] except is_boto3_error_code('%sNotFound' % prefix): results = [] except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # pylint: disable=duplicate-except module.fail_json_aws(e, "trying to get snapshot information") for snapshot in results: try: if snapshot['SnapshotType'] != 'shared': snapshot['Tags'] = boto3_tag_list_to_ansible_dict( conn.list_tags_for_resource(ResourceName=snapshot['%sArn' % prefix], aws_retry=True)['TagList']) except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: module.fail_json_aws( e, "Couldn't get tags for snapshot %s" % snapshot['%sIdentifier' % prefix]) return [ camel_dict_to_snake_dict(snapshot, ignore_list=['Tags']) for snapshot in results ]
def version_details(client, module): """ Returns all lambda function versions. :param client: AWS API client reference (boto3) :param module: Ansible module reference :return dict: """ lambda_info = dict() function_name = module.params.get('function_name') if function_name: params = dict() if module.params.get('max_items'): params['MaxItems'] = module.params.get('max_items') if module.params.get('next_marker'): params['Marker'] = module.params.get('next_marker') try: lambda_info.update(versions=client.list_versions_by_function( FunctionName=function_name, **params)['Versions']) except ClientError as e: if e.response['Error']['Code'] == 'ResourceNotFoundException': lambda_info.update(versions=[]) else: module.fail_json_aws( e, msg="Trying to get {0} versions".format(function_name)) else: module.fail_json( msg='Parameter function_name required for query=versions.') return {function_name: camel_dict_to_snake_dict(lambda_info)}
def alias_details(client, module): """ Returns list of aliases for a specified function. :param client: AWS API client reference (boto3) :param module: Ansible module reference :return dict: """ lambda_info = dict() function_name = module.params.get('function_name') if function_name: params = dict() if module.params.get('max_items'): params['MaxItems'] = module.params.get('max_items') if module.params.get('next_marker'): params['Marker'] = module.params.get('next_marker') try: lambda_info.update(aliases=client.list_aliases( FunctionName=function_name, **params)['Aliases']) except ClientError as e: if e.response['Error']['Code'] == 'ResourceNotFoundException': lambda_info.update(aliases=[]) else: module.fail_json_aws(e, msg="Trying to get aliases") else: module.fail_json( msg='Parameter function_name required for query=aliases.') return {function_name: camel_dict_to_snake_dict(lambda_info)}
def main(): argument_spec = ec2_argument_spec() argument_spec.update(dict( name=dict(type='str'), tags=dict(type='dict'), )) module = AnsibleModule(argument_spec=argument_spec) if module._name == 'ec2_asg_facts': module.deprecate( "The 'ec2_asg_facts' module has been renamed to 'ec2_asg_info'", version='2.13') if not HAS_BOTO3: module.fail_json(msg='boto3 required for this module') asg_name = module.params.get('name') asg_tags = module.params.get('tags') try: region, ec2_url, aws_connect_kwargs = get_aws_connection_info( module, boto3=True) autoscaling = boto3_conn(module, conn_type='client', resource='autoscaling', region=region, endpoint=ec2_url, **aws_connect_kwargs) except ClientError as e: module.fail_json(msg=e.message, **camel_dict_to_snake_dict(e.response)) results = find_asgs(autoscaling, module, name=asg_name, tags=asg_tags) module.exit_json(results=results)
def delete_dms_endpoint(connection): try: endpoint = describe_endpoints(connection, module.params.get('endpointidentifier')) endpoint_arn = endpoint['Endpoints'][0].get('EndpointArn') delete_arn = dict(EndpointArn=endpoint_arn) if module.params.get('wait'): delete_output = connection.delete_endpoint(**delete_arn) delete_waiter = get_endpoint_deleted_waiter(connection) delete_waiter.wait(Filters=[{ 'Name': 'endpoint-arn', 'Values': [endpoint_arn] }], WaiterConfig={ 'Delay': module.params.get('timeout'), 'MaxAttempts': module.params.get('retries') }) return delete_output else: return connection.delete_endpoint(**delete_arn) except botocore.exceptions.ClientError as e: module.fail_json(msg="Failed to delete the DMS endpoint.", exception=traceback.format_exc(), **camel_dict_to_snake_dict(e.response)) except botocore.exceptions.BotoCoreError as e: module.fail_json(msg="Failed to delete the DMS endpoint.", exception=traceback.format_exc())