コード例 #1
0
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)
コード例 #2
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),
             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)
コード例 #3
0
def main():
    argument_spec = 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'

    if overwrite == 'different' and not HAS_MD5:
        module.fail_json(
            msg=
            'overwrite=different is unavailable: ETag calculation requires MD5 support'
        )

    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 mode == 'get':
        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 path_check(dest) and overwrite != 'always':
            if overwrite == 'never':
                module.exit_json(
                    msg=
                    "Local object already exists and overwrite is disabled.",
                    changed=False)
            if etag_compare(module, dest, s3, bucket, obj, version=version):
                module.exit_json(
                    msg=
                    "Local and remote object are identical, ignoring. Use overwrite=always parameter to force.",
                    changed=False)

        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 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

        if not path_check(src):
            module.fail_json(msg="Local object for PUT does not exist")

        if bucketrtn:
            keyrtn = key_check(module,
                               s3,
                               bucket,
                               obj,
                               version=version,
                               validate=validate)
        else:
            # If the bucket doesn't exist we should create it.
            # only use valid bucket acls for create_bucket function
            module.params['permission'] = bucket_acl
            create_bucket(module, s3, bucket, location)

        if keyrtn and overwrite != 'always':
            if overwrite == 'never' or etag_compare(module, src, s3, bucket,
                                                    obj):
                # Return the download URL for the existing object
                get_download_url(module,
                                 s3,
                                 bucket,
                                 obj,
                                 expiry,
                                 changed=False)

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