Пример #1
0
    def test_simple(self):
        with TemporaryDirectory() as tmpdir:
            environ['YAML_TMP_DIR'] = tmpdir.dirname
            tc = Manager(get_config_filename('simple.yaml')) \
                .sync(dry_run=False)
            self.assertEquals(22, tc)

            # try with just one of the zones
            tc = Manager(get_config_filename('simple.yaml')) \
                .sync(dry_run=False, eligible_zones=['unit.tests.'])
            self.assertEquals(16, tc)

            # the subzone, with 2 targets
            tc = Manager(get_config_filename('simple.yaml')) \
                .sync(dry_run=False, eligible_zones=['subzone.unit.tests.'])
            self.assertEquals(6, tc)

            # and finally the empty zone
            tc = Manager(get_config_filename('simple.yaml')) \
                .sync(dry_run=False, eligible_zones=['empty.'])
            self.assertEquals(0, tc)

            # Again with force
            tc = Manager(get_config_filename('simple.yaml')) \
                .sync(dry_run=False, force=True)
            self.assertEquals(22, tc)

            # Again with max_workers = 1
            tc = Manager(get_config_filename('simple.yaml'), max_workers=1) \
                .sync(dry_run=False, force=True)
            self.assertEquals(22, tc)

            # Include meta
            tc = Manager(get_config_filename('simple.yaml'), max_workers=1,
                         include_meta=True) \
                .sync(dry_run=False, force=True)
            self.assertEquals(26, tc)
    def test_aliases(self):
        with TemporaryDirectory() as tmpdir:
            environ['YAML_TMP_DIR'] = tmpdir.dirname
            # Alias zones with a valid target.
            tc = Manager(get_config_filename('simple-alias-zone.yaml')) \
                .sync()
            self.assertEquals(0, tc)

            # Alias zone with an invalid target.
            with self.assertRaises(ManagerException) as ctx:
                tc = Manager(get_config_filename('unknown-source-zone.yaml')) \
                    .sync()
            self.assertEquals(
                'Invalid alias zone alias.tests.: source zone '
                'does-not-exists.tests. does not exist',
                text_type(ctx.exception))

            # Alias zone that points to another alias zone.
            with self.assertRaises(ManagerException) as ctx:
                tc = Manager(get_config_filename('alias-zone-loop.yaml')) \
                    .sync()
            self.assertEquals(
                'Invalid alias zone alias-loop.tests.: source '
                'zone alias.tests. is an alias zone', text_type(ctx.exception))
Пример #3
0
    def test_populate_lenient_fallback(self):
        with TemporaryDirectory() as tmpdir:
            environ['YAML_TMP_DIR'] = tmpdir.dirname
            # Only allow a target that doesn't exist
            manager = Manager(get_config_filename('simple.yaml'))

            class NoLenient(SimpleProvider):

                def populate(self, zone):
                    pass

            # This should be ok, we'll fall back to not passing it
            manager._populate_and_plan('unit.tests.', [], [NoLenient()], [])

            class OtherType(SimpleProvider):

                def populate(self, zone, lenient=False):
                    raise TypeError('something else')

            # This will blow up, we don't fallback for source
            with self.assertRaises(TypeError) as ctx:
                manager._populate_and_plan('unit.tests.', [], [OtherType()],
                                           [])
            self.assertEquals('something else', text_type(ctx.exception))
