Beispiel #1
0
 def __init__(self, dns_name=None, **kwargs):
     self.r53 = Route53Connection(**kwargs)
     if dns_name is not None:
         self.zone = self.get_zone(dns_name)
         if not self.zone:
             raise IcsR53Exception(
                 "Can't find DNS Zone for '%s'" % (dns_name))
def main():
    argument_spec = ec2_argument_spec()
    argument_spec.update(
        dict(zone=dict(required=True),
             state=dict(default='present', choices=['present', 'absent']),
             vpc_id=dict(default=None),
             vpc_region=dict(default=None),
             comment=dict(default='')))
    module = AnsibleModule(argument_spec=argument_spec)

    if not HAS_BOTO:
        module.fail_json(msg='boto required for this module')

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

    private_zone = vpc_id is not None and vpc_region is not None

    _, _, aws_connect_kwargs = get_aws_connection_info(module)

    # connect to the route53 endpoint
    try:
        conn = Route53Connection(**aws_connect_kwargs)
    except boto.exception.BotoServerError, e:
        module.fail_json(msg=e.error_message)
Beispiel #3
0
def main():
    argument_spec = ec2_argument_spec()
    argument_spec.update(dict(
            state               = dict(choices=['present', 'absent'], default='present'),
            ip_address          = dict(),
            port                = dict(type='int'),
            type                = dict(required=True, choices=['HTTP', 'HTTPS', 'HTTP_STR_MATCH', 'HTTPS_STR_MATCH', 'TCP']),
            resource_path       = dict(),
            fqdn                = dict(),
            string_match        = dict(),
            request_interval    = dict(type='int', choices=[10, 30], default=30),
            failure_threshold   = dict(type='int', choices=[1, 2, 3, 4, 5, 6, 7, 8, 9, 10], default=3),
        )
    )
    module = AnsibleModule(argument_spec=argument_spec)

    if not HAS_BOTO:
        module.fail_json(msg='boto 2.27.0+ required for this module')

    state_in              = module.params.get('state')
    ip_addr_in            = module.params.get('ip_address')
    port_in               = module.params.get('port')
    type_in               = module.params.get('type')
    resource_path_in      = module.params.get('resource_path')
    fqdn_in               = module.params.get('fqdn')
    string_match_in       = module.params.get('string_match')
    request_interval_in   = module.params.get('request_interval')
    failure_threshold_in  = module.params.get('failure_threshold')

    if ip_addr_in is None and fqdn_in is None:
        module.fail_json(msg="parameter 'ip_address' or 'fqdn' is required")

    # Default port
    if port_in is None:
      if type_in in ['HTTP', 'HTTP_STR_MATCH']:
        port_in = 80
      elif type_in in ['HTTPS', 'HTTPS_STR_MATCH']:
        port_in = 443
      else:
        module.fail_json(msg="parameter 'port' is required for 'type' TCP")

    # string_match in relation with type
    if type_in in ['HTTP_STR_MATCH', 'HTTPS_STR_MATCH']:
        if string_match_in is None:
            module.fail_json(msg="parameter 'string_match' is required for the HTTP(S)_STR_MATCH types")
        elif len(string_match_in) > 255:
            module.fail_json(msg="parameter 'string_match' is limited to 255 characters max")
    elif string_match_in:
        module.fail_json(msg="parameter 'string_match' argument is only for the HTTP(S)_STR_MATCH types")

    region, ec2_url, aws_connect_kwargs = get_aws_connection_info(module)
    # connect to the route53 endpoint
    try:
        conn = Route53Connection(**aws_connect_kwargs)
    except boto.exception.BotoServerError, e:
        module.fail_json(msg = e.error_message)
Beispiel #4
0
def get_r53_conn():
    """
    Return a connection to Route 53.
    """
    try:
        return Route53Connection()
    except NoAuthHandlerFound:
        sys.stderr.write('Could not authenticate with AWS. Have you set '
                         'AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY?')
        sys.exit(1)
Beispiel #5
0
def connect_route53(aws_access_key_id=None, aws_secret_access_key=None, **kwargs):
    """
    :type aws_access_key_id: string
    :param aws_access_key_id: Your AWS Access Key ID

    :type aws_secret_access_key: string
    :param aws_secret_access_key: Your AWS Secret Access Key

    :rtype: :class:`boto.dns.Route53Connection`
    :return: A connection to Amazon's Route53 DNS Service
    """
    from boto.route53 import Route53Connection
    return Route53Connection(aws_access_key_id, aws_secret_access_key, **kwargs)
Beispiel #6
0
def main():
    argument_spec = ec2_argument_spec()
    argument_spec.update(
        dict(zone=dict(required=True),
             state=dict(default='present', choices=['present', 'absent']),
             vpc_id=dict(default=None),
             vpc_region=dict(default=None),
             comment=dict(default=''),
             hosted_zone_id=dict()))
    module = AnsibleModule(argument_spec=argument_spec)

    if not HAS_BOTO:
        module.fail_json(msg='boto required for this module')

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

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

    private_zone = bool(vpc_id and vpc_region)

    _, _, aws_connect_kwargs = get_aws_connection_info(module)

    # connect to the route53 endpoint
    try:
        conn = Route53Connection(**aws_connect_kwargs)
    except boto.exception.BotoServerError as e:
        module.fail_json(msg=e.error_message)

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

    if isinstance(result, dict):
        module.exit_json(changed=changed, result=result, **result)
    else:
        module.exit_json(changed=changed, result=result)
