示例#1
0
def main():

    argument_spec = ec2_argument_spec()
    argument_spec.update(dict(
        details=dict(type='bool', default=False),
        events=dict(type='bool', default=True),
        cluster=dict(),
        service=dict(type='list')
    ))

    module = AnsibleAWSModule(argument_spec=argument_spec, supports_check_mode=True)

    show_details = module.params.get('details')

    task_mgr = EcsServiceManager(module)
    if show_details:
        if module.params['service']:
            services = module.params['service']
        else:
            services = task_mgr.list_services(module.params['cluster'])['services']
        ecs_facts = dict(services=[], services_not_running=[])
        for chunk in chunks(services, 10):
            running_services, services_not_running = task_mgr.describe_services(module.params['cluster'], chunk)
            ecs_facts['services'].extend(running_services)
            ecs_facts['services_not_running'].extend(services_not_running)
    else:
        ecs_facts = task_mgr.list_services(module.params['cluster'])

    module.exit_json(changed=False, ansible_facts=ecs_facts, **ecs_facts)
def main():
    argument_spec = ec2_argument_spec()

    argument_spec.update(dict(
        caller_reference=dict(),
        distribution_id=dict(),
        alias=dict(),
        target_paths=dict(required=True, type='list')
    ))

    module = AnsibleAWSModule(argument_spec=argument_spec, supports_check_mode=False, mutually_exclusive=[['distribution_id', 'alias']])

    validation_mgr = CloudFrontInvalidationValidationManager(module)
    service_mgr = CloudFrontInvalidationServiceManager(module)

    caller_reference = module.params.get('caller_reference')
    distribution_id = module.params.get('distribution_id')
    alias = module.params.get('alias')
    target_paths = module.params.get('target_paths')

    result = {}

    distribution_id = validation_mgr.validate_distribution_id(distribution_id, alias)
    valid_target_paths = validation_mgr.validate_invalidation_batch(target_paths, caller_reference)
    valid_pascal_target_paths = snake_dict_to_camel_dict(valid_target_paths, True)
    result, changed = service_mgr.create_invalidation(distribution_id, valid_pascal_target_paths)

    module.exit_json(changed=changed, **camel_dict_to_snake_dict(result))
def main():
    argument_spec = ec2_argument_spec()
    argument_spec.update(
        dict(
            autoscaling_group_name=dict(required=True, type='str'),
            lifecycle_hook_name=dict(required=True, type='str'),
            transition=dict(type='str', choices=['autoscaling:EC2_INSTANCE_TERMINATING', 'autoscaling:EC2_INSTANCE_LAUNCHING']),
            role_arn=dict(type='str'),
            notification_target_arn=dict(type='str'),
            notification_meta_data=dict(type='str'),
            heartbeat_timeout=dict(type='int'),
            default_result=dict(default='ABANDON', choices=['ABANDON', 'CONTINUE']),
            state=dict(default='present', choices=['present', 'absent'])
        )
    )

    module = AnsibleAWSModule(argument_spec=argument_spec,
                              required_if=[['state', 'present', ['transition']]])
    state = module.params.get('state')

    region, ec2_url, aws_connect_params = get_aws_connection_info(module, boto3=True)

    connection = boto3_conn(module, conn_type='client', resource='autoscaling', region=region, endpoint=ec2_url, **aws_connect_params)

    changed = False

    if state == 'present':
        changed = create_lifecycle_hook(connection, module)
    elif state == 'absent':
        changed = delete_lifecycle_hook(connection, module)

    module.exit_json(changed=changed)
示例#4
0
def main():
    argument_spec = ec2_argument_spec()
    argument_spec.update(
        dict(
            name=dict(required=True),
            default_action=dict(choices=['block', 'allow', 'count']),
            metric_name=dict(),
            state=dict(default='present', choices=['present', 'absent']),
            rules=dict(type='list'),
            purge_rules=dict(type='bool', default=False)
        ),
    )
    module = AnsibleAWSModule(argument_spec=argument_spec,
                              required_if=[['state', 'present', ['default_action', 'rules']]])
    state = module.params.get('state')

    region, ec2_url, aws_connect_kwargs = get_aws_connection_info(module, boto3=True)
    client = boto3_conn(module, conn_type='client', resource='waf', region=region, endpoint=ec2_url, **aws_connect_kwargs)

    if state == 'present':
        (changed, results) = ensure_web_acl_present(client, module)
    else:
        (changed, results) = ensure_web_acl_absent(client, module)

    module.exit_json(changed=changed, web_acl=camel_dict_to_snake_dict(results))
示例#5
0
def main():
    argument_spec = dict(
        state=dict(type='str', default='present', choices=['present', 'absent']),
        filters=dict(type='dict', default={}),
        vpn_gateway_id=dict(type='str'),
        tags=dict(default={}, type='dict'),
        connection_type=dict(default='ipsec.1', type='str'),
        tunnel_options=dict(type='list', default=[]),
        static_only=dict(default=False, type='bool'),
        customer_gateway_id=dict(type='str'),
        vpn_connection_id=dict(type='str'),
        purge_tags=dict(type='bool', default=False),
        routes=dict(type='list', default=[]),
        purge_routes=dict(type='bool', default=False),
    )
    module = AnsibleAWSModule(argument_spec=argument_spec,
                              supports_check_mode=True)
    connection = module.client('ec2')

    state = module.params.get('state')
    parameters = dict(module.params)

    try:
        if state == 'present':
            changed, response = ensure_present(connection, parameters, module.check_mode)
        elif state == 'absent':
            changed, response = ensure_absent(connection, parameters, module.check_mode)
    except VPNConnectionException as e:
        if e.exception:
            module.fail_json_aws(e.exception, msg=e.msg)
        else:
            module.fail_json(msg=e.msg)

    module.exit_json(changed=changed, **camel_dict_to_snake_dict(response))
示例#6
0
def main():
    """
    Main entry point.

    :return dict: ansible facts
    """
    argument_spec = dict(
        function_name=dict(required=False, default=None, aliases=['function', 'name']),
        query=dict(required=False, choices=['aliases', 'all', 'config', 'mappings', 'policy', 'versions'], default='all'),
        event_source_arn=dict(required=False, default=None)
    )

    module = AnsibleAWSModule(
        argument_spec=argument_spec,
        supports_check_mode=True,
        mutually_exclusive=[],
        required_together=[]
    )

    # validate function_name if present
    function_name = module.params['function_name']
    if function_name:
        if not re.search(r"^[\w\-:]+$", function_name):
            module.fail_json(
                msg='Function name {0} is invalid. Names must contain only alphanumeric characters and hyphens.'.format(function_name)
            )
        if len(function_name) > 64:
            module.fail_json(msg='Function name "{0}" exceeds 64 character limit'.format(function_name))

    try:
        region, endpoint, aws_connect_kwargs = get_aws_connection_info(module, boto3=True)
        aws_connect_kwargs.update(dict(region=region,
                                       endpoint=endpoint,
                                       conn_type='client',
                                       resource='lambda'
                                       ))
        client = boto3_conn(module, **aws_connect_kwargs)
    except ClientError as e:
        module.fail_json_aws(e, "trying to set up boto connection")

    this_module = sys.modules[__name__]

    invocations = dict(
        aliases='alias_details',
        all='all_details',
        config='config_details',
        mappings='mapping_details',
        policy='policy_details',
        versions='version_details',
    )

    this_module_function = getattr(this_module, invocations[module.params['query']])
    all_facts = fix_return(this_module_function(client, module))

    results = dict(ansible_facts={'lambda_facts': {'function': all_facts}}, changed=False)

    if module.check_mode:
        results['msg'] = 'Check mode set but ignored for fact gathering only.'

    module.exit_json(**results)
示例#7
0
def main():
    """
     Module action handler
    """
    argument_spec = ec2_argument_spec()
    argument_spec.update(dict(
        id=dict(),
        name=dict(),
        tags=dict(type="dict", default={}),
        targets=dict(type="list", default=[])
    ))

    module = AnsibleAWSModule(argument_spec=argument_spec,
                              supports_check_mode=True)

    region, _, aws_connect_params = get_aws_connection_info(module, boto3=True)
    connection = EFSConnection(module, region, **aws_connect_params)

    name = module.params.get('name')
    fs_id = module.params.get('id')
    tags = module.params.get('tags')
    targets = module.params.get('targets')

    file_systems_info = connection.get_file_systems(fs_id, name)

    if tags:
        file_systems_info = [item for item in file_systems_info if has_tags(item['tags'], tags)]

    if targets:
        targets = [(item, prefix_to_attr(item)) for item in targets]
        file_systems_info = [item for item in file_systems_info if has_targets(item['mount_targets'], targets)]

    module.exit_json(changed=False, ansible_facts={'efs': file_systems_info})
def main():
    argument_spec = ec2_argument_spec()
    argument_spec.update(dict(
        vpc_id=dict(required=True),
        state=dict(default='present', choices=['present', 'absent'])
    ))

    module = AnsibleAWSModule(argument_spec=argument_spec, supports_check_mode=True)

    region, ec2_url, aws_connect_params = get_aws_connection_info(module, boto3=True)
    connection = boto3_conn(module, conn_type='client', resource='ec2', region=region, endpoint=ec2_url, **aws_connect_params)

    vpc_id = module.params.get('vpc_id')
    state = module.params.get('state')

    eigw_id = describe_eigws(module, connection, vpc_id)

    result = dict(gateway_id=eigw_id, vpc_id=vpc_id)
    changed = False

    if state == 'present' and not eigw_id:
        changed, result['gateway_id'] = create_eigw(module, connection, vpc_id)
    elif state == 'absent' and eigw_id:
        changed = delete_eigw(module, connection, eigw_id)

    module.exit_json(changed=changed, **result)
示例#9
0
def main():
    module = AnsibleAWSModule(
        argument_spec=dict(
            filters=dict(type='dict', default={})
        ),
        supports_check_mode=True
    )

    module.exit_json(changed=False, addresses=get_eips_details(module))
def main():
    argument_spec = ec2_argument_spec()
    argument_spec.update(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))
示例#11
0
def main():
    argument_spec = ec2_argument_spec()
    argument_spec.update(
        dict(
            name=dict(type='str'),
            state=dict(default='present', choices=['present', 'absent']),
            strategy=dict(default='cluster', choices=['cluster', 'spread'])
        )
    )

    module = AnsibleAWSModule(
        argument_spec=argument_spec,
        supports_check_mode=True
    )

    region, ec2_url, aws_connect_params = get_aws_connection_info(
        module, boto3=True)

    connection = boto3_conn(module,
                            resource='ec2', conn_type='client',
                            region=region, endpoint=ec2_url, **aws_connect_params)

    state = module.params.get("state")

    if state == 'present':
        placement_group = get_placement_group_details(connection, module)
        if placement_group is None:
            create_placement_group(connection, module)
        else:
            strategy = module.params.get("strategy")
            if placement_group['strategy'] == strategy:
                module.exit_json(
                    changed=False, placement_group=placement_group)
            else:
                name = module.params.get("name")
                module.fail_json(
                    msg=("Placement group '{}' exists, can't change strategy" +
                         " from '{}' to '{}'").format(
                             name,
                             placement_group['strategy'],
                             strategy))

    elif state == 'absent':
        placement_group = get_placement_group_details(connection, module)
        if placement_group is None:
            module.exit_json(changed=False)
        else:
            delete_placement_group(connection, module)
示例#12
0
def main():
    module = AnsibleAWSModule(
        argument_spec={},
        supports_check_mode=True,
    )

    client = module.client('sts')

    try:
        caller_identity = client.get_caller_identity()
        caller_identity.pop('ResponseMetadata', None)
        module.exit_json(
            changed=False,
            **camel_dict_to_snake_dict(caller_identity)
        )
    except (BotoCoreError, ClientError) as e:
        module.fail_json_aws(e, msg='Failed to retrieve caller identity')
def main():
    argument_spec = ec2_argument_spec()
    argument_spec.update(dict(
        task_definition=dict(required=True, type='str')
    ))

    module = AnsibleAWSModule(argument_spec=argument_spec, supports_check_mode=True)

    region, ec2_url, aws_connect_kwargs = get_aws_connection_info(module, boto3=True)
    ecs = boto3_conn(module, conn_type='client', resource='ecs',
                     region=region, endpoint=ec2_url, **aws_connect_kwargs)

    try:
        ecs_td = ecs.describe_task_definition(taskDefinition=module.params['task_definition'])['taskDefinition']
    except botocore.exceptions.ClientError:
        ecs_td = {}

    module.exit_json(changed=False, **camel_dict_to_snake_dict(ecs_td))
示例#14
0
def main():
    argument_spec = dict(
        zone=dict(required=True),
        state=dict(default='present', choices=['present', 'absent']),
        vpc_id=dict(default=None),
        vpc_region=dict(default=None),
        comment=dict(default=''),
        hosted_zone_id=dict(),
        delegation_set_id=dict(),
    )

    mutually_exclusive = [
        ['delegation_set_id', 'vpc_id'],
        ['delegation_set_id', 'vpc_region'],
    ]

    module = AnsibleAWSModule(
        argument_spec=argument_spec,
        mutually_exclusive=mutually_exclusive,
        supports_check_mode=True,
    )

    zone_in = module.params.get('zone').lower()
    state = module.params.get('state').lower()
    vpc_id = module.params.get('vpc_id')
    vpc_region = module.params.get('vpc_region')

    if not zone_in.endswith('.'):
        zone_in += "."

    private_zone = bool(vpc_id and vpc_region)

    client = module.client('route53')

    zones = find_zones(module, client, zone_in, private_zone)
    if state == 'present':
        changed, result = create(module, client, matching_zones=zones)
    elif state == 'absent':
        changed, result = delete(module, client, matching_zones=zones)

    if isinstance(result, dict):
        module.exit_json(changed=changed, result=result, **result)
    else:
        module.exit_json(changed=changed, result=result)
示例#15
0
def main():
    """
     Module action handler
    """
    argument_spec = ec2_argument_spec()
    argument_spec.update(dict(
        name=dict(aliases=['role_name']),
        path_prefix=dict(),
    ))

    module = AnsibleAWSModule(argument_spec=argument_spec,
                              supports_check_mode=True,
                              mutually_exclusive=[['name', 'path_prefix']])

    region, ec2_url, aws_connect_params = get_aws_connection_info(module, boto3=True)
    client = boto3_conn(module, conn_type='client', resource='iam',
                        region=region, endpoint=ec2_url, **aws_connect_params)

    module.exit_json(changed=False, iam_roles=describe_iam_roles(module, client))
示例#16
0
def main():
    filters_subspec = dict(
        country=dict(),
        field_to_match=dict(choices=['uri', 'query_string', 'header', 'method', 'body']),
        header=dict(),
        transformation=dict(choices=['none', 'compress_white_space',
                                     'html_entity_decode', 'lowercase',
                                     'cmd_line', 'url_decode']),
        position=dict(choices=['exactly', 'starts_with', 'ends_with',
                               'contains', 'contains_word']),
        comparison=dict(choices=['EQ', 'NE', 'LE', 'LT', 'GE', 'GT']),
        target_string=dict(),  # Bytes
        size=dict(type='int'),
        ip_address=dict(),
        regex_pattern=dict(),
    )
    argument_spec = ec2_argument_spec()
    argument_spec.update(
        dict(
            name=dict(required=True),
            type=dict(required=True, choices=['byte', 'geo', 'ip', 'regex', 'size', 'sql', 'xss']),
            filters=dict(type='list'),
            purge_filters=dict(type='bool', default=False),
            state=dict(default='present', choices=['present', 'absent']),
        ),
    )
    module = AnsibleAWSModule(argument_spec=argument_spec,
                              required_if=[['state', 'present', ['filters']]])
    state = module.params.get('state')

    region, ec2_url, aws_connect_kwargs = get_aws_connection_info(module, boto3=True)
    client = boto3_conn(module, conn_type='client', resource='waf', region=region, endpoint=ec2_url, **aws_connect_kwargs)

    condition = Condition(client, module)

    if state == 'present':
        (changed, results) = condition.ensure_condition_present()
        # return a condition agnostic ID for use by aws_waf_rule
        results['ConditionId'] = results[condition.conditionsetid]
    else:
        (changed, results) = condition.ensure_condition_absent()

    module.exit_json(changed=changed, condition=camel_dict_to_snake_dict(results))
示例#17
0
def main():
    argument_spec = ec2_argument_spec()
    argument_spec.update(
        dict(
            az=dict(default=None, required=False),
            cidr=dict(default=None, required=True),
            ipv6_cidr=dict(default='', required=False),
            state=dict(default='present', choices=['present', 'absent']),
            tags=dict(default={}, required=False, type='dict', aliases=['resource_tags']),
            vpc_id=dict(default=None, required=True),
            map_public=dict(default=False, required=False, type='bool'),
            assign_instances_ipv6=dict(default=False, required=False, type='bool'),
            wait=dict(type='bool', default=True),
            wait_timeout=dict(type='int', default=300, required=False),
            purge_tags=dict(default=True, type='bool')
        )
    )

    required_if = [('assign_instances_ipv6', True, ['ipv6_cidr'])]

    module = AnsibleAWSModule(argument_spec=argument_spec, supports_check_mode=True, required_if=required_if)

    if module.params.get('assign_instances_ipv6') and not module.params.get('ipv6_cidr'):
        module.fail_json(msg="assign_instances_ipv6 is True but ipv6_cidr is None or an empty string")

    if LooseVersion(botocore.__version__) < "1.7.0":
        module.warn("botocore >= 1.7.0 is required to use wait_timeout for custom wait times")

    region, ec2_url, aws_connect_params = get_aws_connection_info(module, boto3=True)
    connection = boto3_conn(module, conn_type='client', resource='ec2', region=region, endpoint=ec2_url, **aws_connect_params)

    state = module.params.get('state')

    try:
        if state == 'present':
            result = ensure_subnet_present(connection, module)
        elif state == 'absent':
            result = ensure_subnet_absent(connection, module)
    except botocore.exceptions.ClientError as e:
        module.fail_json_aws(e)

    module.exit_json(**result)
示例#18
0
def main():
    argument_spec = ec2_argument_spec()
    argument_spec.update(
        dict(
            name=dict(required=False),
        )
    )
    module = AnsibleAWSModule(argument_spec=argument_spec, supports_check_mode=True)

    region, ec2_url, aws_connect_kwargs = get_aws_connection_info(module, boto3=True)
    client = boto3_conn(module, conn_type='client', resource='waf', region=region, endpoint=ec2_url, **aws_connect_kwargs)

    web_acls = list_web_acls(client, module)
    name = module.params['name']
    if name:
        web_acls = [web_acl for web_acl in web_acls if
                    web_acl['Name'] == name]
        if not web_acls:
            module.fail_json(msg="WAF named %s not found" % name)
    module.exit_json(wafs=[get_web_acl(client, module, web_acl['WebACLId'])
                           for web_acl in web_acls])