Пример #4
0
    def test_provider(self):
        source = YamlProvider('test', join(dirname(__file__), 'config'))

        zone = Zone('unit.tests.', [])

        # With target we don't add anything
        source.populate(zone, target=source)
        self.assertEquals(0, len(zone.records))

        # without it we see everything
        source.populate(zone)
        self.assertEquals(18, len(zone.records))

        # Assumption here is that a clean round-trip means that everything
        # worked as expected, data that went in came back out and could be
        # pulled in yet again and still match up. That assumes that the input
        # data completely exercises things. This assumption can be tested by
        # relatively well by running
        #   ./script/coverage tests/test_octodns_provider_yaml.py and
        # looking at the coverage file
        #   ./htmlcov/octodns_provider_yaml_py.html

        with TemporaryDirectory() as td:
            # Add some subdirs to make sure that it can create them
            directory = join(td.dirname, 'sub', 'dir')
            yaml_file = join(directory, 'unit.tests.yaml')
            target = YamlProvider('test', directory)

            # We add everything
            plan = target.plan(zone)
            self.assertEquals(
                14, len(filter(lambda c: isinstance(c, Create), plan.changes)))
            self.assertFalse(isfile(yaml_file))

            # Now actually do it
            self.assertEquals(14, target.apply(plan))
            self.assertTrue(isfile(yaml_file))

            # There should be no changes after the round trip
            reloaded = Zone('unit.tests.', [])
            target.populate(reloaded)
            self.assertFalse(zone.changes(reloaded, target=source))

            # A 2nd sync should still create everything
            plan = target.plan(zone)
            self.assertEquals(
                14, len(filter(lambda c: isinstance(c, Create), plan.changes)))

            with open(yaml_file) as fh:
                data = safe_load(fh.read())

                # these are stored as plural 'values'
                for r in data['']:
                    self.assertTrue('values' in r)
                self.assertTrue('values' in data['mx'])
                self.assertTrue('values' in data['naptr'])
                self.assertTrue('values' in data['_srv._tcp'])
                self.assertTrue('values' in data['txt'])
                # these are stored as singular 'value'
                self.assertTrue('value' in data['aaaa'])
                self.assertTrue('value' in data['ptr'])
                self.assertTrue('value' in data['spf'])
                self.assertTrue('value' in data['www'])
Пример #5
0
    def test_provider(self):
        source = YamlProvider('test', join(dirname(__file__), 'config'))

        zone = Zone('unit.tests.', [])
        dynamic_zone = Zone('dynamic.tests.', [])

        # With target we don't add anything
        source.populate(zone, target=source)
        self.assertEqual(0, len(zone.records))

        # without it we see everything
        source.populate(zone)
        self.assertEqual(25, len(zone.records))

        source.populate(dynamic_zone)
        self.assertEqual(6, len(dynamic_zone.records))

        # Assumption here is that a clean round-trip means that everything
        # worked as expected, data that went in came back out and could be
        # pulled in yet again and still match up. That assumes that the input
        # data completely exercises things. This assumption can be tested by
        # relatively well by running
        #   ./script/coverage tests/test_octodns_provider_yaml.py and
        # looking at the coverage file
        #   ./htmlcov/octodns_provider_yaml_py.html

        with TemporaryDirectory() as td:
            # Add some subdirs to make sure that it can create them
            directory = join(td.dirname, 'sub', 'dir')
            yaml_file = join(directory, 'unit.tests.yaml')
            dynamic_yaml_file = join(directory, 'dynamic.tests.yaml')
            target = YamlProvider('test', directory, supports_root_ns=False)

            # We add everything
            plan = target.plan(zone)
            self.assertEqual(
                22, len([c for c in plan.changes if isinstance(c, Create)]))
            self.assertFalse(isfile(yaml_file))

            # Now actually do it
            self.assertEqual(22, target.apply(plan))
            self.assertTrue(isfile(yaml_file))

            # Dynamic plan
            plan = target.plan(dynamic_zone)
            self.assertEqual(
                6, len([c for c in plan.changes if isinstance(c, Create)]))
            self.assertFalse(isfile(dynamic_yaml_file))
            # Apply it
            self.assertEqual(6, target.apply(plan))
            self.assertTrue(isfile(dynamic_yaml_file))

            # There should be no changes after the round trip
            reloaded = Zone('unit.tests.', [])
            target.populate(reloaded)
            self.assertDictEqual(
                {'included': ['test']},
                [x for x in reloaded.records
                 if x.name == 'included'][0]._octodns,
            )

            # manually copy over the root since it will have been ignored
            # when things were written out
            reloaded.add_record(zone.root_ns)

            self.assertFalse(zone.changes(reloaded, target=source))

            # A 2nd sync should still create everything
            plan = target.plan(zone)
            self.assertEqual(
                22, len([c for c in plan.changes if isinstance(c, Create)]))

            with open(yaml_file) as fh:
                data = safe_load(fh.read())

                # '' has some of both
                roots = sorted(data.pop(''), key=lambda r: r['type'])
                self.assertTrue('values' in roots[0])  # A
                self.assertTrue('geo' in roots[0])  # geo made the trip
                self.assertTrue('value' in roots[1])  # CAA
                self.assertTrue('values' in roots[2])  # SSHFP

                # these are stored as plural 'values'
                self.assertTrue('values' in data.pop('_srv._tcp'))
                self.assertTrue('values' in data.pop('mx'))
                self.assertTrue('values' in data.pop('naptr'))
                self.assertTrue('values' in data.pop('sub'))
                self.assertTrue('values' in data.pop('txt'))
                self.assertTrue('values' in data.pop('loc'))
                self.assertTrue('values' in data.pop('urlfwd'))
                self.assertTrue('values' in data.pop('sub.txt'))
                self.assertTrue('values' in data.pop('subzone'))
                # these are stored as singular 'value'
                self.assertTrue('value' in data.pop('_imap._tcp'))
                self.assertTrue('value' in data.pop('_pop3._tcp'))
                self.assertTrue('value' in data.pop('aaaa'))
                self.assertTrue('value' in data.pop('cname'))
                self.assertTrue('value' in data.pop('dname'))
                self.assertTrue('value' in data.pop('included'))
                self.assertTrue('value' in data.pop('ptr'))
                self.assertTrue('value' in data.pop('spf'))
                self.assertTrue('value' in data.pop('www'))
                self.assertTrue('value' in data.pop('www.sub'))

                # make sure nothing is left
                self.assertEqual([], list(data.keys()))

            with open(dynamic_yaml_file) as fh:
                data = safe_load(fh.read())

                # make sure new dynamic records made the trip
                dyna = data.pop('a')
                self.assertTrue('values' in dyna)
                # self.assertTrue('dynamic' in dyna)
                # TODO:

                # make sure new dynamic records made the trip
                dyna = data.pop('aaaa')
                self.assertTrue('values' in dyna)
                # self.assertTrue('dynamic' in dyna)

                dyna = data.pop('cname')
                self.assertTrue('value' in dyna)
                # self.assertTrue('dynamic' in dyna)

                dyna = data.pop('real-ish-a')
                self.assertTrue('values' in dyna)
                # self.assertTrue('dynamic' in dyna)

                dyna = data.pop('simple-weighted')
                self.assertTrue('value' in dyna)
                # self.assertTrue('dynamic' in dyna)

                dyna = data.pop('pool-only-in-fallback')
                self.assertTrue('value' in dyna)
                # self.assertTrue('dynamic' in dyna)

                # make sure nothing is left
                self.assertEqual([], list(data.keys()))