Beispiel #7
0
def _initialise_aws_connections():
    _log.info('Initialising AWS Connections')

    _validate_environment()

    # Even though the Boto lib can use the environment variables we'll import one
    # for easier re-use in this script
    _log.info('Loading credentials from Environment')
    aws_region = os.getenv('AWS_DEFAULT_REGION')

    _log.info('Initializing Boto resources')
    resources = {
        'vpc': vpc.connect_to_region(aws_region),
        'ec2': ec2.connect_to_region(aws_region),
        'elb': elb.connect_to_region(aws_region),
        'iam': iam.connect_to_region(aws_region),
        'route53': Route53Connection(),
        'cloudwatch': cloudwatch.connect_to_region(aws_region),
        'region': aws_region
    }

    return resources
Beispiel #8
0
def get_input(environ):
    '''
    '''
    github_client_id = environ['GITHUB_CLIENT_ID']
    github_client_secret = environ['GITHUB_CLIENT_SECRET']

    gdocs_client_id = environ['GDOCS_CLIENT_ID']
    gdocs_client_secret = environ['GDOCS_CLIENT_SECRET']

    print('--> Enter Github details:')
    username = raw_input('    Github username: '******'    Github password: '******'    New Github repository name: ')

    if not match(r'\w+(-\w+)*$', reponame):
        raise RuntimeError(
            'Repository "{}" does not match "\w+(-\w+)*$"'.format(reponame))

    ec2 = EC2Connection()
    route53 = Route53Connection()

    return github_client_id, github_client_secret, \
        gdocs_client_id, gdocs_client_secret, \
        username, password, reponame, ec2, route53
