예제 #1
0
 def test_record_eq_record_different_values(self):
     """Record with different values is not equal"""
     zone = Zone('test.example.com')
     data = {'type': 'A', 'ttl': 30, 'values': ['1.1.1.1', '2.2.2.2']}
     record_current = Record(zone, 'test-record', data)
     data = {'type': 'A', 'ttl': 30, 'values': ['1.1.1.1', '3.3.3.3']}
     record_desired = Record(zone, 'test-record', data)
     self.assertTrue(record_current != record_desired)
예제 #2
0
 def test_record_eq_record_different_values_order(self):
     """Record with same values in different order is still equal"""
     zone = Zone('test.example.com')
     data = {'type': 'A', 'ttl': 30, 'values': ['1.1.1.1', '2.2.2.2']}
     record_current = Record(zone, 'test-record', data)
     data = {'type': 'A', 'ttl': 30, 'values': ['2.2.2.2', '1.1.1.1']}
     record_desired = Record(zone, 'test-record', data)
     self.assertTrue(record_current == record_desired)
예제 #3
0
 def test_zone_cant_have_duplicate_records(self):
     """Zone cannot add multiple records with same name"""
     zone = Zone('test.example.com')
     recordA = Record(zone, 'test-record', {'type': 'A', 'ttl': 300})
     recordB = Record(zone, 'test-record', {'type': 'A', 'ttl': 300})
     zone.add_record(recordA)
     with self.assertRaises(DuplicateException):
         zone.add_record(recordB)
예제 #4
0
 def test_add_multiple_records_to_zone(self):
     """Zone can add multiple records with different names"""
     zone = Zone('test.example.com')
     recordA = Record(zone, 'test-recorda', {'type': 'A', 'ttl': 300})
     recordB = Record(zone, 'test-recordb', {'type': 'A', 'ttl': 300})
     zone.add_record(recordA)
     zone.add_record(recordB)
     self.assertDictEqual(zone.records, {
         'test-recorda': recordA,
         'test-recordb': recordB,
     })
예제 #5
0
 def test_record_without_ttl_should_fail(self):
     """Record data without a ttl should fail"""
     zone = Zone('test.example.com')
     with self.assertRaises(InvalidRecordData) as e:
         Record(zone, 'test-record', {'type': 'A'})
     self.assertEqual('missing key \'ttl\' in Record data',
                      str(e.exception))
예제 #6
0
def build_current_state(awsapi):
    """
    Build a State object that represents the current state

    :param awsapi: the aws API object to use
    :type awsapi: AWSApi
    :return: returns a tuple that contains the State object and whether there \
        were any errors
    :rtype: (State, bool)
    """
    state = State('aws')
    errors = False

    awsapi.map_route53_resources()
    aws_state = awsapi.get_route53_zones()

    for account_name, zones in aws_state.items():
        account = Account(account_name)
        for zone in zones:
            zone_name = zone['Name']
            new_zone = Zone(zone_name, zone)
            for record in zone['records']:
                # Can't manage SOA records, so ignore it
                if record['Type'] in ['SOA']:
                    continue
                # Can't manage NS records at apex, so ignore them
                if record['Type'] == 'NS' and record['Name'] == zone_name:
                    continue

                record_name = removesuffix(record['Name'], zone_name)
                new_record = Record(
                    new_zone, record_name, {
                        'type': record['Type'],
                        'ttl': record['TTL'],
                        'values':
                        [v['Value'] for v in record['ResourceRecords']],
                    }, record)
                new_zone.add_record(new_record)

            account.add_zone(new_zone)

        state.add_account(account)

    return state, errors
예제 #7
0
 def test_repr_apex(self):
     """Record at the apex (empty name) is represented properly"""
     zone = Zone('test.example.com')
     record = Record(zone, '', {'type': 'A', 'ttl': 300})
     self.assertEqual(f'{record}', 'Record<A>')
예제 #8
0
 def test_repr(self):
     """Record is represented properly"""
     zone = Zone('test.example.com')
     record = Record(zone, "test-record", {'type': 'A', 'ttl': 300})
     self.assertEqual(f'{record}', 'Record<A, test-record>')
