def main(): argument_spec = dict( iam_type=dict(required=True, choices=['user', 'group', 'role']), iam_name=dict(required=True), policy_name=dict(default=None, required=False), ) module = AnsibleAWSModule(argument_spec=argument_spec, supports_check_mode=True) args = dict( client=module.client('iam'), name=module.params.get('iam_name'), policy_name=module.params.get('policy_name'), ) iam_type = module.params.get('iam_type') try: if iam_type == 'user': policy = UserPolicy(**args) elif iam_type == 'role': policy = RolePolicy(**args) elif iam_type == 'group': policy = GroupPolicy(**args) module.exit_json(**(policy.run())) except (BotoCoreError, ClientError) as e: if e.response['Error']['Code'] == 'NoSuchEntity': module.exit_json(changed=False, msg=e.response['Error']['Message']) module.fail_json_aws(e) except PolicyError as e: module.fail_json(msg=str(e))
def main(): argument_spec = 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') client = module.client('events') cwe_rule = CloudWatchEventRule(module, client=client, **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())
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)
def main(): argument_spec = ec2_argument_spec() argument_spec.update( dict(role_arn=dict(required=True), role_session_name=dict(required=True), duration_seconds=dict(required=False, default=None, type='int'), external_id=dict(required=False, default=None), policy=dict(required=False, default=None), mfa_serial_number=dict(required=False, default=None), mfa_token=dict(required=False, default=None))) module = AnsibleAWSModule(argument_spec=argument_spec) region, ec2_url, aws_connect_kwargs = get_aws_connection_info(module, boto3=True) if region: connection = boto3_conn(module, conn_type='client', resource='sts', region=region, endpoint=ec2_url, **aws_connect_kwargs) else: module.fail_json(msg="region must be specified") assume_role_policy(connection, module)
def run_module(): argument_spec = ec2_argument_spec() argument_spec.update( dict( cluster_name=dict(type='str', required=True, aliases=['cluster']), state=dict(type='str', choices=['present', 'absent'], default='present'), region=dict(type='str', required=True, aliases=['source']), destination_region=dict(type='str', required=True, aliases=['destination']), snapshot_copy_grant=dict(type='str', aliases=['copy_grant']), snapshot_retention_period=dict(type='int', required=True, aliases=['retention_period']), )) module = AnsibleAWSModule(argument_spec=argument_spec, supports_check_mode=True) result = dict(changed=False, message='') connection = module.client('redshift') snapshot_controller = SnapshotController( client=connection, cluster_name=module.params.get('cluster_name')) current_config = snapshot_controller.get_cluster_snapshot_copy_status() if current_config is not None: if module.params.get('state') == 'present': if requesting_unsupported_modifications(current_config, module.params): message = 'Cannot modify destination_region or grant_name. ' \ 'Please disable cross-region snapshots, and re-run.' module.fail_json(msg=message, **result) if needs_update(current_config, module.params): result['changed'] = True if not module.check_mode: snapshot_controller.modify_snapshot_copy_retention_period( module.params.get('snapshot_retention_period')) else: result['changed'] = True if not module.check_mode: snapshot_controller.disable_snapshot_copy() else: if module.params.get('state') == 'present': result['changed'] = True if not module.check_mode: snapshot_controller.enable_snapshot_copy( module.params.get('destination_region'), module.params.get('snapshot_copy_grant'), module.params.get('snapshot_retention_period')) module.exit_json(**result)
def main(): event_types = [ 's3:ObjectCreated:*', 's3:ObjectCreated:Put', 's3:ObjectCreated:Post', 's3:ObjectCreated:Copy', 's3:ObjectCreated:CompleteMultipartUpload', 's3:ObjectRemoved:*', 's3:ObjectRemoved:Delete', 's3:ObjectRemoved:DeleteMarkerCreated', 's3:ObjectRestore:Post', 's3:ObjectRestore:Completed', 's3:ReducedRedundancyLostObject' ] argument_spec = dict( state=dict(default='present', choices=['present', 'absent']), event_name=dict(required=True), lambda_function_arn=dict(aliases=['function_arn']), bucket_name=dict(required=True), events=dict(type='list', default=[], choices=event_types), prefix=dict(default=''), suffix=dict(default=''), lambda_alias=dict(), lambda_version=dict(type='int', default=0), ) module = AnsibleAWSModule( argument_spec=argument_spec, supports_check_mode=True, mutually_exclusive=[['lambda_alias', 'lambda_version']], required_if=[['state', 'present', ['events']]]) bucket = AmazonBucket(module.client('s3'), module.params['bucket_name']) current = bucket.current_config(module.params['event_name']) desired = Config.from_params(**module.params) notification_configuration = [cfg.raw for cfg in bucket.full_config()] state = module.params['state'] try: if (state == 'present' and current == desired) or (state == 'absent' and not current): changed = False elif module.check_mode: changed = True elif state == 'present': changed = True notification_configuration = bucket.apply_config(desired) elif state == 'absent': changed = True notification_configuration = bucket.delete_config(desired) except (ClientError, BotoCoreError) as e: module.fail_json(msg='{0}'.format(e)) module.exit_json(**dict(changed=changed, notification_configuration=[ camel_dict_to_snake_dict(cfg) for cfg in notification_configuration ]))
def main(): argument_spec = dict( iam_type=dict(required=True, choices=['user', 'group', 'role']), state=dict(default='present', choices=['present', 'absent']), iam_name=dict(required=True), policy_name=dict(required=True), policy_document=dict(default=None, required=False), policy_json=dict(type='json', default=None, required=False), skip_duplicates=dict(type='bool', default=None, required=False) ) mutually_exclusive = [['policy_document', 'policy_json']] module = AnsibleAWSModule(argument_spec=argument_spec, mutually_exclusive=mutually_exclusive, supports_check_mode=True) skip_duplicates = module.params.get('skip_duplicates') if (skip_duplicates is None): module.deprecate('The skip_duplicates behaviour has caused confusion and' ' will be disabled by default in Ansible 2.14', version='2.14') skip_duplicates = True if module.params.get('policy_document'): module.deprecate('The policy_document option has been deprecated and' ' will be removed in Ansible 2.14', version='2.14') args = dict( client=module.client('iam'), name=module.params.get('iam_name'), policy_name=module.params.get('policy_name'), policy_document=module.params.get('policy_document'), policy_json=module.params.get('policy_json'), skip_duplicates=skip_duplicates, state=module.params.get('state'), check_mode=module.check_mode, ) iam_type = module.params.get('iam_type') try: if iam_type == 'user': policy = UserPolicy(**args) elif iam_type == 'role': policy = RolePolicy(**args) elif iam_type == 'group': policy = GroupPolicy(**args) module.exit_json(**(policy.run())) except (BotoCoreError, ClientError) as e: module.fail_json_aws(e) except PolicyError as e: module.fail_json(msg=str(e))
def main(): argument_spec = dict(instance_id=dict(), image_id=dict(), architecture=dict(default='x86_64'), kernel_id=dict(), virtualization_type=dict(default='hvm'), root_device_name=dict(), delete_snapshot=dict(default=False, type='bool'), name=dict(), wait=dict(type='bool', default=False), wait_timeout=dict(default=900, type='int'), description=dict(default=''), no_reboot=dict(default=False, type='bool'), state=dict(default='present', choices=['present', 'absent']), device_mapping=dict(type='list'), tags=dict(type='dict'), launch_permissions=dict(type='dict'), image_location=dict(), enhanced_networking=dict(type='bool'), billing_products=dict(type='list'), ramdisk_id=dict(), sriov_net_support=dict(), purge_tags=dict(type='bool', default=False)) module = AnsibleAWSModule(argument_spec=argument_spec, required_if=[ ['state', 'absent', ['image_id']], ]) # Using a required_one_of=[['name', 'image_id']] overrides the message that should be provided by # the required_if for state=absent, so check manually instead if not any([module.params['image_id'], module.params['name']]): module.fail_json( msg="one of the following is required: name, image_id") connection = module.client('ec2') if module.params.get('state') == 'absent': deregister_image(module, connection) elif module.params.get('state') == 'present': if module.params.get('image_id'): update_image(module, connection, module.params.get('image_id')) if not module.params.get('instance_id') and not module.params.get( 'device_mapping'): module.fail_json( msg= "The parameters instance_id or device_mapping (register from EBS snapshot) are required for a new image." ) create_image(module, connection)
def main(): argument_spec = ec2_argument_spec() argument_spec.update( dict(name=dict(required=True, 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)
def main(): module = AnsibleAWSModule( argument_spec={ "identity": dict(required=True, type='str'), "state": dict(default='present', choices=['present', 'absent']), "bounce_notifications": dict(type='dict'), "complaint_notifications": dict(type='dict'), "delivery_notifications": dict(type='dict'), "feedback_forwarding": dict(default=True, type='bool'), }, supports_check_mode=True, ) for notification_type in ('bounce', 'complaint', 'delivery'): param_name = notification_type + '_notifications' arg_dict = module.params.get(param_name) if arg_dict: extra_keys = [ x for x in arg_dict.keys() if x not in ('topic', 'include_headers') ] if extra_keys: module.fail_json(msg='Unexpected keys ' + str(extra_keys) + ' in ' + param_name + ' valid keys are topic or include_headers') # SES APIs seem to have a much lower throttling threshold than most of the rest of the AWS APIs. # Docs say 1 call per second. This shouldn't actually be a big problem for normal usage, but # the ansible build runs multiple instances of the test in parallel that's caused throttling # failures so apply a jittered backoff to call SES calls. connection = module.client('ses', retry_decorator=AWSRetry.jittered_backoff()) state = module.params.get("state") if state == 'present': region = get_aws_connection_info(module, boto3=True)[0] account_id = get_account_id(module) validate_params_for_identity_present(module) create_or_update_identity(connection, module, region, account_id) else: destroy_identity(connection, module)
def main(): argument_spec = ec2_argument_spec() argument_spec.update( dict( az=dict(default=None, required=False), cidr=dict(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(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 not module.botocore_at_least("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)
def main(): argument_spec = dict(gather_local_disks=dict(type='bool', default=True), gather_tapes=dict(type='bool', default=True), gather_file_shares=dict(type='bool', default=True), gather_volumes=dict(type='bool', default=True)) module = AnsibleAWSModule(argument_spec=argument_spec) if module._name == 'aws_sgw_facts': module.deprecate( "The 'aws_sgw_facts' module has been renamed to 'aws_sgw_info'", version='2.13') client = module.client('storagegateway') if client is None: # this should never happen module.fail_json( msg= 'Unknown error, failed to create storagegateway client, no information from boto.' ) SGWInformationManager(client, module).fetch()
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(no_log=True, 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), wait_timeout=dict(type='int', default=600), delay=dict(type='int', default=15), ) 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))
def main(): argument_spec = 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']]]) connection = module.client('directconnect') 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))
def main(): argument_spec = dict(name=dict(required=False), waf_regional=dict(type='bool', default=False)) module = AnsibleAWSModule(argument_spec=argument_spec, supports_check_mode=True) if module._name == 'aws_waf_facts': module.deprecate( "The 'aws_waf_facts' module has been renamed to 'aws_waf_info'", version='2.13') resource = 'waf' if not module.params['waf_regional'] else 'waf-regional' client = module.client(resource) 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 = dict( certificate_arn=dict(aliases=['arn']), domain_name=dict(aliases=['name']), statuses=dict(type='list', choices=[ 'PENDING_VALIDATION', 'ISSUED', 'INACTIVE', 'EXPIRED', 'VALIDATION_TIMED_OUT', 'REVOKED', 'FAILED' ]), tags=dict(type='dict'), ) module = AnsibleAWSModule(argument_spec=argument_spec, supports_check_mode=True) acm_info = ACMServiceManager(module) if module._name == 'aws_acm_facts': module.deprecate( "The 'aws_acm_facts' module has been renamed to 'aws_acm_info'", version='2.13') client = module.client('acm') certificates = acm_info.get_certificates( client, module, domain_name=module.params['domain_name'], statuses=module.params['statuses'], arn=module.params['certificate_arn'], only_tags=module.params['tags']) if module.params['certificate_arn'] and len(certificates) != 1: module.fail_json( msg="No certificate exists in this region with ARN %s" % module.params['certificate_arn']) module.exit_json(certificates=certificates)
def main(): argument_spec = dict(state=dict(required=True, choices=['present', 'absent']), name=dict(), location=dict(), bandwidth=dict(choices=['1Gbps', '10Gbps']), link_aggregation_group=dict(), connection_id=dict(), forced_update=dict(type='bool', default=False)) module = AnsibleAWSModule(argument_spec=argument_spec, required_one_of=[('connection_id', 'name')], required_if=[('state', 'present', ('location', 'bandwidth'))]) connection = module.client('directconnect') state = module.params.get('state') try: connection_id = connection_exists( connection, connection_id=module.params.get('connection_id'), connection_name=module.params.get('name')) if not connection_id and module.params.get('connection_id'): module.fail_json( msg="The Direct Connect connection {0} does not exist.".format( module.params.get('connection_id'))) if state == 'present': changed, connection_id = ensure_present( connection, connection_id=connection_id, connection_name=module.params.get('name'), location=module.params.get('location'), bandwidth=module.params.get('bandwidth'), lag_id=module.params.get('link_aggregation_group'), forced_update=module.params.get('forced_update')) response = connection_status(connection, connection_id) elif state == 'absent': changed = ensure_absent(connection, connection_id) response = {} except DirectConnectError as e: if e.last_traceback: module.fail_json(msg=e.msg, exception=e.last_traceback, **camel_dict_to_snake_dict(e.exception.response)) else: module.fail_json(msg=e.msg) module.exit_json(changed=changed, **camel_dict_to_snake_dict(response))
def main(): argument_spec = dict(name=dict(required=True, type='str'), expiration_days=dict(type='int'), expiration_date=dict(), noncurrent_version_expiration_days=dict(type='int'), noncurrent_version_storage_class=dict( default='glacier', type='str', choices=['glacier', 'onezone_ia', 'standard_ia']), noncurrent_version_transition_days=dict(type='int'), noncurrent_version_transitions=dict(type='list'), prefix=dict(), requester_pays=dict(type='bool', removed_in_version='2.14'), rule_id=dict(), state=dict(default='present', choices=['present', 'absent']), status=dict(default='enabled', choices=['enabled', 'disabled']), storage_class=dict( default='glacier', type='str', choices=['glacier', 'onezone_ia', 'standard_ia']), transition_days=dict(type='int'), transition_date=dict(), transitions=dict(type='list'), purge_transitions=dict(default='yes', type='bool')) module = AnsibleAWSModule( argument_spec=argument_spec, mutually_exclusive=[ ['expiration_days', 'expiration_date'], ['expiration_days', 'transition_date'], ['transition_days', 'transition_date'], ['transition_days', 'expiration_date'], ['transition_days', 'transitions'], ['transition_date', 'transitions'], [ 'noncurrent_version_transition_days', 'noncurrent_version_transitions' ], ], ) if not HAS_DATEUTIL: module.fail_json(msg='dateutil required for this module') client = module.client('s3') expiration_date = module.params.get("expiration_date") transition_date = module.params.get("transition_date") state = module.params.get("state") if state == 'present' and module.params[ "status"] == "enabled": # allow deleting/disabling a rule by id/prefix required_when_present = ('expiration_date', 'expiration_days', 'transition_date', 'transition_days', 'transitions', 'noncurrent_version_expiration_days', 'noncurrent_version_transition_days', 'noncurrent_version_transitions') for param in required_when_present: if module.params.get(param): break else: msg = "one of the following is required when 'state' is 'present': %s" % ', '.join( required_when_present) module.fail_json(msg=msg) # If expiration_date set, check string is valid if expiration_date is not None: try: datetime.datetime.strptime(expiration_date, "%Y-%m-%dT%H:%M:%S.000Z") except ValueError as e: module.fail_json( msg= "expiration_date is not a valid ISO-8601 format. The time must be midnight and a timezone of GMT must be included" ) if transition_date is not None: try: datetime.datetime.strptime(transition_date, "%Y-%m-%dT%H:%M:%S.000Z") except ValueError as e: module.fail_json( msg= "expiration_date is not a valid ISO-8601 format. The time must be midnight and a timezone of GMT must be included" ) if state == 'present': create_lifecycle_rule(client, module) elif state == 'absent': destroy_lifecycle_rule(client, module)
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(), tracing_mode=dict(choices=['Active', 'PassThrough']), 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') tracing_mode = module.params.get('tracing_mode') 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 re.match(r'^arn:aws(-([a-z\-]+))?:iam', role): role_arn = role else: # get account ID and assemble ARN account_id, partition = get_account_info(module, region=region, endpoint=ec2_url, **aws_connect_kwargs) role_arn = 'arn:{0}:iam::{1}:role/{2}'.format( partition, 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 runtime and current_config['Runtime'] != runtime: func_kwargs.update({'Runtime': runtime}) 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 }}) if tracing_mode and (current_config.get('TracingConfig', {}).get( 'Mode', 'PassThrough') != tracing_mode): func_kwargs.update({'TracingConfig': {'Mode': tracing_mode}}) # 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 tracing_mode: func_kwargs.update({'TracingConfig': {'Mode': tracing_mode}}) # 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(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))
def main(): argument_spec = ec2_argument_spec() argument_spec.update(dict( device_id=dict(required=False, aliases=['instance_id']), public_ip=dict(required=False, aliases=['ip']), state=dict(required=False, default='present', choices=['present', 'absent']), in_vpc=dict(required=False, type='bool', default=False), reuse_existing_ip_allowed=dict(required=False, type='bool', default=False), release_on_disassociation=dict(required=False, type='bool', default=False), allow_reassociation=dict(type='bool', default=False), wait_timeout=dict(type='int', removed_in_version='2.14'), private_ip_address=dict(), tag_name=dict(), tag_value=dict(), public_ipv4_pool=dict() )) module = AnsibleAWSModule( argument_spec=argument_spec, supports_check_mode=True, required_by={ 'private_ip_address': ['device_id'], }, ) ec2 = module.client('ec2', retry_decorator=AWSRetry.jittered_backoff()) device_id = module.params.get('device_id') instance_id = module.params.get('instance_id') public_ip = module.params.get('public_ip') private_ip_address = module.params.get('private_ip_address') state = module.params.get('state') in_vpc = module.params.get('in_vpc') domain = 'vpc' if in_vpc else None reuse_existing_ip_allowed = module.params.get('reuse_existing_ip_allowed') release_on_disassociation = module.params.get('release_on_disassociation') allow_reassociation = module.params.get('allow_reassociation') tag_name = module.params.get('tag_name') tag_value = module.params.get('tag_value') public_ipv4_pool = module.params.get('public_ipv4_pool') if instance_id: warnings = ["instance_id is no longer used, please use device_id going forward"] is_instance = True device_id = instance_id else: if device_id and device_id.startswith('i-'): is_instance = True elif device_id: if device_id.startswith('eni-') and not in_vpc: module.fail_json(msg="If you are specifying an ENI, in_vpc must be true") is_instance = False tag_dict = generate_tag_dict(module, tag_name, tag_value) try: if device_id: address = find_address(ec2, module, public_ip, device_id, is_instance=is_instance) else: address = find_address(ec2, module, public_ip, None) if state == 'present': if device_id: result = ensure_present( ec2, module, domain, address, private_ip_address, device_id, reuse_existing_ip_allowed, allow_reassociation, module.check_mode, is_instance=is_instance ) else: if address: changed = False else: address, changed = allocate_address( ec2, module, domain, reuse_existing_ip_allowed, module.check_mode, tag_dict, public_ipv4_pool ) result = { 'changed': changed, 'public_ip': address['PublicIp'], 'allocation_id': address['AllocationId'] } else: if device_id: disassociated = ensure_absent( ec2, module, address, device_id, module.check_mode, is_instance=is_instance ) if release_on_disassociation and disassociated['changed']: released = release_address(ec2, module, address, module.check_mode) result = { 'changed': True, 'disassociated': disassociated, 'released': released } else: result = { 'changed': disassociated['changed'], 'disassociated': disassociated, 'released': {'changed': False} } else: released = release_address(ec2, module, address, module.check_mode) result = { 'changed': released['changed'], 'disassociated': {'changed': False}, 'released': released } except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e: module.fail_json_aws(str(e)) if instance_id: result['warnings'] = warnings module.exit_json(**result)
def main(): argument_spec = 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') key_id = module.params.get('key_id') alias = module.params.get('alias') if alias and alias.startswith('alias/'): alias = alias[6:] # Fetch/Canonicalize key_id where possible if key_id: try: # Don't use get_key_details it triggers module.fail when the key # doesn't exist key_metadata = get_kms_metadata_with_backoff(kms, key_id)['KeyMetadata'] key_id = key_metadata['Arn'] except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: # We can't create keys with a specific ID, if we can't access the # key we'll have to fail if module.params.get('state') == 'present': module.fail_json(msg="Could not find key with id %s to update") key_metadata = None elif alias: try: key_metadata = get_kms_metadata_with_backoff( kms, 'alias/%s' % alias)['KeyMetadata'] key_id = key_metadata['Arn'] except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: key_metadata = None 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(module, kms, key_id, 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 key_metadata: key_details = get_key_details(kms, module, key_id) update_key(kms, module, key_details) else: if key_id: module.fail_json( msg="Could not find key with id %s to update" % key_id) else: create_key(kms, module) else: if key_metadata: delete_key(kms, module, key_metadata, key_id) else: module.exit_json(changed=False)
def main(): argument_spec = ec2_argument_spec() argument_spec.update( dict(force=dict(default=False, type='bool'), policy=dict(type='json'), name=dict(required=True), requester_pays=dict(default=False, type='bool'), s3_url=dict(aliases=['S3_URL']), state=dict(default='present', choices=['present', 'absent']), tags=dict(type='dict'), purge_tags=dict(type='bool', default=True), versioning=dict(type='bool'), ceph=dict(default=False, type='bool'), encryption=dict(choices=['none', 'AES256', 'aws:kms']), encryption_key_id=dict())) module = AnsibleAWSModule(argument_spec=argument_spec, ) 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 s3_url = module.params.get('s3_url') ceph = module.params.get('ceph') # 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 ceph and not s3_url: module.fail_json(msg='ceph flavour requires s3_url') # Look at s3_url and tweak connection settings # if connecting to Ceph RGW, Walrus or fakes3 if s3_url: for key in ['validate_certs', 'security_token', 'profile_name']: aws_connect_kwargs.pop(key, None) s3_client = get_s3_client(module, aws_connect_kwargs, location, ceph, s3_url) if s3_client is None: # this should never happen module.fail_json( msg= 'Unknown error, failed to create s3 connection, no information from boto.' ) state = module.params.get("state") encryption = module.params.get("encryption") encryption_key_id = module.params.get("encryption_key_id") # Parameter validation if encryption_key_id is not None and encryption is None: module.fail_json( msg= "You must specify encryption parameter along with encryption_key_id." ) elif encryption_key_id is not None and encryption != 'aws:kms': module.fail_json( msg= "Only 'aws:kms' is a valid option for encryption parameter when you specify encryption_key_id." ) if state == 'present': create_or_update_bucket(s3_client, module, location) elif state == 'absent': destroy_bucket(s3_client, module)
def main(): protocols = [ 'http', 'https', 'email', 'email_json', 'sms', 'sqs', 'application', 'lambda', ] argument_spec = dict( msg=dict(required=True, aliases=['default']), subject=dict(), topic=dict(required=True), message_attributes=dict(type='dict'), message_structure=dict(choices=['json', 'string'], default='json'), ) for p in protocols: argument_spec[p] = dict() module = AnsibleAWSModule(argument_spec=argument_spec) sns_kwargs = dict( Message=module.params['msg'], Subject=module.params['subject'], MessageStructure=module.params['message_structure'], ) if module.params['message_attributes']: if module.params['message_structure'] != 'string': module.fail_json( msg= 'message_attributes is only supported when the message_structure is "string".' ) sns_kwargs['MessageAttributes'] = module.params['message_attributes'] dict_msg = {'default': sns_kwargs['Message']} for p in protocols: if module.params[p]: if sns_kwargs['MessageStructure'] != 'json': module.fail_json( msg= 'Protocol-specific messages are only supported when message_structure is "json".' ) dict_msg[p.replace('_', '-')] = module.params[p] client = module.client('sns') topic = module.params['topic'] if ':' in topic: # Short names can't contain ':' so we'll assume this is the full ARN sns_kwargs['TopicArn'] = topic else: sns_kwargs['TopicArn'] = arn_topic_lookup(module, client, topic) if not sns_kwargs['TopicArn']: module.fail_json(msg='Could not find topic: {0}'.format(topic)) if sns_kwargs['MessageStructure'] == 'json': sns_kwargs['Message'] = json.dumps(dict_msg) try: result = client.publish(**sns_kwargs) except (BotoCoreError, ClientError) as e: module.fail_json_aws(e, msg='Failed to publish message') module.exit_json(msg='OK', message_id=result['MessageId'])
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']), tags=dict(required=False, type='dict'))) 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') if module.params['tags']: if not service_mgr.ecs_api_handles_tags(): module.fail_json(msg=missing_required_lib("botocore >= 1.12.46", reason="to use tags")) if not service_mgr.ecs_task_long_format_enabled(): module.fail_json( msg= "Cannot set task tags: long format task arns are required to set tags" ) 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'], module.params['tags'], ) 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'], module.params['tags'], ) 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)
def main(): argument_spec = 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 = {} ebs = module.client('elasticbeanstalk') 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)
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), force_new_deployment=dict(required=False, default=False, type='bool'), deployment_configuration=dict(required=False, default={}, type='dict'), placement_constraints=dict(required=False, default=[], type='list'), placement_strategy=dict(required=False, default=[], type='list'), health_check_grace_period_seconds=dict(required=False, type='int'), 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']), service_registries=dict(required=False, type='list', default=[]), scheduling_strategy=dict(required=False, choices=['DAEMON', 'REPLICA']))) module = AnsibleAWSModule(argument_spec=argument_spec, supports_check_mode=True, required_if=[('state', 'present', ['task_definition']), ('launch_type', 'FARGATE', ['network_configuration'])], required_together=[['load_balancers', 'role']]) if module.params['state'] == 'present' and module.params[ 'scheduling_strategy'] == 'REPLICA': if module.params['desired_count'] is None: module.fail_json( msg= 'state is present, scheduling_strategy is REPLICA; missing desired_count' ) 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) serviceRegistries = list( map(snake_dict_to_camel_dict, module.params['service_registries'])) 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['force_new_deployment']: 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 force_new_deployment' ) if module.params['health_check_grace_period_seconds']: if not module.botocore_at_least('1.8.20'): module.fail_json( msg= 'botocore needs to be version 1.8.20 or higher to use health_check_grace_period_seconds' ) if module.params['state'] == 'present': matching = False update = False if existing and 'status' in existing and existing['status'] == "ACTIVE": if module.params['force_new_deployment']: update = True elif 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 = [] for loadBalancer in module.params['load_balancers']: if 'containerPort' in loadBalancer: loadBalancer['containerPort'] = int( loadBalancer['containerPort']) loadBalancers.append(loadBalancer) for loadBalancer in loadBalancers: if 'containerPort' in loadBalancer: loadBalancer['containerPort'] = int( loadBalancer['containerPort']) if update: # check various parameters and boto versions and give a helpful error in boto is not new enough for feature if module.params['scheduling_strategy']: if not module.botocore_at_least('1.10.37'): module.fail_json( msg= 'botocore needs to be version 1.10.37 or higher to use scheduling_strategy' ) elif (existing['schedulingStrategy'] ) != module.params['scheduling_strategy']: module.fail_json( msg= "It is not possible to update the scheduling strategy of an existing service" ) if module.params['service_registries']: if not module.botocore_at_least('1.9.15'): module.fail_json( msg= 'botocore needs to be version 1.9.15 or higher to use service_registries' ) elif (existing['serviceRegistries'] or []) != serviceRegistries: module.fail_json( msg= "It is not possible to update the service registries of an existing service" ) 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, module.params['health_check_grace_period_seconds'], module.params['force_new_deployment']) else: 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'], module.params['health_check_grace_period_seconds'], network_configuration, serviceRegistries, module.params['launch_type'], module.params['scheduling_strategy']) 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)
def main(): argument_spec = dict( name=dict(required=True), cidr_block=dict(type='list', required=True), ipv6_cidr=dict(type='bool', default=False), 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')) ipv6_cidr = module.params.get('ipv6_cidr') 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 try: connection.associate_vpc_cidr_block(CidrBlock=cidr, VpcId=vpc_id) except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: module.fail_json_aws(e, "Unable to associate CIDR {0}.".format(ipv6_cidr)) if ipv6_cidr: if 'Ipv6CidrBlockAssociationSet' in vpc_obj.keys(): module.warn("Only one IPv6 CIDR is permitted per VPC, {0} already has CIDR {1}".format( vpc_id, vpc_obj['Ipv6CidrBlockAssociationSet'][0]['Ipv6CidrBlock'])) else: try: connection.associate_vpc_cidr_block(AmazonProvidedIpv6CidrBlock=ipv6_cidr, VpcId=vpc_id) changed = True except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: module.fail_json_aws(e, "Unable to associate CIDR {0}.".format(ipv6_cidr)) 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={})
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(required=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 specify 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(): 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)