From fd148d1803002a79d196678423375b7ae771dcad Mon Sep 17 00:00:00 2001 From: Ross McFarland Date: Thu, 26 Aug 2021 15:56:27 -0700 Subject: [PATCH] Documentation of strict_supports and lenient, changelog info --- CHANGELOG.md | 11 ++++++++++- README.md | 26 ++++++++++++++++++++++++++ octodns/provider/__init__.py | 4 ++++ octodns/provider/base.py | 4 ++-- tests/test_octodns_provider_base.py | 5 +++-- 5 files changed, 45 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ca42a68..3111716 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,16 @@ -## v0.9.14 - 2021-??-?? - ... +## v0.9.14 - 2021-??-?? - A new supports system #### Noteworthy changes +* Provider `strict_supports` param added, currently defaults to `false`, along + with Provider._process_desired_zone this forms the foundations of a new + "supports" system where providers will warn or error (depending on the value + of `strict_supports` during planning about their inability to do what they're + being asked. When `false` they will warn and "adjust" the desired records. + When true they will abort with an error indicating the problem. Over time it + is expected that all "supports" checking/handling will move into this + paradigm and `strict_supports` will likely be changed to default to `true`. +* Zone shallow copy support, reworking of Processors (alpha) semantics * NS1 NA target now includes `SX` and `UM`. If `NA` continent is in use in dynamic records care must be taken to upgrade/downgrade to v0.9.13. * Ns1Provider now supports a new parameter, shared_notifylist, which results in diff --git a/README.md b/README.md index 1f0e9e3..b6530b0 100644 --- a/README.md +++ b/README.md @@ -228,6 +228,32 @@ The above command pulled the existing data out of Route53 and placed the results * Dnsimple's uses the configured TTL when serving things through the ALIAS, there's also a secondary TXT record created alongside the ALIAS that octoDNS ignores * octoDNS itself supports non-ASCII character sets, but in testing Cloudflare is the only provider where that is currently functional end-to-end. Others have failures either in the client libraries or API calls +## Compatibilty & Compliance + +### `lenient` + +`lenient` mostly focuses on the details of `Record`s and standards compliance. When set to `true` will octoDNS will allow allow non-compliant configurations & values when possible. For example CNAME values that don't end with a `.`, label length restrictions, or invalid geo codes on `dynamic` records. When in lenient mode octoDNS will log validation problems at `WARNING` and try and continue with the configuration or source data as it exists to the degree possible. See [Lenience](/docs/records.md#lenience) for more information on the concept and how it can be configured. + +### `strict_supports` (Work In Progress) + +`strict_supports` is a `Provider` level parameter that comes into play when a provider has been asked to create a record that it is unable to support. The simplest case of this would be record type, e.g. `SSHFP` not being supported by `AzureProvider`. If such a record is passed to an `AzureProvider` as a target the provider will take action based on the `strict_supports`. When `true` it will throw an exception saying that it's unable to create the record, when set to `false` it will log at `WARNING` with information about what it's unable to do and how it is attempting to working around it. Other examples of things that cannot be supported would be `dynamic` records on a provider that only supports simple or the lack of support for specific geos in a provider, e.g. Route53Provider does not support `NA-CA-*`. + +It is worth noting that these errors will happen during the plan phase of things so that problems will be indicated without having to make changes. + +This concept is currently a work in progress and partially implemented. While work is on-going `strict_supports` will defaults to `false`. Once the work is considered complete & ready the default will change to `true` as it's a much safer and less surprising default as what you configure is what you'll get unless an error is throw telling you why it cannot be done. You will then have the choice to explicitly request that things continue with a work-around. In the meantime it is encouraged that you manually configure the parameter to `true` in your provider configs. + +### Configuring `strict_supports` + +The `strict_supports` parameter is available on all providers and can be configured in YAML as follows: + +```yaml +providers: + someprovider: + class: whatever.TheProvider + ... + strict_supports: true +``` + ## Custom Sources and Providers You can check out the [source](/octodns/source/) and [provider](/octodns/provider/) directory to see what's currently supported. Sources act as a source of record information. AxfrSource and TinyDnsFileSource are currently the only OSS sources, though we have several others internally that are specific to our environment. These include something to pull host data from [gPanel](https://githubengineering.com/githubs-metal-cloud/) and a similar provider that sources information about our network gear to create both `A` & `PTR` records for their interfaces. Things that might make good OSS sources might include an `ElbSource` that pulls information about [AWS Elastic Load Balancers](https://aws.amazon.com/elasticloadbalancing/) and dynamically creates `CNAME`s for them, or `Ec2Source` that pulls instance information so that records can be created for hosts similar to how our `GPanelProvider` works. diff --git a/octodns/provider/__init__.py b/octodns/provider/__init__.py index dbbaaa8..7e18783 100644 --- a/octodns/provider/__init__.py +++ b/octodns/provider/__init__.py @@ -8,3 +8,7 @@ from __future__ import absolute_import, division, print_function, \ class ProviderException(Exception): pass + + +class SupportsException(ProviderException): + pass diff --git a/octodns/provider/base.py b/octodns/provider/base.py index c862e2d..b636d65 100644 --- a/octodns/provider/base.py +++ b/octodns/provider/base.py @@ -10,7 +10,7 @@ from six import text_type from ..source.base import BaseSource from ..zone import Zone from .plan import Plan -from . import ProviderException +from . import SupportsException class BaseProvider(BaseSource): @@ -85,7 +85,7 @@ class BaseProvider(BaseSource): def supports_warn_or_except(self, msg, fallback): if self.strict_supports: - raise ProviderException('{}: {}'.format(self.id, msg)) + raise SupportsException('{}: {}'.format(self.id, msg)) self.log.warning('{}; {}'.format(msg, fallback)) def plan(self, desired, processors=[]): diff --git a/tests/test_octodns_provider_base.py b/tests/test_octodns_provider_base.py index 501177e..cee7c2c 100644 --- a/tests/test_octodns_provider_base.py +++ b/tests/test_octodns_provider_base.py @@ -11,7 +11,8 @@ from six import text_type from unittest import TestCase from octodns.processor.base import BaseProcessor -from octodns.provider.base import BaseProvider, ProviderException +from octodns.provider import SupportsException +from octodns.provider.base import BaseProvider from octodns.provider.plan import Plan, UnsafePlan from octodns.record import Create, Delete, Record, Update from octodns.zone import Zone @@ -465,7 +466,7 @@ class TestBaseProvider(TestCase): strict = MinimalProvider(strict_supports=True) # Should log and not expect - with self.assertRaises(ProviderException) as ctx: + with self.assertRaises(SupportsException) as ctx: strict.supports_warn_or_except('Hello World!', 'Will not see') self.assertEquals('minimal: Hello World!', text_type(ctx.exception)) strict.log.warning.assert_not_called()