def main():
    argument_spec = ec2_argument_spec()
    argument_spec.update(
        dict(
            names=dict(type='list', default=[])
        )
    )

    module = AnsibleAWSModule(
        argument_spec=argument_spec,
        supports_check_mode=True
    )

    region, ec2_url, aws_connect_params = get_aws_connection_info(
        module, boto3=True)

    connection = boto3_conn(module,
                            resource='ec2', conn_type='client',
                            region=region, endpoint=ec2_url, **aws_connect_params)

    placement_groups = get_placement_groups_details(connection, module)
    module.exit_json(changed=False, placement_groups=placement_groups)
def main():
    argument_spec = ec2_argument_spec()
    argument_spec.update(dict(
        state=dict(required=True, choices=['present', 'absent'], type='str'),
        policy_name=dict(required=True, type='str'),
        service_namespace=dict(required=True, choices=['ecs', 'elasticmapreduce', 'ec2', 'appstream', 'dynamodb'], type='str'),
        resource_id=dict(required=True, type='str'),
        scalable_dimension=dict(required=True, choices=['ecs:service:DesiredCount',
                                                        'ec2:spot-fleet-request:TargetCapacity',
                                                        'elasticmapreduce:instancegroup:InstanceCount',
                                                        'appstream:fleet:DesiredCapacity',
                                                        'dynamodb:table:ReadCapacityUnits',
                                                        'dynamodb:table:WriteCapacityUnits',
                                                        'dynamodb:index:ReadCapacityUnits',
                                                        'dynamodb:index:WriteCapacityUnits'
                                                        ], type='str'),
        policy_type=dict(required=True, choices=['StepScaling', 'TargetTrackingScaling'], type='str'),
        step_scaling_policy_configuration=dict(required=False, type='dict'),
        target_tracking_scaling_policy_configuration=dict(required=False, type='dict'),
        minimum_tasks=dict(required=False, type='int'),
        maximum_tasks=dict(required=False, type='int'),
        override_task_capacity=dict(required=False, type=bool)
    ))

    module = AnsibleAWSModule(argument_spec=argument_spec, supports_check_mode=True)

    connection = module.client('application-autoscaling')

    if module.params.get("state") == 'present':
        # A scalable target must be registered prior to creating a scaling policy
        scalable_target_result = create_scalable_target(connection, module)
        policy_result = create_scaling_policy(connection, module)
        # Merge the results of the scalable target creation and policy deletion/creation
        # There's no risk in overriding values since mutual keys have the same values in our case
        merged_result = merge_results(scalable_target_result, policy_result)
        module.exit_json(**merged_result)
    else:
        policy_result = delete_scaling_policy(connection, module)
        module.exit_json(**policy_result)
def main():
    argument_spec = ec2_argument_spec()
    argument_spec.update(dict(
        state=dict(required=True, choices=['present', 'absent']),
        id_to_associate=dict(required=True, aliases=['link_aggregation_group_id', 'connection_id']),
        public=dict(type='bool'),
        name=dict(),
        vlan=dict(type='int', default=100),
        bgp_asn=dict(type='int', default=65000),
        authentication_key=dict(),
        amazon_address=dict(),
        customer_address=dict(),
        address_type=dict(),
        cidr=dict(type='list'),
        virtual_gateway_id=dict(),
        virtual_interface_id=dict()
    ))

    module = AnsibleAWSModule(argument_spec=argument_spec,
                              required_one_of=[['virtual_interface_id', 'name']],
                              required_if=[['state', 'present', ['public']],
                                           ['public', False, ['virtual_gateway_id']],
                                           ['public', True, ['amazon_address']],
                                           ['public', True, ['customer_address']],
                                           ['public', True, ['cidr']]])

    region, ec2_url, aws_connect_kwargs = get_aws_connection_info(module, boto3=True)
    connection = boto3_conn(module, conn_type='client', resource='directconnect', region=region, endpoint=ec2_url, **aws_connect_kwargs)

    try:
        changed, latest_state = ensure_state(connection, module)
    except DirectConnectError as e:
        if e.exception:
            module.fail_json_aws(exception=e.exception, msg=e.msg)
        else:
            module.fail_json(msg=e.msg)

    module.exit_json(changed=changed, **camel_dict_to_snake_dict(latest_state))
示例#22
0
def main():
    argument_spec = ec2_argument_spec()
    argument_spec.update(
        dict(
            lookup=dict(default='tag', choices=['tag', 'id']),
            propagating_vgw_ids=dict(type='list'),
            purge_routes=dict(default=True, type='bool'),
            purge_subnets=dict(default=True, type='bool'),
            purge_tags=dict(default=False, type='bool'),
            route_table_id=dict(),
            routes=dict(default=[], type='list'),
            state=dict(default='present', choices=['present', 'absent']),
            subnets=dict(type='list'),
            tags=dict(type='dict', aliases=['resource_tags']),
            vpc_id=dict()
        )
    )

    module = AnsibleAWSModule(argument_spec=argument_spec,
                              required_if=[['lookup', 'id', ['route_table_id']],
                                           ['lookup', 'tag', ['vpc_id']],
                                           ['state', 'present', ['vpc_id']]],
                              supports_check_mode=True)

    region, ec2_url, aws_connect_params = get_aws_connection_info(module, boto3=True)

    connection = boto3_conn(module, conn_type='client', resource='ec2',
                            region=region, endpoint=ec2_url, **aws_connect_params)

    state = module.params.get('state')

    if state == 'present':
        result = ensure_route_table_present(connection, module)
    elif state == 'absent':
        result = ensure_route_table_absent(connection, module)

    module.exit_json(**result)
def main():
    argument_spec = ec2_argument_spec()
    argument_spec.update(
        dict(
            name=dict(required=True),
            schedule_expression=dict(),
            event_pattern=dict(),
            state=dict(choices=['present', 'disabled', 'absent'],
                       default='present'),
            description=dict(),
            role_arn=dict(),
            targets=dict(type='list', default=[]),
        )
    )
    module = AnsibleAWSModule(argument_spec=argument_spec)

    rule_data = dict(
        [(rf, module.params.get(rf)) for rf in CloudWatchEventRuleManager.RULE_FIELDS]
    )
    targets = module.params.get('targets')
    state = module.params.get('state')

    cwe_rule = CloudWatchEventRule(module,
                                   client=get_cloudwatchevents_client(module),
                                   **rule_data)
    cwe_rule_manager = CloudWatchEventRuleManager(cwe_rule, targets)

    if state == 'present':
        cwe_rule_manager.ensure_present()
    elif state == 'disabled':
        cwe_rule_manager.ensure_disabled()
    elif state == 'absent':
        cwe_rule_manager.ensure_absent()
    else:
        module.fail_json(msg="Invalid state '{0}' provided".format(state))

    module.exit_json(**cwe_rule_manager.fetch_aws_state())
示例#24
0
def main():
    argument_spec = ec2_argument_spec()
    argument_spec.update(
        dict(bucket=dict(required=True),
             dest=dict(default=None, type='path'),
             encrypt=dict(default=True, type='bool'),
             encryption_mode=dict(choices=['AES256', 'aws:kms'],
                                  default='AES256'),
             expiry=dict(default=600, type='int', aliases=['expiration']),
             headers=dict(type='dict'),
             marker=dict(default=""),
             max_keys=dict(default=1000, type='int'),
             metadata=dict(type='dict'),
             mode=dict(choices=[
                 'get', 'put', 'delete', 'create', 'geturl', 'getstr',
                 'delobj', 'list'
             ],
                       required=True),
             object=dict(),
             permission=dict(type='list', default=['private']),
             version=dict(default=None),
             overwrite=dict(aliases=['force'], default='always'),
             prefix=dict(default=""),
             retries=dict(aliases=['retry'], type='int', default=0),
             s3_url=dict(aliases=['S3_URL']),
             dualstack=dict(default='no', type='bool'),
             rgw=dict(default='no', type='bool'),
             src=dict(),
             ignore_nonexistent_bucket=dict(default=False, type='bool'),
             encryption_kms_key_id=dict()), )
    module = AnsibleAWSModule(
        argument_spec=argument_spec,
        supports_check_mode=True,
        required_if=[['mode', 'put', ['src', 'object']],
                     ['mode', 'get', ['dest', 'object']],
                     ['mode', 'getstr', ['object']],
                     ['mode', 'geturl', ['object']]],
    )

    bucket = module.params.get('bucket')
    encrypt = module.params.get('encrypt')
    expiry = module.params.get('expiry')
    dest = module.params.get('dest', '')
    headers = module.params.get('headers')
    marker = module.params.get('marker')
    max_keys = module.params.get('max_keys')
    metadata = module.params.get('metadata')
    mode = module.params.get('mode')
    obj = module.params.get('object')
    version = module.params.get('version')
    overwrite = module.params.get('overwrite')
    prefix = module.params.get('prefix')
    retries = module.params.get('retries')
    s3_url = module.params.get('s3_url')
    dualstack = module.params.get('dualstack')
    rgw = module.params.get('rgw')
    src = module.params.get('src')
    ignore_nonexistent_bucket = module.params.get('ignore_nonexistent_bucket')

    object_canned_acl = [
        "private", "public-read", "public-read-write", "aws-exec-read",
        "authenticated-read", "bucket-owner-read", "bucket-owner-full-control"
    ]
    bucket_canned_acl = [
        "private", "public-read", "public-read-write", "authenticated-read"
    ]

    if overwrite not in ['always', 'never', 'different']:
        if module.boolean(overwrite):
            overwrite = 'always'
        else:
            overwrite = 'never'

    region, ec2_url, aws_connect_kwargs = get_aws_connection_info(module,
                                                                  boto3=True)

    if region in ('us-east-1', '', None):
        # default to US Standard region
        location = 'us-east-1'
    else:
        # Boto uses symbolic names for locations but region strings will
        # actually work fine for everything except us-east-1 (US Standard)
        location = region

    if module.params.get('object'):
        obj = module.params['object']
        # If there is a top level object, do nothing - if the object starts with /
        # remove the leading character to maintain compatibility with Ansible versions < 2.4
        if obj.startswith('/'):
            obj = obj[1:]

    # Bucket deletion does not require obj.  Prevents ambiguity with delobj.
    if obj and mode == "delete":
        module.fail_json(msg='Parameter obj cannot be used with mode=delete')

    # allow eucarc environment variables to be used if ansible vars aren't set
    if not s3_url and 'S3_URL' in os.environ:
        s3_url = os.environ['S3_URL']

    if dualstack and s3_url is not None and 'amazonaws.com' not in s3_url:
        module.fail_json(msg='dualstack only applies to AWS S3')

    if dualstack and not module.botocore_at_least('1.4.45'):
        module.fail_json(msg='dualstack requires botocore >= 1.4.45')

    # rgw requires an explicit url
    if rgw and not s3_url:
        module.fail_json(msg='rgw flavour requires s3_url')

    # Look at s3_url and tweak connection settings
    # if connecting to RGW, Walrus or fakes3
    if s3_url:
        for key in ['validate_certs', 'security_token', 'profile_name']:
            aws_connect_kwargs.pop(key, None)
    s3 = get_s3_connection(module, aws_connect_kwargs, location, rgw, s3_url)

    validate = not ignore_nonexistent_bucket

    # separate types of ACLs
    bucket_acl = [
        acl for acl in module.params.get('permission')
        if acl in bucket_canned_acl
    ]
    object_acl = [
        acl for acl in module.params.get('permission')
        if acl in object_canned_acl
    ]
    error_acl = [
        acl for acl in module.params.get('permission')
        if acl not in bucket_canned_acl and acl not in object_canned_acl
    ]
    if error_acl:
        module.fail_json(msg='Unknown permission specified: %s' % error_acl)

    # First, we check to see if the bucket exists, we get "bucket" returned.
    bucketrtn = bucket_check(module, s3, bucket, validate=validate)

    if validate and mode not in ('create', 'put', 'delete') and not bucketrtn:
        module.fail_json(msg="Source bucket cannot be found.")

    # If our mode is a GET operation (download), go through the procedure as appropriate ...
    if mode == 'get':
        # Next, we check to see if the key in the bucket exists. If it exists, it also returns key_matches md5sum check.
        keyrtn = key_check(module,
                           s3,
                           bucket,
                           obj,
                           version=version,
                           validate=validate)
        if keyrtn is False:
            if version:
                module.fail_json(
                    msg="Key %s with version id %s does not exist." %
                    (obj, version))
            else:
                module.fail_json(msg="Key %s does not exist." % obj)

        # If the destination path doesn't exist or overwrite is True, no need to do the md5sum ETag check, so just download.
        # Compare the remote MD5 sum of the object with the local dest md5sum, if it already exists.
        if path_check(dest):
            # Determine if the remote and local object are identical
            if keysum_compare(module, dest, s3, bucket, obj, version=version):
                sum_matches = True
                if overwrite == 'always':
                    try:
                        download_s3file(module,
                                        s3,
                                        bucket,
                                        obj,
                                        dest,
                                        retries,
                                        version=version)
                    except Sigv4Required:
                        s3 = get_s3_connection(module,
                                               aws_connect_kwargs,
                                               location,
                                               rgw,
                                               s3_url,
                                               sig_4=True)
                        download_s3file(module,
                                        s3,
                                        bucket,
                                        obj,
                                        dest,
                                        retries,
                                        version=version)
                else:
                    module.exit_json(
                        msg=
                        "Local and remote object are identical, ignoring. Use overwrite=always parameter to force.",
                        changed=False)
            else:
                sum_matches = False

                if overwrite in ('always', 'different'):
                    try:
                        download_s3file(module,
                                        s3,
                                        bucket,
                                        obj,
                                        dest,
                                        retries,
                                        version=version)
                    except Sigv4Required:
                        s3 = get_s3_connection(module,
                                               aws_connect_kwargs,
                                               location,
                                               rgw,
                                               s3_url,
                                               sig_4=True)
                        download_s3file(module,
                                        s3,
                                        bucket,
                                        obj,
                                        dest,
                                        retries,
                                        version=version)
                else:
                    module.exit_json(
                        msg=
                        "WARNING: Checksums do not match. Use overwrite parameter to force download."
                    )
        else:
            try:
                download_s3file(module,
                                s3,
                                bucket,
                                obj,
                                dest,
                                retries,
                                version=version)
            except Sigv4Required:
                s3 = get_s3_connection(module,
                                       aws_connect_kwargs,
                                       location,
                                       rgw,
                                       s3_url,
                                       sig_4=True)
                download_s3file(module,
                                s3,
                                bucket,
                                obj,
                                dest,
                                retries,
                                version=version)

    # if our mode is a PUT operation (upload), go through the procedure as appropriate ...
    if mode == 'put':

        # if putting an object in a bucket yet to be created, acls for the bucket and/or the object may be specified
        # these were separated into the variables bucket_acl and object_acl above

        # Lets check the src path.
        if not path_check(src):
            module.fail_json(msg="Local object for PUT does not exist")

        # Lets check to see if bucket exists to get ground truth.
        if bucketrtn:
            keyrtn = key_check(module,
                               s3,
                               bucket,
                               obj,
                               version=version,
                               validate=validate)

        # Lets check key state. Does it exist and if it does, compute the ETag md5sum.
        if bucketrtn and keyrtn:
            # Compare the local and remote object
            if keysum_compare(module, src, s3, bucket, obj):
                sum_matches = True
                if overwrite == 'always':
                    # only use valid object acls for the upload_s3file function
                    module.params['permission'] = object_acl
                    upload_s3file(module, s3, bucket, obj, src, expiry,
                                  metadata, encrypt, headers)
                else:
                    get_download_url(module,
                                     s3,
                                     bucket,
                                     obj,
                                     expiry,
                                     changed=False)
            else:
                sum_matches = False
                if overwrite in ('always', 'different'):
                    # only use valid object acls for the upload_s3file function
                    module.params['permission'] = object_acl
                    upload_s3file(module, s3, bucket, obj, src, expiry,
                                  metadata, encrypt, headers)
                else:
                    module.exit_json(
                        msg=
                        "WARNING: Checksums do not match. Use overwrite parameter to force upload."
                    )

        # If neither exist (based on bucket existence), we can create both.
        if not bucketrtn:
            # only use valid bucket acls for create_bucket function
            module.params['permission'] = bucket_acl
            create_bucket(module, s3, bucket, location)
            # only use valid object acls for the upload_s3file function
            module.params['permission'] = object_acl
            upload_s3file(module, s3, bucket, obj, src, expiry, metadata,
                          encrypt, headers)

        # If bucket exists but key doesn't, just upload.
        if bucketrtn and not keyrtn:
            # only use valid object acls for the upload_s3file function
            module.params['permission'] = object_acl
            upload_s3file(module, s3, bucket, obj, src, expiry, metadata,
                          encrypt, headers)

    # Delete an object from a bucket, not the entire bucket
    if mode == 'delobj':
        if obj is None:
            module.fail_json(msg="object parameter is required")
        if bucket:
            deletertn = delete_key(module, s3, bucket, obj)
            if deletertn is True:
                module.exit_json(msg="Object deleted from bucket %s." % bucket,
                                 changed=True)
        else:
            module.fail_json(msg="Bucket parameter is required.")

    # Delete an entire bucket, including all objects in the bucket
    if mode == 'delete':
        if bucket:
            deletertn = delete_bucket(module, s3, bucket)
            if deletertn is True:
                module.exit_json(
                    msg="Bucket %s and all keys have been deleted." % bucket,
                    changed=True)
        else:
            module.fail_json(msg="Bucket parameter is required.")

    # Support for listing a set of keys
    if mode == 'list':
        exists = bucket_check(module, s3, bucket)

        # If the bucket does not exist then bail out
        if not exists:
            module.fail_json(msg="Target bucket (%s) cannot be found" % bucket)

        list_keys(module, s3, bucket, prefix, marker, max_keys)

    # Need to research how to create directories without "populating" a key, so this should just do bucket creation for now.
    # WE SHOULD ENABLE SOME WAY OF CREATING AN EMPTY KEY TO CREATE "DIRECTORY" STRUCTURE, AWS CONSOLE DOES THIS.
    if mode == 'create':

        # if both creating a bucket and putting an object in it, acls for the bucket and/or the object may be specified
        # these were separated above into the variables bucket_acl and object_acl

        if bucket and not obj:
            if bucketrtn:
                module.exit_json(msg="Bucket already exists.", changed=False)
            else:
                # only use valid bucket acls when creating the bucket
                module.params['permission'] = bucket_acl
                module.exit_json(msg="Bucket created successfully",
                                 changed=create_bucket(module, s3, bucket,
                                                       location))
        if bucket and obj:
            if obj.endswith('/'):
                dirobj = obj
            else:
                dirobj = obj + "/"
            if bucketrtn:
                if key_check(module, s3, bucket, dirobj):
                    module.exit_json(
                        msg="Bucket %s and key %s already exists." %
                        (bucket, obj),
                        changed=False)
                else:
                    # setting valid object acls for the create_dirkey function
                    module.params['permission'] = object_acl
                    create_dirkey(module, s3, bucket, dirobj, encrypt)
            else:
                # only use valid bucket acls for the create_bucket function
                module.params['permission'] = bucket_acl
                created = create_bucket(module, s3, bucket, location)
                # only use valid object acls for the create_dirkey function
                module.params['permission'] = object_acl
                create_dirkey(module, s3, bucket, dirobj, encrypt)

    # Support for grabbing the time-expired URL for an object in S3/Walrus.
    if mode == 'geturl':
        if not bucket and not obj:
            module.fail_json(msg="Bucket and Object parameters must be set")

        keyrtn = key_check(module,
                           s3,
                           bucket,
                           obj,
                           version=version,
                           validate=validate)
        if keyrtn:
            get_download_url(module, s3, bucket, obj, expiry)
        else:
            module.fail_json(msg="Key %s does not exist." % obj)

    if mode == 'getstr':
        if bucket and obj:
            keyrtn = key_check(module,
                               s3,
                               bucket,
                               obj,
                               version=version,
                               validate=validate)
            if keyrtn:
                try:
                    download_s3str(module, s3, bucket, obj, version=version)
                except Sigv4Required:
                    s3 = get_s3_connection(module,
                                           aws_connect_kwargs,
                                           location,
                                           rgw,
                                           s3_url,
                                           sig_4=True)
                    download_s3str(module, s3, bucket, obj, version=version)
            elif version is not None:
                module.fail_json(
                    msg="Key %s with version id %s does not exist." %
                    (obj, version))
            else:
                module.fail_json(msg="Key %s does not exist." % obj)

    module.exit_json(failed=False)
