diff --git a/controller/controller.go b/controller/controller.go index c9c8149c15..263f243c81 100644 --- a/controller/controller.go +++ b/controller/controller.go @@ -21,8 +21,8 @@ import ( log "github.com/Sirupsen/logrus" - "github.com/kubernetes-incubator/external-dns/dnsprovider" "github.com/kubernetes-incubator/external-dns/plan" + "github.com/kubernetes-incubator/external-dns/provider" "github.com/kubernetes-incubator/external-dns/source" ) @@ -35,13 +35,13 @@ import ( type Controller struct { Zone string - Source source.Source - DNSProvider dnsprovider.DNSProvider + Source source.Source + Provider provider.Provider } // RunOnce runs a single iteration of a reconciliation loop. func (c *Controller) RunOnce() error { - records, err := c.DNSProvider.Records(c.Zone) + records, err := c.Provider.Records(c.Zone) if err != nil { return err } @@ -58,7 +58,7 @@ func (c *Controller) RunOnce() error { plan = plan.Calculate() - return c.DNSProvider.ApplyChanges(c.Zone, &plan.Changes) + return c.Provider.ApplyChanges(c.Zone, &plan.Changes) } // Run runs RunOnce in a loop with a delay until stopChan receives a value. diff --git a/controller/controller_test.go b/controller/controller_test.go index fb60dc8b10..2c472832e4 100644 --- a/controller/controller_test.go +++ b/controller/controller_test.go @@ -20,26 +20,26 @@ import ( "errors" "testing" - "github.com/kubernetes-incubator/external-dns/dnsprovider" "github.com/kubernetes-incubator/external-dns/endpoint" "github.com/kubernetes-incubator/external-dns/plan" + "github.com/kubernetes-incubator/external-dns/provider" "github.com/kubernetes-incubator/external-dns/source" ) -// mockDNSProvider returns mock endpoints and validates changes. -type mockDNSProvider struct { +// mockProvider returns mock endpoints and validates changes. +type mockProvider struct { RecordsStore []endpoint.Endpoint ExpectZone string ExpectChanges *plan.Changes } // Records returns the desired mock endpoints. -func (p *mockDNSProvider) Records(zone string) ([]endpoint.Endpoint, error) { +func (p *mockProvider) Records(zone string) ([]endpoint.Endpoint, error) { return p.RecordsStore, nil } // ApplyChanges validates that the passed in changes satisfy the assumtions. -func (p *mockDNSProvider) ApplyChanges(zone string, changes *plan.Changes) error { +func (p *mockProvider) ApplyChanges(zone string, changes *plan.Changes) error { if zone != p.ExpectZone { return errors.New("zone is incorrect") } @@ -75,9 +75,9 @@ func (p *mockDNSProvider) ApplyChanges(zone string, changes *plan.Changes) error return nil } -// newMockDNSProvider creates a new mockDNSProvider returning the given endpoints and validating the desired changes. -func newMockDNSProvider(endpoints []endpoint.Endpoint, zone string, changes *plan.Changes) dnsprovider.DNSProvider { - dnsProvider := &mockDNSProvider{ +// newMockProvider creates a new mockProvider returning the given endpoints and validating the desired changes. +func newMockProvider(endpoints []endpoint.Endpoint, zone string, changes *plan.Changes) provider.Provider { + dnsProvider := &mockProvider{ RecordsStore: endpoints, ExpectZone: zone, ExpectChanges: changes, @@ -103,7 +103,7 @@ func TestRunOnce(t *testing.T) { ) // Fake some existing records in our DNS provider and validate some desired changes. - provider := newMockDNSProvider( + provider := newMockProvider( []endpoint.Endpoint{ { DNSName: "update-record", @@ -133,9 +133,9 @@ func TestRunOnce(t *testing.T) { // Run our controller once to trigger the validation. ctrl := &Controller{ - Zone: "test-zone", - Source: source, - DNSProvider: provider, + Zone: "test-zone", + Source: source, + Provider: provider, } err := ctrl.RunOnce() diff --git a/docs/legacy/kops-dns-controller.md b/docs/legacy/kops-dns-controller.md index 7d06b623dd..45fc7e12f5 100644 --- a/docs/legacy/kops-dns-controller.md +++ b/docs/legacy/kops-dns-controller.md @@ -56,7 +56,7 @@ The DNS record mappings try to "do the right thing", but what this means is diff We consult the `Status.LoadBalancer.Ingress` records on the ingress. For each one, we create a record. If the record is an IP address, we add an A record. If the record is a hostname (AWS ELB), we use a CNAME. -We would like to use an ALIAS, but we have not yet done this because of limitations of the dnsprovider. +We would like to use an ALIAS, but we have not yet done this because of limitations of the DNS provider. ### Pods diff --git a/docs/project-structure.md b/docs/project-structure.md index f955477deb..68f761a323 100644 --- a/docs/project-structure.md +++ b/docs/project-structure.md @@ -22,7 +22,7 @@ external-dns --in-cluster=false --dnsprovider=aws --source=ingress --source=serv aws.go google.go fake.go - dnsprovider.go - interface + provider.go - interface ./pkg/apis/externaldns - types that we will want to be subject to apimachinery (e.g. configuration) ./pkg/apis/externaldns/validation - validation for our types ./source/ - list of sources diff --git a/docs/proposal/storage.md b/docs/proposal/storage.md index a7da2c1d40..0ac279f3e5 100644 --- a/docs/proposal/storage.md +++ b/docs/proposal/storage.md @@ -4,22 +4,22 @@ Initial discussion - https://github.com/kubernetes-incubator/external-dns/issues ## Purpose -One should not be afraid to use external-dns, because it can delete or overwrite the records preexisting in the DNS provider. +One should not be afraid to use external-dns, because it can delete or overwrite the records preexisting in the DNS provider. **Why we need it?** -DNS provider (AWS Route53, Google DNS, etc.) stores dns records which are created via various means. Integration of External-DNS should be safe and should not delete or overwrite the records which it is not responsible for. Moreover, it should certainly be possible for multiple kubernetes clusters to share the same hosted zone within the dns provider, additionally multiple external-dns instances inside the same cluster should be able to co-exist without messing with the same set of records. +DNS provider (AWS Route53, Google DNS, etc.) stores dns records which are created via various means. Integration of External-DNS should be safe and should not delete or overwrite the records which it is not responsible for. Moreover, it should certainly be possible for multiple kubernetes clusters to share the same hosted zone within the dns provider, additionally multiple external-dns instances inside the same cluster should be able to co-exist without messing with the same set of records. Storage provides a persistent storage with information to track the records created by the external-dns. -This proposal introduces multiple possible implementation with the details depending on the setup. +This proposal introduces multiple possible implementation with the details depending on the setup. ## Requirements and assumptions 1. Pre-existing records should not be modified by external-dns 2. External-dns instance only creates/modifies/deletes records which are created by this instance 3. It should be possible to transfer the ownership to another external-dns instance -4. Any integrated dns-provider should provide at least a single way to implement the storage +4. Any integrated DNS provider should provide at least a single way to implement the storage 5. Lifetime of the records should not be limited to lifetime of external-dns 6. External-dns should have its identifier for marking the managed records - **`storage-id`** @@ -31,7 +31,7 @@ The following presents two ways to implement the storage, and we are planning to This implementation idea is borrowed from [Mate](https://github.com/zalando-incubator/mate/) -Each record created by external-dns is accompanied by the TXT record, which internally stores the external-dns identifier. For example, if external dns with `storage-id="external-dns-1"` record to be created with dns name `foo.zone.org`, external-dns will create a TXT record with the same dns name `foo.zone.org` and injected value of `"external-dns-1"`. The transfer of ownership can be done by modifying the value of the TXT record. If no TXT record exists for the record or the value does not match its own `storage-id`, then external-dns will simply ignore it. +Each record created by external-dns is accompanied by the TXT record, which internally stores the external-dns identifier. For example, if external dns with `storage-id="external-dns-1"` record to be created with dns name `foo.zone.org`, external-dns will create a TXT record with the same dns name `foo.zone.org` and injected value of `"external-dns-1"`. The transfer of ownership can be done by modifying the value of the TXT record. If no TXT record exists for the record or the value does not match its own `storage-id`, then external-dns will simply ignore it. #### Goods @@ -47,7 +47,7 @@ Each record created by external-dns is accompanied by the TXT record, which inte ### ConfigMap -Store the state in the configmap. ConfigMap is created and managed by each external-dns individually, i.e. external-dns with **`storage-id=external-dns-1`** will create and operate on `extern-dns-1-storage` ConfigMap. ConfigMap will store **all** the records present in the DNS provider as serialized JSON. For example: +Store the state in the configmap. ConfigMap is created and managed by each external-dns individually, i.e. external-dns with **`storage-id=external-dns-1`** will create and operate on `extern-dns-1-storage` ConfigMap. ConfigMap will store **all** the records present in the DNS provider as serialized JSON. For example: ``` kind: ConfigMap @@ -93,35 +93,35 @@ ConfigMap will be periodically resynced with the dns provider by fetching the dn ## Component integration -Components: +Components: * Source - all endpoints ( collection of ingress, service[type=LoadBalancer] etc.) -* [Plan](https://github.com/kubernetes-incubator/external-dns/issues/13) - object responsible for the create of change lists in external-dns -* DNSProvider - interface to access the DNS provider API +* [Plan](https://github.com/kubernetes-incubator/external-dns/issues/13) - object responsible for the create of change lists in external-dns +* Provider - interface to access the DNS provider API -A single loop iteration of external-dns operation: +A single loop iteration of external-dns operation: -1. Get all endpoints ( collection ingress, service[type=LoadBalancer] etc.) into collection of `endpoints` -2. Get storage `Records()` +1. Get all endpoints ( collection ingress, service[type=LoadBalancer] etc.) into collection of `endpoints` +2. Get storage `Records()` 3. Pass `Records` (including ownership information) and list of endpoints to `Plan` to do the calculation 4. Make a call to DNS provider with `Plan` provided change list -5. If call succeeded pass the change list to storage `Assign()` to mark the records that are created +5. If call succeeded pass the change list to storage `Assign()` to mark the records that are created Storage gets updated all the time via `Poll`. `Plan` does not call DNS provider directly. Good value of the `Poll` is to have simple rate limiting mechanism on DNS provider. #### Notes: 1. DNS Provider should use batch operations -2. DNS Provider should be called with CREATE operation (not UPSERT!) when the record does not yet exist! -3. Storage does not need to be in complete sync with DNS provider due to #2. Hence resolving the potential caveats of ConfigMap implementation +2. DNS Provider should be called with CREATE operation (not UPSERT!) when the record does not yet exist! +3. Storage does not need to be in complete sync with DNS provider due to #2. Hence resolving the potential caveats of ConfigMap implementation ## Implementation -Basic implementation of the storage interface: +Basic implementation of the storage interface: 1. Storage has the dnsprovider object to retrieve the list of records, but it never makes the call to modify the records (think layer to help out with endpoint filtering) 2. Record() - returns whatever is stored in the storage -3. Assign(endpoints) - called when the records are registered with dns provider - hence storage need to mark its ownership. **Therefore DNSProvider serves as a safe-guard from race conditions** +3. Assign(endpoints) - called when the records are registered with dns provider - hence storage need to mark its ownership. **Therefore Provider serves as a safe-guard from race conditions** 4. WaitForSync() - called in the beginning to populate the storage, in case of configmap would be the configmap creation and fetching the dns provider records 5. Poll() - resync loop to stay-up-to-date with dns provider state @@ -132,9 +132,9 @@ We will provide `InMemoryStorage` non-persistent storage which should help us wi ``` type InMemoryStorage struct { - registry dnsprovider.DNSProvider + registry provider.Provider zone string - owner string + owner string cache map[string]*SharedEndpoint sync.Mutex } diff --git a/docs/tutorials/gke.md b/docs/tutorials/gke.md index 256507cd73..8f60966a92 100644 --- a/docs/tutorials/gke.md +++ b/docs/tutorials/gke.md @@ -79,7 +79,7 @@ spec: - --zone=external-dns-test-gcp-zalan-do - --source=service - --source=ingress - - --dns-provider=google + - --provider=google - --google-project=zalando-external-dns-test - --dry-run=false ``` diff --git a/main.go b/main.go index 4dba20b567..09ed109b79 100644 --- a/main.go +++ b/main.go @@ -30,9 +30,9 @@ import ( "k8s.io/client-go/tools/clientcmd" "github.com/kubernetes-incubator/external-dns/controller" - "github.com/kubernetes-incubator/external-dns/dnsprovider" "github.com/kubernetes-incubator/external-dns/pkg/apis/externaldns" "github.com/kubernetes-incubator/external-dns/pkg/apis/externaldns/validation" + "github.com/kubernetes-incubator/external-dns/provider" "github.com/kubernetes-incubator/external-dns/source" ) @@ -79,23 +79,23 @@ func main() { sources := source.NewMultiSource(source.LookupMultiple(cfg.Sources...)...) - var provider dnsprovider.DNSProvider - switch cfg.DNSProvider { + var p provider.Provider + switch cfg.Provider { case "google": - provider, err = dnsprovider.NewGoogleProvider(cfg.GoogleProject, cfg.DryRun) + p, err = provider.NewGoogleProvider(cfg.GoogleProject, cfg.DryRun) case "aws": - provider, err = dnsprovider.NewAWSProvider(cfg.DryRun) + p, err = provider.NewAWSProvider(cfg.DryRun) default: - log.Fatalf("unknown dns provider: %s", cfg.DNSProvider) + log.Fatalf("unknown dns provider: %s", cfg.Provider) } if err != nil { log.Fatal(err) } ctrl := controller.Controller{ - Zone: cfg.Zone, - Source: sources, - DNSProvider: provider, + Zone: cfg.Zone, + Source: sources, + Provider: p, } if cfg.Once { diff --git a/pkg/apis/externaldns/types.go b/pkg/apis/externaldns/types.go index 138646fed4..6f0020d242 100644 --- a/pkg/apis/externaldns/types.go +++ b/pkg/apis/externaldns/types.go @@ -34,7 +34,7 @@ type Config struct { Namespace string Zone string Sources []string - DNSProvider string + Provider string GoogleProject string HealthPort string Once bool @@ -57,7 +57,7 @@ func (cfg *Config) ParseFlags(args []string) error { flags.StringVar(&cfg.Namespace, "namespace", v1.NamespaceAll, "the namespace to look for endpoints; all namespaces by default") flags.StringVar(&cfg.Zone, "zone", "", "the ID of the hosted zone to target") flags.StringArrayVar(&cfg.Sources, "source", nil, "the sources to gather endpoints from") - flags.StringVar(&cfg.DNSProvider, "dns-provider", "", "the DNS provider to materialize the records in") + flags.StringVar(&cfg.Provider, "provider", "", "the DNS provider to materialize the records in") flags.StringVar(&cfg.GoogleProject, "google-project", "", "gcloud project to target") flags.StringVar(&cfg.HealthPort, "health-port", defaultHealthPort, "health port to listen on") flags.StringVar(&cfg.LogFormat, "log-format", defaultLogFormat, "log format output. options: [\"text\", \"json\"]") diff --git a/pkg/apis/externaldns/types_test.go b/pkg/apis/externaldns/types_test.go index 54cb6d8811..f8188d24cc 100644 --- a/pkg/apis/externaldns/types_test.go +++ b/pkg/apis/externaldns/types_test.go @@ -37,7 +37,7 @@ func TestParseFlags(t *testing.T) { Namespace: "", Zone: "", Sources: nil, - DNSProvider: "", + Provider: "", GoogleProject: "", HealthPort: defaultHealthPort, DryRun: true, @@ -55,7 +55,7 @@ func TestParseFlags(t *testing.T) { Namespace: "", Zone: "", Sources: nil, - DNSProvider: "", + Provider: "", GoogleProject: "", HealthPort: defaultHealthPort, DryRun: true, @@ -73,7 +73,7 @@ func TestParseFlags(t *testing.T) { Namespace: "", Zone: "", Sources: nil, - DNSProvider: "", + Provider: "", GoogleProject: "", HealthPort: defaultHealthPort, DryRun: true, @@ -96,7 +96,7 @@ func TestParseFlags(t *testing.T) { Namespace: "", Zone: "", Sources: nil, - DNSProvider: "", + Provider: "", GoogleProject: "", HealthPort: defaultHealthPort, DryRun: true, @@ -113,7 +113,7 @@ func TestParseFlags(t *testing.T) { "--namespace", "namespace", "--zone", "zone", "--source", "source", - "--dns-provider", "provider", + "--provider", "provider", "--google-project", "project", "--health-port", "1234", "--dry-run", "true", @@ -125,7 +125,7 @@ func TestParseFlags(t *testing.T) { Namespace: "namespace", Zone: "zone", Sources: []string{"source"}, - DNSProvider: "provider", + Provider: "provider", GoogleProject: "project", HealthPort: "1234", DryRun: true, diff --git a/pkg/apis/externaldns/validation/validation.go b/pkg/apis/externaldns/validation/validation.go index 736f382bd5..436b44b6bd 100644 --- a/pkg/apis/externaldns/validation/validation.go +++ b/pkg/apis/externaldns/validation/validation.go @@ -35,7 +35,7 @@ func ValidateConfig(cfg *externaldns.Config) error { if len(cfg.Sources) == 0 { return errors.New("no sources specified") } - if cfg.DNSProvider == "" { + if cfg.Provider == "" { return errors.New("no provider specified") } diff --git a/pkg/apis/externaldns/validation/validation_test.go b/pkg/apis/externaldns/validation/validation_test.go index b3be4478ed..5eff447b5c 100644 --- a/pkg/apis/externaldns/validation/validation_test.go +++ b/pkg/apis/externaldns/validation/validation_test.go @@ -56,7 +56,7 @@ func TestValidateFlags(t *testing.T) { } cfg = newValidConfig(t) - cfg.DNSProvider = "" + cfg.Provider = "" if err := ValidateConfig(cfg); err == nil { t.Error("missing provider should fail") } @@ -68,7 +68,7 @@ func newValidConfig(t *testing.T) *externaldns.Config { cfg.LogFormat = "json" cfg.Zone = "test-zone" cfg.Sources = []string{"test-source"} - cfg.DNSProvider = "test-provider" + cfg.Provider = "test-provider" if err := ValidateConfig(cfg); err != nil { t.Fatalf("newValidConfig should return valid config") diff --git a/dnsprovider/aws.go b/provider/aws.go similarity index 97% rename from dnsprovider/aws.go rename to provider/aws.go index 09f1dfc9c4..b9b5d2efb5 100644 --- a/dnsprovider/aws.go +++ b/provider/aws.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package dnsprovider +package provider import ( "fmt" @@ -41,14 +41,14 @@ type Route53API interface { DeleteHostedZone(*route53.DeleteHostedZoneInput) (*route53.DeleteHostedZoneOutput, error) } -// AWSProvider is an implementation of DNSProvider for AWS Route53. +// AWSProvider is an implementation of Provider for AWS Route53. type AWSProvider struct { Client Route53API DryRun bool } -// NewAWSProvider initializes a new AWS Route53 based DNSProvider. -func NewAWSProvider(dryRun bool) (DNSProvider, error) { +// NewAWSProvider initializes a new AWS Route53 based Provider. +func NewAWSProvider(dryRun bool) (Provider, error) { config := aws.NewConfig() session, err := session.NewSessionWithOptions(session.Options{ diff --git a/dnsprovider/aws_test.go b/provider/aws_test.go similarity index 99% rename from dnsprovider/aws_test.go rename to provider/aws_test.go index 4054fe6bcc..587ec61472 100644 --- a/dnsprovider/aws_test.go +++ b/provider/aws_test.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package dnsprovider +package provider import ( "fmt" diff --git a/dnsprovider/google.go b/provider/google.go similarity index 97% rename from dnsprovider/google.go rename to provider/google.go index 7d7eea8909..ef286c3288 100644 --- a/dnsprovider/google.go +++ b/provider/google.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package dnsprovider +package provider import ( "strings" @@ -97,7 +97,7 @@ func (c changesService) Create(project string, managedZone string, change *dns.C return c.service.Create(project, managedZone, change) } -// googleProvider is an implementation of DNSProvider for Google CloudDNS. +// googleProvider is an implementation of Provider for Google CloudDNS. type googleProvider struct { // The Google project to work in project string @@ -111,8 +111,8 @@ type googleProvider struct { changesClient changesServiceInterface } -// NewGoogleProvider initializes a new Google CloudDNS based DNSProvider. -func NewGoogleProvider(project string, dryRun bool) (DNSProvider, error) { +// NewGoogleProvider initializes a new Google CloudDNS based Provider. +func NewGoogleProvider(project string, dryRun bool) (Provider, error) { gcloud, err := google.DefaultClient(context.TODO(), dns.NdevClouddnsReadwriteScope) if err != nil { return nil, err diff --git a/dnsprovider/google_test.go b/provider/google_test.go similarity index 99% rename from dnsprovider/google_test.go rename to provider/google_test.go index a3f06c4396..b6201ba28b 100644 --- a/dnsprovider/google_test.go +++ b/provider/google_test.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package dnsprovider +package provider import ( "fmt" diff --git a/dnsprovider/inmemory.go b/provider/inmemory.go similarity index 99% rename from dnsprovider/inmemory.go rename to provider/inmemory.go index d6959cba42..00c2b72ef0 100644 --- a/dnsprovider/inmemory.go +++ b/provider/inmemory.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package dnsprovider +package provider import ( "errors" diff --git a/dnsprovider/inmemory_test.go b/provider/inmemory_test.go similarity index 99% rename from dnsprovider/inmemory_test.go rename to provider/inmemory_test.go index eac5223e10..713733c187 100644 --- a/dnsprovider/inmemory_test.go +++ b/provider/inmemory_test.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package dnsprovider +package provider import "testing" import "reflect" diff --git a/dnsprovider/dnsprovider.go b/provider/provider.go similarity index 87% rename from dnsprovider/dnsprovider.go rename to provider/provider.go index a6e5c043a2..befc504655 100644 --- a/dnsprovider/dnsprovider.go +++ b/provider/provider.go @@ -14,15 +14,15 @@ See the License for the specific language governing permissions and limitations under the License. */ -package dnsprovider +package provider import ( "github.com/kubernetes-incubator/external-dns/endpoint" "github.com/kubernetes-incubator/external-dns/plan" ) -// DNSProvider defines the interface DNS providers should implement. -type DNSProvider interface { +// Provider defines the interface DNS providers should implement. +type Provider interface { Records(zone string) ([]endpoint.Endpoint, error) ApplyChanges(zone string, changes *plan.Changes) error }