예제 #9
0
 def test_record_eq_record_different_ttl(self):
     """Record with a different TTL is not equal"""
     zone = Zone('test.example.com')
     record_current = Record(zone, 'test-record', {'type': 'A', 'ttl': 30})
     record_desired = Record(zone, 'test-record', {'type': 'A', 'ttl': 300})
     self.assertTrue(record_current != record_desired)
예제 #10
0
 def test_record_eq_record(self):
     """Record with the same type, ttl and values are equal"""
     zone = Zone('test.example.com')
     record_current = Record(zone, 'test-record', {'type': 'A', 'ttl': 300})
     record_desired = Record(zone, 'test-record', {'type': 'A', 'ttl': 300})
     self.assertTrue(record_current == record_desired)
예제 #11
0
 def test_record_without_values(self):
     """Record can have no values"""
     zone = Zone('test.example.com')
     record = Record(zone, 'test-record', {'type': 'A', 'ttl': 300})
     self.assertListEqual(record.values, [])
예제 #12
0
 def test_record_with_invalid_type_should_fail(self):
     """Record can only have a supported type"""
     zone = Zone('test.example.com')
     with self.assertRaises(InvalidRecordType) as e:
         Record(zone, 'test-record', {'type': 'FOO', 'ttl': 300})
     self.assertEqual('Type FOO is not supported', str(e.exception))
예제 #13
0
 def test_record_fqdn(self):
     """Record can return it's fqdn"""
     zone = Zone('test.example.com')
     record = Record(zone, 'test-record', {'type': 'A', 'ttl': 300})
     self.assertEqual(record.fqdn, 'test-record.test.example.com')
예제 #14
0
 def test_record_name(self):
     """Record can return it's name"""
     zone = Zone('test.example.com')
     record = Record(zone, 'test-record', {'type': 'A', 'ttl': 300})
     self.assertEqual(record.name, 'test-record')
예제 #15
0
 def test_record_returns_values(self):
     """Record can return it's values"""
     zone = Zone('test.example.com')
     record = Record(zone, 'test-record', {'type': 'A', 'ttl': 300})
     record.add_targets(['1.1.1.1', '2.2.2.2', '3.3.3.3'])
     self.assertListEqual(record.values, ['1.1.1.1', '2.2.2.2', '3.3.3.3'])
예제 #16
0
def build_desired_state(zones):
    """
    Build a State object that represents the desired state

    :param zones: a representation of DNS zones as retrieved from app-interface
    :type zones: dict
    :return: returns a tuple that contains the State object and whether there \
        were any errors
    :rtype: (State, bool)
    """
    state = State('app-interface')
    errors = False

    for zone in zones:
        account_name = zone['account']['name']

        account = state.get_account(account_name)
        if not account:
            account = Account(account_name)

        new_zone = Zone(zone['name'], zone)

        for record in zone['records']:
            new_record = Record(new_zone, record['name'], {
                'type': record['type'],
                'ttl': record['ttl'] or DEFAULT_RECORD_TTL
            }, record)

            targets = []

            record_target = record.get('target')
            if record_target:
                if record['type'] == 'TXT':
                    # TXT records values need to be enclosed in double quotes
                    targets.append(f'"{record_target}"')
                else:
                    targets.append(record_target)

            record_targets = record.get('targets')
            if record_targets:
                targets.extend(record_targets)

            record_target_cluster = record.get('target_cluster')
            if record_target_cluster:
                cluster = record_target_cluster
                cluster_name = cluster['name']
                elb_fqdn = cluster.get('elbFQDN')
                if not elb_fqdn:
                    logging.error(f'[{account}] elbFQDN not set for cluster '
                                  f'{cluster_name}')
                    errors = True
                    continue
                targets.append(elb_fqdn)

            if not targets:
                logging.error(f'[{account}] no targets found for '
                              f'{new_record} in {new_zone}')
                errors = True
                continue
            new_record.add_targets(targets)
            new_zone.add_record(new_record)

        try:
            account.add_zone(new_zone)
        except DuplicateException as e:
            logging.error(e)
            errors = True

        if not state.get_account(account_name):
            state.add_account(account)

    return state, errors
예제 #17
0
 def test_add_record_to_zone(self):
     """Zone can add a record to zone and return it"""
     zone = Zone('test.example.com')
     record = Record(zone, 'test-record', {'type': 'A', 'ttl': 300})
     zone.add_record(record)
     self.assertEqual(zone.records.get('test-record'), record)