def main():
    argument_spec = ec2_argument_spec()
    argument_spec.update(
        dict(
            command=dict(choices=['create', 'facts', 'delete', 'modify'],
                         required=True),
            identifier=dict(required=True),
            node_type=dict(choices=[
                'ds1.xlarge', 'ds1.8xlarge', 'ds2.xlarge', 'ds2.8xlarge',
                'dc1.large', 'dc2.large', 'dc1.8xlarge', 'dw1.xlarge',
                'dw1.8xlarge', 'dw2.large', 'dw2.8xlarge'
            ],
                           required=False),
            username=dict(required=False),
            password=dict(no_log=True, required=False),
            db_name=dict(require=False),
            cluster_type=dict(choices=['multi-node', 'single-node'],
                              default='single-node'),
            cluster_security_groups=dict(aliases=['security_groups'],
                                         type='list'),
            vpc_security_group_ids=dict(aliases=['vpc_security_groups'],
                                        type='list'),
            skip_final_cluster_snapshot=dict(aliases=['skip_final_snapshot'],
                                             type='bool',
                                             default=False),
            final_cluster_snapshot_identifier=dict(
                aliases=['final_snapshot_id'], required=False),
            cluster_subnet_group_name=dict(aliases=['subnet']),
            availability_zone=dict(aliases=['aws_zone', 'zone']),
            preferred_maintenance_window=dict(
                aliases=['maintance_window', 'maint_window']),
            cluster_parameter_group_name=dict(aliases=['param_group_name']),
            automated_snapshot_retention_period=dict(
                aliases=['retention_period'], type='int'),
            port=dict(type='int'),
            cluster_version=dict(aliases=['version'], choices=['1.0']),
            allow_version_upgrade=dict(aliases=['version_upgrade'],
                                       type='bool',
                                       default=True),
            number_of_nodes=dict(type='int'),
            publicly_accessible=dict(type='bool', default=False),
            encrypted=dict(type='bool', default=False),
            elastic_ip=dict(required=False),
            new_cluster_identifier=dict(aliases=['new_identifier']),
            enhanced_vpc_routing=dict(type='bool', default=False),
            wait=dict(type='bool', default=False),
            wait_timeout=dict(type='int', default=300),
        ))

    required_if = [('command', 'delete', ['skip_final_cluster_snapshot']),
                   ('command', 'create', ['node_type', 'username',
                                          'password'])]

    module = AnsibleAWSModule(argument_spec=argument_spec,
                              required_if=required_if)

    command = module.params.get('command')
    skip_final_cluster_snapshot = module.params.get(
        'skip_final_cluster_snapshot')
    final_cluster_snapshot_identifier = module.params.get(
        'final_cluster_snapshot_identifier')
    # can't use module basic required_if check for this case
    if command == 'delete' and skip_final_cluster_snapshot is False and final_cluster_snapshot_identifier is None:
        module.fail_json(
            msg=
            "Need to specifiy final_cluster_snapshot_identifier if skip_final_cluster_snapshot is False"
        )

    conn = module.client('redshift')

    changed = True
    if command == 'create':
        (changed, cluster) = create_cluster(module, conn)

    elif command == 'facts':
        (changed, cluster) = describe_cluster(module, conn)

    elif command == 'delete':
        (changed, cluster) = delete_cluster(module, conn)

    elif command == 'modify':
        (changed, cluster) = modify_cluster(module, conn)

    module.exit_json(changed=changed, cluster=cluster)
def main():
    argument_spec = ec2_argument_spec()
    argument_spec.update(
        dict(state=dict(required=True,
                        choices=['present', 'absent', 'deleting']),
             name=dict(required=True, type='str'),
             cluster=dict(required=False, type='str'),
             task_definition=dict(required=False, type='str'),
             load_balancers=dict(required=False, default=[], type='list'),
             desired_count=dict(required=False, type='int'),
             client_token=dict(required=False, default='', type='str'),
             role=dict(required=False, default='', type='str'),
             delay=dict(required=False, type='int', default=10),
             repeat=dict(required=False, type='int', default=10),
             deployment_configuration=dict(required=False,
                                           default={},
                                           type='dict'),
             placement_constraints=dict(required=False,
                                        default=[],
                                        type='list'),
             placement_strategy=dict(required=False, default=[], type='list'),
             network_configuration=dict(required=False,
                                        type='dict',
                                        options=dict(
                                            subnets=dict(type='list'),
                                            security_groups=dict(type='list'),
                                            assign_public_ip=dict(type='bool'),
                                        )),
             launch_type=dict(required=False, choices=['EC2', 'FARGATE'])))

    module = AnsibleAWSModule(
        argument_spec=argument_spec,
        supports_check_mode=True,
        required_if=[('state', 'present', ['task_definition',
                                           'desired_count']),
                     ('launch_type', 'FARGATE', ['network_configuration'])],
        required_together=[['load_balancers', 'role']])

    service_mgr = EcsServiceManager(module)
    if module.params['network_configuration']:
        if not service_mgr.ecs_api_handles_network_configuration():
            module.fail_json(
                msg=
                'botocore needs to be version 1.7.44 or higher to use network configuration'
            )
        network_configuration = service_mgr.format_network_configuration(
            module.params['network_configuration'])
    else:
        network_configuration = None

    deployment_configuration = map_complex_type(
        module.params['deployment_configuration'],
        DEPLOYMENT_CONFIGURATION_TYPE_MAP)

    deploymentConfiguration = snake_dict_to_camel_dict(
        deployment_configuration)

    try:
        existing = service_mgr.describe_service(module.params['cluster'],
                                                module.params['name'])
    except Exception as e:
        module.fail_json(msg="Exception describing service '" +
                         module.params['name'] + "' in cluster '" +
                         module.params['cluster'] + "': " + str(e))

    results = dict(changed=False)

    if module.params['launch_type']:
        if not module.botocore_at_least('1.8.4'):
            module.fail_json(
                msg=
                'botocore needs to be version 1.8.4 or higher to use launch_type'
            )

    if module.params['state'] == 'present':

        matching = False
        update = False

        if existing and 'status' in existing and existing['status'] == "ACTIVE":
            if service_mgr.is_matching_service(module.params, existing):
                matching = True
                results['service'] = existing
            else:
                update = True

        if not matching:
            if not module.check_mode:

                role = module.params['role']
                clientToken = module.params['client_token']
                loadBalancers = module.params['load_balancers']

                if update:
                    if (existing['loadBalancers'] or []) != loadBalancers:
                        module.fail_json(
                            msg=
                            "It is not possible to update the load balancers of an existing service"
                        )
                    # update required
                    response = service_mgr.update_service(
                        module.params['name'], module.params['cluster'],
                        module.params['task_definition'],
                        module.params['desired_count'],
                        deploymentConfiguration, network_configuration)
                else:
                    for loadBalancer in loadBalancers:
                        if 'containerPort' in loadBalancer:
                            loadBalancer['containerPort'] = int(
                                loadBalancer['containerPort'])
                    # doesn't exist. create it.
                    try:
                        response = service_mgr.create_service(
                            module.params['name'], module.params['cluster'],
                            module.params['task_definition'], loadBalancers,
                            module.params['desired_count'], clientToken, role,
                            deploymentConfiguration,
                            module.params['placement_constraints'],
                            module.params['placement_strategy'],
                            network_configuration,
                            module.params['launch_type'])
                    except botocore.exceptions.ClientError as e:
                        module.fail_json_aws(e, msg="Couldn't create service")

                results['service'] = response

            results['changed'] = True

    elif module.params['state'] == 'absent':
        if not existing:
            pass
        else:
            # it exists, so we should delete it and mark changed.
            # return info about the cluster deleted
            del existing['deployments']
            del existing['events']
            results['ansible_facts'] = existing
            if 'status' in existing and existing['status'] == "INACTIVE":
                results['changed'] = False
            else:
                if not module.check_mode:
                    try:
                        service_mgr.delete_service(module.params['name'],
                                                   module.params['cluster'])
                    except botocore.exceptions.ClientError as e:
                        module.fail_json_aws(e, msg="Couldn't delete service")
                results['changed'] = True

    elif module.params['state'] == 'deleting':
        if not existing:
            module.fail_json(msg="Service '" + module.params['name'] +
                             " not found.")
            return
        # it exists, so we should delete it and mark changed.
        # return info about the cluster deleted
        delay = module.params['delay']
        repeat = module.params['repeat']
        time.sleep(delay)
        for i in range(repeat):
            existing = service_mgr.describe_service(module.params['cluster'],
                                                    module.params['name'])
            status = existing['status']
            if status == "INACTIVE":
                results['changed'] = True
                break
            time.sleep(delay)
        if i is repeat - 1:
            module.fail_json(msg="Service still not deleted after " +
                             str(repeat) + " tries of " + str(delay) +
                             " seconds each.")
            return

    module.exit_json(**results)
示例#27
0
def main():
    argument_spec = dict(
        name=dict(required=True),
        cidr_block=dict(type='list', required=True),
        tenancy=dict(choices=['default', 'dedicated'], default='default'),
        dns_support=dict(type='bool', default=True),
        dns_hostnames=dict(type='bool', default=True),
        dhcp_opts_id=dict(),
        tags=dict(type='dict', aliases=['resource_tags']),
        state=dict(choices=['present', 'absent'], default='present'),
        multi_ok=dict(type='bool', default=False),
        purge_cidrs=dict(type='bool', default=False),
    )

    module = AnsibleAWSModule(argument_spec=argument_spec,
                              supports_check_mode=True)

    name = module.params.get('name')
    cidr_block = get_cidr_network_bits(module, module.params.get('cidr_block'))
    purge_cidrs = module.params.get('purge_cidrs')
    tenancy = module.params.get('tenancy')
    dns_support = module.params.get('dns_support')
    dns_hostnames = module.params.get('dns_hostnames')
    dhcp_id = module.params.get('dhcp_opts_id')
    tags = module.params.get('tags')
    state = module.params.get('state')
    multi = module.params.get('multi_ok')

    changed = False

    connection = module.client(
        'ec2',
        retry_decorator=AWSRetry.jittered_backoff(
            retries=8,
            delay=3,
            catch_extra_error_codes=['InvalidVpcID.NotFound']))

    if dns_hostnames and not dns_support:
        module.fail_json(
            msg=
            'In order to enable DNS Hostnames you must also enable DNS support'
        )

    if state == 'present':

        # Check if VPC exists
        vpc_id = vpc_exists(module, connection, name, cidr_block, multi)

        if vpc_id is None:
            vpc_id = create_vpc(connection, module, cidr_block[0], tenancy)
            changed = True

        vpc_obj = get_vpc(module, connection, vpc_id)

        associated_cidrs = dict(
            (cidr['CidrBlock'], cidr['AssociationId'])
            for cidr in vpc_obj.get('CidrBlockAssociationSet', [])
            if cidr['CidrBlockState']['State'] != 'disassociated')
        to_add = [cidr for cidr in cidr_block if cidr not in associated_cidrs]
        to_remove = [
            associated_cidrs[cidr] for cidr in associated_cidrs
            if cidr not in cidr_block
        ]
        expected_cidrs = [
            cidr for cidr in associated_cidrs
            if associated_cidrs[cidr] not in to_remove
        ] + to_add

        if len(cidr_block) > 1:
            for cidr in to_add:
                changed = True
                connection.associate_vpc_cidr_block(CidrBlock=cidr,
                                                    VpcId=vpc_id)

        if purge_cidrs:
            for association_id in to_remove:
                changed = True
                try:
                    connection.disassociate_vpc_cidr_block(
                        AssociationId=association_id)
                except (botocore.exceptions.ClientError,
                        botocore.exceptions.BotoCoreError) as e:
                    module.fail_json_aws(
                        e,
                        "Unable to disassociate {0}. You must detach or delete all gateways and resources that "
                        "are associated with the CIDR block before you can disassociate it."
                        .format(association_id))

        if dhcp_id is not None:
            try:
                if update_dhcp_opts(connection, module, vpc_obj, dhcp_id):
                    changed = True
            except (botocore.exceptions.ClientError,
                    botocore.exceptions.BotoCoreError) as e:
                module.fail_json_aws(e, "Failed to update DHCP options")

        if tags is not None or name is not None:
            try:
                if update_vpc_tags(connection, module, vpc_id, tags, name):
                    changed = True
            except (botocore.exceptions.ClientError,
                    botocore.exceptions.BotoCoreError) as e:
                module.fail_json_aws(e, msg="Failed to update tags")

        current_dns_enabled = connection.describe_vpc_attribute(
            Attribute='enableDnsSupport', VpcId=vpc_id,
            aws_retry=True)['EnableDnsSupport']['Value']
        current_dns_hostnames = connection.describe_vpc_attribute(
            Attribute='enableDnsHostnames', VpcId=vpc_id,
            aws_retry=True)['EnableDnsHostnames']['Value']
        if current_dns_enabled != dns_support:
            changed = True
            if not module.check_mode:
                try:
                    connection.modify_vpc_attribute(
                        VpcId=vpc_id, EnableDnsSupport={'Value': dns_support})
                except (botocore.exceptions.ClientError,
                        botocore.exceptions.BotoCoreError) as e:
                    module.fail_json_aws(
                        e, "Failed to update enabled dns support attribute")
        if current_dns_hostnames != dns_hostnames:
            changed = True
            if not module.check_mode:
                try:
                    connection.modify_vpc_attribute(
                        VpcId=vpc_id,
                        EnableDnsHostnames={'Value': dns_hostnames})
                except (botocore.exceptions.ClientError,
                        botocore.exceptions.BotoCoreError) as e:
                    module.fail_json_aws(
                        e, "Failed to update enabled dns hostnames attribute")

        # wait for associated cidrs to match
        if to_add or to_remove:
            try:
                connection.get_waiter('vpc_available').wait(
                    VpcIds=[vpc_id],
                    Filters=[{
                        'Name': 'cidr-block-association.cidr-block',
                        'Values': expected_cidrs
                    }])
            except (botocore.exceptions.ClientError,
                    botocore.exceptions.BotoCoreError) as e:
                module.fail_json_aws(e, "Failed to wait for CIDRs to update")

        # try to wait for enableDnsSupport and enableDnsHostnames to match
        wait_for_vpc_attribute(connection, module, vpc_id, 'enableDnsSupport',
                               dns_support)
        wait_for_vpc_attribute(connection, module, vpc_id,
                               'enableDnsHostnames', dns_hostnames)

        final_state = camel_dict_to_snake_dict(
            get_vpc(module, connection, vpc_id))
        final_state['tags'] = boto3_tag_list_to_ansible_dict(
            final_state.get('tags', []))
        final_state['id'] = final_state.pop('vpc_id')

        module.exit_json(changed=changed, vpc=final_state)

    elif state == 'absent':

        # Check if VPC exists
        vpc_id = vpc_exists(module, connection, name, cidr_block, multi)

        if vpc_id is not None:
            try:
                if not module.check_mode:
                    connection.delete_vpc(VpcId=vpc_id)
                changed = True
            except (botocore.exceptions.ClientError,
                    botocore.exceptions.BotoCoreError) as e:
                module.fail_json_aws(
                    e,
                    msg=
                    "Failed to delete VPC {0} You may want to use the ec2_vpc_subnet, ec2_vpc_igw, "
                    "and/or ec2_vpc_route_table modules to ensure the other components are absent."
                    .format(vpc_id))

        module.exit_json(changed=changed, vpc={})
