def get_subnet_by_cidr_and_vpc(ec2, cidr, vpc_id):
    # vpc id was not provided, assume default VPC
    if not vpc_id:
        default_vpc = ec2_vpc_utils.get_default_vpc(ec2)
        vpc_id = default_vpc.id

    subnet_collection = ec2.subnets.filter(
        Filters=ec2_filters.from_dict({
            'cidr': cidr,
            'vpc-id': vpc_id,
        }))

    subnets = list(subnet_collection)

    if not subnets:
        return None

    # vpc id + subnet cidr uniquely identify the subnet.
    # subnet cidr blocks are unique and non-overlapping in the scope of a VPC.
    # This is why we don't need to handle the case when there is more than
    # one subnet.
    subnet = subnets[0]
    subnet.load()

    return subnet
def _detach_dependencies(ec2, secgroup_id):
    """Detaches secgroup from instances as a prerequisite for deletion."""
    instances = ec2.instances.filter(
        Filters=ec2_filters.from_dict({"instance.group-id": secgroup_id}))
    for inst in instances:
        existing_groups = inst.security_groups
        new_groups = [
            g for g in existing_groups if g["group-id"] != secgroup_id
        ]
        inst.modify_attribute(Groups=new_groups)
def get_default_security_group_for_vpc(ec2, vpc_id):
    secgroups = list(
        ec2.security_groups.filter(
            Filters=ec2_filters.from_dict({
                "vpc-id": vpc_id,
                "group-name": "default"
            })))
    # there is exactly one secgroup that matches this filter, it can't be deleted
    sg = secgroups[0]
    sg.load()
    return sg
def validate_security_group_references(ec2, security_groups, vpc_id):
    groups = ec2.security_groups.filter(
        Filters=ec2_filters.from_dict({
            'group-id': security_groups,
            'vpc-id': vpc_id,
        }))
    present_groups = {group.id for group in groups}
    invalid_refs = set(security_groups) - present_groups
    if invalid_refs:
        raise errors.ObjectDoesNotExist(
            "Security groups ({0}) do not exist in {1}".format(
                ", ".join(sorted(invalid_refs)), vpc_id))
def identify_existing_eni(ec2, params_entity):
    """
    Identification logic, in order:
      - if an ID exists, use (unique = id)
      - if both subnet and IP exist, use (unique = subnet + ip)
      - if subnet exists, but IP doesn't exist:
          - if name and attachment are set, use (subnet + name + attachment (+branch to #1))
          - if name is set, but attachment isn't, use (nonunique = subnet + name)
          - if name is not set, but attachment is set, use (subnet + attachment (+branch to #1))
    #1
      - if device_index is set, use (unique = instance + device_index)
      - if device_index is not set, use (nonunique = instance)

    :type params_entity: NetworkInterface
    """
    if params_entity.eni_id is not None:
        return get_network_interface_by_id(ec2,
                                           params_entity.eni_id,
                                           fail_nonexisting_id=True)

    filters = {}
    if params_entity.subnet_id is not None:
        if params_entity.private_ip_primary is not None:
            filters["subnet-id"] = params_entity.subnet_id
            filters[
                "addresses.private-ip-address"] = params_entity.private_ip_primary
            filters["addresses.primary"] = "true"
        else:
            if params_entity.tags is not None and params_entity.tags.get(
                    "Name") is not None:
                filters["subnet-id"] = params_entity.subnet_id
                filters["tag:Name"] = params_entity.tags["Name"]
            if params_entity.attachment is not None:
                filters["subnet-id"] = params_entity.subnet_id
                filters[
                    "attachment.instance-id"] = params_entity.attachment.instance_id
                if params_entity.attachment.device_index is not None:
                    filters[
                        "attachment.device-index"] = params_entity.attachment.device_index

    if not filters:
        return None
    all_enis = list(
        ec2.network_interfaces.filter(Filters=ec2_filters.from_dict(filters)))

    if len(all_enis) == 0:
        return None
    elif len(all_enis) == 1:
        all_enis[0].load()
        return all_enis[0]
    raise errors.UnexpectedStateError(
        "More than one network interface exists matching the task's identifying arguments."
    )
