diff --git a/README.md b/README.md index f015dbc..23ac0e8 100644 --- a/README.md +++ b/README.md @@ -191,7 +191,7 @@ The above command pulled the existing data out of Route53 and placed the results | [EnvVarSource](/octodns/source/envvar.py) | | TXT | No | read-only environment variable injection | | [GoogleCloudProvider](/octodns/provider/googlecloud.py) | google-cloud-dns | A, AAAA, CAA, CNAME, MX, NAPTR, NS, PTR, SPF, SRV, TXT | No | | | [MythicBeastsProvider](/octodns/provider/mythicbeasts.py) | Mythic Beasts | A, AAAA, ALIAS, CNAME, MX, NS, SRV, SSHFP, CAA, TXT | No | | -| [Ns1Provider](/octodns/provider/ns1.py) | ns1-python | All | Yes | No CNAME support, missing `NA` geo target | +| [Ns1Provider](/octodns/provider/ns1.py) | ns1-python | All | Yes | Missing `NA` geo target | | [OVH](/octodns/provider/ovh.py) | ovh | A, AAAA, CAA, CNAME, MX, NAPTR, NS, PTR, SPF, SRV, SSHFP, TXT, DKIM | No | | | [PowerDnsProvider](/octodns/provider/powerdns.py) | | All | No | | | [Rackspace](/octodns/provider/rackspace.py) | | A, AAAA, ALIAS, CNAME, MX, NS, PTR, SPF, TXT | No | | diff --git a/octodns/cmds/sync.py b/octodns/cmds/sync.py index 60793e7..dbf4103 100755 --- a/octodns/cmds/sync.py +++ b/octodns/cmds/sync.py @@ -25,18 +25,19 @@ def main(): parser.add_argument('zone', nargs='*', default=[], help='Limit sync to the specified zone(s)') - # --sources isn't an option here b/c filtering sources out would be super - # dangerous since you could easily end up with an empty zone and delete - # everything, or even just part of things when there are multiple sources - + parser.add_argument('--source', default=[], action='append', + help='Limit sync to zones with the specified ' + 'source(s) (all sources will be synchronized for the ' + 'selected zones)') parser.add_argument('--target', default=[], action='append', help='Limit sync to the specified target(s)') args = parser.parse_args() manager = Manager(args.config_file) - manager.sync(eligible_zones=args.zone, eligible_targets=args.target, - dry_run=not args.doit, force=args.force) + manager.sync(eligible_zones=args.zone, eligible_sources=args.source, + eligible_targets=args.target, dry_run=not args.doit, + force=args.force) if __name__ == '__main__': diff --git a/octodns/manager.py b/octodns/manager.py index 0665938..288645f 100644 --- a/octodns/manager.py +++ b/octodns/manager.py @@ -255,8 +255,8 @@ class Manager(object): return plans - def sync(self, eligible_zones=[], eligible_targets=[], dry_run=True, - force=False): + def sync(self, eligible_zones=[], eligible_sources=[], eligible_targets=[], + dry_run=True, force=False): self.log.info('sync: eligible_zones=%s, eligible_targets=%s, ' 'dry_run=%s, force=%s', eligible_zones, eligible_targets, dry_run, force) @@ -280,6 +280,12 @@ class Manager(object): except KeyError: raise ManagerException('Zone {} is missing targets' .format(zone_name)) + + if (eligible_sources and not + [s for s in sources if s in eligible_sources]): + self.log.info('sync: no eligible sources, skipping') + continue + if eligible_targets: targets = [t for t in targets if t in eligible_targets] diff --git a/requirements.txt b/requirements.txt index dd1643f..24f57ff 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,14 +1,14 @@ PyYaml==5.3.1 azure-common==1.1.25 azure-mgmt-dns==3.0.0 -boto3==1.14.14 -botocore==1.17.14 +boto3==1.14.52 +botocore==1.17.52 dnspython==1.16.0 docutils==0.16 dyn==1.8.1 edgegrid-python==1.1.1 futures==3.2.0; python_version < '3.2' -google-cloud-core==1.3.0 +google-cloud-core==1.4.1 google-cloud-dns==0.32.0 ipaddress==1.0.23; python_version < '3.3' jmespath==0.10.0 @@ -17,7 +17,7 @@ natsort==6.2.1 ns1-python==0.16.0 ovh==0.5.0 pycountry-convert==0.7.2 -pycountry==19.8.18 +pycountry==20.7.3 python-dateutil==2.8.1 requests==2.24.0 s3transfer==0.3.3 diff --git a/tests/test_octodns_manager.py b/tests/test_octodns_manager.py index 581689a..9956790 100644 --- a/tests/test_octodns_manager.py +++ b/tests/test_octodns_manager.py @@ -151,6 +151,14 @@ class TestManager(TestCase): .sync(dry_run=False, force=True) self.assertEquals(25, tc) + def test_eligible_sources(self): + with TemporaryDirectory() as tmpdir: + environ['YAML_TMP_DIR'] = tmpdir.dirname + # Only allow a target that doesn't exist + tc = Manager(get_config_filename('simple.yaml')) \ + .sync(eligible_sources=['foo']) + self.assertEquals(0, tc) + def test_eligible_targets(self): with TemporaryDirectory() as tmpdir: environ['YAML_TMP_DIR'] = tmpdir.dirname