示例#28
0
def main():
    template_options = dict(
        block_device_mappings=dict(
            type='list',
            options=dict(
                device_name=dict(),
                ebs=dict(
                    type='dict',
                    options=dict(
                        delete_on_termination=dict(type='bool'),
                        encrypted=dict(type='bool'),
                        iops=dict(type='int'),
                        kms_key_id=dict(),
                        snapshot_id=dict(),
                        volume_size=dict(type='int'),
                        volume_type=dict(),
                    ),
                ),
                no_device=dict(),
                virtual_name=dict(),
            ),
        ),
        cpu_options=dict(
            type='dict',
            options=dict(
                core_count=dict(type='int'),
                threads_per_core=dict(type='int'),
            ),
        ),
        credit_specification=dict(
            dict(type='dict'),
            options=dict(
                cpu_credits=dict(),
            ),
        ),
        disable_api_termination=dict(type='bool'),
        ebs_optimized=dict(type='bool'),
        elastic_gpu_specifications=dict(
            options=dict(type=dict()),
            type='list',
        ),
        iam_instance_profile=dict(),
        image_id=dict(),
        instance_initiated_shutdown_behavior=dict(choices=['stop', 'terminate']),
        instance_market_options=dict(
            type='dict',
            options=dict(
                market_type=dict(),
                spot_options=dict(
                    type='dict',
                    options=dict(
                        block_duration_minutes=dict(type='int'),
                        instance_interruption_behavior=dict(choices=['hibernate', 'stop', 'terminate']),
                        max_price=dict(),
                        spot_instance_type=dict(choices=['one-time', 'persistent']),
                    ),
                ),
            ),
        ),
        instance_type=dict(),
        kernel_id=dict(),
        key_name=dict(),
        monitoring=dict(
            type='dict',
            options=dict(
                enabled=dict(type='bool')
            ),
        ),
        network_interfaces=dict(
            type='list',
            options=dict(
                associate_public_ip_address=dict(type='bool'),
                delete_on_termination=dict(type='bool'),
                description=dict(),
                device_index=dict(type='int'),
                groups=dict(type='list'),
                ipv6_address_count=dict(type='int'),
                ipv6_addresses=dict(type='list'),
                network_interface_id=dict(),
                private_ip_address=dict(),
                subnet_id=dict(),
            ),
        ),
        placement=dict(
            options=dict(
                affinity=dict(),
                availability_zone=dict(),
                group_name=dict(),
                host_id=dict(),
                tenancy=dict(),
            ),
            type='dict',
        ),
        ram_disk_id=dict(),
        security_group_ids=dict(type='list'),
        security_groups=dict(type='list'),
        tags=dict(type='dict'),
        user_data=dict(),
    )

    arg_spec = dict(
        state=dict(choices=['present', 'absent'], default='present'),
        template_name=dict(aliases=['name']),
        template_id=dict(aliases=['id']),
        default_version=dict(default='latest'),
    )

    arg_spec.update(template_options)

    module = AnsibleAWSModule(
        argument_spec=arg_spec,
        required_one_of=[
            ('template_name', 'template_id')
        ],
        supports_check_mode=True
    )

    if not module.boto3_at_least('1.6.0'):
        module.fail_json(msg="ec2_launch_template requires boto3 >= 1.6.0")

    for interface in (module.params.get('network_interfaces') or []):
        if interface.get('ipv6_addresses'):
            interface['ipv6_addresses'] = [{'ipv6_address': x} for x in interface['ipv6_addresses']]

    if module.params.get('state') == 'present':
        out = create_or_update(module, template_options)
        out.update(format_module_output(module))
    elif module.params.get('state') == 'absent':
        out = delete_template(module)
    else:
        module.fail_json(msg='Unsupported value "{0}" for `state` parameter'.format(module.params.get('state')))

    module.exit_json(**out)
示例#29
0
def main():
    argument_spec = ec2_argument_spec()
    argument_spec.update(
        dict(
            operation=dict(required=True, choices=['run', 'start', 'stop']),
            cluster=dict(required=False, type='str'),  # R S P
            task_definition=dict(required=False, type='str'),  # R* S*
            overrides=dict(required=False, type='dict'),  # R S
            count=dict(required=False, type='int'),  # R
            task=dict(required=False, type='str'),  # P*
            container_instances=dict(required=False, type='list'),  # S*
            started_by=dict(required=False, type='str'),  # R S
            network_configuration=dict(required=False, type='dict'),
            launch_type=dict(required=False, choices=['EC2', 'FARGATE'])))

    module = AnsibleAWSModule(argument_spec=argument_spec,
                              supports_check_mode=True,
                              required_if=[('launch_type', 'FARGATE',
                                            ['network_configuration'])])

    # Validate Inputs
    if module.params['operation'] == 'run':
        if 'task_definition' not in module.params and module.params[
                'task_definition'] is None:
            module.fail_json(
                msg="To run a task, a task_definition must be specified")
        task_to_list = module.params['task_definition']
        status_type = "RUNNING"

    if module.params['operation'] == 'start':
        if 'task_definition' not in module.params and module.params[
                'task_definition'] is None:
            module.fail_json(
                msg="To start a task, a task_definition must be specified")
        if 'container_instances' not in module.params and module.params[
                'container_instances'] is None:
            module.fail_json(
                msg="To start a task, container instances must be specified")
        task_to_list = module.params['task']
        status_type = "RUNNING"

    if module.params['operation'] == 'stop':
        if 'task' not in module.params and module.params['task'] is None:
            module.fail_json(msg="To stop a task, a task must be specified")
        if 'task_definition' not in module.params and module.params[
                'task_definition'] is None:
            module.fail_json(
                msg="To stop a task, a task definition must be specified")
        task_to_list = module.params['task_definition']
        status_type = "STOPPED"

    service_mgr = EcsExecManager(module)

    if module.params[
            'network_configuration'] and not service_mgr.ecs_api_handles_network_configuration(
            ):
        module.fail_json(
            msg=
            'botocore needs to be version 1.7.44 or higher to use network configuration'
        )

    if module.params[
            'launch_type'] and not service_mgr.ecs_api_handles_launch_type():
        module.fail_json(
            msg=
            'botocore needs to be version 1.8.4 or higher to use launch type')

    existing = service_mgr.list_tasks(module.params['cluster'], task_to_list,
                                      status_type)

    results = dict(changed=False)
    if module.params['operation'] == 'run':
        if existing:
            # TBD - validate the rest of the details
            results['task'] = existing
        else:
            if not module.check_mode:
                results['task'] = service_mgr.run_task(
                    module.params['cluster'], module.params['task_definition'],
                    module.params['overrides'], module.params['count'],
                    module.params['started_by'], module.params['launch_type'])
            results['changed'] = True

    elif module.params['operation'] == 'start':
        if existing:
            # TBD - validate the rest of the details
            results['task'] = existing
        else:
            if not module.check_mode:
                results['task'] = service_mgr.start_task(
                    module.params['cluster'], module.params['task_definition'],
                    module.params['overrides'],
                    module.params['container_instances'],
                    module.params['started_by'])
            results['changed'] = True

    elif module.params['operation'] == 'stop':
        if existing:
            results['task'] = existing
        else:
            if not module.check_mode:
                # it exists, so we should delete it and mark changed.
                # return info about the cluster deleted
                results['task'] = service_mgr.stop_task(
                    module.params['cluster'], module.params['task'])
            results['changed'] = True

    module.exit_json(**results)
示例#30
0
def main():
    argument_spec = dict(
        resource=dict(required=True),
        tags=dict(type='dict'),
        purge_tags=dict(type='bool', default=False),
        state=dict(default='present', choices=['present', 'absent', 'list']),
    )
    required_if = [('state', 'present', ['tags']),
                   ('state', 'absent', ['tags'])]

    module = AnsibleAWSModule(argument_spec=argument_spec,
                              required_if=required_if,
                              supports_check_mode=True)

    resource = module.params['resource']
    tags = module.params['tags']
    state = module.params['state']
    purge_tags = module.params['purge_tags']

    result = {'changed': False}

    ec2 = module.client('ec2')

    current_tags = get_tags(ec2, module, resource)

    if state == 'list':
        module.exit_json(changed=False, tags=current_tags)

    add_tags, remove = compare_aws_tags(current_tags,
                                        tags,
                                        purge_tags=purge_tags)

    remove_tags = {}
    if state == 'absent':
        for key in tags:
            if key in current_tags and (tags[key] is None
                                        or current_tags[key] == tags[key]):
                remove_tags[key] = current_tags[key]

    for key in remove:
        remove_tags[key] = current_tags[key]

    if remove_tags:
        result['changed'] = True
        result['removed_tags'] = remove_tags
        if not module.check_mode:
            try:
                ec2.delete_tags(
                    Resources=[resource],
                    Tags=ansible_dict_to_boto3_tag_list(remove_tags))
            except (BotoCoreError, ClientError) as e:
                module.fail_json_aws(
                    e,
                    msg='Failed to remove tags {0} from resource {1}'.format(
                        remove_tags, resource))

    if state == 'present' and add_tags:
        result['changed'] = True
        result['added_tags'] = add_tags
        current_tags.update(add_tags)
        if not module.check_mode:
            try:
                ec2.create_tags(Resources=[resource],
                                Tags=ansible_dict_to_boto3_tag_list(add_tags))
            except (BotoCoreError, ClientError) as e:
                module.fail_json_aws(
                    e,
                    msg='Failed to set tags {0} on resource {1}'.format(
                        add_tags, resource))

    result['tags'] = get_tags(ec2, module, resource)
    module.exit_json(**result)
示例#31
0
def main():
    argument_spec = dict(
        name=dict(required=True),
        state=dict(default='present', choices=['present', 'absent']),
        runtime=dict(),
        role=dict(),
        handler=dict(),
        zip_file=dict(aliases=['src']),
        s3_bucket=dict(),
        s3_key=dict(),
        s3_object_version=dict(),
        description=dict(default=''),
        timeout=dict(type='int', default=3),
        memory_size=dict(type='int', default=128),
        vpc_subnet_ids=dict(type='list'),
        vpc_security_group_ids=dict(type='list'),
        environment_variables=dict(type='dict'),
        dead_letter_arn=dict(),
        tags=dict(type='dict'),
    )

    mutually_exclusive = [['zip_file', 's3_key'],
                          ['zip_file', 's3_bucket'],
                          ['zip_file', 's3_object_version']]

    required_together = [['s3_key', 's3_bucket'],
                         ['vpc_subnet_ids', 'vpc_security_group_ids']]

    required_if = [['state', 'present', ['runtime', 'handler', 'role']]]

    module = AnsibleAWSModule(argument_spec=argument_spec,
                              supports_check_mode=True,
                              mutually_exclusive=mutually_exclusive,
                              required_together=required_together,
                              required_if=required_if)

    name = module.params.get('name')
    state = module.params.get('state').lower()
    runtime = module.params.get('runtime')
    role = module.params.get('role')
    handler = module.params.get('handler')
    s3_bucket = module.params.get('s3_bucket')
    s3_key = module.params.get('s3_key')
    s3_object_version = module.params.get('s3_object_version')
    zip_file = module.params.get('zip_file')
    description = module.params.get('description')
    timeout = module.params.get('timeout')
    memory_size = module.params.get('memory_size')
    vpc_subnet_ids = module.params.get('vpc_subnet_ids')
    vpc_security_group_ids = module.params.get('vpc_security_group_ids')
    environment_variables = module.params.get('environment_variables')
    dead_letter_arn = module.params.get('dead_letter_arn')
    tags = module.params.get('tags')

    check_mode = module.check_mode
    changed = False

    region, ec2_url, aws_connect_kwargs = get_aws_connection_info(module, boto3=True)
    if not region:
        module.fail_json(msg='region must be specified')

    try:
        client = boto3_conn(module, conn_type='client', resource='lambda',
                            region=region, endpoint=ec2_url, **aws_connect_kwargs)
    except (ClientError, ValidationError) as e:
        module.fail_json_aws(e, msg="Trying to connect to AWS")

    if state == 'present':
        if role.startswith('arn:aws:iam'):
            role_arn = role
        else:
            # get account ID and assemble ARN
            account_id = get_account_id(module, region=region, endpoint=ec2_url, **aws_connect_kwargs)
            role_arn = 'arn:aws:iam::{0}:role/{1}'.format(account_id, role)

    # Get function configuration if present, False otherwise
    current_function = get_current_function(client, name)

    # Update existing Lambda function
    if state == 'present' and current_function:

        # Get current state
        current_config = current_function['Configuration']
        current_version = None

        # Update function configuration
        func_kwargs = {'FunctionName': name}

        # Update configuration if needed
        if role_arn and current_config['Role'] != role_arn:
            func_kwargs.update({'Role': role_arn})
        if handler and current_config['Handler'] != handler:
            func_kwargs.update({'Handler': handler})
        if description and current_config['Description'] != description:
            func_kwargs.update({'Description': description})
        if timeout and current_config['Timeout'] != timeout:
            func_kwargs.update({'Timeout': timeout})
        if memory_size and current_config['MemorySize'] != memory_size:
            func_kwargs.update({'MemorySize': memory_size})
        if (environment_variables is not None) and (current_config.get(
                'Environment', {}).get('Variables', {}) != environment_variables):
            func_kwargs.update({'Environment': {'Variables': environment_variables}})
        if dead_letter_arn is not None:
            if current_config.get('DeadLetterConfig'):
                if current_config['DeadLetterConfig']['TargetArn'] != dead_letter_arn:
                    func_kwargs.update({'DeadLetterConfig': {'TargetArn': dead_letter_arn}})
            else:
                if dead_letter_arn != "":
                    func_kwargs.update({'DeadLetterConfig': {'TargetArn': dead_letter_arn}})

        # Check for unsupported mutation
        if current_config['Runtime'] != runtime:
            module.fail_json(msg='Cannot change runtime. Please recreate the function')

        # If VPC configuration is desired
        if vpc_subnet_ids or vpc_security_group_ids:
            if not vpc_subnet_ids or not vpc_security_group_ids:
                module.fail_json(msg='vpc connectivity requires at least one security group and one subnet')

            if 'VpcConfig' in current_config:
                # Compare VPC config with current config
                current_vpc_subnet_ids = current_config['VpcConfig']['SubnetIds']
                current_vpc_security_group_ids = current_config['VpcConfig']['SecurityGroupIds']

                subnet_net_id_changed = sorted(vpc_subnet_ids) != sorted(current_vpc_subnet_ids)
                vpc_security_group_ids_changed = sorted(vpc_security_group_ids) != sorted(current_vpc_security_group_ids)

            if 'VpcConfig' not in current_config or subnet_net_id_changed or vpc_security_group_ids_changed:
                new_vpc_config = {'SubnetIds': vpc_subnet_ids,
                                  'SecurityGroupIds': vpc_security_group_ids}
                func_kwargs.update({'VpcConfig': new_vpc_config})
        else:
            # No VPC configuration is desired, assure VPC config is empty when present in current config
            if 'VpcConfig' in current_config and current_config['VpcConfig'].get('VpcId'):
                func_kwargs.update({'VpcConfig': {'SubnetIds': [], 'SecurityGroupIds': []}})

        # Upload new configuration if configuration has changed
        if len(func_kwargs) > 1:
            try:
                if not check_mode:
                    response = client.update_function_configuration(**func_kwargs)
                    current_version = response['Version']
                changed = True
            except (ParamValidationError, ClientError) as e:
                module.fail_json_aws(e, msg="Trying to update lambda configuration")

        # Update code configuration
        code_kwargs = {'FunctionName': name, 'Publish': True}

        # Update S3 location
        if s3_bucket and s3_key:
            # If function is stored on S3 always update
            code_kwargs.update({'S3Bucket': s3_bucket, 'S3Key': s3_key})

            # If S3 Object Version is given
            if s3_object_version:
                code_kwargs.update({'S3ObjectVersion': s3_object_version})

        # Compare local checksum, update remote code when different
        elif zip_file:
            local_checksum = sha256sum(zip_file)
            remote_checksum = current_config['CodeSha256']

            # Only upload new code when local code is different compared to the remote code
            if local_checksum != remote_checksum:
                try:
                    with open(zip_file, 'rb') as f:
                        encoded_zip = f.read()
                    code_kwargs.update({'ZipFile': encoded_zip})
                except IOError as e:
                    module.fail_json(msg=str(e), exception=traceback.format_exc())

        # Tag Function
        if tags is not None:
            if set_tag(client, module, tags, current_function):
                changed = True

        # Upload new code if needed (e.g. code checksum has changed)
        if len(code_kwargs) > 2:
            try:
                if not check_mode:
                    response = client.update_function_code(**code_kwargs)
                    current_version = response['Version']
                changed = True
            except (ParamValidationError, ClientError) as e:
                module.fail_json_aws(e, msg="Trying to upload new code")

        # Describe function code and configuration
        response = get_current_function(client, name, qualifier=current_version)
        if not response:
            module.fail_json(msg='Unable to get function information after updating')

        # We're done
        module.exit_json(changed=changed, **camel_dict_to_snake_dict(response))

    # Function doesn't exists, create new Lambda function
    elif state == 'present':
        if s3_bucket and s3_key:
            # If function is stored on S3
            code = {'S3Bucket': s3_bucket,
                    'S3Key': s3_key}
            if s3_object_version:
                code.update({'S3ObjectVersion': s3_object_version})
        elif zip_file:
            # If function is stored in local zipfile
            try:
                with open(zip_file, 'rb') as f:
                    zip_content = f.read()

                code = {'ZipFile': zip_content}
            except IOError as e:
                module.fail_json(msg=str(e), exception=traceback.format_exc())

        else:
            module.fail_json(msg='Either S3 object or path to zipfile required')

        func_kwargs = {'FunctionName': name,
                       'Publish': True,
                       'Runtime': runtime,
                       'Role': role_arn,
                       'Code': code,
                       'Timeout': timeout,
                       'MemorySize': memory_size,
                       }

        if description is not None:
            func_kwargs.update({'Description': description})

        if handler is not None:
            func_kwargs.update({'Handler': handler})

        if environment_variables:
            func_kwargs.update({'Environment': {'Variables': environment_variables}})

        if dead_letter_arn:
            func_kwargs.update({'DeadLetterConfig': {'TargetArn': dead_letter_arn}})

        # If VPC configuration is given
        if vpc_subnet_ids or vpc_security_group_ids:
            if not vpc_subnet_ids or not vpc_security_group_ids:
                module.fail_json(msg='vpc connectivity requires at least one security group and one subnet')

            func_kwargs.update({'VpcConfig': {'SubnetIds': vpc_subnet_ids,
                                              'SecurityGroupIds': vpc_security_group_ids}})

        # Finally try to create function
        try:
            if not check_mode:
                response = client.create_function(**func_kwargs)
                current_version = response['Version']
            changed = True
        except (ParamValidationError, ClientError) as e:
            module.fail_json_aws(e, msg="Trying to create function")

        # Tag Function
        if tags is not None:
            if set_tag(client, module, tags, get_current_function(client, name)):
                changed = True

        response = get_current_function(client, name, qualifier=current_version)
        if not response:
            module.fail_json(msg='Unable to get function information after creating')
        module.exit_json(changed=changed, **camel_dict_to_snake_dict(response))

    # Delete existing Lambda function
    if state == 'absent' and current_function:
        try:
            if not check_mode:
                client.delete_function(FunctionName=name)
            changed = True
        except (ParamValidationError, ClientError) as e:
            module.fail_json_aws(e, msg="Trying to delete Lambda function")

        module.exit_json(changed=changed)

    # Function already absent, do nothing
    elif state == 'absent':
        module.exit_json(changed=changed)