def _create_keypair_new(client, key_name, public_key_material, check_mode):
    if check_mode:
        return None, True
    else:
        # fingerprints are not important here and have been checked in the action plugin
        if public_key_material is None:
            response_object = client.create_key_pair(KeyName=key_name)
        else:
            response_object = client.import_key_pair(
                KeyName=key_name, PublicKeyMaterial=public_key_material)
        waiter = client.get_waiter("key_pair_exists")
        waiter.wait(Filters=ec2_filters.from_dict({"key-name": key_name}))
        return response_object, True
Beispiel #7
0
def get_subnet_by_id(ec2, subnet_id, fail_nonexisting_id=False):
    subnet = ec2.Subnet(subnet_id)
    if subnet not in ec2.subnets.filter(
            Filters=ec2_filters.from_dict({
                'subnet-id': subnet_id,
            })):
        if fail_nonexisting_id:
            raise errors.ObjectDoesNotExist(
                'Subnet with id {0} does not exist'.format(subnet_id))
        return None

    subnet.load()

    return subnet
def get_internet_gateway_by_id(ec2, gateway_id, fail_nonexisting_id=False):
    gateway = ec2.InternetGateway(gateway_id)
    if gateway not in ec2.internet_gateways.filter(
            Filters=ec2_filters.from_dict({
                'internet-gateway-id': gateway_id,
            })):
        if fail_nonexisting_id:
            raise errors.ObjectDoesNotExist(
                'Internet gateway with id {0} does not exist.'.format(
                    gateway_id))
        return None

    gateway.load()

    return gateway
def _get_existing_secgroup_by_name_and_vpc(ec2, name, vpc_id):
    # errors out when this does not exist
    # prevents boto.ClientError.response["Error"]["Code"] == "InvalidParameterValue" below
    vpc = ec2_vpc_utils.get_vpc(ec2, vpc_id)
    secgroups = list(
        vpc.security_groups.filter(
            Filters=ec2_filters.from_dict({"group-name": name})))

    if len(secgroups) == 0:
        return None
    elif len(secgroups) == 1:
        return secgroups[0]

    raise errors.AmbiguousObjectError(
        "More than one security group with the name '{0}' "
        "exists in VPC {1}".format(name, vpc_id))
def _update_keypair(client, key_name, public_key_material, fingerprints, force,
                    check_mode, existing_keypair):
    response_object = existing_keypair
    changed = False
    warning = None
    if public_key_material is None:
        if force:
            changed = True
            if check_mode:
                # we don't want to return the initial object, as that'd be incorrect
                response_object = None
            else:
                client.delete_key_pair(KeyName=key_name)
                response_object = client.create_key_pair(KeyName=key_name)
                waiter = client.get_waiter("key_pair_exists")
                waiter.wait(
                    Filters=ec2_filters.from_dict({"key-name": key_name}))
        else:
            warning = "Any subsequent invocation of this module does not return the remotely-" \
                      "generated private key as only the initial generation creates it!"
    else:
        # existing_key with same name exists, public_key specified
        local_fingerprint_matches_existing_keypair = \
            any(fp for fp in fingerprints
                if fingerprints_equal(fp, existing_keypair["KeyFingerprint"]))

        if local_fingerprint_matches_existing_keypair:
            # the fingerprint now MUST be MD5, as there is no way to have a local SHA1 fingerprint
            # do nothing, locally-generated key already present
            pass
        else:
            if force:
                changed = True
                if check_mode:
                    # same argumentation as above
                    response_object = None
                else:
                    client.delete_key_pair(KeyName=key_name)
                    response_object = client.import_key_pair(
                        KeyName=key_name,
                        PublicKeyMaterial=public_key_material)
            else:
                raise errors.DisallowedOperationError(
                    "A key pair with name {0} already exists. Set force: true to overwrite."
                    .format(key_name))

    return response_object, changed, warning