Пример #6
0
    def test_provider(self):
        source = SplitYamlProvider('test',
                                   join(dirname(__file__), 'config/split'),
                                   extension='.tst')

        zone = Zone('unit.tests.', [])
        dynamic_zone = Zone('dynamic.tests.', [])

        # With target we don't add anything
        source.populate(zone, target=source)
        self.assertEqual(0, len(zone.records))

        # without it we see everything
        source.populate(zone)
        self.assertEqual(20, len(zone.records))

        source.populate(dynamic_zone)
        self.assertEqual(5, len(dynamic_zone.records))

        with TemporaryDirectory() as td:
            # Add some subdirs to make sure that it can create them
            directory = join(td.dirname, 'sub', 'dir')
            zone_dir = join(directory, 'unit.tests.tst')
            dynamic_zone_dir = join(directory, 'dynamic.tests.tst')
            target = SplitYamlProvider('test',
                                       directory,
                                       extension='.tst',
                                       supports_root_ns=False)

            # We add everything
            plan = target.plan(zone)
            self.assertEqual(
                17, len([c for c in plan.changes if isinstance(c, Create)]))
            self.assertFalse(isdir(zone_dir))

            # Now actually do it
            self.assertEqual(17, target.apply(plan))

            # Dynamic plan
            plan = target.plan(dynamic_zone)
            self.assertEqual(
                5, len([c for c in plan.changes if isinstance(c, Create)]))
            self.assertFalse(isdir(dynamic_zone_dir))
            # Apply it
            self.assertEqual(5, target.apply(plan))
            self.assertTrue(isdir(dynamic_zone_dir))

            # There should be no changes after the round trip
            reloaded = Zone('unit.tests.', [])
            target.populate(reloaded)
            self.assertDictEqual(
                {'included': ['test']},
                [x for x in reloaded.records
                 if x.name == 'included'][0]._octodns,
            )

            # manually copy over the root since it will have been ignored
            # when things were written out
            reloaded.add_record(zone.root_ns)

            self.assertFalse(zone.changes(reloaded, target=source))

            # A 2nd sync should still create everything
            plan = target.plan(zone)
            self.assertEqual(
                17, len([c for c in plan.changes if isinstance(c, Create)]))

            yaml_file = join(zone_dir, '$unit.tests.yaml')
            self.assertTrue(isfile(yaml_file))
            with open(yaml_file) as fh:
                data = safe_load(fh.read())
                roots = sorted(data.pop(''), key=lambda r: r['type'])
                self.assertTrue('values' in roots[0])  # A
                self.assertTrue('geo' in roots[0])  # geo made the trip
                self.assertTrue('value' in roots[1])  # CAA
                self.assertTrue('values' in roots[2])  # SSHFP

            # These records are stored as plural "values." Check each file to
            # ensure correctness.
            for record_name in (
                    '_srv._tcp',
                    'mx',
                    'naptr',
                    'sub',
                    'txt',
                    'urlfwd',
            ):
                yaml_file = join(zone_dir, f'{record_name}.yaml')
                self.assertTrue(isfile(yaml_file))
                with open(yaml_file) as fh:
                    data = safe_load(fh.read())
                    self.assertTrue('values' in data.pop(record_name))

            # These are stored as singular "value." Again, check each file.
            for record_name in (
                    'aaaa',
                    'cname',
                    'dname',
                    'included',
                    'ptr',
                    'spf',
                    'www.sub',
                    'www',
            ):
                yaml_file = join(zone_dir, f'{record_name}.yaml')
                self.assertTrue(isfile(yaml_file))
                with open(yaml_file) as fh:
                    data = safe_load(fh.read())
                    self.assertTrue('value' in data.pop(record_name))

            # Again with the plural, this time checking dynamic.tests.
            for record_name in ('a', 'aaaa', 'real-ish-a'):
                yaml_file = join(dynamic_zone_dir, f'{record_name}.yaml')
                self.assertTrue(isfile(yaml_file))
                with open(yaml_file) as fh:
                    data = safe_load(fh.read())
                    dyna = data.pop(record_name)
                    self.assertTrue('values' in dyna)
                    self.assertTrue('dynamic' in dyna)

            # Singular again.
            for record_name in ('cname', 'simple-weighted'):
                yaml_file = join(dynamic_zone_dir, f'{record_name}.yaml')
                self.assertTrue(isfile(yaml_file))
                with open(yaml_file) as fh:
                    data = safe_load(fh.read())
                    dyna = data.pop(record_name)
                    self.assertTrue('value' in dyna)
                    self.assertTrue('dynamic' in dyna)