def main():
    argument_spec = dict(
        name=dict(required=True),
        state=dict(choices=['absent', 'present'], default='present'),
        tags=dict(type='dict'),
    )

    required_if = [['state', 'present', ['tags']]]

    module = AnsibleAWSModule(
        argument_spec=argument_spec,
        supports_check_mode=False,
        required_if=required_if,
    )

    if not HAS_BOTO3:
        module.fail_json(msg='boto3 and botocore are required for this module')

    name = module.params.get('name')
    state = module.params.get('state').lower()
    tags = module.params.get('tags')
    if tags:
        tags = ansible_dict_to_boto3_tag_list(tags, 'key', 'value')

    client = module.client('inspector')

    try:
        existing_target_arn = client.list_assessment_targets(
            filter={'assessmentTargetNamePattern': name},
        ).get('assessmentTargetArns')[0]

        existing_target = camel_dict_to_snake_dict(
            client.describe_assessment_targets(
                assessmentTargetArns=[existing_target_arn],
            ).get('assessmentTargets')[0]
        )

        existing_resource_group_arn = existing_target.get('resource_group_arn')
        existing_resource_group_tags = client.describe_resource_groups(
            resourceGroupArns=[existing_resource_group_arn],
        ).get('resourceGroups')[0].get('tags')

        target_exists = True
    except (
        botocore.exceptions.BotoCoreError,
        botocore.exceptions.ClientError,
    ) as e:
        module.fail_json_aws(e, msg="trying to retrieve targets")
    except IndexError:
        target_exists = False

    if state == 'present' and target_exists:
        ansible_dict_tags = boto3_tag_list_to_ansible_dict(tags)
        ansible_dict_existing_tags = boto3_tag_list_to_ansible_dict(
            existing_resource_group_tags
        )
        tags_to_add, tags_to_remove = compare_aws_tags(
            ansible_dict_tags,
            ansible_dict_existing_tags
        )
        if not (tags_to_add or tags_to_remove):
            existing_target.update({'tags': ansible_dict_existing_tags})
            module.exit_json(changed=False, **existing_target)
        else:
            try:
                updated_resource_group_arn = client.create_resource_group(
                    resourceGroupTags=tags,
                ).get('resourceGroupArn')

                client.update_assessment_target(
                    assessmentTargetArn=existing_target_arn,
                    assessmentTargetName=name,
                    resourceGroupArn=updated_resource_group_arn,
                )

                updated_target = camel_dict_to_snake_dict(
                    client.describe_assessment_targets(
                        assessmentTargetArns=[existing_target_arn],
                    ).get('assessmentTargets')[0]
                )

                updated_target.update({'tags': ansible_dict_tags})
                module.exit_json(changed=True, **updated_target),
            except (
                botocore.exceptions.BotoCoreError,
                botocore.exceptions.ClientError,
            ) as e:
                module.fail_json_aws(e, msg="trying to update target")

    elif state == 'present' and not target_exists:
        try:
            new_resource_group_arn = client.create_resource_group(
                resourceGroupTags=tags,
            ).get('resourceGroupArn')

            new_target_arn = client.create_assessment_target(
                assessmentTargetName=name,
                resourceGroupArn=new_resource_group_arn,
            ).get('assessmentTargetArn')

            new_target = camel_dict_to_snake_dict(
                client.describe_assessment_targets(
                    assessmentTargetArns=[new_target_arn],
                ).get('assessmentTargets')[0]
            )

            new_target.update({'tags': boto3_tag_list_to_ansible_dict(tags)})
            module.exit_json(changed=True, **new_target)
        except (
            botocore.exceptions.BotoCoreError,
            botocore.exceptions.ClientError,
        ) as e:
            module.fail_json_aws(e, msg="trying to create target")

    elif state == 'absent' and target_exists:
        try:
            client.delete_assessment_target(
                assessmentTargetArn=existing_target_arn,
            )
            module.exit_json(changed=True)
        except (
            botocore.exceptions.BotoCoreError,
            botocore.exceptions.ClientError,
        ) as e:
            module.fail_json_aws(e, msg="trying to delete target")

    elif state == 'absent' and not target_exists:
        module.exit_json(changed=False)
示例#33
0
def main():
    argument_spec = ec2_argument_spec()
    argument_spec.update(
        dict(
            alias=dict(aliases=['key_alias']),
            policy_mode=dict(aliases=['mode'],
                             choices=['grant', 'deny'],
                             default='grant'),
            policy_role_name=dict(aliases=['role_name']),
            policy_role_arn=dict(aliases=['role_arn']),
            policy_grant_types=dict(aliases=['grant_types'], type='list'),
            policy_clean_invalid_entries=dict(
                aliases=['clean_invalid_entries'], type='bool', default=True),
            key_id=dict(aliases=['key_arn']),
            description=dict(),
            enabled=dict(type='bool', default=True),
            tags=dict(type='dict', default={}),
            purge_tags=dict(type='bool', default=False),
            grants=dict(type='list', default=[]),
            policy=dict(),
            purge_grants=dict(type='bool', default=False),
            state=dict(default='present', choices=['present', 'absent']),
        ))

    module = AnsibleAWSModule(
        supports_check_mode=True,
        argument_spec=argument_spec,
        required_one_of=[['alias', 'key_id']],
    )

    result = {}
    mode = module.params['policy_mode']

    kms = module.client('kms')
    iam = module.client('iam')

    all_keys = get_kms_facts(kms, module)
    key_id = module.params.get('key_id')
    alias = module.params.get('alias')
    if alias.startswith('alias/'):
        alias = alias[6:]
    if key_id:
        filtr = ('key-id', key_id)
    elif module.params.get('alias'):
        filtr = ('alias', alias)

    candidate_keys = [
        key for key in all_keys if key_matches_filter(key, filtr)
    ]

    if module.params.get('policy_grant_types') or mode == 'deny':
        module.deprecate(
            'Managing the KMS IAM Policy via policy_mode and policy_grant_types is fragile'
            ' and has been deprecated in favour of the policy option.',
            version='2.13')
        if module.params.get('policy_role_name'
                             ) and not module.params.get('policy_role_arn'):
            module.params['policy_role_arn'] = get_arn_from_role_name(
                iam, module.params['policy_role_name'])
        if not module.params.get('policy_role_arn'):
            module.fail_json(
                msg='policy_role_arn or policy_role_name is required to {0}'.
                format(module.params['policy_mode']))

        # check the grant types for 'grant' only.
        if mode == 'grant':
            for g in module.params['policy_grant_types']:
                if g not in statement_label:
                    module.fail_json(
                        msg='{0} is an unknown grant type.'.format(g))

        ret = do_policy_grant(kms,
                              candidate_keys[0]['key_arn'],
                              module.params['policy_role_arn'],
                              module.params['policy_grant_types'],
                              mode=mode,
                              dry_run=module.check_mode,
                              clean_invalid_entries=module.
                              params['policy_clean_invalid_entries'])
        result.update(ret)

        module.exit_json(**result)
    else:

        if module.params.get('state') == 'present':
            if candidate_keys:
                update_key(kms, module, candidate_keys[0])
            else:
                if module.params.get('key_id'):
                    module.fail_json(
                        msg="Could not find key with id %s to update")
                else:
                    create_key(kms, module)
        else:
            if candidate_keys:
                delete_key(kms, module, candidate_keys[0])
            else:
                module.exit_json(changed=False)
示例#34
0
def main():
    argument_spec = dict(
        name=dict(required=True),
        cidr_block=dict(type='list', required=True),
        tenancy=dict(choices=['default', 'dedicated'], default='default'),
        dns_support=dict(type='bool', default=True),
        dns_hostnames=dict(type='bool', default=True),
        dhcp_opts_id=dict(),
        tags=dict(type='dict', aliases=['resource_tags']),
        state=dict(choices=['present', 'absent'], default='present'),
        multi_ok=dict(type='bool', default=False),
        purge_cidrs=dict(type='bool', default=False),
    )

    module = AnsibleAWSModule(
        argument_spec=argument_spec,
        supports_check_mode=True
    )

    name = module.params.get('name')
    cidr_block = module.params.get('cidr_block')
    purge_cidrs = module.params.get('purge_cidrs')
    tenancy = module.params.get('tenancy')
    dns_support = module.params.get('dns_support')
    dns_hostnames = module.params.get('dns_hostnames')
    dhcp_id = module.params.get('dhcp_opts_id')
    tags = module.params.get('tags')
    state = module.params.get('state')
    multi = module.params.get('multi_ok')

    changed = False

    connection = module.client(
        'ec2',
        retry_decorator=AWSRetry.jittered_backoff(
            retries=8, delay=3, catch_extra_error_codes=['InvalidVpcID.NotFound']
        )
    )

    if dns_hostnames and not dns_support:
        module.fail_json(msg='In order to enable DNS Hostnames you must also enable DNS support')

    if state == 'present':

        # Check if VPC exists
        vpc_id = vpc_exists(module, connection, name, cidr_block, multi)

        if vpc_id is None:
            vpc_id = create_vpc(connection, module, cidr_block[0], tenancy)
            changed = True

        vpc_obj = get_vpc(module, connection, vpc_id)

        associated_cidrs = dict((cidr['CidrBlock'], cidr['AssociationId']) for cidr in vpc_obj.get('CidrBlockAssociationSet', [])
                                if cidr['CidrBlockState']['State'] != 'disassociated')
        to_add = [cidr for cidr in cidr_block if cidr not in associated_cidrs]
        to_remove = [associated_cidrs[cidr] for cidr in associated_cidrs if cidr not in cidr_block]
        expected_cidrs = [cidr for cidr in associated_cidrs if associated_cidrs[cidr] not in to_remove] + to_add

        if len(cidr_block) > 1:
            for cidr in to_add:
                changed = True
                connection.associate_vpc_cidr_block(CidrBlock=cidr, VpcId=vpc_id)

        if purge_cidrs:
            for association_id in to_remove:
                changed = True
                try:
                    connection.disassociate_vpc_cidr_block(AssociationId=association_id)
                except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
                    module.fail_json_aws(e, "Unable to disassociate {0}. You must detach or delete all gateways and resources that "
                                         "are associated with the CIDR block before you can disassociate it.".format(association_id))

        if dhcp_id is not None:
            try:
                if update_dhcp_opts(connection, module, vpc_obj, dhcp_id):
                    changed = True
            except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
                module.fail_json_aws(e, "Failed to update DHCP options")

        if tags is not None or name is not None:
            try:
                if update_vpc_tags(connection, module, vpc_id, tags, name):
                    changed = True
            except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
                module.fail_json_aws(e, msg="Failed to update tags")

        current_dns_enabled = connection.describe_vpc_attribute(Attribute='enableDnsSupport', VpcId=vpc_id, aws_retry=True)['EnableDnsSupport']['Value']
        current_dns_hostnames = connection.describe_vpc_attribute(Attribute='enableDnsHostnames', VpcId=vpc_id, aws_retry=True)['EnableDnsHostnames']['Value']
        if current_dns_enabled != dns_support:
            changed = True
            if not module.check_mode:
                try:
                    connection.modify_vpc_attribute(VpcId=vpc_id, EnableDnsSupport={'Value': dns_support})
                except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
                    module.fail_json_aws(e, "Failed to update enabled dns support attribute")
        if current_dns_hostnames != dns_hostnames:
            changed = True
            if not module.check_mode:
                try:
                    connection.modify_vpc_attribute(VpcId=vpc_id, EnableDnsHostnames={'Value': dns_hostnames})
                except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
                    module.fail_json_aws(e, "Failed to update enabled dns hostnames attribute")

        # wait for associated cidrs to match
        if to_add or to_remove:
            try:
                connection.get_waiter('vpc_available').wait(
                    VpcIds=[vpc_id],
                    Filters=[{'Name': 'cidr-block-association.cidr-block', 'Values': expected_cidrs}]
                )
            except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
                module.fail_json_aws(e, "Failed to wait for CIDRs to update")

        # try to wait for enableDnsSupport and enableDnsHostnames to match
        wait_for_vpc_attribute(connection, module, vpc_id, 'enableDnsSupport', dns_support)
        wait_for_vpc_attribute(connection, module, vpc_id, 'enableDnsHostnames', dns_hostnames)

        final_state = camel_dict_to_snake_dict(get_vpc(module, connection, vpc_id))
        final_state['tags'] = boto3_tag_list_to_ansible_dict(final_state.get('tags', []))
        final_state['id'] = final_state.pop('vpc_id')

        module.exit_json(changed=changed, vpc=final_state)

    elif state == 'absent':

        # Check if VPC exists
        vpc_id = vpc_exists(module, connection, name, cidr_block, multi)

        if vpc_id is not None:
            try:
                if not module.check_mode:
                    connection.delete_vpc(VpcId=vpc_id)
                changed = True
            except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
                module.fail_json_aws(e, msg="Failed to delete VPC {0} You may want to use the ec2_vpc_subnet, ec2_vpc_igw, "
                                     "and/or ec2_vpc_route_table modules to ensure the other components are absent.".format(vpc_id))

        module.exit_json(changed=changed, vpc={})
示例#35
0
def main():
    argument_spec = ec2_argument_spec()
    argument_spec.update(dict(
        operation=dict(required=True, choices=['run', 'start', 'stop']),
        cluster=dict(required=False, type='str'),  # R S P
        task_definition=dict(required=False, type='str'),  # R* S*
        overrides=dict(required=False, type='dict'),  # R S
        count=dict(required=False, type='int'),  # R
        task=dict(required=False, type='str'),  # P*
        container_instances=dict(required=False, type='list'),  # S*
        started_by=dict(required=False, type='str'),  # R S
        network_configuration=dict(required=False, type='dict')
    ))

    module = AnsibleAWSModule(argument_spec=argument_spec, supports_check_mode=True)

    # Validate Inputs
    if module.params['operation'] == 'run':
        if 'task_definition' not in module.params and module.params['task_definition'] is None:
            module.fail_json(msg="To run a task, a task_definition must be specified")
        task_to_list = module.params['task_definition']
        status_type = "RUNNING"

    if module.params['operation'] == 'start':
        if 'task_definition' not in module.params and module.params['task_definition'] is None:
            module.fail_json(msg="To start a task, a task_definition must be specified")
        if 'container_instances' not in module.params and module.params['container_instances'] is None:
            module.fail_json(msg="To start a task, container instances must be specified")
        task_to_list = module.params['task']
        status_type = "RUNNING"

    if module.params['operation'] == 'stop':
        if 'task' not in module.params and module.params['task'] is None:
            module.fail_json(msg="To stop a task, a task must be specified")
        if 'task_definition' not in module.params and module.params['task_definition'] is None:
            module.fail_json(msg="To stop a task, a task definition must be specified")
        task_to_list = module.params['task_definition']
        status_type = "STOPPED"

    service_mgr = EcsExecManager(module)
    if module.params['network_configuration'] and not service_mgr.ecs_api_handles_network_configuration():
        module.fail_json(msg='botocore needs to be version 1.7.44 or higher to use network configuration')
    existing = service_mgr.list_tasks(module.params['cluster'], task_to_list, status_type)

    results = dict(changed=False)
    if module.params['operation'] == 'run':
        if existing:
            # TBD - validate the rest of the details
            results['task'] = existing
        else:
            if not module.check_mode:
                results['task'] = service_mgr.run_task(
                    module.params['cluster'],
                    module.params['task_definition'],
                    module.params['overrides'],
                    module.params['count'],
                    module.params['started_by'])
            results['changed'] = True

    elif module.params['operation'] == 'start':
        if existing:
            # TBD - validate the rest of the details
            results['task'] = existing
        else:
            if not module.check_mode:
                results['task'] = service_mgr.start_task(
                    module.params['cluster'],
                    module.params['task_definition'],
                    module.params['overrides'],
                    module.params['container_instances'],
                    module.params['started_by']
                )
            results['changed'] = True

    elif module.params['operation'] == 'stop':
        if existing:
            results['task'] = existing
        else:
            if not module.check_mode:
                # it exists, so we should delete it and mark changed.
                # return info about the cluster deleted
                results['task'] = service_mgr.stop_task(
                    module.params['cluster'],
                    module.params['task']
                )
            results['changed'] = True

    module.exit_json(**results)
示例#36
0
def main():
    module = AnsibleAWSModule(
        argument_spec={
            'name':
            dict(type='str', required=True),
            'state':
            dict(type='str', choices=['present', 'absent'], default='present'),
            'description':
            dict(type='str'),
            'scope':
            dict(type='dict'),
            'source':
            dict(type='dict', required=True),
            'input_parameters':
            dict(type='str'),
            'execution_frequency':
            dict(type='str',
                 choices=[
                     'One_Hour', 'Three_Hours', 'Six_Hours', 'Twelve_Hours',
                     'TwentyFour_Hours'
                 ]),
        },
        supports_check_mode=False,
    )

    result = {'changed': False}

    name = module.params.get('name')
    resource_type = module.params.get('resource_type')
    state = module.params.get('state')

    params = {}
    if name:
        params['ConfigRuleName'] = name
    if module.params.get('description'):
        params['Description'] = module.params.get('description')
    if module.params.get('scope'):
        params['Scope'] = {}
        if module.params.get('scope').get('compliance_types'):
            params['Scope'].update({
                'ComplianceResourceTypes':
                module.params.get('scope').get('compliance_types')
            })
        if module.params.get('scope').get('tag_key'):
            params['Scope'].update(
                {'TagKey': module.params.get('scope').get('tag_key')})
        if module.params.get('scope').get('tag_value'):
            params['Scope'].update(
                {'TagValue': module.params.get('scope').get('tag_value')})
        if module.params.get('scope').get('compliance_id'):
            params['Scope'].update({
                'ComplianceResourceId':
                module.params.get('scope').get('compliance_id')
            })
    if module.params.get('source'):
        params['Source'] = {}
        if module.params.get('source').get('owner'):
            params['Source'].update(
                {'Owner': module.params.get('source').get('owner')})
        if module.params.get('source').get('identifier'):
            params['Source'].update({
                'SourceIdentifier':
                module.params.get('source').get('identifier')
            })
        if module.params.get('source').get('details'):
            params['Source'].update(
                {'SourceDetails': module.params.get('source').get('details')})
    if module.params.get('input_parameters'):
        params['InputParameters'] = module.params.get('input_parameters')
    if module.params.get('execution_frequency'):
        params['MaximumExecutionFrequency'] = module.params.get(
            'execution_frequency')
    params['ConfigRuleState'] = 'ACTIVE'

    client = module.client('config',
                           retry_decorator=AWSRetry.jittered_backoff())

    existing_rule = rule_exists(client, module, params)

    if state == 'present':
        if not existing_rule:
            create_resource(client, module, params, result)
        else:
            update_resource(client, module, params, result)

    if state == 'absent':
        if existing_rule:
            delete_resource(client, module, params, result)

    module.exit_json(**result)