Beispiel #9
0
def main():
    argument_spec = ec2_argument_spec()
    argument_spec.update(
        dict(
            state=dict(choices=['present', 'absent'], default='present'),
            ip_address=dict(),
            port=dict(type='int'),
            type=dict(required=True,
                      choices=[
                          'HTTP', 'HTTPS', 'HTTP_STR_MATCH', 'HTTPS_STR_MATCH',
                          'TCP'
                      ]),
            resource_path=dict(),
            fqdn=dict(),
            string_match=dict(),
            request_interval=dict(type='int', choices=[10, 30], default=30),
            failure_threshold=dict(type='int',
                                   choices=[1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
                                   default=3),
        ))
    module = AnsibleModule(argument_spec=argument_spec)

    if not HAS_BOTO:
        module.fail_json(msg='boto 2.27.0+ required for this module')

    state_in = module.params.get('state')
    ip_addr_in = module.params.get('ip_address')
    port_in = module.params.get('port')
    type_in = module.params.get('type')
    resource_path_in = module.params.get('resource_path')
    fqdn_in = module.params.get('fqdn')
    string_match_in = module.params.get('string_match')
    request_interval_in = module.params.get('request_interval')
    failure_threshold_in = module.params.get('failure_threshold')

    if ip_addr_in is None and fqdn_in is None:
        module.fail_json(msg="parameter 'ip_address' or 'fqdn' is required")

    # Default port
    if port_in is None:
        if type_in in ['HTTP', 'HTTP_STR_MATCH']:
            port_in = 80
        elif type_in in ['HTTPS', 'HTTPS_STR_MATCH']:
            port_in = 443
        else:
            module.fail_json(msg="parameter 'port' is required for 'type' TCP")

    # string_match in relation with type
    if type_in in ['HTTP_STR_MATCH', 'HTTPS_STR_MATCH']:
        if string_match_in is None:
            module.fail_json(
                msg=
                "parameter 'string_match' is required for the HTTP(S)_STR_MATCH types"
            )
        elif len(string_match_in) > 255:
            module.fail_json(
                msg="parameter 'string_match' is limited to 255 characters max"
            )
    elif string_match_in:
        module.fail_json(
            msg=
            "parameter 'string_match' argument is only for the HTTP(S)_STR_MATCH types"
        )

    region, ec2_url, aws_connect_kwargs = get_aws_connection_info(module)
    # connect to the route53 endpoint
    try:
        conn = Route53Connection(**aws_connect_kwargs)
    except boto.exception.BotoServerError as e:
        module.fail_json(msg=e.error_message)

    changed = False
    action = None
    check_id = None
    wanted_config = HealthCheck(ip_addr_in, port_in, type_in, resource_path_in,
                                fqdn_in, string_match_in, request_interval_in,
                                failure_threshold_in)
    existing_check = find_health_check(conn, wanted_config)
    if existing_check:
        check_id = existing_check.Id
        existing_config = to_health_check(existing_check.HealthCheckConfig)

    if state_in == 'present':
        if existing_check is None:
            action = "create"
            check_id = create_health_check(conn, wanted_config).HealthCheck.Id
            changed = True
        else:
            diff = health_check_diff(existing_config, wanted_config)
            if diff:
                action = "update"
                update_health_check(conn, existing_check.Id,
                                    int(existing_check.HealthCheckVersion),
                                    wanted_config)
                changed = True
    elif state_in == 'absent':
        if check_id:
            action = "delete"
            conn.delete_health_check(check_id)
            changed = True
    else:
        module.fail_json(msg="Logic Error: Unknown state")

    module.exit_json(changed=changed,
                     health_check=dict(id=check_id),
                     action=action)
Beispiel #10
0
def main():
    argument_spec = ec2_argument_spec()
    argument_spec.update(
        dict(
            state=dict(
                type='str',
                required=True,
                choices=['absent', 'create', 'delete', 'get', 'present'],
                aliases=['command']),
            zone=dict(type='str'),
            hosted_zone_id=dict(type='str'),
            record=dict(type='str', required=True),
            ttl=dict(type='int', default=3600),
            type=dict(type='str',
                      required=True,
                      choices=[
                          'A', 'AAAA', 'CAA', 'CNAME', 'MX', 'NS', 'PTR',
                          'SOA', 'SPF', 'SRV', 'TXT'
                      ]),
            alias=dict(type='bool'),
            alias_hosted_zone_id=dict(type='str'),
            alias_evaluate_target_health=dict(type='bool', default=False),
            value=dict(type='list'),
            overwrite=dict(type='bool'),
            retry_interval=dict(type='int', default=500),
            private_zone=dict(type='bool', default=False),
            identifier=dict(type='str'),
            weight=dict(type='int'),
            region=dict(type='str'),
            health_check=dict(type='str'),
            failover=dict(type='str', choices=['PRIMARY', 'SECONDARY']),
            vpc_id=dict(type='str'),
            wait=dict(type='bool', default=False),
            wait_timeout=dict(type='int', default=300),
        ))

    module = AnsibleModule(
        argument_spec=argument_spec,
        supports_check_mode=True,
        required_one_of=[['zone', 'hosted_zone_id']],
        # If alias is True then you must specify alias_hosted_zone as well
        required_together=[['alias', 'alias_hosted_zone_id']],
        # state=present, absent, create, delete THEN value is required
        required_if=(
            ('state', 'present', ['value']),
            ('state', 'create', ['value']),
            ('state', 'absent', ['value']),
            ('state', 'delete', ['value']),
        ),
        # failover, region and weight are mutually exclusive
        mutually_exclusive=[('failover', 'region', 'weight')],
        # failover, region and weight require identifier
        required_by=dict(
            failover=('identifier', ),
            region=('identifier', ),
            weight=('identifier', ),
        ),
    )

    if not HAS_BOTO:
        module.fail_json(msg='boto required for this module')

    if distutils.version.StrictVersion(
            boto.__version__) < distutils.version.StrictVersion(
                MINIMUM_BOTO_VERSION):
        module.fail_json(
            msg='Found boto in version %s, but >= %s is required' %
            (boto.__version__, MINIMUM_BOTO_VERSION))

    if module.params['state'] in ('present', 'create'):
        command_in = 'create'
    elif module.params['state'] in ('absent', 'delete'):
        command_in = 'delete'
    elif module.params['state'] == 'get':
        command_in = 'get'

    zone_in = (module.params.get('zone') or '').lower()
    hosted_zone_id_in = module.params.get('hosted_zone_id')
    ttl_in = module.params.get('ttl')
    record_in = module.params.get('record').lower()
    type_in = module.params.get('type')
    value_in = module.params.get('value') or []
    alias_in = module.params.get('alias')
    alias_hosted_zone_id_in = module.params.get('alias_hosted_zone_id')
    alias_evaluate_target_health_in = module.params.get(
        'alias_evaluate_target_health')
    retry_interval_in = module.params.get('retry_interval')

    if module.params['vpc_id'] is not None:
        private_zone_in = True
    else:
        private_zone_in = module.params.get('private_zone')

    identifier_in = module.params.get('identifier')
    weight_in = module.params.get('weight')
    region_in = module.params.get('region')
    health_check_in = module.params.get('health_check')
    failover_in = module.params.get('failover')
    vpc_id_in = module.params.get('vpc_id')
    wait_in = module.params.get('wait')
    wait_timeout_in = module.params.get('wait_timeout')

    region, ec2_url, aws_connect_kwargs = get_aws_connection_info(module)

    if zone_in[-1:] != '.':
        zone_in += "."

    if record_in[-1:] != '.':
        record_in += "."

    if command_in == 'create' or command_in == 'delete':
        if alias_in and len(value_in) != 1:
            module.fail_json(
                msg=
                "parameter 'value' must contain a single dns name for alias records"
            )
        if (weight_in is None and region_in is None
                and failover_in is None) and identifier_in is not None:
            module.fail_json(
                msg=
                "You have specified identifier which makes sense only if you specify one of: weight, region or failover."
            )

    # connect to the route53 endpoint
    try:
        conn = Route53Connection(**aws_connect_kwargs)
    except boto.exception.BotoServerError as e:
        module.fail_json(msg=e.error_message)

    # Find the named zone ID
    zone_id = hosted_zone_id_in or get_zone_id_by_name(
        conn, module, zone_in, private_zone_in, vpc_id_in)

    # Verify that the requested zone is already defined in Route53
    if zone_id is None:
        errmsg = "Zone %s does not exist in Route53" % (zone_in
                                                        or hosted_zone_id_in)
        module.fail_json(msg=errmsg)

    record = {}

    found_record = False
    wanted_rset = Record(name=record_in,
                         type=type_in,
                         ttl=ttl_in,
                         identifier=identifier_in,
                         weight=weight_in,
                         region=region_in,
                         health_check=health_check_in,
                         failover=failover_in)
    for v in value_in:
        if alias_in:
            wanted_rset.set_alias(alias_hosted_zone_id_in, v,
                                  alias_evaluate_target_health_in)
        else:
            wanted_rset.add_value(v)

    need_to_sort_records = (type_in == 'CAA')

    # Sort records for wanted_rset if necessary (keep original list)
    unsorted_records = wanted_rset.resource_records
    if need_to_sort_records:
        wanted_rset.resource_records = sorted(unsorted_records)

    sets = invoke_with_throttling_retries(conn.get_all_rrsets,
                                          zone_id,
                                          name=record_in,
                                          type=type_in,
                                          identifier=identifier_in)
    sets_iter = iter(sets)
    while True:
        try:
            rset = invoke_with_throttling_retries(next, sets_iter)
        except StopIteration:
            break
        # Due to a bug in either AWS or Boto, "special" characters are returned as octals, preventing round
        # tripping of things like * and @.
        decoded_name = rset.name.replace(r'\052', '*')
        decoded_name = decoded_name.replace(r'\100', '@')
        # Need to save this changes in rset, because of comparing rset.to_xml() == wanted_rset.to_xml() in next block
        rset.name = decoded_name

        if identifier_in is not None:
            identifier_in = str(identifier_in)

        if rset.type == type_in and decoded_name.lower() == record_in.lower(
        ) and rset.identifier == identifier_in:
            if need_to_sort_records:
                # Sort records
                rset.resource_records = sorted(rset.resource_records)
            found_record = True
            record['zone'] = zone_in
            record['type'] = rset.type
            record['record'] = decoded_name
            record['ttl'] = rset.ttl
            record['identifier'] = rset.identifier
            record['weight'] = rset.weight
            record['region'] = rset.region
            record['failover'] = rset.failover
            record['health_check'] = rset.health_check
            record['hosted_zone_id'] = zone_id
            if rset.alias_dns_name:
                record['alias'] = True
                record['value'] = rset.alias_dns_name
                record['values'] = [rset.alias_dns_name]
                record['alias_hosted_zone_id'] = rset.alias_hosted_zone_id
                record[
                    'alias_evaluate_target_health'] = rset.alias_evaluate_target_health
            else:
                record['alias'] = False
                record['value'] = ','.join(sorted(rset.resource_records))
                record['values'] = sorted(rset.resource_records)
            if command_in == 'create' and rset.to_xml() == wanted_rset.to_xml(
            ):
                module.exit_json(changed=False)

        # We need to look only at the first rrset returned by the above call,
        # so break here. The returned elements begin with the one matching our
        # requested name, type, and identifier, if such an element exists,
        # followed by all others that come after it in alphabetical order.
        # Therefore, if the first set does not match, no subsequent set will
        # match either.
        break

    if command_in == 'get':
        if type_in == 'NS':
            ns = record.get('values', [])
        else:
            # Retrieve name servers associated to the zone.
            z = invoke_with_throttling_retries(conn.get_zone, zone_in)
            ns = invoke_with_throttling_retries(z.get_nameservers)

        module.exit_json(changed=False, set=record, nameservers=ns)

    if command_in == 'delete' and not found_record:
        module.exit_json(changed=False)

    changes = ResourceRecordSets(conn, zone_id)

    if command_in == 'create' or command_in == 'delete':
        if command_in == 'create' and found_record:
            if not module.params['overwrite']:
                module.fail_json(
                    msg=
                    "Record already exists with different value. Set 'overwrite' to replace it"
                )
            command = 'UPSERT'
        else:
            command = command_in.upper()
        # Restore original order of records
        wanted_rset.resource_records = unsorted_records
        changes.add_change_record(command, wanted_rset)

    if not module.check_mode:
        try:
            invoke_with_throttling_retries(commit, changes, retry_interval_in,
                                           wait_in, wait_timeout_in)
        except boto.route53.exception.DNSServerError as e:
            txt = e.body.split("<Message>")[1]
            txt = txt.split("</Message>")[0]
            if "but it already exists" in txt:
                module.exit_json(changed=False)
            else:
                module.fail_json(msg=txt)
        except TimeoutError:
            module.fail_json(msg='Timeout waiting for changes to replicate')

    module.exit_json(changed=True)
def main():
    argument_spec = ec2_argument_spec()
    argument_spec.update(dict(
            zone=dict(required=True),
            state=dict(default='present', choices=['present', 'absent']),
            vpc_id=dict(default=None),
            vpc_region=dict(default=None),
            comment=dict(default='')))
    module = AnsibleModule(argument_spec=argument_spec)

    if not HAS_BOTO:
        module.fail_json(msg='boto required for this module')

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

    if zone_in[-1:] != '.':
        zone_in += "."

    private_zone = vpc_id is not None and vpc_region is not None

    _, _, aws_connect_kwargs = get_aws_connection_info(module)

    # connect to the route53 endpoint
    try:
        conn = Route53Connection(**aws_connect_kwargs)
    except boto.exception.BotoServerError as e:
        module.fail_json(msg=e.error_message)

    results = conn.get_all_hosted_zones()
    zones = {}

    for r53zone in results['ListHostedZonesResponse']['HostedZones']:
        zone_id = r53zone['Id'].replace('/hostedzone/', '')
        zone_details = conn.get_hosted_zone(zone_id)['GetHostedZoneResponse']
        if vpc_id and 'VPCs' in zone_details:
            # this is to deal with this boto bug: https://github.com/boto/boto/pull/2882
            if isinstance(zone_details['VPCs'], dict):
                if zone_details['VPCs']['VPC']['VPCId'] == vpc_id:
                    zones[r53zone['Name']] = zone_id
            else: # Forward compatibility for when boto fixes that bug
                if vpc_id in [v['VPCId'] for v in zone_details['VPCs']]:
                    zones[r53zone['Name']] = zone_id
        else:
            zones[r53zone['Name']] = zone_id

    record = {
        'private_zone': private_zone,
        'vpc_id': vpc_id,
        'vpc_region': vpc_region,
        'comment': comment,
    }

    if state == 'present' and zone_in in zones:
        if private_zone:
            details = conn.get_hosted_zone(zones[zone_in])

            if 'VPCs' not in details['GetHostedZoneResponse']:
                module.fail_json(
                    msg="Can't change VPC from public to private"
                )

            vpc_details = details['GetHostedZoneResponse']['VPCs']['VPC']
            current_vpc_id = vpc_details['VPCId']
            current_vpc_region = vpc_details['VPCRegion']

            if current_vpc_id != vpc_id:
                module.fail_json(
                    msg="Can't change VPC ID once a zone has been created"
                )
            if current_vpc_region != vpc_region:
                module.fail_json(
                    msg="Can't change VPC Region once a zone has been created"
                )

        record['zone_id'] = zones[zone_in]
        record['name'] = zone_in
        module.exit_json(changed=False, set=record)

    elif state == 'present':
        result = conn.create_hosted_zone(zone_in, **record)
        hosted_zone = result['CreateHostedZoneResponse']['HostedZone']
        zone_id = hosted_zone['Id'].replace('/hostedzone/', '')
        record['zone_id'] = zone_id
        record['name'] = zone_in
        module.exit_json(changed=True, set=record)

    elif state == 'absent' and zone_in in zones:
        conn.delete_hosted_zone(zones[zone_in])
        module.exit_json(changed=True)

    elif state == 'absent':
        module.exit_json(changed=False)
def get_connection():
    from route53 import app
    return Route53Connection(
        aws_access_key_id=app.config['AWS_ACCESS_KEY_ID'],
        aws_secret_access_key=app.config['AWS_SECRET_ACCESS_KEY'])
def main():
    argument_spec = ec2_argument_spec()
    argument_spec.update(
        dict(
            command=dict(choices=['get', 'create', 'delete'], required=True),
            zone=dict(required=True),
            hosted_zone_id=dict(required=False, default=None),
            record=dict(required=True),
            ttl=dict(required=False, type='int', default=3600),
            type=dict(choices=[
                'A', 'CNAME', 'MX', 'AAAA', 'TXT', 'PTR', 'SRV', 'SPF', 'NS',
                'SOA'
            ],
                      required=True),
            alias=dict(required=False, type='bool'),
            alias_hosted_zone_id=dict(required=False),
            alias_evaluate_target_health=dict(required=False,
                                              type='bool',
                                              default=False),
            value=dict(required=False),
            overwrite=dict(required=False, type='bool'),
            retry_interval=dict(required=False, default=500),
            private_zone=dict(required=False, type='bool', default=False),
            identifier=dict(required=False, default=None),
            weight=dict(required=False, type='int'),
            region=dict(required=False),
            health_check=dict(required=False),
            failover=dict(required=False, choices=['PRIMARY', 'SECONDARY']),
            vpc_id=dict(required=False),
            wait=dict(required=False, type='bool', default=False),
            wait_timeout=dict(required=False, type='int', default=300),
        ))
    module = AnsibleModule(argument_spec=argument_spec)

    if not HAS_BOTO:
        module.fail_json(msg='boto required for this module')

    if distutils.version.StrictVersion(
            boto.__version__) < distutils.version.StrictVersion(
                MINIMUM_BOTO_VERSION):
        module.fail_json(
            msg='Found boto in version %s, but >= %s is required' %
            (boto.__version__, MINIMUM_BOTO_VERSION))

    command_in = module.params.get('command')
    zone_in = module.params.get('zone').lower()
    hosted_zone_id_in = module.params.get('hosted_zone_id')
    ttl_in = module.params.get('ttl')
    record_in = module.params.get('record').lower()
    type_in = module.params.get('type')
    value_in = module.params.get('value')
    alias_in = module.params.get('alias')
    alias_hosted_zone_id_in = module.params.get('alias_hosted_zone_id')
    alias_evaluate_target_health_in = module.params.get(
        'alias_evaluate_target_health')
    retry_interval_in = module.params.get('retry_interval')
    private_zone_in = module.params.get('private_zone')
    identifier_in = module.params.get('identifier')
    weight_in = module.params.get('weight')
    region_in = module.params.get('region')
    health_check_in = module.params.get('health_check')
    failover_in = module.params.get('failover')
    vpc_id_in = module.params.get('vpc_id')
    wait_in = module.params.get('wait')
    wait_timeout_in = module.params.get('wait_timeout')

    region, ec2_url, aws_connect_kwargs = get_aws_connection_info(module)

    value_list = ()

    if type(value_in) is str:
        if value_in:
            value_list = sorted([s.strip() for s in value_in.split(',')])
    elif type(value_in) is list:
        value_list = sorted(value_in)

    if zone_in[-1:] != '.':
        zone_in += "."

    if record_in[-1:] != '.':
        record_in += "."

    if command_in == 'create' or command_in == 'delete':
        if not value_in:
            module.fail_json(
                msg="parameter 'value' required for create/delete")
        elif alias_in:
            if len(value_list) != 1:
                module.fail_json(
                    msg=
                    "parameter 'value' must contain a single dns name for alias create/delete"
                )
            elif not alias_hosted_zone_id_in:
                module.fail_json(
                    msg=
                    "parameter 'alias_hosted_zone_id' required for alias create/delete"
                )
        elif (weight_in != None or region_in != None
              or failover_in != None) and identifier_in == None:
            module.fail_json(
                msg=
                "If you specify failover, region or weight you must also specify identifier"
            )

    if command_in == 'create':
        if (weight_in != None or region_in != None
                or failover_in != None) and identifier_in == None:
            module.fail_json(
                msg=
                "If you specify failover, region or weight you must also specify identifier"
            )
        elif (weight_in == None and region_in == None
              and failover_in == None) and identifier_in != None:
            module.fail_json(
                msg=
                "You have specified identifier which makes sense only if you specify one of: weight, region or failover."
            )

    if vpc_id_in and not private_zone_in:
        module.fail_json(
            msg="parameter 'private_zone' must be true when specifying parameter"
            " 'vpc_id'")

    # connect to the route53 endpoint
    try:
        conn = Route53Connection(**aws_connect_kwargs)
    except boto.exception.BotoServerError, e:
        module.fail_json(msg=e.error_message)
Beispiel #14
0
def main():
  parser = argparse.ArgumentParser(description='Push/pull Amazon Route 53 configs.')
  parser.add_argument('--push', metavar='file_to_push.xml', help="Push the config in this file to R53.")
  parser.add_argument('--pull', action='store_true', help="Dump current R53 config to stdout.")
  parser.add_argument('--confirm', action='store_true', help="Do not prompt before push.")
  parser.add_argument('--dryrun', action='store_true', help="Do not actually apply changes.")
  parser.add_argument('--verbose', action='store_true')
  parser.add_argument('--zone', required=True, metavar="foursquare.com", help="Zone to push/pull.")
  args = parser.parse_args()

  ch = logging.StreamHandler()
  if args.verbose:
    ch.setLevel(logging.DEBUG)
  else:
    ch.setLevel(logging.INFO)
  log.addHandler(ch)

  if args.push == args.pull:
    print "You must specify either --push or --pull."
    sys.exit(1)

  # confirm wants stdin to itself
  if args.push == '-':
    args.confirm = True

  conn = Route53Connection()

  log.info('looking up zone for %s' % args.zone)
  zone_id = lookup_zone(conn, args.zone)
  log.info('fetching live config for zone %s' % zone_id)
  live_config = merge_config(fetch_config(zone_id, conn))

  if args.pull:
    print lxml.etree.tostring(live_config, pretty_print=True)

  if args.push:
    if args.push == '-':
        args.push = sys.stdin
    new_config = lxml.etree.parse(args.push)
    normalize_xml(live_config)
    normalize_xml(new_config.getroot())
    changeset = generate_changeset(live_config, new_config.getroot())
    if changeset is None:
        print "No changes found; exiting"
        sys.exit(0)
    changesetstr = lxml.etree.tostring(changeset, pretty_print=True)
    print "==CHANGESET=="
    print changesetstr
    errs = validate_changeset(changeset)
    if len(errs) > 0:
      print "changeset invalid. errors:"
      print '\n'.join(errs)
      print "exiting"
      sys.exit(1)
    if not args.confirm:
      ans = raw_input("Push y/N? ")
      if ans not in ['y', 'Y']:
        print "Confirmation failed; exiting"
        sys.exit(0)
    if args.dryrun:
      print "Dry run mode: exiting without applying changes"
      sys.exit(0)
    else:
      conn.change_rrsets(zone_id, changesetstr)
Beispiel #15
0
def main():
    argument_spec = ec2_argument_spec()
    argument_spec.update(
        dict(
            command=dict(choices=['get', 'create', 'delete'], required=True),
            zone=dict(required=True),
            record=dict(required=True),
            ttl=dict(required=False, type='int', default=3600),
            type=dict(choices=[
                'A', 'CNAME', 'MX', 'AAAA', 'TXT', 'PTR', 'SRV', 'SPF', 'NS'
            ],
                      required=True),
            alias=dict(required=False, type='bool'),
            alias_hosted_zone_id=dict(required=False),
            value=dict(required=False),
            overwrite=dict(required=False, type='bool'),
            retry_interval=dict(required=False, default=500),
            private_zone=dict(required=False, type='bool', default=False),
            identifier=dict(required=False),
            weight=dict(required=False, type='int'),
            region=dict(required=False),
            health_check=dict(required=False),
            failover=dict(required=False),
        ))
    module = AnsibleModule(argument_spec=argument_spec)

    if not HAS_BOTO:
        module.fail_json(msg='boto required for this module')

    command_in = module.params.get('command')
    zone_in = module.params.get('zone').lower()
    ttl_in = module.params.get('ttl')
    record_in = module.params.get('record').lower()
    type_in = module.params.get('type')
    value_in = module.params.get('value')
    alias_in = module.params.get('alias')
    alias_hosted_zone_id_in = module.params.get('alias_hosted_zone_id')
    retry_interval_in = module.params.get('retry_interval')
    private_zone_in = module.params.get('private_zone')
    identifier_in = module.params.get('identifier')
    weight_in = module.params.get('weight')
    region_in = module.params.get('region')
    health_check_in = module.params.get('health_check')
    failover_in = module.params.get('failover')

    region, ec2_url, aws_connect_kwargs = get_aws_connection_info(module)

    value_list = ()

    if type(value_in) is str:
        if value_in:
            value_list = sorted([s.strip() for s in value_in.split(',')])
    elif type(value_in) is list:
        value_list = sorted(value_in)

    if zone_in[-1:] != '.':
        zone_in += "."

    if record_in[-1:] != '.':
        record_in += "."

    if command_in == 'create' or command_in == 'delete':
        if not value_in:
            module.fail_json(
                msg="parameter 'value' required for create/delete")
        elif alias_in:
            if len(value_list) != 1:
                module.fail_json(
                    msg=
                    "parameter 'value' must contain a single dns name for alias create/delete"
                )
            elif not alias_hosted_zone_id_in:
                module.fail_json(
                    msg=
                    "parameter 'alias_hosted_zone_id' required for alias create/delete"
                )

    # connect to the route53 endpoint
    try:
        conn = Route53Connection(**aws_connect_kwargs)
    except boto.exception.BotoServerError, e:
        module.fail_json(msg=e.error_message)
Beispiel #16
0
def main():
    argument_spec = ec2_argument_spec()
    argument_spec.update(dict(
        command                      = dict(choices=['get', 'create', 'delete'], required=True),
        zone                         = dict(required=True),
        hosted_zone_id               = dict(required=False, default=None),
        record                       = dict(required=True),
        ttl                          = dict(required=False, type='int', default=3600),
        type                         = dict(choices=['A', 'CNAME', 'MX', 'AAAA', 'TXT', 'PTR', 'SRV', 'SPF', 'NS', 'SOA'], required=True),
        alias                        = dict(required=False, type='bool'),
        alias_hosted_zone_id         = dict(required=False),
        alias_evaluate_target_health = dict(required=False, type='bool', default=False),
        value                        = dict(required=False),
        overwrite                    = dict(required=False, type='bool'),
        retry_interval               = dict(required=False, default=500),
        private_zone                 = dict(required=False, type='bool', default=False),
        identifier                   = dict(required=False, default=None),
        weight                       = dict(required=False, type='int'),
        region                       = dict(required=False),
        health_check                 = dict(required=False),
        failover                     = dict(required=False,choices=['PRIMARY','SECONDARY']),
        vpc_id                       = dict(required=False),
        wait                         = dict(required=False, type='bool', default=False),
        wait_timeout                 = dict(required=False, type='int', default=300),
    )
    )
    module = AnsibleModule(argument_spec=argument_spec)

    if not HAS_BOTO:
        module.fail_json(msg='boto required for this module')

    if distutils.version.StrictVersion(boto.__version__) < distutils.version.StrictVersion(MINIMUM_BOTO_VERSION):
        module.fail_json(msg='Found boto in version %s, but >= %s is required' % (boto.__version__, MINIMUM_BOTO_VERSION))

    command_in                      = module.params.get('command')
    zone_in                         = module.params.get('zone').lower()
    hosted_zone_id_in               = module.params.get('hosted_zone_id')
    ttl_in                          = module.params.get('ttl')
    record_in                       = module.params.get('record').lower()
    type_in                         = module.params.get('type')
    value_in                        = module.params.get('value')
    alias_in                        = module.params.get('alias')
    alias_hosted_zone_id_in         = module.params.get('alias_hosted_zone_id')
    alias_evaluate_target_health_in = module.params.get('alias_evaluate_target_health')
    retry_interval_in               = module.params.get('retry_interval')
    private_zone_in                 = module.params.get('private_zone')
    identifier_in                   = module.params.get('identifier')
    weight_in                       = module.params.get('weight')
    region_in                       = module.params.get('region')
    health_check_in                 = module.params.get('health_check')
    failover_in                     = module.params.get('failover')
    vpc_id_in                       = module.params.get('vpc_id')
    wait_in                         = module.params.get('wait')
    wait_timeout_in                 = module.params.get('wait_timeout')

    region, ec2_url, aws_connect_kwargs = get_aws_connection_info(module)

    value_list = ()

    if isinstance(value_in, str):
        if value_in:
            value_list = sorted([s.strip() for s in value_in.split(',')])
    elif isinstance(value_in, list):
        value_list = sorted(value_in)

    if zone_in[-1:] != '.':
        zone_in += "."

    if record_in[-1:] != '.':
        record_in += "."

    if command_in == 'create' or command_in == 'delete':
        if not value_in:
            module.fail_json(msg = "parameter 'value' required for create/delete")
        elif alias_in:
            if len(value_list) != 1:
                module.fail_json(msg = "parameter 'value' must contain a single dns name for alias create/delete")
            elif not alias_hosted_zone_id_in:
                module.fail_json(msg = "parameter 'alias_hosted_zone_id' required for alias create/delete")
        elif ( weight_in is not None or region_in is not None or failover_in is not None ) and identifier_in is None:
            module.fail_json(msg= "If you specify failover, region or weight you must also specify identifier")

    if command_in == 'create':
        if ( weight_in is not None or region_in is not None or failover_in is not None ) and identifier_in is None:
          module.fail_json(msg= "If you specify failover, region or weight you must also specify identifier")
        elif ( weight_in is None and region_in is None and failover_in is None ) and identifier_in is not None:
          module.fail_json(msg= "You have specified identifier which makes sense only if you specify one of: weight, region or failover.")



    if vpc_id_in and not private_zone_in:
        module.fail_json(msg="parameter 'private_zone' must be true when specifying parameter"
            " 'vpc_id'")


    # connect to the route53 endpoint
    try:
        conn = Route53Connection(**aws_connect_kwargs)
    except boto.exception.BotoServerError as e:
        module.fail_json(msg = e.error_message)

    # Find the named zone ID
    zone = get_zone_by_name(conn, module, zone_in, private_zone_in, hosted_zone_id_in, vpc_id_in)

    # Verify that the requested zone is already defined in Route53
    if zone is None:
        errmsg = "Zone %s does not exist in Route53" % zone_in
        module.fail_json(msg = errmsg)

    record = {}

    found_record = False
    wanted_rset = Record(name=record_in, type=type_in, ttl=ttl_in,
        identifier=identifier_in, weight=weight_in, region=region_in,
        health_check=health_check_in, failover=failover_in)
    for v in value_list:
        if alias_in:
            wanted_rset.set_alias(alias_hosted_zone_id_in, v, alias_evaluate_target_health_in)
        else:
            wanted_rset.add_value(v)

    sets = conn.get_all_rrsets(zone.id, name=record_in, type=type_in, identifier=identifier_in)
    for rset in sets:
        # Due to a bug in either AWS or Boto, "special" characters are returned as octals, preventing round
        # tripping of things like * and @.
        decoded_name = rset.name.replace(r'\052', '*')
        decoded_name = decoded_name.replace(r'\100', '@')
        #Need to save this changes in rset, because of comparing rset.to_xml() == wanted_rset.to_xml() in next block
        rset.name = decoded_name

        if identifier_in is not None:
            identifier_in = str(identifier_in)

        if rset.type == type_in and decoded_name.lower() == record_in.lower() and rset.identifier == identifier_in:
            found_record = True
            record['zone'] = zone_in
            record['type'] = rset.type
            record['record'] = decoded_name
            record['ttl'] = rset.ttl
            record['value'] = ','.join(sorted(rset.resource_records))
            record['values'] = sorted(rset.resource_records)
            if hosted_zone_id_in:
                record['hosted_zone_id'] = hosted_zone_id_in
            record['identifier'] = rset.identifier
            record['weight'] = rset.weight
            record['region'] = rset.region
            record['failover'] = rset.failover
            record['health_check'] = rset.health_check
            if hosted_zone_id_in:
                record['hosted_zone_id'] = hosted_zone_id_in
            if rset.alias_dns_name:
              record['alias'] = True
              record['value'] = rset.alias_dns_name
              record['values'] = [rset.alias_dns_name]
              record['alias_hosted_zone_id'] = rset.alias_hosted_zone_id
              record['alias_evaluate_target_health'] = rset.alias_evaluate_target_health
            else:
              record['alias'] = False
              record['value'] = ','.join(sorted(rset.resource_records))
              record['values'] = sorted(rset.resource_records)
            if command_in == 'create' and rset.to_xml() == wanted_rset.to_xml():
                module.exit_json(changed=False)
            break

    if command_in == 'get':
        if type_in == 'NS':
            ns = record['values']
        else:
            # Retrieve name servers associated to the zone.
            ns = conn.get_zone(zone_in).get_nameservers()

        module.exit_json(changed=False, set=record, nameservers=ns)

    if command_in == 'delete' and not found_record:
        module.exit_json(changed=False)

    changes = ResourceRecordSets(conn, zone.id)

    if command_in == 'create' or command_in == 'delete':
        if command_in == 'create' and found_record:
            if not module.params['overwrite']:
                module.fail_json(msg = "Record already exists with different value. Set 'overwrite' to replace it")
            command = 'UPSERT'
        else:
            command = command_in.upper()
        changes.add_change_record(command, wanted_rset)

    try:
        result = invoke_with_throttling_retries(commit, changes, retry_interval_in, wait_in, wait_timeout_in)
    except boto.route53.exception.DNSServerError as e:
        txt = e.body.split("<Message>")[1]
        txt = txt.split("</Message>")[0]
        if "but it already exists" in txt:
                module.exit_json(changed=False)
        else:
                module.fail_json(msg = txt)
    except TimeoutError:
        module.fail_json(msg='Timeout waiting for changes to replicate')

    module.exit_json(changed=True)
Beispiel #17
0
 def __init__(self):
     self.route53 = Route53Connection()