Пример #7
0
    def test_dump_output_provider(self):
        with TemporaryDirectory() as tmpdir:
            environ['YAML_TMP_DIR'] = tmpdir.dirname
            # this time we'll use seperate tmp dirs
            with TemporaryDirectory() as tmpdir2:
                environ['YAML_TMP_DIR2'] = tmpdir2.dirname
                manager = Manager(get_config_filename('simple.yaml'))

                # we're going to tell it to use dump2 to do the dumping, but a
                # copy should be made and directory set to tmpdir.dirname
                # rather than 2's tmpdir2.dirname
                manager.dump(
                    zone='unit.tests.',
                    output_dir=tmpdir.dirname,
                    output_provider='dump2',
                    sources=['in'],
                )

                self.assertTrue(isfile(join(tmpdir.dirname,
                                            'unit.tests.yaml')))
                self.assertFalse(
                    isfile(join(tmpdir2.dirname, 'unit.tests.yaml')))

                # let's run that again, this time telling it to use tmpdir2 and
                # dump2 which should allow it to skip the copying
                manager.dump(
                    zone='unit.tests.',
                    output_dir=tmpdir2.dirname,
                    output_provider='dump2',
                    sources=['in'],
                )
                self.assertTrue(
                    isfile(join(tmpdir2.dirname, 'unit.tests.yaml')))

                # tell it to use an output_provider that doesn't exist
                with self.assertRaises(ManagerException) as ctx:
                    manager.dump(
                        zone='unit.tests.',
                        output_dir=tmpdir.dirname,
                        output_provider='nope',
                        sources=['in'],
                    )
                self.assertEqual('Unknown output_provider: nope',
                                 str(ctx.exception))

                # tell it to use an output_provider that doesn't support
                # directory
                with self.assertRaises(ManagerException) as ctx:
                    manager.dump(
                        zone='unit.tests.',
                        output_dir=tmpdir.dirname,
                        output_provider='simple',
                        sources=['in'],
                    )
                self.assertEqual(
                    'output_provider=simple, does not support '
                    'directory property',
                    str(ctx.exception),
                )

                # hack a directory property onto the simple provider so that
                # it'll pass that check and fail the copy one instead
                manager.providers['simple'].directory = 42
                with self.assertRaises(ManagerException) as ctx:
                    manager.dump(
                        zone='unit.tests.',
                        output_dir=tmpdir.dirname,
                        output_provider='simple',
                        sources=['in'],
                    )
                self.assertEqual(
                    'output_provider=simple, does not support '
                    'copy method',
                    str(ctx.exception),
                )