def main():
    argument_spec = ec2_argument_spec()

    argument_spec.update(
        dict(
            app_name=dict(aliases=['name'], type='str', required=False),
            description=dict(),
            state=dict(choices=['present', 'absent'], default='present'),
            terminate_by_force=dict(type='bool', default=False, required=False)
        )
    )

    module = AnsibleAWSModule(argument_spec=argument_spec, supports_check_mode=True)

    app_name = module.params['app_name']
    description = module.params['description']
    state = module.params['state']
    terminate_by_force = module.params['terminate_by_force']

    if app_name is None:
        module.fail_json(msg='Module parameter "app_name" is required')

    result = {}
    region, ec2_url, aws_connect_params = get_aws_connection_info(module, boto3=True)
    ebs = boto3_conn(module, conn_type='client', resource='elasticbeanstalk',
                     region=region, endpoint=ec2_url, **aws_connect_params)

    app = describe_app(ebs, app_name, module)

    if module.check_mode:
        check_app(ebs, app, module)
        module.fail_json(msg='ASSERTION FAILURE: check_app() should not return control.')

    if state == 'present':
        if app is None:
            try:
                create_app = ebs.create_application(**filter_empty(ApplicationName=app_name,
                                                    Description=description))
            except (BotoCoreError, ClientError) as e:
                module.fail_json_aws(e, msg="Could not create application")

            app = describe_app(ebs, app_name, module)

            result = dict(changed=True, app=app)
        else:
            if app.get("Description", None) != description:
                try:
                    if not description:
                        ebs.update_application(ApplicationName=app_name)
                    else:
                        ebs.update_application(ApplicationName=app_name, Description=description)
                except (BotoCoreError, ClientError) as e:
                    module.fail_json_aws(e, msg="Could not update application")

                app = describe_app(ebs, app_name, module)

                result = dict(changed=True, app=app)
            else:
                result = dict(changed=False, app=app)

    else:
        if app is None:
            result = dict(changed=False, output='Application not found', app={})
        else:
            try:
                if terminate_by_force:
                    # Running environments will be terminated before deleting the application
                    ebs.delete_application(ApplicationName=app_name, TerminateEnvByForce=terminate_by_force)
                else:
                    ebs.delete_application(ApplicationName=app_name)
                changed = True
            except BotoCoreError as e:
                module.fail_json_aws(e, msg="Cannot terminate app")
            except ClientError as e:
                if 'It is currently pending deletion.' not in e.response['Error']['Message']:
                    module.fail_json_aws(e, msg="Cannot terminate app")
                else:
                    changed = False

            result = dict(changed=changed, app=app)

    module.exit_json(**result)
示例#38
0
def main():
    argument_spec = ec2_argument_spec()
    argument_spec.update(
        dict(
            query=dict(choices=[
                'change',
                'checker_ip_range',
                'health_check',
                'hosted_zone',
                'record_sets',
                'reusable_delegation_set',
            ],
                       required=True),
            change_id=dict(),
            hosted_zone_id=dict(),
            max_items=dict(type='str'),
            next_marker=dict(),
            delegation_set_id=dict(),
            start_record_name=dict(),
            type=dict(choices=[
                'A', 'CNAME', 'MX', 'AAAA', 'TXT', 'PTR', 'SRV', 'SPF', 'CAA',
                'NS'
            ]),
            dns_name=dict(),
            resource_id=dict(type='list', aliases=['resource_ids']),
            health_check_id=dict(),
            hosted_zone_method=dict(
                choices=['details', 'list', 'list_by_name', 'count', 'tags'],
                default='list'),
            health_check_method=dict(choices=[
                'list',
                'details',
                'status',
                'failure_reason',
                'count',
                'tags',
            ],
                                     default='list'),
        ))

    module = AnsibleAWSModule(
        argument_spec=argument_spec,
        supports_check_mode=True,
        mutually_exclusive=[
            ['hosted_zone_method', 'health_check_method'],
        ],
    )

    resource_id = module.params.get('resource_id')
    if resource_id:
        if len(resource_id) > 1:
            module.fail_json(
                msg=
                'Using multiple resource_ids is no longer supported. Use a loop'
            )
        module.deprecate(
            'resource_id is deprecated. Use hosted_zone_id or health_check_id',
            version=2.9)
        # inject proper parameters into module.params
        if module.params.get('query') == 'hosted_zone':
            module.params['hosted_zone_id'] = '/hostedzone/%s' % resource_id[0]
        if module.params.get('query') == 'health_check':
            module.params['health_check_id'] = resource_id[0]
    if module.params.get('health_check_method') == 'tags' or module.params.get(
            'hosted_zone_method') == 'tags':
        module.deprecate(
            'Using tags with health_check_method or hosted_zone_method is no longer necessary - use details instead',
            version=2.9)
    try:
        region, ec2_url, aws_connect_kwargs = get_aws_connection_info(
            module, boto3=True)
        route53 = boto3_conn(module,
                             conn_type='client',
                             resource='route53',
                             region=region,
                             endpoint=ec2_url,
                             **aws_connect_kwargs)
    except botocore.exceptions.ProfileNotFound as e:
        module.fail_json_aws(e)

    invocations = {
        'change': change_details,
        'checker_ip_range': checker_ip_range_details,
        'health_check': health_check_details,
        'hosted_zone': hosted_zone_details,
        'record_sets': record_sets_details,
        'reusable_delegation_set': reusable_delegation_set_details,
    }
    results = invocations[module.params.get('query')](route53, module)

    # tidy up results
    for field in ['ResponseMetadata', 'MaxItems', 'IsTruncated']:
        if field in results:
            del (results[field])
    tags = results.get('Tags')

    results = camel_dict_to_snake_dict(results)
    if tags is not None:
        results['tags'] = tags

    module.exit_json(**results)
示例#39
0
def main():
    argument_spec = dict(cluster_name=dict(required=True),
                         resource=dict(required=False),
                         tags=dict(type='dict'),
                         purge_tags=dict(type='bool', default=False),
                         state=dict(default='present',
                                    choices=['present', 'absent']),
                         resource_type=dict(default='cluster',
                                            choices=[
                                                'cluster', 'task', 'service',
                                                'task_definition', 'container'
                                            ]))
    required_if = [('state', 'present', ['tags']),
                   ('state', 'absent', ['tags'])]

    module = AnsibleAWSModule(argument_spec=argument_spec,
                              required_if=required_if,
                              supports_check_mode=True)

    resource_type = module.params['resource_type']
    cluster_name = module.params['cluster_name']
    if resource_type == 'cluster':
        resource = cluster_name
    else:
        resource = module.params['resource']
    tags = module.params['tags']
    state = module.params['state']
    purge_tags = module.params['purge_tags']

    result = {'changed': False}

    ecs = module.client('ecs')

    resource_arn = get_arn(ecs, module, cluster_name, resource_type, resource)

    current_tags = get_tags(ecs, module, resource_arn)

    add_tags, remove = compare_aws_tags(current_tags,
                                        tags,
                                        purge_tags=purge_tags)

    remove_tags = {}
    if state == 'absent':
        for key in tags:
            if key in current_tags and (tags[key] is None
                                        or current_tags[key] == tags[key]):
                remove_tags[key] = current_tags[key]

    for key in remove:
        remove_tags[key] = current_tags[key]

    if remove_tags:
        result['changed'] = True
        result['removed_tags'] = remove_tags
        if not module.check_mode:
            try:
                ecs.untag_resource(resourceArn=resource_arn,
                                   tagKeys=list(remove_tags.keys()))
            except (BotoCoreError, ClientError) as e:
                module.fail_json_aws(
                    e,
                    msg='Failed to remove tags {0} from resource {1}'.format(
                        remove_tags, resource))

    if state == 'present' and add_tags:
        result['changed'] = True
        result['added_tags'] = add_tags
        current_tags.update(add_tags)
        if not module.check_mode:
            try:
                tags = ansible_dict_to_boto3_tag_list(
                    add_tags,
                    tag_name_key_name='key',
                    tag_value_key_name='value')
                ecs.tag_resource(resourceArn=resource_arn, tags=tags)
            except (BotoCoreError, ClientError) as e:
                module.fail_json_aws(
                    e,
                    msg='Failed to set tags {0} on resource {1}'.format(
                        add_tags, resource))

    result['tags'] = get_tags(ecs, module, resource_arn)
    module.exit_json(**result)
示例#40
0
def main():
    argument_spec = ec2_argument_spec()
    argument_spec.update(dict(
        state=dict(required=True, choices=['present', 'absent', 'deleting']),
        name=dict(required=True, type='str'),
        cluster=dict(required=False, type='str'),
        task_definition=dict(required=False, type='str'),
        load_balancers=dict(required=False, default=[], type='list'),
        desired_count=dict(required=False, type='int'),
        client_token=dict(required=False, default='', type='str'),
        role=dict(required=False, default='', type='str'),
        delay=dict(required=False, type='int', default=10),
        repeat=dict(required=False, type='int', default=10),
        deployment_configuration=dict(required=False, default={}, type='dict'),
        placement_constraints=dict(required=False, default=[], type='list'),
        placement_strategy=dict(required=False, default=[], type='list'),
        network_configuration=dict(required=False, type='dict')
    ))

    module = AnsibleAWSModule(argument_spec=argument_spec,
                              supports_check_mode=True,
                              required_if=[('state', 'present', ['task_definition', 'desired_count'])],
                              required_together=[['load_balancers', 'role']])

    service_mgr = EcsServiceManager(module)
    if module.params['network_configuration']:
        if not service_mgr.ecs_api_handles_network_configuration():
            module.fail_json(msg='botocore needs to be version 1.7.44 or higher to use network configuration')
        network_configuration = service_mgr.format_network_configuration(module.params['network_configuration'])
    else:
        network_configuration = None

    deployment_configuration = map_complex_type(module.params['deployment_configuration'],
                                                DEPLOYMENT_CONFIGURATION_TYPE_MAP)

    deploymentConfiguration = snake_dict_to_camel_dict(deployment_configuration)

    try:
        existing = service_mgr.describe_service(module.params['cluster'], module.params['name'])
    except Exception as e:
        module.fail_json(msg="Exception describing service '" + module.params['name'] + "' in cluster '" + module.params['cluster'] + "': " + str(e))

    results = dict(changed=False)
    if module.params['state'] == 'present':

        matching = False
        update = False
        if existing and 'status' in existing and existing['status'] == "ACTIVE":
            if service_mgr.is_matching_service(module.params, existing):
                matching = True
                results['service'] = existing
            else:
                update = True

        if not matching:
            if not module.check_mode:

                role = module.params['role']
                clientToken = module.params['client_token']
                loadBalancers = module.params['load_balancers']

                if update:
                    if (existing['loadBalancers'] or []) != loadBalancers:
                        module.fail_json(msg="It is not possible to update the load balancers of an existing service")
                    # update required
                    response = service_mgr.update_service(module.params['name'],
                                                          module.params['cluster'],
                                                          module.params['task_definition'],
                                                          module.params['desired_count'],
                                                          deploymentConfiguration,
                                                          network_configuration)
                else:
                    for loadBalancer in loadBalancers:
                        if 'containerPort' in loadBalancer:
                            loadBalancer['containerPort'] = int(loadBalancer['containerPort'])
                    # doesn't exist. create it.
                    response = service_mgr.create_service(module.params['name'],
                                                          module.params['cluster'],
                                                          module.params['task_definition'],
                                                          loadBalancers,
                                                          module.params['desired_count'],
                                                          clientToken,
                                                          role,
                                                          deploymentConfiguration,
                                                          module.params['placement_constraints'],
                                                          module.params['placement_strategy'],
                                                          network_configuration)

                results['service'] = response

            results['changed'] = True

    elif module.params['state'] == 'absent':
        if not existing:
            pass
        else:
            # it exists, so we should delete it and mark changed.
            # return info about the cluster deleted
            del existing['deployments']
            del existing['events']
            results['ansible_facts'] = existing
            if 'status' in existing and existing['status'] == "INACTIVE":
                results['changed'] = False
            else:
                if not module.check_mode:
                    try:
                        service_mgr.delete_service(
                            module.params['name'],
                            module.params['cluster']
                        )
                    except botocore.exceptions.ClientError as e:
                        module.fail_json(msg=e.message)
                results['changed'] = True

    elif module.params['state'] == 'deleting':
        if not existing:
            module.fail_json(msg="Service '" + module.params['name'] + " not found.")
            return
        # it exists, so we should delete it and mark changed.
        # return info about the cluster deleted
        delay = module.params['delay']
        repeat = module.params['repeat']
        time.sleep(delay)
        for i in range(repeat):
            existing = service_mgr.describe_service(module.params['cluster'], module.params['name'])
            status = existing['status']
            if status == "INACTIVE":
                results['changed'] = True
                break
            time.sleep(delay)
        if i is repeat - 1:
            module.fail_json(msg="Service still not deleted after " + str(repeat) + " tries of " + str(delay) + " seconds each.")
            return

    module.exit_json(**results)
示例#41
0
def main():
    argument_spec = dict(
        direction=dict(required=True, choices=['push', 'pull']),
        overwrite=dict(
            choices=['always', 'never', 'different', 'newer', 'larger'],
            default='never'),
        diff_attributes=dict(type='list', default=['e_tag']),
        bucket=dict(required=True),
        prefix=dict(default=''),
        path=dict(type='path', required=True),
        directory_mode=dict(),
        permission=dict(required=False,
                        choices=[
                            'private', 'public-read', 'public-read-write',
                            'authenticated-read', 'aws-exec-read',
                            'bucket-owner-read', 'bucket-owner-full-control'
                        ]),
        mime_encodings_map=dict(type='dict', default={}),
        mime_types_map=dict(type='dict', default={}),
        mime_override=dict(type='bool', default=False),
        mime_strict=dict(type='bool', default=False),
        patterns=dict(required=False, type='list', aliases=['pattern']),
        excludes=dict(required=False, type='list', aliases=['exclude']),
        hidden=dict(type='bool', default=False),
        use_regex=dict(type='bool', default=False),
        metadata=dict(type='dict', default={}),
        delete=dict(type='bool', default=False),
    )

    module = AnsibleAWSModule(
        argument_spec=argument_spec,
        add_file_common_args=True,
        supports_check_mode=True,
    )

    if not HAS_DATEUTIL:
        module.fail_json(msg=missing_required_lib('dateutil'),
                         exception=HAS_DATEUTIL_EXC)

    if module.params['overwrite'] == 'different' and 'e_tag' in module.params[
            'diff_attributes'] and not HAS_MD5:
        module.fail_json(
            msg=
            'Invalid diff_attributes: ETag calculation requires MD5 support, which is not available.'
        )

    if not os.path.exists(
            to_bytes(module.params['path'], errors='surrogate_or_strict')):
        module.fail_json(msg="path not found: %s" % module.params['path'])

    syncer = S3Syncer(module)
    syncer.gather_local_files()
    syncer.gather_s3_files()
    if module.params['direction'] == 'push':
        syncer.upload_files()
        if module.params['delete']:
            syncer.delete_s3_files()
    else:
        syncer.download_files()
        if module.params['delete']:
            syncer.delete_local_files()

    module.exit_json(changed=syncer.changed, objects=syncer.objects)
示例#42
0
def main():
    """
    Main entry point.

    :return dict: ansible facts
    """
    argument_spec = dict(function_name=dict(required=False,
                                            default=None,
                                            aliases=['function', 'name']),
                         query=dict(required=False,
                                    choices=[
                                        'aliases', 'all', 'config', 'mappings',
                                        'policy', 'versions'
                                    ],
                                    default='all'),
                         event_source_arn=dict(required=False, default=None))

    module = AnsibleAWSModule(argument_spec=argument_spec,
                              supports_check_mode=True,
                              mutually_exclusive=[],
                              required_together=[])

    # validate function_name if present
    function_name = module.params['function_name']
    if function_name:
        if not re.search(r"^[\w\-:]+$", function_name):
            module.fail_json(
                msg=
                'Function name {0} is invalid. Names must contain only alphanumeric characters and hyphens.'
                .format(function_name))
        if len(function_name) > 64:
            module.fail_json(
                msg='Function name "{0}" exceeds 64 character limit'.format(
                    function_name))

    try:
        region, endpoint, aws_connect_kwargs = get_aws_connection_info(
            module, boto3=True)
        aws_connect_kwargs.update(
            dict(region=region,
                 endpoint=endpoint,
                 conn_type='client',
                 resource='lambda'))
        client = boto3_conn(module, **aws_connect_kwargs)
    except ClientError as e:
        module.fail_json_aws(e, "trying to set up boto connection")

    this_module = sys.modules[__name__]

    invocations = dict(
        aliases='alias_details',
        all='all_details',
        config='config_details',
        mappings='mapping_details',
        policy='policy_details',
        versions='version_details',
    )

    this_module_function = getattr(this_module,
                                   invocations[module.params['query']])
    all_facts = fix_return(this_module_function(client, module))

    results = dict(ansible_facts={'lambda_facts': {
        'function': all_facts
    }},
                   changed=False)

    if module.check_mode:
        results['msg'] = 'Check mode set but ignored for fact gathering only.'

    module.exit_json(**results)