Beispiel #11
0
def _get_vpc_by_primary_cidr_and_name(ec2, name, cidr):
    vpc_collection = ec2.vpcs.filter(
        Filters=ec2_filters.from_dict({
            'cidr': cidr,
            'tag:Name': name,
        }))
    vpcs = list(vpc_collection)

    # It can happen that we have multiple VPCs with identical CIDR
    # and name tags on AWS
    if len(vpcs) > 1:
        raise errors.AmbiguousObjectError(
            "Duplicate VPCs exist ({0}), could not reliably "
            "determine the correct one.".format(vpcs))
    if not vpcs:
        return None
    return vpcs[0]
Beispiel #12
0
def get_default_vpc(ec2):
    """
    Retrieves the default VPC.

    :raises errors.ObjectDoesNotExist: when the default VPC does not exist.
    """
    vpc_collection = ec2.vpcs.filter(
        Filters=ec2_filters.from_dict(dict(isDefault='true', )))
    vpcs = list(vpc_collection)
    if not vpcs:  # we don't have a default VPC
        raise errors.ObjectDoesNotExist(
            "Default VPC does not exist. Create one or pass "
            "the VPC id via 'vpc' parameter.")
    # we cannot have more than one default VPC per region
    vpc = vpcs[0]
    vpc.load()

    return vpc
def get_internet_gateway_by_name(ec2, gateway_name):
    gateway_collection = ec2.internet_gateways.filter(
        Filters=ec2_filters.from_dict({
            'tag:Name': gateway_name,
        }))
    gateways = list(gateway_collection)

    if not gateways:
        return None

    if len(gateways) > 1:
        raise errors.AmbiguousObjectError(
            "More than one internet gateway named {0} exists".format(
                gateway_name))
    gateway = gateways[0]
    gateway.load()

    return gateway
Beispiel #14
0
def get_default_subnet_for_az(ec2, availability_zone_id):
    subnet_collection = ec2.subnets.filter(
        Filters=ec2_filters.from_dict({
            'availability-zone-id': availability_zone_id,
            'default-for-az': 'true',
        }))
    subnets = list(subnet_collection)

    if not subnets:
        raise errors.ObjectDoesNotExist(
            'Availability zone with id {0} does not'
            ' have a default subnet'.format(availability_zone_id))

    # there can't be more than 1 default subnet per AZ
    subnet = subnets[0]
    subnet.load()

    return subnet
def update_monitoring(instance, monitoring_type, check_mode):
    # Reference: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-cloudwatch-new.html  # noqa: 501
    validate_state_dependent_operation(instance, ['running', 'stopped'],
                                       'CloudWatch monitoring')

    if check_mode:
        return

    if monitoring_type == 'detailed':
        instance.monitor()
        wait_state = 'enabled'
    else:
        instance.unmonitor()
        wait_state = 'disabled'

    # modifying monitoring state is an async operation,
    # so we need to wait to ensure the desired state
    instance.wait_until_exists(
        Filters=ec2_filters.from_dict({
            'monitoring-state': wait_state,
        }))
def get_instance_by_alternative_params(ec2, name, ami, subnet_id):
    instance_collection = ec2.instances.filter(Filters=ec2_filters.from_dict(
        {
            'tag:Name': name,
            'image-id': ami,
            'subnet-id': subnet_id,
            'instance-state-name': list(ec2_instance_utils.PRESENT_STATES),
        }))
    instances = list(instance_collection)

    if not instances:
        return None

    if len(instances) > 1:
        raise errors.AmbiguousObjectError(
            "Unable to identify the instance based on name ({0}),"
            "ami ({1}) and subnet ({2})".format(name, ami, subnet_id))
    instance = instances[0]
    instance.load()

    return instance
def detach_and_wait(eni):
    eni.detach()
    waiter = eni.meta.client.get_waiter("network_interface_available")
    waiter.wait(NetworkInterfaceIds=[eni.id],
                Filters=ec2_filters.from_dict({"status": "available"}))