Пример #8
0
    def test_provider(self):
        source = EtcHostsProvider('test', path.join(dirname(__file__),
                                                    'config'))

        zone = Zone('unit.tests.', [])

        # We never populate anything, when acting as a source
        source.populate(zone, target=source)
        self.assertEquals(0, len(zone.records))
        # Same if we're acting as a target
        source.populate(zone)
        self.assertEquals(0, len(zone.records))

        record = Record.new(zone, '', {
            'ttl': 60,
            'type': 'ALIAS',
            'value': 'www.unit.tests.'
        })
        zone.add_record(record)

        record = Record.new(zone, 'www', {
            'ttl': 60,
            'type': 'AAAA',
            'value': '2001:4860:4860::8888',
        })
        zone.add_record(record)
        record = Record.new(zone, 'www', {
            'ttl': 60,
            'type': 'A',
            'values': ['1.1.1.1', '2.2.2.2'],
        })
        zone.add_record(record)

        record = record.new(zone, 'v6', {
            'ttl': 60,
            'type': 'AAAA',
            'value': '2001:4860:4860::8844',
        })
        zone.add_record(record)

        record = record.new(zone, 'start', {
            'ttl': 60,
            'type': 'CNAME',
            'value': 'middle.unit.tests.',
        })
        zone.add_record(record)
        record = record.new(zone, 'middle', {
            'ttl': 60,
            'type': 'CNAME',
            'value': 'unit.tests.',
        })
        zone.add_record(record)

        record = record.new(zone, 'ext', {
            'ttl': 60,
            'type': 'CNAME',
            'value': 'github.com.',
        })
        zone.add_record(record)

        record = record.new(zone, '*', {
            'ttl': 60,
            'type': 'A',
            'value': '3.3.3.3',
        })
        zone.add_record(record)

        with TemporaryDirectory() as td:
            # Add some subdirs to make sure that it can create them
            directory = path.join(td.dirname, 'sub', 'dir')
            hosts_file = path.join(directory, 'unit.tests.hosts')
            target = EtcHostsProvider('test', directory)

            # We add everything
            plan = target.plan(zone)
            self.assertEquals(len(zone.records), len(plan.changes))
            self.assertFalse(isfile(hosts_file))

            # Now actually do it
            self.assertEquals(len(zone.records), target.apply(plan))
            self.assertTrue(isfile(hosts_file))

            with open(hosts_file) as fh:
                data = fh.read()
                # v6
                self.assertTrue('2001:4860:4860::8844\tv6.unit.tests' in data)
                # www
                self.assertTrue('1.1.1.1\twww.unit.tests' in data)
                # root ALIAS
                self.assertTrue('# unit.tests -> www.unit.tests' in data)
                self.assertTrue('1.1.1.1\tunit.tests' in data)

                self.assertTrue(
                    '# start.unit.tests -> middle.unit.tests' in data)
                self.assertTrue('# middle.unit.tests -> unit.tests' in data)
                self.assertTrue('# unit.tests -> www.unit.tests' in data)
                self.assertTrue('1.1.1.1	start.unit.tests' in data)

            # second empty run that won't create dirs and overwrites file
            plan = Plan(zone, zone, [], True)
            self.assertEquals(0, target.apply(plan))