示例#43
0
文件: lambda.py 项目: ydd171/public
def main():
    argument_spec = dict(
        name=dict(required=True),
        state=dict(default='present', choices=['present', 'absent']),
        runtime=dict(),
        role=dict(),
        handler=dict(),
        zip_file=dict(aliases=['src']),
        s3_bucket=dict(),
        s3_key=dict(),
        s3_object_version=dict(),
        description=dict(default=''),
        timeout=dict(type='int', default=3),
        memory_size=dict(type='int', default=128),
        vpc_subnet_ids=dict(type='list'),
        vpc_security_group_ids=dict(type='list'),
        environment_variables=dict(type='dict'),
        dead_letter_arn=dict(),
        tags=dict(type='dict'),
    )

    mutually_exclusive = [['zip_file', 's3_key'], ['zip_file', 's3_bucket'],
                          ['zip_file', 's3_object_version']]

    required_together = [['s3_key', 's3_bucket'],
                         ['vpc_subnet_ids', 'vpc_security_group_ids']]

    required_if = [['state', 'present', ['runtime', 'handler', 'role']]]

    module = AnsibleAWSModule(argument_spec=argument_spec,
                              supports_check_mode=True,
                              mutually_exclusive=mutually_exclusive,
                              required_together=required_together,
                              required_if=required_if)

    name = module.params.get('name')
    state = module.params.get('state').lower()
    runtime = module.params.get('runtime')
    role = module.params.get('role')
    handler = module.params.get('handler')
    s3_bucket = module.params.get('s3_bucket')
    s3_key = module.params.get('s3_key')
    s3_object_version = module.params.get('s3_object_version')
    zip_file = module.params.get('zip_file')
    description = module.params.get('description')
    timeout = module.params.get('timeout')
    memory_size = module.params.get('memory_size')
    vpc_subnet_ids = module.params.get('vpc_subnet_ids')
    vpc_security_group_ids = module.params.get('vpc_security_group_ids')
    environment_variables = module.params.get('environment_variables')
    dead_letter_arn = module.params.get('dead_letter_arn')
    tags = module.params.get('tags')

    check_mode = module.check_mode
    changed = False

    region, ec2_url, aws_connect_kwargs = get_aws_connection_info(module,
                                                                  boto3=True)
    if not region:
        module.fail_json(msg='region must be specified')

    try:
        client = boto3_conn(module,
                            conn_type='client',
                            resource='lambda',
                            region=region,
                            endpoint=ec2_url,
                            **aws_connect_kwargs)
    except (ClientError, ValidationError) as e:
        module.fail_json_aws(e, msg="Trying to connect to AWS")

    if state == 'present':
        if role.startswith('arn:aws:iam'):
            role_arn = role
        else:
            # get account ID and assemble ARN
            account_id = get_account_id(module,
                                        region=region,
                                        endpoint=ec2_url,
                                        **aws_connect_kwargs)
            role_arn = 'arn:aws:iam::{0}:role/{1}'.format(account_id, role)

    # Get function configuration if present, False otherwise
    current_function = get_current_function(client, name)

    # Update existing Lambda function
    if state == 'present' and current_function:

        # Get current state
        current_config = current_function['Configuration']
        current_version = None

        # Update function configuration
        func_kwargs = {'FunctionName': name}

        # Update configuration if needed
        if role_arn and current_config['Role'] != role_arn:
            func_kwargs.update({'Role': role_arn})
        if handler and current_config['Handler'] != handler:
            func_kwargs.update({'Handler': handler})
        if description and current_config['Description'] != description:
            func_kwargs.update({'Description': description})
        if timeout and current_config['Timeout'] != timeout:
            func_kwargs.update({'Timeout': timeout})
        if memory_size and current_config['MemorySize'] != memory_size:
            func_kwargs.update({'MemorySize': memory_size})
        if (environment_variables
                is not None) and (current_config.get('Environment', {}).get(
                    'Variables', {}) != environment_variables):
            func_kwargs.update(
                {'Environment': {
                    'Variables': environment_variables
                }})
        if dead_letter_arn is not None:
            if current_config.get('DeadLetterConfig'):
                if current_config['DeadLetterConfig'][
                        'TargetArn'] != dead_letter_arn:
                    func_kwargs.update(
                        {'DeadLetterConfig': {
                            'TargetArn': dead_letter_arn
                        }})
            else:
                if dead_letter_arn != "":
                    func_kwargs.update(
                        {'DeadLetterConfig': {
                            'TargetArn': dead_letter_arn
                        }})

        # Check for unsupported mutation
        if current_config['Runtime'] != runtime:
            module.fail_json(
                msg='Cannot change runtime. Please recreate the function')

        # If VPC configuration is desired
        if vpc_subnet_ids or vpc_security_group_ids:
            if not vpc_subnet_ids or not vpc_security_group_ids:
                module.fail_json(
                    msg=
                    'vpc connectivity requires at least one security group and one subnet'
                )

            if 'VpcConfig' in current_config:
                # Compare VPC config with current config
                current_vpc_subnet_ids = current_config['VpcConfig'][
                    'SubnetIds']
                current_vpc_security_group_ids = current_config['VpcConfig'][
                    'SecurityGroupIds']

                subnet_net_id_changed = sorted(vpc_subnet_ids) != sorted(
                    current_vpc_subnet_ids)
                vpc_security_group_ids_changed = sorted(
                    vpc_security_group_ids) != sorted(
                        current_vpc_security_group_ids)

            if 'VpcConfig' not in current_config or subnet_net_id_changed or vpc_security_group_ids_changed:
                new_vpc_config = {
                    'SubnetIds': vpc_subnet_ids,
                    'SecurityGroupIds': vpc_security_group_ids
                }
                func_kwargs.update({'VpcConfig': new_vpc_config})
        else:
            # No VPC configuration is desired, assure VPC config is empty when present in current config
            if 'VpcConfig' in current_config and current_config[
                    'VpcConfig'].get('VpcId'):
                func_kwargs.update(
                    {'VpcConfig': {
                        'SubnetIds': [],
                        'SecurityGroupIds': []
                    }})

        # Upload new configuration if configuration has changed
        if len(func_kwargs) > 1:
            try:
                if not check_mode:
                    response = client.update_function_configuration(
                        **func_kwargs)
                    current_version = response['Version']
                changed = True
            except (ParamValidationError, ClientError) as e:
                module.fail_json_aws(
                    e, msg="Trying to update lambda configuration")

        # Update code configuration
        code_kwargs = {'FunctionName': name, 'Publish': True}

        # Update S3 location
        if s3_bucket and s3_key:
            # If function is stored on S3 always update
            code_kwargs.update({'S3Bucket': s3_bucket, 'S3Key': s3_key})

            # If S3 Object Version is given
            if s3_object_version:
                code_kwargs.update({'S3ObjectVersion': s3_object_version})

        # Compare local checksum, update remote code when different
        elif zip_file:
            local_checksum = sha256sum(zip_file)
            remote_checksum = current_config['CodeSha256']

            # Only upload new code when local code is different compared to the remote code
            if local_checksum != remote_checksum:
                try:
                    with open(zip_file, 'rb') as f:
                        encoded_zip = f.read()
                    code_kwargs.update({'ZipFile': encoded_zip})
                except IOError as e:
                    module.fail_json(msg=str(e),
                                     exception=traceback.format_exc())

        # Tag Function
        if tags is not None:
            if set_tag(client, module, tags, current_function):
                changed = True

        # Upload new code if needed (e.g. code checksum has changed)
        if len(code_kwargs) > 2:
            try:
                if not check_mode:
                    response = client.update_function_code(**code_kwargs)
                    current_version = response['Version']
                changed = True
            except (ParamValidationError, ClientError) as e:
                module.fail_json_aws(e, msg="Trying to upload new code")

        # Describe function code and configuration
        response = get_current_function(client,
                                        name,
                                        qualifier=current_version)
        if not response:
            module.fail_json(
                msg='Unable to get function information after updating')

        # We're done
        module.exit_json(changed=changed, **camel_dict_to_snake_dict(response))

    # Function doesn't exists, create new Lambda function
    elif state == 'present':
        if s3_bucket and s3_key:
            # If function is stored on S3
            code = {'S3Bucket': s3_bucket, 'S3Key': s3_key}
            if s3_object_version:
                code.update({'S3ObjectVersion': s3_object_version})
        elif zip_file:
            # If function is stored in local zipfile
            try:
                with open(zip_file, 'rb') as f:
                    zip_content = f.read()

                code = {'ZipFile': zip_content}
            except IOError as e:
                module.fail_json(msg=str(e), exception=traceback.format_exc())

        else:
            module.fail_json(
                msg='Either S3 object or path to zipfile required')

        func_kwargs = {
            'FunctionName': name,
            'Publish': True,
            'Runtime': runtime,
            'Role': role_arn,
            'Code': code,
            'Timeout': timeout,
            'MemorySize': memory_size,
        }

        if description is not None:
            func_kwargs.update({'Description': description})

        if handler is not None:
            func_kwargs.update({'Handler': handler})

        if environment_variables:
            func_kwargs.update(
                {'Environment': {
                    'Variables': environment_variables
                }})

        if dead_letter_arn:
            func_kwargs.update(
                {'DeadLetterConfig': {
                    'TargetArn': dead_letter_arn
                }})

        # If VPC configuration is given
        if vpc_subnet_ids or vpc_security_group_ids:
            if not vpc_subnet_ids or not vpc_security_group_ids:
                module.fail_json(
                    msg=
                    'vpc connectivity requires at least one security group and one subnet'
                )

            func_kwargs.update({
                'VpcConfig': {
                    'SubnetIds': vpc_subnet_ids,
                    'SecurityGroupIds': vpc_security_group_ids
                }
            })

        # Finally try to create function
        current_version = None
        try:
            if not check_mode:
                response = client.create_function(**func_kwargs)
                current_version = response['Version']
            changed = True
        except (ParamValidationError, ClientError) as e:
            module.fail_json_aws(e, msg="Trying to create function")

        # Tag Function
        if tags is not None:
            if set_tag(client, module, tags,
                       get_current_function(client, name)):
                changed = True

        response = get_current_function(client,
                                        name,
                                        qualifier=current_version)
        if not response:
            module.fail_json(
                msg='Unable to get function information after creating')
        module.exit_json(changed=changed, **camel_dict_to_snake_dict(response))

    # Delete existing Lambda function
    if state == 'absent' and current_function:
        try:
            if not check_mode:
                client.delete_function(FunctionName=name)
            changed = True
        except (ParamValidationError, ClientError) as e:
            module.fail_json_aws(e, msg="Trying to delete Lambda function")

        module.exit_json(changed=changed)

    # Function already absent, do nothing
    elif state == 'absent':
        module.exit_json(changed=changed)
def main():
    argument_spec = dict(
        stack_set_name=dict(required=True),
        description=dict(),
        wait=dict(type='bool', default=False),
        wait_timeout=dict(type='int', default=900),
        state=dict(default='present', choices=['present', 'absent']),
        parameters=dict(type='dict', default={}),
        permission_model=dict(type='str',
                              choices=['SERVICE_MANAGED', 'SELF_MANAGED']),
        auto_deployment=dict(
            type=dict,
            default={},
            options=dict(enabled=dict(type='bool'),
                         retain_stacks_on_account_removal=dict(type='bool'))),
        template=dict(type='path'),
        template_url=dict(),
        template_body=dict(),
        capabilities=dict(type='list',
                          elements='str',
                          choices=['CAPABILITY_IAM', 'CAPABILITY_NAMED_IAM']),
        administration_role_arn=dict(
            aliases=['admin_role_arn', 'administration_role', 'admin_role']),
        execution_role_name=dict(
            aliases=['execution_role', 'exec_role', 'exec_role_name']),
        tags=dict(type='dict'),
    )

    module = AnsibleAWSModule(
        argument_spec=argument_spec,
        mutually_exclusive=[['template_url', 'template', 'template_body']],
        supports_check_mode=True)
    if not (module.boto3_at_least('1.14.0')
            and module.botocore_at_least('1.17.7')):
        module.fail_json(
            msg=
            "Boto3 or botocore version is too low. This module requires at least boto3 1.6 and botocore 1.10.26"
        )

    # Wrap the cloudformation client methods that this module uses with
    # automatic backoff / retry for throttling error codes
    jittered_backoff_decorator = AWSRetry.jittered_backoff(
        retries=10,
        delay=3,
        max_delay=30,
        catch_extra_error_codes=['StackSetNotFound'])
    cfn = module.client('cloudformation',
                        retry_decorator=jittered_backoff_decorator)
    existing_stack_set = stack_set_facts(cfn, module.params['stack_set_name'])

    operation_uuid = to_native(uuid.uuid4())
    operation_ids = []
    # collect the parameters that are passed to boto3. Keeps us from having so many scalars floating around.
    stack_params = {}
    state = module.params['state']
    stack_params['StackSetName'] = module.params['stack_set_name']
    if module.params.get('description'):
        stack_params['Description'] = module.params['description']

    if module.params.get('capabilities'):
        stack_params['Capabilities'] = module.params['capabilities']

    if module.params['template'] is not None:
        with open(module.params['template'], 'r') as tpl:
            stack_params['TemplateBody'] = tpl.read()
    elif module.params['template_body'] is not None:
        stack_params['TemplateBody'] = module.params['template_body']
    elif module.params['template_url'] is not None:
        stack_params['TemplateURL'] = module.params['template_url']
    else:
        # no template is provided, but if the stack set exists already, we can use the existing one.
        if existing_stack_set:
            stack_params['UsePreviousTemplate'] = True
        else:
            module.fail_json(
                msg=
                "The Stack Set {0} does not exist, and no template was provided. Provide one of `template`, "
                "`template_body`, or `template_url`".format(
                    module.params['stack_set_name']))

    stack_params['Parameters'] = []
    for k, v in module.params['parameters'].items():
        if isinstance(v, dict):
            # set parameter based on a dict to allow additional CFN Parameter Attributes
            param = dict(ParameterKey=k)

            if 'value' in v:
                param['ParameterValue'] = to_native(v['value'])

            if 'use_previous_value' in v and bool(v['use_previous_value']):
                param['UsePreviousValue'] = True
                param.pop('ParameterValue', None)

            stack_params['Parameters'].append(param)
        else:
            # allow default k/v configuration to set a template parameter
            stack_params['Parameters'].append({
                'ParameterKey': k,
                'ParameterValue': str(v)
            })

    if module.params.get('tags') and isinstance(module.params.get('tags'),
                                                dict):
        stack_params['Tags'] = ansible_dict_to_boto3_tag_list(
            module.params['tags'])

    if module.params.get('administration_role_arn'):
        # TODO loosen the semantics here to autodetect the account ID and build the ARN
        stack_params['AdministrationRoleARN'] = module.params[
            'administration_role_arn']
    if module.params.get('execution_role_name'):
        stack_params['ExecutionRoleName'] = module.params[
            'execution_role_name']
    if module.params.get('permission_model'):
        stack_params['PermissionModel'] = module.params.get('permission_model')
    if module.params.get('auto_deployment'):
        param_auto_deployment = {}
        auto_deployment = module.params.get('auto_deployment')
        if 'enabled' in auto_deployment.keys():
            param_auto_deployment['Enabled'] = auto_deployment['enabled']
        if 'retain_stacks_on_account_removal' in auto_deployment.keys():
            param_auto_deployment[
                'RetainStacksOnAccountRemoval'] = auto_deployment[
                    'retain_stacks_on_account_removal']
        stack_params['AutoDeployment'] = param_auto_deployment

    result = {}

    if module.check_mode:
        if state == 'absent' and existing_stack_set:
            module.exit_json(changed=True,
                             msg='Stack set would be deleted',
                             meta=[])
        elif state == 'absent' and not existing_stack_set:
            module.exit_json(changed=False,
                             msg='Stack set doesn\'t exist',
                             meta=[])
        elif state == 'present' and not existing_stack_set:
            module.exit_json(changed=True,
                             msg='New stack set would be created',
                             meta=[])
        elif state == 'present' and existing_stack_set:
            module.exit_json(changed=True,
                             msg='Existing stack set would be updated',
                             meta=[])
        else:
            # TODO: need to check the template and other settings for correct check mode
            module.exit_json(changed=False, msg='No changes detected', meta=[])

    changed = False
    if state == 'present':
        if not existing_stack_set:
            # on create this parameter has a different name, and cannot be referenced later in the job log
            stack_params[
                'ClientRequestToken'] = 'Ansible-StackSet-Create-{0}'.format(
                    operation_uuid)
            changed = True
            create_stack_set(module, stack_params, cfn)
        else:
            stack_params['OperationId'] = 'Ansible-StackSet-Update-{0}'.format(
                operation_uuid)
            operation_ids.append(stack_params['OperationId'])
            changed |= update_stack_set(module, stack_params, cfn)

    elif state == 'absent':
        if not existing_stack_set:
            module.exit_json(msg='Stack set {0} does not exist'.format(
                module.params['stack_set_name']))
        try:
            cfn.delete_stack_set(
                StackSetName=module.params['stack_set_name'], )
            module.exit_json(msg='Stack set {0} deleted'.format(
                module.params['stack_set_name']))
        except is_boto3_error_code('OperationInProgressException') as e:  # pylint: disable=duplicate-except
            module.fail_json_aws(
                e,
                msg=
                'Cannot delete stack {0} while there is an operation in progress'
                .format(module.params['stack_set_name']))
        except is_boto3_error_code('StackSetNotEmptyException'):  # pylint: disable=duplicate-except
            try:
                cfn.delete_stack_set(
                    StackSetName=module.params['stack_set_name'], )
            except is_boto3_error_code('StackSetNotEmptyException') as exc:  # pylint: disable=duplicate-except
                module.fail_json_aws(
                    exc,
                    msg=
                    'Could not purge stacks, or not all accounts/regions were chosen for deletion'
                )
            module.exit_json(changed=True,
                             msg='Stack set {0} deleted'.format(
                                 module.params['stack_set_name']))

    result.update(**describe_stack_tree(
        module, stack_params['StackSetName'], operation_ids=operation_ids))
    if 'operations' in result.keys():
        if any(o['status'] == 'FAILED' for o in result['operations']):
            module.fail_json(msg="One or more operations failed to execute",
                             **result)
    module.exit_json(changed=changed, **result)
示例#45
0
def main():
    argument_spec = ec2_argument_spec()
    argument_spec.update(
        dict(
            name=dict(required=True),
            cidr_block=dict(type='list', required=True),
            tenancy=dict(choices=['default', 'dedicated'], default='default'),
            dns_support=dict(type='bool', default=True),
            dns_hostnames=dict(type='bool', default=True),
            dhcp_opts_id=dict(),
            tags=dict(type='dict', aliases=['resource_tags']),
            state=dict(choices=['present', 'absent'], default='present'),
            multi_ok=dict(type='bool', default=False),
            purge_cidrs=dict(type='bool', default=False),
        ))

    module = AnsibleAWSModule(argument_spec=argument_spec,
                              supports_check_mode=True)

    name = module.params.get('name')
    cidr_block = module.params.get('cidr_block')
    purge_cidrs = module.params.get('purge_cidrs')
    tenancy = module.params.get('tenancy')
    dns_support = module.params.get('dns_support')
    dns_hostnames = module.params.get('dns_hostnames')
    dhcp_id = module.params.get('dhcp_opts_id')
    tags = module.params.get('tags')
    state = module.params.get('state')
    multi = module.params.get('multi_ok')

    changed = False

    region, ec2_url, aws_connect_params = get_aws_connection_info(module,
                                                                  boto3=True)
    connection = boto3_conn(module,
                            conn_type='client',
                            resource='ec2',
                            region=region,
                            endpoint=ec2_url,
                            **aws_connect_params)

    if dns_hostnames and not dns_support:
        module.fail_json(
            msg=
            'In order to enable DNS Hostnames you must also enable DNS support'
        )

    if state == 'present':

        # Check if VPC exists
        vpc_id = vpc_exists(module, connection, name, cidr_block, multi)

        if vpc_id is None:
            vpc_id = create_vpc(connection, module, cidr_block[0], tenancy)
            changed = True

        vpc_obj = get_vpc(module, connection, vpc_id)

        associated_cidrs = dict(
            (cidr['CidrBlock'], cidr['AssociationId'])
            for cidr in vpc_obj.get('CidrBlockAssociationSet', [])
            if cidr['CidrBlockState']['State'] != 'disassociated')
        to_add = [cidr for cidr in cidr_block if cidr not in associated_cidrs]
        to_remove = [
            associated_cidrs[cidr] for cidr in associated_cidrs
            if cidr not in cidr_block
        ]

        if len(cidr_block) > 1:
            for cidr in to_add:
                changed = True
                connection.associate_vpc_cidr_block(CidrBlock=cidr,
                                                    VpcId=vpc_id)

        if purge_cidrs:
            for association_id in to_remove:
                changed = True
                try:
                    connection.disassociate_vpc_cidr_block(
                        AssociationId=association_id)
                except (botocore.exceptions.ClientError,
                        botocore.exceptions.BotoCoreError) as e:
                    module.fail_json_aws(
                        e,
                        "Unable to disassociate {0}. You must detach or delete all gateways and resources that "
                        "are associated with the CIDR block before you can disassociate it."
                        .format(association_id))

        if dhcp_id is not None:
            try:
                if update_dhcp_opts(connection, module, vpc_obj, dhcp_id):
                    changed = True
            except (botocore.exceptions.ClientError,
                    botocore.exceptions.BotoCoreError) as e:
                module.fail_json_aws(e, "Failed to update DHCP options")

        if tags is not None or name is not None:
            try:
                if update_vpc_tags(connection, module, vpc_id, tags, name):
                    changed = True
            except (botocore.exceptions.ClientError,
                    botocore.exceptions.BotoCoreError) as e:
                module.fail_json_aws(e, msg="Failed to update tags")

        current_dns_enabled = connection.describe_vpc_attribute(
            Attribute='enableDnsSupport',
            VpcId=vpc_id)['EnableDnsSupport']['Value']
        current_dns_hostnames = connection.describe_vpc_attribute(
            Attribute='enableDnsHostnames',
            VpcId=vpc_id)['EnableDnsHostnames']['Value']
        if current_dns_enabled != dns_support:
            changed = True
            if not module.check_mode:
                try:
                    connection.modify_vpc_attribute(
                        VpcId=vpc_id, EnableDnsSupport={'Value': dns_support})
                except (botocore.exceptions.ClientError,
                        botocore.exceptions.BotoCoreError) as e:
                    module.fail_json_aws(
                        e, "Failed to update enabled dns support attribute")
        if current_dns_hostnames != dns_hostnames:
            changed = True
            if not module.check_mode:
                try:
                    connection.modify_vpc_attribute(
                        VpcId=vpc_id,
                        EnableDnsHostnames={'Value': dns_hostnames})
                except (botocore.exceptions.ClientError,
                        botocore.exceptions.BotoCoreError) as e:
                    module.fail_json_aws(
                        e, "Failed to update enabled dns hostnames attribute")

        final_state = camel_dict_to_snake_dict(
            get_vpc(module, connection, vpc_id))
        final_state['id'] = final_state.pop('vpc_id')

        module.exit_json(changed=changed, vpc=final_state)

    elif state == 'absent':

        # Check if VPC exists
        vpc_id = vpc_exists(module, connection, name, cidr_block, multi)

        if vpc_id is not None:
            try:
                if not module.check_mode:
                    connection.delete_vpc(VpcId=vpc_id)
                changed = True
            except (botocore.exceptions.ClientError,
                    botocore.exceptions.BotoCoreError) as e:
                module.fail_json_aws(
                    e,
                    msg=
                    "Failed to delete VPC {0} You may want to use the ec2_vpc_subnet, ec2_vpc_igw, "
                    "and/or ec2_vpc_route_table modules to ensure the other components are absent."
                    .format(vpc_id))

        module.exit_json(changed=changed, vpc={})
示例#46
0
def main():
    argument_spec = dict(certificate=dict(),
                         certificate_arn=dict(aliases=['arn']),
                         certificate_chain=dict(),
                         domain_name=dict(aliases=['domain']),
                         name_tag=dict(aliases=['name']),
                         private_key=dict(no_log=True),
                         state=dict(default='present',
                                    choices=['present', 'absent']))
    module = AnsibleAWSModule(argument_spec=argument_spec,
                              supports_check_mode=True)
    acm = ACMServiceManager(module)

    # Check argument requirements
    if module.params['state'] == 'present':
        if not module.params['certificate']:
            module.fail_json(
                msg=
                "Parameter 'certificate' must be specified if 'state' is specified as 'present'"
            )
        elif module.params['certificate_arn']:
            module.fail_json(
                msg=
                "Parameter 'certificate_arn' is only valid if parameter 'state' is specified as 'absent'"
            )
        elif not module.params['name_tag']:
            module.fail_json(
                msg=
                "Parameter 'name_tag' must be specified if parameter 'state' is specified as 'present'"
            )
        elif not module.params['private_key']:
            module.fail_json(
                msg=
                "Parameter 'private_key' must be specified if 'state' is specified as 'present'"
            )
    else:  # absent

        # exactly one of these should be specified
        absent_args = ['certificate_arn', 'domain_name', 'name_tag']
        if sum([(module.params[a] is not None) for a in absent_args]) != 1:
            for a in absent_args:
                module.debug("%s is %s" % (a, module.params[a]))
            module.fail_json(
                msg=
                "If 'state' is specified as 'absent' then exactly one of 'name_tag', certificate_arn' or 'domain_name' must be specified"
            )

    if module.params['name_tag']:
        tags = dict(Name=module.params['name_tag'])
    else:
        tags = None

    client = module.client('acm')

    # fetch the list of certificates currently in ACM
    certificates = acm.get_certificates(
        client=client,
        module=module,
        domain_name=module.params['domain_name'],
        arn=module.params['certificate_arn'],
        only_tags=tags)

    module.debug("Found %d corresponding certificates in ACM" %
                 len(certificates))

    if module.params['state'] == 'present':
        if len(certificates) > 1:
            msg = "More than one certificate with Name=%s exists in ACM in this region" % module.params[
                'name_tag']
            module.fail_json(msg=msg, certificates=certificates)
        elif len(certificates) == 1:
            # update the existing certificate
            module.debug("Existing certificate found in ACM")
            old_cert = certificates[0]  # existing cert in ACM
            if ('tags'
                    not in old_cert) or ('Name' not in old_cert['tags']) or (
                        old_cert['tags']['Name'] != module.params['name_tag']):
                # shouldn't happen
                module.fail_json(
                    msg="Internal error, unsure which certificate to update",
                    certificate=old_cert)

            if 'certificate' not in old_cert:
                # shouldn't happen
                module.fail_json(
                    msg=
                    "Internal error, unsure what the existing cert in ACM is",
                    certificate=old_cert)

            # Are the existing certificate in ACM and the local certificate the same?
            same = True
            same &= chain_compare(module, old_cert['certificate'],
                                  module.params['certificate'])
            if module.params['certificate_chain']:
                # Need to test this
                # not sure if Amazon appends the cert itself to the chain when self-signed
                same &= chain_compare(module, old_cert['certificate_chain'],
                                      module.params['certificate_chain'])
            else:
                # When there is no chain with a cert
                # it seems Amazon returns the cert itself as the chain
                same &= chain_compare(module, old_cert['certificate_chain'],
                                      module.params['certificate'])

            if same:
                module.debug(
                    "Existing certificate in ACM is the same, doing nothing")
                domain = acm.get_domain_of_cert(
                    client=client,
                    module=module,
                    arn=old_cert['certificate_arn'])
                module.exit_json(certificate=dict(
                    domain_name=domain, arn=old_cert['certificate_arn']),
                                 changed=False)
            else:
                module.debug(
                    "Existing certificate in ACM is different, overwriting")

                # update cert in ACM
                arn = acm.import_certificate(
                    client,
                    module,
                    certificate=module.params['certificate'],
                    private_key=module.params['private_key'],
                    certificate_chain=module.params['certificate_chain'],
                    arn=old_cert['certificate_arn'],
                    tags=tags)
                domain = acm.get_domain_of_cert(client=client,
                                                module=module,
                                                arn=arn)
                module.exit_json(certificate=dict(domain_name=domain, arn=arn),
                                 changed=True)
        else:  # len(certificates) == 0
            module.debug("No certificate in ACM. Creating new one.")
            arn = acm.import_certificate(
                client=client,
                module=module,
                certificate=module.params['certificate'],
                private_key=module.params['private_key'],
                certificate_chain=module.params['certificate_chain'],
                tags=tags)
            domain = acm.get_domain_of_cert(client=client,
                                            module=module,
                                            arn=arn)

            module.exit_json(certificate=dict(domain_name=domain, arn=arn),
                             changed=True)

    else:  # state == absent
        for cert in certificates:
            acm.delete_certificate(client, module, cert['certificate_arn'])
        module.exit_json(
            arns=[cert['certificate_arn'] for cert in certificates],
            changed=(len(certificates) > 0))
示例#47
0
def main():
    module = AnsibleAWSModule(
        argument_spec={
            'name': dict(required=True),
            'state': dict(choices=['present', 'absent'], default='present'),
            'description': dict(default=""),
            'kms_key_id': dict(),
            'secret_type': dict(choices=['binary', 'string'],
                                default="string"),
            'secret': dict(default=""),
            'tags': dict(type='dict', default={}),
            'rotation_lambda': dict(),
            'rotation_interval': dict(type='int', default=30),
            'recovery_window': dict(type='int', default=30),
        },
        supports_check_mode=True,
    )

    changed = False
    state = module.params.get('state')
    secrets_mgr = SecretsManagerInterface(module)
    recovery_window = module.params.get('recovery_window')
    secret = Secret(module.params.get('name'),
                    module.params.get('secret_type'),
                    module.params.get('secret'),
                    description=module.params.get('description'),
                    kms_key_id=module.params.get('kms_key_id'),
                    tags=module.params.get('tags'),
                    lambda_arn=module.params.get('rotation_lambda'),
                    rotation_interval=module.params.get('rotation_interval'))

    current_secret = secrets_mgr.get_secret(secret.name)

    if state == 'absent':
        if current_secret:
            if not current_secret.get("DeletedDate"):
                result = camel_dict_to_snake_dict(
                    secrets_mgr.delete_secret(secret.name,
                                              recovery_window=recovery_window))
                changed = True
            elif current_secret.get("DeletedDate") and recovery_window == 0:
                result = camel_dict_to_snake_dict(
                    secrets_mgr.delete_secret(secret.name,
                                              recovery_window=recovery_window))
                changed = True
        else:
            result = "secret does not exist"
    if state == 'present':
        if current_secret is None:
            result = secrets_mgr.create_secret(secret)
            changed = True
        else:
            if current_secret.get("DeletedDate"):
                secrets_mgr.restore_secret(secret.name)
                changed = True
            if not secrets_mgr.secrets_match(secret, current_secret):
                result = secrets_mgr.update_secret(secret)
                changed = True
            if not rotation_match(secret, current_secret):
                result = secrets_mgr.update_rotation(secret)
                changed = True
            current_tags = boto3_tag_list_to_ansible_dict(
                current_secret.get('Tags', []))
            tags_to_add, tags_to_remove = compare_aws_tags(
                current_tags, secret.tags)
            if tags_to_add:
                secrets_mgr.tag_secret(
                    secret.name, ansible_dict_to_boto3_tag_list(tags_to_add))
                changed = True
            if tags_to_remove:
                secrets_mgr.untag_secret(secret.name, tags_to_remove)
                changed = True
        result = camel_dict_to_snake_dict(secrets_mgr.get_secret(secret.name))
        result.pop("response_metadata")
    module.exit_json(changed=changed, secret=result)
示例#48
0
def main():
    argument_spec = ec2_argument_spec()
    argument_spec.update(
        dict(state=dict(required=True, choices=['present', 'absent']),
             arn=dict(required=False, type='str'),
             family=dict(required=False, type='str'),
             revision=dict(required=False, type='int'),
             force_create=dict(required=False, default=False, type='bool'),
             containers=dict(required=False, type='list'),
             network_mode=dict(required=False,
                               default='bridge',
                               choices=['bridge', 'host', 'none', 'awsvpc'],
                               type='str'),
             task_role_arn=dict(required=False, default='', type='str'),
             execution_role_arn=dict(required=False, default='', type='str'),
             volumes=dict(required=False, type='list'),
             launch_type=dict(required=False, choices=['EC2', 'FARGATE']),
             cpu=dict(),
             memory=dict(required=False, type='str')))

    module = AnsibleAWSModule(argument_spec=argument_spec,
                              supports_check_mode=True,
                              required_if=[('launch_type', 'FARGATE',
                                            ['cpu', 'memory'])])

    if not HAS_BOTO3:
        module.fail_json(msg='boto3 is required.')

    task_to_describe = None
    task_mgr = EcsTaskManager(module)
    results = dict(changed=False)

    if module.params['launch_type']:
        if not module.botocore_at_least('1.8.4'):
            module.fail_json(
                msg=
                'botocore needs to be version 1.8.4 or higher to use launch_type'
            )

    if module.params['execution_role_arn']:
        if not module.botocore_at_least('1.10.44'):
            module.fail_json(
                msg=
                'botocore needs to be version 1.10.44 or higher to use execution_role_arn'
            )

    if module.params['containers']:
        for container in module.params['containers']:
            for environment in container.get('environment', []):
                environment['value'] = to_text(environment['value'])

    if module.params['state'] == 'present':
        if 'containers' not in module.params or not module.params['containers']:
            module.fail_json(
                msg=
                "To use task definitions, a list of containers must be specified"
            )

        if 'family' not in module.params or not module.params['family']:
            module.fail_json(
                msg="To use task definitions, a family must be specified")

        network_mode = module.params['network_mode']
        launch_type = module.params['launch_type']
        if launch_type == 'FARGATE' and network_mode != 'awsvpc':
            module.fail_json(
                msg="To use FARGATE launch type, network_mode must be awsvpc")

        family = module.params['family']
        existing_definitions_in_family = task_mgr.describe_task_definitions(
            module.params['family'])

        if 'revision' in module.params and module.params['revision']:
            # The definition specifies revision. We must gurantee that an active revision of that number will result from this.
            revision = int(module.params['revision'])

            # A revision has been explicitly specified. Attempt to locate a matching revision
            tasks_defs_for_revision = [
                td for td in existing_definitions_in_family
                if td['revision'] == revision
            ]
            existing = tasks_defs_for_revision[0] if len(
                tasks_defs_for_revision) > 0 else None

            if existing and existing['status'] != "ACTIVE":
                # We cannot reactivate an inactive revision
                module.fail_json(
                    msg=
                    "A task in family '%s' already exists for revsion %d, but it is inactive"
                    % (family, revision))
            elif not existing:
                if not existing_definitions_in_family and revision != 1:
                    module.fail_json(
                        msg=
                        "You have specified a revision of %d but a created revision would be 1"
                        % revision)
                elif existing_definitions_in_family and existing_definitions_in_family[
                        -1]['revision'] + 1 != revision:
                    module.fail_json(
                        msg=
                        "You have specified a revision of %d but a created revision would be %d"
                        % (revision,
                           existing_definitions_in_family[-1]['revision'] + 1))
        else:
            existing = None

            def _right_has_values_of_left(left, right):
                # Make sure the values are equivalent for everything left has
                for k, v in left.items():
                    if not ((not v and (k not in right or not right[k])) or
                            (k in right and v == right[k])):
                        # We don't care about list ordering because ECS can change things
                        if isinstance(v, list) and k in right:
                            left_list = v
                            right_list = right[k] or []

                            if len(left_list) != len(right_list):
                                return False

                            for list_val in left_list:
                                if list_val not in right_list:
                                    return False
                        else:
                            return False

                # Make sure right doesn't have anything that left doesn't
                for k, v in right.items():
                    if v and k not in left:
                        return False

                return True

            def _task_definition_matches(requested_volumes,
                                         requested_containers,
                                         requested_task_role_arn,
                                         existing_task_definition):
                if td['status'] != "ACTIVE":
                    return None

                if requested_task_role_arn != td.get('taskRoleArn', ""):
                    return None

                existing_volumes = td.get('volumes', []) or []

                if len(requested_volumes) != len(existing_volumes):
                    # Nope.
                    return None

                if len(requested_volumes) > 0:
                    for requested_vol in requested_volumes:
                        found = False

                        for actual_vol in existing_volumes:
                            if _right_has_values_of_left(
                                    requested_vol, actual_vol):
                                found = True
                                break

                        if not found:
                            return None

                existing_containers = td.get('containerDefinitions', []) or []

                if len(requested_containers) != len(existing_containers):
                    # Nope.
                    return None

                for requested_container in requested_containers:
                    found = False

                    for actual_container in existing_containers:
                        if _right_has_values_of_left(requested_container,
                                                     actual_container):
                            found = True
                            break

                    if not found:
                        return None

                return existing_task_definition

            # No revision explicitly specified. Attempt to find an active, matching revision that has all the properties requested
            for td in existing_definitions_in_family:
                requested_volumes = module.params['volumes'] or []
                requested_containers = module.params['containers'] or []
                requested_task_role_arn = module.params['task_role_arn']
                existing = _task_definition_matches(requested_volumes,
                                                    requested_containers,
                                                    requested_task_role_arn,
                                                    td)

                if existing:
                    break

        if existing and not module.params.get('force_create'):
            # Awesome. Have an existing one. Nothing to do.
            results['taskdefinition'] = existing
        else:
            if not module.check_mode:
                # Doesn't exist. create it.
                volumes = module.params.get('volumes', []) or []
                results['taskdefinition'] = task_mgr.register_task(
                    module.params['family'], module.params['task_role_arn'],
                    module.params['execution_role_arn'],
                    module.params['network_mode'], module.params['containers'],
                    volumes, module.params['launch_type'],
                    module.params['cpu'], module.params['memory'])
            results['changed'] = True

    elif module.params['state'] == 'absent':
        # When de-registering a task definition, we can specify the ARN OR the family and revision.
        if module.params['state'] == 'absent':
            if 'arn' in module.params and module.params['arn'] is not None:
                task_to_describe = module.params['arn']
            elif 'family' in module.params and module.params['family'] is not None and 'revision' in module.params and \
                    module.params['revision'] is not None:
                task_to_describe = module.params['family'] + ":" + str(
                    module.params['revision'])
            else:
                module.fail_json(
                    msg=
                    "To use task definitions, an arn or family and revision must be specified"
                )

        existing = task_mgr.describe_task(task_to_describe)

        if not existing:
            pass
        else:
            # It exists, so we should delete it and mark changed. Return info about the task definition deleted
            results['taskdefinition'] = existing
            if 'status' in existing and existing['status'] == "INACTIVE":
                results['changed'] = False
            else:
                if not module.check_mode:
                    task_mgr.deregister_task(task_to_describe)
                results['changed'] = True

    module.exit_json(**results)