Vladimir Smagin 5 months ago
parent
commit
0b63ca8997
62 changed files with 40 additions and 28332 deletions
  1. +38
    -38
      go.mod
  2. +2
    -0
      go.sum
  3. +0
    -172
      main.go
  4. +0
    -382
      provider/akamai/akamai.go
  5. +0
    -344
      provider/akamai/akamai_test.go
  6. +0
    -1071
      provider/alibabacloud/alibaba_cloud.go
  7. +0
    -464
      provider/alibabacloud/alibaba_cloud_test.go
  8. +0
    -787
      provider/aws/aws.go
  9. +0
    -1277
      provider/aws/aws_test.go
  10. +0
    -684
      provider/awssd/aws_sd.go
  11. +0
    -828
      provider/awssd/aws_sd_test.go
  12. +0
    -513
      provider/azure/azure.go
  13. +0
    -420
      provider/azure/azure_private_dns.go
  14. +0
    -471
      provider/azure/azure_privatedns_test.go
  15. +0
    -498
      provider/azure/azure_test.go
  16. +0
    -2
      provider/cloudflare/OWNERS
  17. +0
    -445
      provider/cloudflare/cloudflare.go
  18. +0
    -1135
      provider/cloudflare/cloudflare_test.go
  19. +0
    -2
      provider/coredns/OWNERS
  20. +0
    -472
      provider/coredns/coredns.go
  21. +0
    -361
      provider/coredns/coredns_test.go
  22. +0
    -463
      provider/designate/designate.go
  23. +0
    -583
      provider/designate/designate_test.go
  24. +0
    -614
      provider/digitalocean/digital_ocean.go
  25. +0
    -661
      provider/digitalocean/digital_ocean_test.go
  26. +0
    -367
      provider/dnsimple/dnsimple.go
  27. +0
    -301
      provider/dnsimple/dnsimple_test.go
  28. +0
    -689
      provider/dyn/dyn.go
  29. +0
    -294
      provider/dyn/dyn_test.go
  30. +0
    -296
      provider/exoscale/exoscale.go
  31. +0
    -332
      provider/exoscale/exoscale_test.go
  32. +0
    -460
      provider/google/google.go
  33. +0
    -800
      provider/google/google_test.go
  34. +0
    -485
      provider/infoblox/infoblox.go
  35. +0
    -529
      provider/infoblox/infoblox_test.go
  36. +0
    -546
      provider/linode/linode.go
  37. +0
    -529
      provider/linode/linode_test.go
  38. +0
    -325
      provider/ns1/ns1.go
  39. +0
    -320
      provider/ns1/ns1_test.go
  40. +0
    -301
      provider/oci/oci.go
  41. +0
    -842
      provider/oci/oci_test.go
  42. +0
    -355
      provider/ovh/ovh.go
  43. +0
    -299
      provider/ovh/ovh_test.go
  44. +0
    -480
      provider/pdns/pdns.go
  45. +0
    -1026
      provider/pdns/pdns_test.go
  46. +0
    -319
      provider/rcode0/rcode0.go
  47. +0
    -416
      provider/rcode0/rcode0_test.go
  48. +0
    -552
      provider/rdns/rdns.go
  49. +0
    -356
      provider/rdns/rdns_test.go
  50. +0
    -331
      provider/rfc2136/rfc2136.go
  51. +0
    -336
      provider/rfc2136/rfc2136_test.go
  52. +0
    -29
      provider/scaleway/interface.go
  53. +0
    -337
      provider/scaleway/scaleway.go
  54. +0
    -517
      provider/scaleway/scaleway_test.go
  55. +0
    -393
      provider/transip/transip.go
  56. +0
    -232
      provider/transip/transip_test.go
  57. +0
    -500
      provider/ultradns/ultradns.go
  58. +0
    -776
      provider/ultradns/ultradns_test.go
  59. +0
    -272
      provider/vinyldns/vinyldns.go
  60. +0
    -223
      provider/vinyldns/vinyldns_test.go
  61. +0
    -289
      provider/vultr/vultr.go
  62. +0
    -191
      provider/vultr/vultr_test.go

+ 38
- 38
go.mod View File

@ -3,62 +3,62 @@ module sigs.k8s.io/external-dns
go 1.14
require (
cloud.google.com/go v0.50.0
cloud.google.com/go v0.50.0 // indirect
git.blindage.org/21h/hcloud-dns v0.0.0-20200807003420-f768ffe03f8d
github.com/Azure/azure-sdk-for-go v45.1.0+incompatible
github.com/Azure/go-autorest/autorest v0.11.4
github.com/Azure/go-autorest/autorest/adal v0.9.2
github.com/Azure/go-autorest/autorest/azure/auth v0.5.1
github.com/Azure/go-autorest/autorest/to v0.4.0
github.com/akamai/AkamaiOPEN-edgegrid-golang v0.9.11
github.com/Azure/azure-sdk-for-go v45.1.0+incompatible // indirect
github.com/Azure/go-autorest/autorest v0.11.4 // indirect
github.com/Azure/go-autorest/autorest/adal v0.9.2 // indirect
github.com/Azure/go-autorest/autorest/azure/auth v0.5.1 // indirect
github.com/Azure/go-autorest/autorest/to v0.4.0 // indirect
github.com/akamai/AkamaiOPEN-edgegrid-golang v0.9.11 // indirect
github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38 // indirect
github.com/alecthomas/colour v0.1.0 // indirect
github.com/alecthomas/kingpin v2.2.5+incompatible
github.com/alecthomas/repr v0.0.0-20200325044227-4184120f674c // indirect
github.com/aliyun/alibaba-cloud-sdk-go v1.61.357
github.com/aliyun/alibaba-cloud-sdk-go v1.61.357 // indirect
github.com/aws/aws-sdk-go v1.31.4
github.com/cloudflare/cloudflare-go v0.10.1
github.com/cloudflare/cloudflare-go v0.10.1 // indirect
github.com/cloudfoundry-community/go-cfclient v0.0.0-20190201205600-f136f9222381
github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba
github.com/digitalocean/godo v1.36.0
github.com/dnsimple/dnsimple-go v0.60.0
github.com/exoscale/egoscale v0.18.1
github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba // indirect
github.com/digitalocean/godo v1.36.0 // indirect
github.com/dnsimple/dnsimple-go v0.60.0 // indirect
github.com/exoscale/egoscale v0.18.1 // indirect
github.com/fatih/structs v1.1.0 // indirect
github.com/ffledgling/pdns-go v0.0.0-20180219074714-524e7daccd99
github.com/golang/sync v0.0.0-20180314180146-1d60e4601c6f
github.com/google/go-cmp v0.4.1
github.com/gophercloud/gophercloud v0.1.0
github.com/ffledgling/pdns-go v0.0.0-20180219074714-524e7daccd99 // indirect
github.com/golang/sync v0.0.0-20180314180146-1d60e4601c6f // indirect
github.com/google/go-cmp v0.4.1 // indirect
github.com/gophercloud/gophercloud v0.1.0 // indirect
github.com/gorilla/mux v1.7.4 // indirect
github.com/infobloxopen/infoblox-go-client v0.0.0-20180606155407-61dc5f9b0a65
github.com/infobloxopen/infoblox-go-client v0.0.0-20180606155407-61dc5f9b0a65 // indirect
github.com/linki/instrumented_http v0.2.0
github.com/linode/linodego v0.19.0
github.com/maxatome/go-testdeep v1.4.0
github.com/miekg/dns v1.1.30
github.com/nesv/go-dynect v0.6.0
github.com/nic-at/rc0go v1.1.1
github.com/linode/linodego v0.19.0 // indirect
github.com/maxatome/go-testdeep v1.4.0 // indirect
github.com/miekg/dns v1.1.30 // indirect
github.com/nesv/go-dynect v0.6.0 // indirect
github.com/nic-at/rc0go v1.1.1 // indirect
github.com/openshift/api v0.0.0-20200605231317-fb2a6ca106ae
github.com/openshift/client-go v0.0.0-20200608144219-584632b8fc73
github.com/oracle/oci-go-sdk v21.4.0+incompatible
github.com/ovh/go-ovh v0.0.0-20181109152953-ba5adb4cf014
github.com/oracle/oci-go-sdk v21.4.0+incompatible // indirect
github.com/ovh/go-ovh v0.0.0-20181109152953-ba5adb4cf014 // indirect
github.com/pkg/errors v0.9.1
github.com/projectcontour/contour v1.5.0
github.com/prometheus/client_golang v1.7.1
github.com/sanyu/dynectsoap v0.0.0-20181203081243-b83de5edc4e0
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.6.0.20200623155123-84df6c4b5301
github.com/sanyu/dynectsoap v0.0.0-20181203081243-b83de5edc4e0 // indirect
github.com/scaleway/scaleway-sdk-go v1.0.0-beta.6.0.20200623155123-84df6c4b5301 // indirect
github.com/sirupsen/logrus v1.6.0
github.com/stretchr/testify v1.5.1
github.com/terra-farm/udnssdk v1.3.5 // indirect
github.com/transip/gotransip v5.8.2+incompatible
github.com/ultradns/ultradns-sdk-go v0.0.0-20200616202852-e62052662f60
github.com/vinyldns/go-vinyldns v0.0.0-20200211145900-fe8a3d82e556
github.com/vultr/govultr v0.4.2
go.etcd.io/etcd v0.5.0-alpha.5.0.20200401174654-e694b7bb0875
go.uber.org/ratelimit v0.1.0
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
google.golang.org/api v0.15.0
gopkg.in/ns1/ns1-go.v2 v2.0.0-20190322154155-0dafb5275fd1
gopkg.in/yaml.v2 v2.2.8
github.com/transip/gotransip v5.8.2+incompatible // indirect
github.com/ultradns/ultradns-sdk-go v0.0.0-20200616202852-e62052662f60 // indirect
github.com/vinyldns/go-vinyldns v0.0.0-20200211145900-fe8a3d82e556 // indirect
github.com/vultr/govultr v0.4.2 // indirect
go.etcd.io/etcd v0.5.0-alpha.5.0.20200401174654-e694b7bb0875 // indirect
go.uber.org/ratelimit v0.1.0 // indirect
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e // indirect
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d // indirect
google.golang.org/api v0.15.0 // indirect
gopkg.in/ns1/ns1-go.v2 v2.0.0-20190322154155-0dafb5275fd1 // indirect
gopkg.in/yaml.v2 v2.2.8 // indirect
istio.io/api v0.0.0-20200529165953-72dad51d4ffc
istio.io/client-go v0.0.0-20200529172309-31c16ea3f751
k8s.io/api v0.18.8


+ 2
- 0
go.sum View File

@ -15,6 +15,8 @@ code.cloudfoundry.org/gofileutils v0.0.0-20170111115228-4d0c80011a0f/go.mod h1:s
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
git.blindage.org/21h/hcloud-dns v0.0.0-20200525170043-def10a4a28e0 h1:kdxglEveTcqIG5zEPdQ0Y5KctnIGR7zXsQCQakoTNxU=
git.blindage.org/21h/hcloud-dns v0.0.0-20200525170043-def10a4a28e0/go.mod h1:n26Twiii5jhkMC+Ocz/s8R73cBBcXRIwyTqQ+6bOZGo=
git.blindage.org/21h/hcloud-dns v0.0.0-20200807003420-f768ffe03f8d h1:d6sdozgfqtgaOhjUn++lbo5siX3HELjcOUnbtrvVQi4=
git.blindage.org/21h/hcloud-dns v0.0.0-20200807003420-f768ffe03f8d/go.mod h1:n26Twiii5jhkMC+Ocz/s8R73cBBcXRIwyTqQ+6bOZGo=
github.com/Azure/azure-sdk-for-go v45.1.0+incompatible h1:kxtaPD8n2z5Za+9e3sKsYG2IX6PG2R6VXtgS7gAbh3A=
github.com/Azure/azure-sdk-for-go v45.1.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=


+ 0
- 172
main.go View File

@ -34,35 +34,8 @@ import (
"sigs.k8s.io/external-dns/pkg/apis/externaldns/validation"
"sigs.k8s.io/external-dns/plan"
"sigs.k8s.io/external-dns/provider"
"sigs.k8s.io/external-dns/provider/akamai"
"sigs.k8s.io/external-dns/provider/alibabacloud"
"sigs.k8s.io/external-dns/provider/aws"
"sigs.k8s.io/external-dns/provider/awssd"
"sigs.k8s.io/external-dns/provider/azure"
"sigs.k8s.io/external-dns/provider/cloudflare"
"sigs.k8s.io/external-dns/provider/coredns"
"sigs.k8s.io/external-dns/provider/designate"
"sigs.k8s.io/external-dns/provider/digitalocean"
"sigs.k8s.io/external-dns/provider/dnsimple"
"sigs.k8s.io/external-dns/provider/dyn"
"sigs.k8s.io/external-dns/provider/exoscale"
"sigs.k8s.io/external-dns/provider/google"
"sigs.k8s.io/external-dns/provider/hetzner"
"sigs.k8s.io/external-dns/provider/infoblox"
"sigs.k8s.io/external-dns/provider/inmemory"
"sigs.k8s.io/external-dns/provider/linode"
"sigs.k8s.io/external-dns/provider/ns1"
"sigs.k8s.io/external-dns/provider/oci"
"sigs.k8s.io/external-dns/provider/ovh"
"sigs.k8s.io/external-dns/provider/pdns"
"sigs.k8s.io/external-dns/provider/rcode0"
"sigs.k8s.io/external-dns/provider/rdns"
"sigs.k8s.io/external-dns/provider/rfc2136"
"sigs.k8s.io/external-dns/provider/scaleway"
"sigs.k8s.io/external-dns/provider/transip"
"sigs.k8s.io/external-dns/provider/ultradns"
"sigs.k8s.io/external-dns/provider/vinyldns"
"sigs.k8s.io/external-dns/provider/vultr"
"sigs.k8s.io/external-dns/registry"
"sigs.k8s.io/external-dns/source"
)
@ -147,153 +120,10 @@ func main() {
var p provider.Provider
switch cfg.Provider {
case "akamai":
p = akamai.NewAkamaiProvider(
akamai.AkamaiConfig{
DomainFilter: domainFilter,
ZoneIDFilter: zoneIDFilter,
ServiceConsumerDomain: cfg.AkamaiServiceConsumerDomain,
ClientToken: cfg.AkamaiClientToken,
ClientSecret: cfg.AkamaiClientSecret,
AccessToken: cfg.AkamaiAccessToken,
DryRun: cfg.DryRun,
},
)
case "alibabacloud":
p, err = alibabacloud.NewAlibabaCloudProvider(cfg.AlibabaCloudConfigFile, domainFilter, zoneIDFilter, cfg.AlibabaCloudZoneType, cfg.DryRun)
case "aws":
p, err = aws.NewAWSProvider(
aws.AWSConfig{
DomainFilter: domainFilter,
ZoneIDFilter: zoneIDFilter,
ZoneTypeFilter: zoneTypeFilter,
ZoneTagFilter: zoneTagFilter,
BatchChangeSize: cfg.AWSBatchChangeSize,
BatchChangeInterval: cfg.AWSBatchChangeInterval,
EvaluateTargetHealth: cfg.AWSEvaluateTargetHealth,
AssumeRole: cfg.AWSAssumeRole,
APIRetries: cfg.AWSAPIRetries,
PreferCNAME: cfg.AWSPreferCNAME,
DryRun: cfg.DryRun,
ZoneCacheDuration: cfg.AWSZoneCacheDuration,
},
)
case "aws-sd":
// Check that only compatible Registry is used with AWS-SD
if cfg.Registry != "noop" && cfg.Registry != "aws-sd" {
log.Infof("Registry \"%s\" cannot be used with AWS Cloud Map. Switching to \"aws-sd\".", cfg.Registry)
cfg.Registry = "aws-sd"
}
p, err = awssd.NewAWSSDProvider(domainFilter, cfg.AWSZoneType, cfg.AWSAssumeRole, cfg.DryRun)
case "azure-dns", "azure":
p, err = azure.NewAzureProvider(cfg.AzureConfigFile, domainFilter, zoneIDFilter, cfg.AzureResourceGroup, cfg.AzureUserAssignedIdentityClientID, cfg.DryRun)
case "azure-private-dns":
p, err = azure.NewAzurePrivateDNSProvider(domainFilter, zoneIDFilter, cfg.AzureResourceGroup, cfg.AzureSubscriptionID, cfg.DryRun)
case "vinyldns":
p, err = vinyldns.NewVinylDNSProvider(domainFilter, zoneIDFilter, cfg.DryRun)
case "vultr":
p, err = vultr.NewVultrProvider(domainFilter, cfg.DryRun)
case "ultradns":
p, err = ultradns.NewUltraDNSProvider(domainFilter, cfg.DryRun)
case "cloudflare":
p, err = cloudflare.NewCloudFlareProvider(domainFilter, zoneIDFilter, cfg.CloudflareZonesPerPage, cfg.CloudflareProxied, cfg.DryRun)
case "rcodezero":
p, err = rcode0.NewRcodeZeroProvider(domainFilter, cfg.DryRun, cfg.RcodezeroTXTEncrypt)
case "google":
p, err = google.NewGoogleProvider(ctx, cfg.GoogleProject, domainFilter, zoneIDFilter, cfg.GoogleBatchChangeSize, cfg.GoogleBatchChangeInterval, cfg.DryRun)
case "digitalocean":
p, err = digitalocean.NewDigitalOceanProvider(ctx, domainFilter, cfg.DryRun, cfg.DigitalOceanAPIPageSize)
case "hetzner":
p, err = hetzner.NewHetznerProvider(ctx, domainFilter, cfg.DryRun)
case "ovh":
p, err = ovh.NewOVHProvider(ctx, domainFilter, cfg.OVHEndpoint, cfg.OVHApiRateLimit, cfg.DryRun)
case "linode":
p, err = linode.NewLinodeProvider(domainFilter, cfg.DryRun, externaldns.Version)
case "dnsimple":
p, err = dnsimple.NewDnsimpleProvider(domainFilter, zoneIDFilter, cfg.DryRun)
case "infoblox":
p, err = infoblox.NewInfobloxProvider(
infoblox.InfobloxConfig{
DomainFilter: domainFilter,
ZoneIDFilter: zoneIDFilter,
Host: cfg.InfobloxGridHost,
Port: cfg.InfobloxWapiPort,
Username: cfg.InfobloxWapiUsername,
Password: cfg.InfobloxWapiPassword,
Version: cfg.InfobloxWapiVersion,
SSLVerify: cfg.InfobloxSSLVerify,
View: cfg.InfobloxView,
MaxResults: cfg.InfobloxMaxResults,
DryRun: cfg.DryRun,
},
)
case "dyn":
p, err = dyn.NewDynProvider(
dyn.DynConfig{
DomainFilter: domainFilter,
ZoneIDFilter: zoneIDFilter,
DryRun: cfg.DryRun,
CustomerName: cfg.DynCustomerName,
Username: cfg.DynUsername,
Password: cfg.DynPassword,
MinTTLSeconds: cfg.DynMinTTLSeconds,
AppVersion: externaldns.Version,
},
)
case "coredns", "skydns":
p, err = coredns.NewCoreDNSProvider(domainFilter, cfg.CoreDNSPrefix, cfg.DryRun)
case "rdns":
p, err = rdns.NewRDNSProvider(
rdns.RDNSConfig{
DomainFilter: domainFilter,
DryRun: cfg.DryRun,
},
)
case "exoscale":
p, err = exoscale.NewExoscaleProvider(cfg.ExoscaleEndpoint, cfg.ExoscaleAPIKey, cfg.ExoscaleAPISecret, cfg.DryRun, exoscale.ExoscaleWithDomain(domainFilter), exoscale.ExoscaleWithLogging()), nil
case "inmemory":
p, err = inmemory.NewInMemoryProvider(inmemory.InMemoryInitZones(cfg.InMemoryZones), inmemory.InMemoryWithDomain(domainFilter), inmemory.InMemoryWithLogging()), nil
case "designate":
p, err = designate.NewDesignateProvider(domainFilter, cfg.DryRun)
case "pdns":
p, err = pdns.NewPDNSProvider(
ctx,
pdns.PDNSConfig{
DomainFilter: domainFilter,
DryRun: cfg.DryRun,
Server: cfg.PDNSServer,
APIKey: cfg.PDNSAPIKey,
TLSConfig: pdns.TLSConfig{
TLSEnabled: cfg.PDNSTLSEnabled,
CAFilePath: cfg.TLSCA,
ClientCertFilePath: cfg.TLSClientCert,
ClientCertKeyFilePath: cfg.TLSClientCertKey,
},
},
)
case "oci":
var config *oci.OCIConfig
config, err = oci.LoadOCIConfig(cfg.OCIConfigFile)
if err == nil {
p, err = oci.NewOCIProvider(*config, domainFilter, zoneIDFilter, cfg.DryRun)
}
case "rfc2136":
p, err = rfc2136.NewRfc2136Provider(cfg.RFC2136Host, cfg.RFC2136Port, cfg.RFC2136Zone, cfg.RFC2136Insecure, cfg.RFC2136TSIGKeyName, cfg.RFC2136TSIGSecret, cfg.RFC2136TSIGSecretAlg, cfg.RFC2136TAXFR, domainFilter, cfg.DryRun, cfg.RFC2136MinTTL, nil)
case "ns1":
p, err = ns1.NewNS1Provider(
ns1.NS1Config{
DomainFilter: domainFilter,
ZoneIDFilter: zoneIDFilter,
NS1Endpoint: cfg.NS1Endpoint,
NS1IgnoreSSL: cfg.NS1IgnoreSSL,
DryRun: cfg.DryRun,
MinTTLSeconds: cfg.NS1MinTTLSeconds,
},
)
case "transip":
p, err = transip.NewTransIPProvider(cfg.TransIPAccountName, cfg.TransIPPrivateKeyFile, domainFilter, cfg.DryRun)
case "scaleway":
p, err = scaleway.NewScalewayProvider(ctx, domainFilter, cfg.DryRun)
default:
log.Fatalf("unknown dns provider: %s", cfg.Provider)
}
@ -307,8 +137,6 @@ func main() {
r, err = registry.NewNoopRegistry(p)
case "txt":
r, err = registry.NewTXTRegistry(p, cfg.TXTPrefix, cfg.TXTSuffix, cfg.TXTOwnerID, cfg.TXTCacheInterval)
case "aws-sd":
r, err = registry.NewAWSSDRegistry(p.(*awssd.AWSSDProvider), cfg.TXTOwnerID)
default:
log.Fatalf("unknown registry: %s", cfg.Registry)
}


+ 0
- 382
provider/akamai/akamai.go View File

@ -1,382 +0,0 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package akamai
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"strings"
c "github.com/akamai/AkamaiOPEN-edgegrid-golang/client-v1"
"github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid"
log "github.com/sirupsen/logrus"
"sigs.k8s.io/external-dns/endpoint"
"sigs.k8s.io/external-dns/plan"
"sigs.k8s.io/external-dns/provider"
)
type akamaiClient interface {
NewRequest(config edgegrid.Config, method, path string, body io.Reader) (*http.Request, error)
Do(config edgegrid.Config, req *http.Request) (*http.Response, error)
}
type akamaiOpenClient struct{}
func (*akamaiOpenClient) NewRequest(config edgegrid.Config, method, path string, body io.Reader) (*http.Request, error) {
return c.NewRequest(config, method, path, body)
}
func (*akamaiOpenClient) Do(config edgegrid.Config, req *http.Request) (*http.Response, error) {
return c.Do(config, req)
}
// AkamaiConfig clarifies the method signature
type AkamaiConfig struct {
DomainFilter endpoint.DomainFilter
ZoneIDFilter provider.ZoneIDFilter
ServiceConsumerDomain string
ClientToken string
ClientSecret string
AccessToken string
DryRun bool
}
// AkamaiProvider implements the DNS provider for Akamai.
type AkamaiProvider struct {
provider.BaseProvider
domainFilter endpoint.DomainFilter
zoneIDFilter provider.ZoneIDFilter
config edgegrid.Config
dryRun bool
client akamaiClient
}
type akamaiZones struct {
Zones []akamaiZone `json:"zones"`
}
type akamaiZone struct {
ContractID string `json:"contractId"`
Zone string `json:"zone"`
}
type akamaiRecordsets struct {
Recordsets []akamaiRecord `json:"recordsets"`
}
type akamaiRecord struct {
Name string `json:"name"`
Type string `json:"type"`
TTL int64 `json:"ttl"`
Rdata []interface{} `json:"rdata"`
}
// NewAkamaiProvider initializes a new Akamai DNS based Provider.
func NewAkamaiProvider(akamaiConfig AkamaiConfig) *AkamaiProvider {
edgeGridConfig := edgegrid.Config{
Host: akamaiConfig.ServiceConsumerDomain,
ClientToken: akamaiConfig.ClientToken,
ClientSecret: akamaiConfig.ClientSecret,
AccessToken: akamaiConfig.AccessToken,
MaxBody: 1024,
HeaderToSign: []string{
"X-External-DNS",
},
Debug: false,
}
provider := &AkamaiProvider{
domainFilter: akamaiConfig.DomainFilter,
zoneIDFilter: akamaiConfig.ZoneIDFilter,
config: edgeGridConfig,
dryRun: akamaiConfig.DryRun,
client: &akamaiOpenClient{},
}
return provider
}
func (p *AkamaiProvider) request(method, path string, body io.Reader) (*http.Response, error) {
req, err := p.client.NewRequest(p.config, method, fmt.Sprintf("https://%s/%s", p.config.Host, path), body)
if err != nil {
log.Errorf("Akamai client failed to prepare the request")
return nil, err
}
resp, err := p.client.Do(p.config, req)
if err != nil {
log.Errorf("Akamai client failed to do the request")
return nil, err
}
if !c.IsSuccess(resp) {
return nil, c.NewAPIError(resp)
}
return resp, err
}
//Look here for endpoint documentation -> https://developer.akamai.com/api/web_performance/fast_dns_zone_management/v2.html#getzones
func (p *AkamaiProvider) fetchZones() (zones akamaiZones, err error) {
log.Debugf("Trying to fetch zones from Akamai")
resp, err := p.request("GET", "config-dns/v2/zones?showAll=true&types=primary%2Csecondary", nil)
if err != nil {
log.Errorf("Failed to fetch zones from Akamai")
return zones, err
}
err = json.NewDecoder(resp.Body).Decode(&zones)
if err != nil {
log.Errorf("Could not decode json response from Akamai on zone request")
return zones, err
}
defer resp.Body.Close()
filteredZones := akamaiZones{}
for _, zone := range zones.Zones {
if !p.zoneIDFilter.Match(zone.ContractID) {
log.Debugf("Skipping zone: '%s' with ZoneID: '%s', it does not match against ZoneID filters", zone.Zone, zone.ContractID)
continue
}
filteredZones.Zones = append(filteredZones.Zones, akamaiZone{ContractID: zone.ContractID, Zone: zone.Zone})
log.Debugf("Fetched zone: '%s' (ZoneID: %s)", zone.Zone, zone.ContractID)
}
lenFilteredZones := len(filteredZones.Zones)
if lenFilteredZones == 0 {
log.Warnf("No zones could be fetched")
} else {
log.Debugf("Fetched '%d' zones from Akamai", lenFilteredZones)
}
return filteredZones, nil
}
//Look here for endpoint documentation -> https://developer.akamai.com/api/web_performance/fast_dns_zone_management/v2.html#getzonerecordsets
func (p *AkamaiProvider) fetchRecordSet(zone string) (recordSet akamaiRecordsets, err error) {
log.Debugf("Trying to fetch endpoints for zone: '%s' from Akamai", zone)
resp, err := p.request("GET", "config-dns/v2/zones/"+zone+"/recordsets?showAll=true&types=A%2CTXT%2CCNAME", nil)
if err != nil {
log.Errorf("Failed to fetch records from Akamai for zone: '%s'", zone)
return recordSet, err
}
defer resp.Body.Close()
err = json.NewDecoder(resp.Body).Decode(&recordSet)
if err != nil {
log.Errorf("Could not decode json response from Akamai for zone: '%s' on request", zone)
return recordSet, err
}
return recordSet, nil
}
//Records returns the list of records in a given zone.
func (p *AkamaiProvider) Records(context.Context) (endpoints []*endpoint.Endpoint, err error) {
zones, err := p.fetchZones()
if err != nil {
log.Warnf("No zones to fetch endpoints from!")
return endpoints, err
}
for _, zone := range zones.Zones {
records, err := p.fetchRecordSet(zone.Zone)
if err != nil {
log.Warnf("No recordsets could be fetched for zone: '%s'!", zone.Zone)
continue
}
for _, record := range records.Recordsets {
rdata := make([]string, len(record.Rdata))
for i, v := range record.Rdata {
rdata[i] = v.(string)
}
if !p.domainFilter.Match(record.Name) {
log.Debugf("Skipping endpoint DNSName: '%s' RecordType: '%s', it does not match against Domain filters", record.Name, record.Type)
continue
}
endpoints = append(endpoints, endpoint.NewEndpoint(record.Name, record.Type, rdata...))
log.Debugf("Fetched endpoint DNSName: '%s' RecordType: '%s' Rdata: '%s')", record.Name, record.Type, rdata)
}
}
lenEndpoints := len(endpoints)
if lenEndpoints == 0 {
log.Warnf("No endpoints could be fetched")
} else {
log.Debugf("Fetched '%d' endpoints from Akamai", lenEndpoints)
}
return endpoints, nil
}
// ApplyChanges applies a given set of changes in a given zone.
func (p *AkamaiProvider) ApplyChanges(ctx context.Context, changes *plan.Changes) error {
zoneNameIDMapper := provider.ZoneIDName{}
zones, err := p.fetchZones()
if err != nil {
log.Warnf("No zones to fetch endpoints from!")
return nil
}
for _, z := range zones.Zones {
zoneNameIDMapper[z.Zone] = z.Zone
}
_, cf := p.createRecords(zoneNameIDMapper, changes.Create)
if !p.dryRun {
if len(cf) > 0 {
log.Warnf("Not all desired endpoints could be created, retrying next iteration")
for _, f := range cf {
log.Warnf("Not created was DNSName: '%s' RecordType: '%s'", f.DNSName, f.RecordType)
}
}
}
_, df := p.deleteRecords(zoneNameIDMapper, changes.Delete)
if !p.dryRun {
if len(df) > 0 {
log.Warnf("Not all endpoints that require deletion could be deleted, retrying next iteration")
for _, f := range df {
log.Warnf("Not deleted was DNSName: '%s' RecordType: '%s'", f.DNSName, f.RecordType)
}
}
}
_, uf := p.updateNewRecords(zoneNameIDMapper, changes.UpdateNew)
if !p.dryRun {
if len(uf) > 0 {
log.Warnf("Not all endpoints that require updating could be updated, retrying next iteration")
for _, f := range uf {
log.Warnf("Not updated was DNSName: '%s' RecordType: '%s'", f.DNSName, f.RecordType)
}
}
}
for _, uold := range changes.UpdateOld {
if !p.dryRun {
log.Debugf("UpdateOld (ignored) for DNSName: '%s' RecordType: '%s'", uold.DNSName, uold.RecordType)
}
}
return nil
}
func (p *AkamaiProvider) newAkamaiRecord(dnsName, recordType string, targets ...string) *akamaiRecord {
cleanTargets := make([]interface{}, len(targets))
for idx, target := range targets {
cleanTargets[idx] = strings.TrimSuffix(target, ".")
}
return &akamaiRecord{
Name: strings.TrimSuffix(dnsName, "."),
Rdata: cleanTargets,
Type: recordType,
TTL: 300,
}
}
func (p *AkamaiProvider) createRecords(zoneNameIDMapper provider.ZoneIDName, endpoints []*endpoint.Endpoint) (created []*endpoint.Endpoint, failed []*endpoint.Endpoint) {
for _, endpoint := range endpoints {
if !p.domainFilter.Match(endpoint.DNSName) {
log.Debugf("Skipping creation at Akamai of endpoint DNSName: '%s' RecordType: '%s', it does not match against Domain filters", endpoint.DNSName, endpoint.RecordType)
continue
}
if zoneName, _ := zoneNameIDMapper.FindZone(endpoint.DNSName); zoneName != "" {
akamaiRecord := p.newAkamaiRecord(endpoint.DNSName, endpoint.RecordType, endpoint.Targets...)
body, _ := json.MarshalIndent(akamaiRecord, "", " ")
log.Infof("Create new Endpoint at Akamai FastDNS - Zone: '%s', DNSName: '%s', RecordType: '%s', Targets: '%+v'", zoneName, endpoint.DNSName, endpoint.RecordType, endpoint.Targets)
if p.dryRun {
continue
}
_, err := p.request("POST", "config-dns/v2/zones/"+zoneName+"/names/"+endpoint.DNSName+"/types/"+endpoint.RecordType, bytes.NewReader(body))
if err != nil {
log.Errorf("Failed to create Akamai endpoint DNSName: '%s' RecordType: '%s' for zone: '%s'", endpoint.DNSName, endpoint.RecordType, zoneName)
failed = append(failed, endpoint)
continue
}
created = append(created, endpoint)
} else {
log.Warnf("No matching zone for endpoint addition DNSName: '%s' RecordType: '%s'", endpoint.DNSName, endpoint.RecordType)
failed = append(failed, endpoint)
}
}
return created, failed
}
func (p *AkamaiProvider) deleteRecords(zoneNameIDMapper provider.ZoneIDName, endpoints []*endpoint.Endpoint) (deleted []*endpoint.Endpoint, failed []*endpoint.Endpoint) {
for _, endpoint := range endpoints {
if !p.domainFilter.Match(endpoint.DNSName) {
log.Debugf("Skipping deletion at Akamai of endpoint: '%s' type: '%s', it does not match against Domain filters", endpoint.DNSName, endpoint.RecordType)
continue
}
if zoneName, _ := zoneNameIDMapper.FindZone(endpoint.DNSName); zoneName != "" {
log.Infof("Deletion at Akamai FastDNS - Zone: '%s', DNSName: '%s', RecordType: '%s', Targets: '%+v'", zoneName, endpoint.DNSName, endpoint.RecordType, endpoint.Targets)
if p.dryRun {
continue
}
_, err := p.request("DELETE", "config-dns/v2/zones/"+zoneName+"/names/"+endpoint.DNSName+"/types/"+endpoint.RecordType, nil)
if err != nil {
log.Errorf("Failed to delete Akamai endpoint DNSName: '%s' for zone: '%s'", endpoint.DNSName, zoneName)
failed = append(failed, endpoint)
continue
}
deleted = append(deleted, endpoint)
} else {
log.Warnf("No matching zone for endpoint deletion DNSName: '%s' RecordType: '%s'", endpoint.DNSName, endpoint.RecordType)
failed = append(failed, endpoint)
}
}
return deleted, failed
}
func (p *AkamaiProvider) updateNewRecords(zoneNameIDMapper provider.ZoneIDName, endpoints []*endpoint.Endpoint) (updated []*endpoint.Endpoint, failed []*endpoint.Endpoint) {
for _, endpoint := range endpoints {
if !p.domainFilter.Match(endpoint.DNSName) {
log.Debugf("Skipping update at Akamai of endpoint DNSName: '%s' RecordType: '%s', it does not match against Domain filters", endpoint.DNSName, endpoint.RecordType)
continue
}
if zoneName, _ := zoneNameIDMapper.FindZone(endpoint.DNSName); zoneName != "" {
akamaiRecord := p.newAkamaiRecord(endpoint.DNSName, endpoint.RecordType, endpoint.Targets...)
body, _ := json.MarshalIndent(akamaiRecord, "", " ")
log.Infof("Updating endpoint at Akamai FastDNS - Zone: '%s', DNSName: '%s', RecordType: '%s', Targets: '%+v'", zoneName, endpoint.DNSName, endpoint.RecordType, endpoint.Targets)
if p.dryRun {
continue
}
_, err := p.request("PUT", "config-dns/v2/zones/"+zoneName+"/names/"+endpoint.DNSName+"/types/"+endpoint.RecordType, bytes.NewReader(body))
if err != nil {
log.Errorf("Failed to update Akamai endpoint DNSName: '%s' for zone: '%s'", endpoint.DNSName, zoneName)
failed = append(failed, endpoint)
continue
}
updated = append(updated, endpoint)
} else {
log.Warnf("No matching zone for endpoint update DNSName: '%s' RecordType: '%s'", endpoint.DNSName, endpoint.RecordType)
failed = append(failed, endpoint)
}
}
return updated, failed
}

+ 0
- 344
provider/akamai/akamai_test.go View File

@ -1,344 +0,0 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package akamai
import (
"bytes"
"context"
"encoding/json"
"io"
"io/ioutil"
"net/http"
"net/http/httptest"
"strings"
"testing"
"github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"sigs.k8s.io/external-dns/endpoint"
"sigs.k8s.io/external-dns/plan"
"sigs.k8s.io/external-dns/provider"
)
type mockAkamaiClient struct {
mock.Mock
}
func (m *mockAkamaiClient) NewRequest(config edgegrid.Config, met, p string, b io.Reader) (*http.Request, error) {
switch {
case met == "GET":
switch {
case strings.HasPrefix(p, "https:///config-dns/v2/zones?"):
b = bytes.NewReader([]byte("{\"zones\":[{\"contractId\":\"Test\",\"zone\":\"example.com\"},{\"contractId\":\"Exclude-Me\",\"zone\":\"exclude.me\"}]}"))
case strings.HasPrefix(p, "https:///config-dns/v2/zones/example.com/"):
b = bytes.NewReader([]byte("{\"recordsets\":[{\"name\":\"www.example.com\",\"type\":\"A\",\"ttl\":300,\"rdata\":[\"10.0.0.2\",\"10.0.0.3\"]},{\"name\":\"www.example.com\",\"type\":\"TXT\",\"ttl\":300,\"rdata\":[\"heritage=external-dns,external-dns/owner=default\"]}]}"))
case strings.HasPrefix(p, "https:///config-dns/v2/zones/exclude.me/"):
b = bytes.NewReader([]byte("{\"recordsets\":[{\"name\":\"www.exclude.me\",\"type\":\"A\",\"ttl\":300,\"rdata\":[\"192.168.0.1\",\"192.168.0.2\"]}]}"))
}
case met == "DELETE":
b = bytes.NewReader([]byte("{\"title\": \"Success\", \"status\": 200, \"detail\": \"Record deleted\", \"requestId\": \"4321\"}"))
case met == "ERROR":
b = bytes.NewReader([]byte("{\"status\": 404 }"))
}
req := httptest.NewRequest(met, p, b)
return req, nil
}
func (m *mockAkamaiClient) Do(config edgegrid.Config, req *http.Request) (*http.Response, error) {
handler := func(w http.ResponseWriter, r *http.Request) (isError bool) {
b, _ := ioutil.ReadAll(r.Body)
io.WriteString(w, string(b))
return string(b) == "{\"status\": 404 }"
}
w := httptest.NewRecorder()
err := handler(w, req)
resp := w.Result()
if err == true {
resp.StatusCode = 400
}
return resp, nil
}
func TestRequestError(t *testing.T) {
config := AkamaiConfig{}
client := &mockAkamaiClient{}
c := NewAkamaiProvider(config)
c.client = client
m := "ERROR"
p := ""
b := ""
x, err := c.request(m, p, bytes.NewReader([]byte(b)))
assert.Nil(t, x)
assert.NotNil(t, err)
}
func TestFetchZonesZoneIDFilter(t *testing.T) {
config := AkamaiConfig{
ZoneIDFilter: provider.NewZoneIDFilter([]string{"Test"}),
}
client := &mockAkamaiClient{}
c := NewAkamaiProvider(config)
c.client = client
x, _ := c.fetchZones()
y, _ := json.Marshal(x)
if assert.NotNil(t, y) {
assert.Equal(t, "{\"zones\":[{\"contractId\":\"Test\",\"zone\":\"example.com\"}]}", string(y))
}
}
func TestFetchZonesEmpty(t *testing.T) {
config := AkamaiConfig{
DomainFilter: endpoint.NewDomainFilter([]string{"Nonexistent"}),
ZoneIDFilter: provider.NewZoneIDFilter([]string{"Nonexistent"}),
}
client := &mockAkamaiClient{}
c := NewAkamaiProvider(config)
c.client = client
x, _ := c.fetchZones()
y, _ := json.Marshal(x)
if assert.NotNil(t, y) {
assert.Equal(t, "{\"zones\":null}", string(y))
}
}
func TestFetchRecordset1(t *testing.T) {
config := AkamaiConfig{}
client := &mockAkamaiClient{}
c := NewAkamaiProvider(config)
c.client = client
x, _ := c.fetchRecordSet("example.com")
y, _ := json.Marshal(x)
if assert.NotNil(t, y) {
assert.Equal(t, "{\"recordsets\":[{\"name\":\"www.example.com\",\"type\":\"A\",\"ttl\":300,\"rdata\":[\"10.0.0.2\",\"10.0.0.3\"]},{\"name\":\"www.example.com\",\"type\":\"TXT\",\"ttl\":300,\"rdata\":[\"heritage=external-dns,external-dns/owner=default\"]}]}", string(y))
}
}
func TestFetchRecordset2(t *testing.T) {
config := AkamaiConfig{}
client := &mockAkamaiClient{}
c := NewAkamaiProvider(config)
c.client = client
x, _ := c.fetchRecordSet("exclude.me")
y, _ := json.Marshal(x)
if assert.NotNil(t, y) {
assert.Equal(t, "{\"recordsets\":[{\"name\":\"www.exclude.me\",\"type\":\"A\",\"ttl\":300,\"rdata\":[\"192.168.0.1\",\"192.168.0.2\"]}]}", string(y))
}
}
func TestAkamaiRecords(t *testing.T) {
config := AkamaiConfig{}
client := &mockAkamaiClient{}
c := NewAkamaiProvider(config)
c.client = client
endpoints := make([]*endpoint.Endpoint, 0)
endpoints = append(endpoints, endpoint.NewEndpoint("www.example.com", endpoint.RecordTypeA, "10.0.0.2", "10.0.0.3"))
endpoints = append(endpoints, endpoint.NewEndpoint("www.example.com", endpoint.RecordTypeTXT, "heritage=external-dns,external-dns/owner=default"))
endpoints = append(endpoints, endpoint.NewEndpoint("www.exclude.me", endpoint.RecordTypeA, "192.168.0.1", "192.168.0.2"))
x, _ := c.Records(context.Background())
if assert.NotNil(t, x) {
assert.Equal(t, endpoints, x)
}
}
func TestAkamaiRecordsEmpty(t *testing.T) {
config := AkamaiConfig{
ZoneIDFilter: provider.NewZoneIDFilter([]string{"Nonexistent"}),
}
client := &mockAkamaiClient{}
c := NewAkamaiProvider(config)
c.client = client
x, _ := c.Records(context.Background())
assert.Nil(t, x)
}
func TestAkamaiRecordsFilters(t *testing.T) {
config := AkamaiConfig{
DomainFilter: endpoint.NewDomainFilter([]string{"www.exclude.me"}),
ZoneIDFilter: provider.NewZoneIDFilter([]string{"Exclude-Me"}),
}
client := &mockAkamaiClient{}
c := NewAkamaiProvider(config)
c.client = client
endpoints := make([]*endpoint.Endpoint, 0)
endpoints = append(endpoints, endpoint.NewEndpoint("www.exclude.me", endpoint.RecordTypeA, "192.168.0.1", "192.168.0.2"))
x, _ := c.Records(context.Background())
if assert.NotNil(t, x) {
assert.Equal(t, endpoints, x)
}
}
func TestCreateRecords(t *testing.T) {
config := AkamaiConfig{}
client := &mockAkamaiClient{}
c := NewAkamaiProvider(config)
c.client = client
zoneNameIDMapper := provider.ZoneIDName{"example.com": "example.com"}
endpoints := make([]*endpoint.Endpoint, 0)
endpoints = append(endpoints, endpoint.NewEndpoint("www.example.com", endpoint.RecordTypeA, "10.0.0.2", "10.0.0.3"))
endpoints = append(endpoints, endpoint.NewEndpoint("www.example.com", endpoint.RecordTypeTXT, "heritage=external-dns,external-dns/owner=default"))
x, _ := c.createRecords(zoneNameIDMapper, endpoints)
if assert.NotNil(t, x) {
assert.Equal(t, endpoints, x)
}
}
func TestCreateRecordsDomainFilter(t *testing.T) {
config := AkamaiConfig{
DomainFilter: endpoint.NewDomainFilter([]string{"example.com"}),
}
client := &mockAkamaiClient{}
c := NewAkamaiProvider(config)
c.client = client
zoneNameIDMapper := provider.ZoneIDName{"example.com": "example.com"}
endpoints := make([]*endpoint.Endpoint, 0)
endpoints = append(endpoints, endpoint.NewEndpoint("www.example.com", endpoint.RecordTypeA, "10.0.0.2", "10.0.0.3"))
endpoints = append(endpoints, endpoint.NewEndpoint("www.example.com", endpoint.RecordTypeTXT, "heritage=external-dns,external-dns/owner=default"))
exclude := append(endpoints, endpoint.NewEndpoint("www.exclude.me", endpoint.RecordTypeA, "10.0.0.2", "10.0.0.3"))
x, _ := c.createRecords(zoneNameIDMapper, exclude)
if assert.NotNil(t, x) {
assert.Equal(t, endpoints, x)
}
}
func TestDeleteRecords(t *testing.T) {
config := AkamaiConfig{}
client := &mockAkamaiClient{}
c := NewAkamaiProvider(config)
c.client = client
zoneNameIDMapper := provider.ZoneIDName{"example.com": "example.com"}
endpoints := make([]*endpoint.Endpoint, 0)
endpoints = append(endpoints, endpoint.NewEndpoint("www.example.com", endpoint.RecordTypeA, "10.0.0.2", "10.0.0.3"))
endpoints = append(endpoints, endpoint.NewEndpoint("www.example.com", endpoint.RecordTypeTXT, "heritage=external-dns,external-dns/owner=default"))
x, _ := c.deleteRecords(zoneNameIDMapper, endpoints)
if assert.NotNil(t, x) {
assert.Equal(t, endpoints, x)
}
}
func TestDeleteRecordsDomainFilter(t *testing.T) {
config := AkamaiConfig{
DomainFilter: endpoint.NewDomainFilter([]string{"example.com"}),
}
client := &mockAkamaiClient{}
c := NewAkamaiProvider(config)
c.client = client
zoneNameIDMapper := provider.ZoneIDName{"example.com": "example.com"}
endpoints := make([]*endpoint.Endpoint, 0)
endpoints = append(endpoints, endpoint.NewEndpoint("www.example.com", endpoint.RecordTypeA, "10.0.0.2", "10.0.0.3"))
endpoints = append(endpoints, endpoint.NewEndpoint("www.example.com", endpoint.RecordTypeTXT, "heritage=external-dns,external-dns/owner=default"))
exclude := append(endpoints, endpoint.NewEndpoint("www.exclude.me", endpoint.RecordTypeA, "10.0.0.2", "10.0.0.3"))
x, _ := c.deleteRecords(zoneNameIDMapper, exclude)
if assert.NotNil(t, x) {
assert.Equal(t, endpoints, x)
}
}
func TestUpdateRecords(t *testing.T) {
config := AkamaiConfig{}
client := &mockAkamaiClient{}
c := NewAkamaiProvider(config)
c.client = client
zoneNameIDMapper := provider.ZoneIDName{"example.com": "example.com"}
endpoints := make([]*endpoint.Endpoint, 0)
endpoints = append(endpoints, endpoint.NewEndpoint("www.example.com", endpoint.RecordTypeA, "10.0.0.2", "10.0.0.3"))
endpoints = append(endpoints, endpoint.NewEndpoint("www.example.com", endpoint.RecordTypeTXT, "heritage=external-dns,external-dns/owner=default"))
x, _ := c.updateNewRecords(zoneNameIDMapper, endpoints)
if assert.NotNil(t, x) {
assert.Equal(t, endpoints, x)
}
}
func TestUpdateRecordsDomainFilter(t *testing.T) {
config := AkamaiConfig{
DomainFilter: endpoint.NewDomainFilter([]string{"example.com"}),
}
client := &mockAkamaiClient{}
c := NewAkamaiProvider(config)
c.client = client
zoneNameIDMapper := provider.ZoneIDName{"example.com": "example.com"}
endpoints := make([]*endpoint.Endpoint, 0)
endpoints = append(endpoints, endpoint.NewEndpoint("www.example.com", endpoint.RecordTypeA, "10.0.0.2", "10.0.0.3"))
endpoints = append(endpoints, endpoint.NewEndpoint("www.example.com", endpoint.RecordTypeTXT, "heritage=external-dns,external-dns/owner=default"))
exclude := append(endpoints, endpoint.NewEndpoint("www.exclude.me", endpoint.RecordTypeA, "10.0.0.2", "10.0.0.3"))
x, _ := c.updateNewRecords(zoneNameIDMapper, exclude)
if assert.NotNil(t, x) {
assert.Equal(t, endpoints, x)
}
}
func TestAkamaiApplyChanges(t *testing.T) {
config := AkamaiConfig{}
client := &mockAkamaiClient{}
c := NewAkamaiProvider(config)
c.client = client
changes := &plan.Changes{}
changes.Create = []*endpoint.Endpoint{
{DNSName: "www.example.com", RecordType: "A", Targets: endpoint.Targets{"target"}, RecordTTL: 300},
{DNSName: "test.example.com", RecordType: "A", Targets: endpoint.Targets{"target"}, RecordTTL: 300},
{DNSName: "test.this.example.com", RecordType: "A", Targets: endpoint.Targets{"127.0.0.1"}, RecordTTL: 300},
{DNSName: "www.example.com", RecordType: "TXT", Targets: endpoint.Targets{"heritage=external-dns,external-dns/owner=default"}, RecordTTL: 300},
{DNSName: "test.example.com", RecordType: "TXT", Targets: endpoint.Targets{"heritage=external-dns,external-dns/owner=default"}, RecordTTL: 300},
{DNSName: "test.this.example.com", RecordType: "TXT", Targets: endpoint.Targets{"heritage=external-dns,external-dns/owner=default"}, RecordTTL: 300},
{DNSName: "another.example.com", RecordType: "A", Targets: endpoint.Targets{"target"}},
}
changes.Delete = []*endpoint.Endpoint{{DNSName: "delete.example.com", RecordType: "A", Targets: endpoint.Targets{"target"}, RecordTTL: 300}}
changes.UpdateOld = []*endpoint.Endpoint{{DNSName: "old.example.com", RecordType: "A", Targets: endpoint.Targets{"target-old"}, RecordTTL: 300}}
changes.UpdateNew = []*endpoint.Endpoint{{DNSName: "update.example.com", Targets: endpoint.Targets{"target-new"}, RecordType: "CNAME", RecordTTL: 300}}
apply := c.ApplyChanges(context.Background(), changes)
assert.Nil(t, apply)
}

+ 0
- 1071
provider/alibabacloud/alibaba_cloud.go
File diff suppressed because it is too large
View File


+ 0
- 464
provider/alibabacloud/alibaba_cloud_test.go View File

@ -1,464 +0,0 @@
/*
Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package alibabacloud
import (
"context"
"testing"
"github.com/aliyun/alibaba-cloud-sdk-go/services/alidns"
"github.com/aliyun/alibaba-cloud-sdk-go/services/pvtz"
"sigs.k8s.io/external-dns/endpoint"
"sigs.k8s.io/external-dns/plan"
)
type MockAlibabaCloudDNSAPI struct {
records []alidns.Record
}
func NewMockAlibabaCloudDNSAPI() *MockAlibabaCloudDNSAPI {
api := MockAlibabaCloudDNSAPI{}
api.records = []alidns.Record{
{
RecordId: "1",
DomainName: "container-service.top",
Type: "A",
TTL: 300,
RR: "abc",
Value: "1.2.3.4",
},
{
RecordId: "2",
DomainName: "container-service.top",
Type: "TXT",
TTL: 300,
RR: "abc",
Value: "heritage=external-dns;external-dns/owner=default",
},
}
return &api
}
func (m *MockAlibabaCloudDNSAPI) AddDomainRecord(request *alidns.AddDomainRecordRequest) (response *alidns.AddDomainRecordResponse, err error) {
ttl, _ := request.TTL.GetValue()
m.records = append(m.records, alidns.Record{
RecordId: "3",
DomainName: request.DomainName,
Type: request.Type,
TTL: int64(ttl),
RR: request.RR,
Value: request.Value,
})
response = alidns.CreateAddDomainRecordResponse()
return response, nil
}
func (m *MockAlibabaCloudDNSAPI) DeleteDomainRecord(request *alidns.DeleteDomainRecordRequest) (response *alidns.DeleteDomainRecordResponse, err error) {
var result []alidns.Record
for _, record := range m.records {
if record.RecordId != request.RecordId {
result = append(result, record)
}
}
m.records = result
response = alidns.CreateDeleteDomainRecordResponse()
response.RecordId = request.RecordId
return response, nil
}
func (m *MockAlibabaCloudDNSAPI) UpdateDomainRecord(request *alidns.UpdateDomainRecordRequest) (response *alidns.UpdateDomainRecordResponse, err error) {
ttl, _ := request.TTL.GetValue64()
for i := range m.records {
if m.records[i].RecordId == request.RecordId {
m.records[i].TTL = ttl
}
}
response = alidns.CreateUpdateDomainRecordResponse()
response.RecordId = request.RecordId
return response, nil
}
func (m *MockAlibabaCloudDNSAPI) DescribeDomains(request *alidns.DescribeDomainsRequest) (response *alidns.DescribeDomainsResponse, err error) {
var result alidns.Domains
for _, record := range m.records {
domain := alidns.Domain{}
domain.DomainName = record.DomainName
}
response = alidns.CreateDescribeDomainsResponse()
response.Domains = result
return response, nil
}
func (m *MockAlibabaCloudDNSAPI) DescribeDomainRecords(request *alidns.DescribeDomainRecordsRequest) (response *alidns.DescribeDomainRecordsResponse, err error) {
var result []alidns.Record
for _, record := range m.records {
if record.DomainName == request.DomainName {
result = append(result, record)
}
}
response = alidns.CreateDescribeDomainRecordsResponse()
response.DomainRecords.Record = result
return response, nil
}
type MockAlibabaCloudPrivateZoneAPI struct {
zone pvtz.Zone
records []pvtz.Record
}
func NewMockAlibabaCloudPrivateZoneAPI() *MockAlibabaCloudPrivateZoneAPI {
vpc := pvtz.Vpc{
RegionId: "cn-beijing",
VpcId: "vpc-xxxxxx",
}
api := MockAlibabaCloudPrivateZoneAPI{zone: pvtz.Zone{
ZoneId: "test-zone",
ZoneName: "container-service.top",
Vpcs: pvtz.Vpcs{
Vpc: []pvtz.Vpc{vpc},
},
}}
api.records = []pvtz.Record{
{
RecordId: 1,
Type: "A",
Ttl: 300,
Rr: "abc",
Value: "1.2.3.4",
},
{
RecordId: 2,
Type: "TXT",
Ttl: 300,
Rr: "abc",
Value: "heritage=external-dns;external-dns/owner=default",
},
}
return &api
}
func (m *MockAlibabaCloudPrivateZoneAPI) AddZoneRecord(request *pvtz.AddZoneRecordRequest) (response *pvtz.AddZoneRecordResponse, err error) {
ttl, _ := request.Ttl.GetValue()
m.records = append(m.records, pvtz.Record{
RecordId: 3,
Type: request.Type,
Ttl: ttl,
Rr: request.Rr,
Value: request.Value,
})
response = pvtz.CreateAddZoneRecordResponse()
return response, nil
}
func (m *MockAlibabaCloudPrivateZoneAPI) DeleteZoneRecord(request *pvtz.DeleteZoneRecordRequest) (response *pvtz.DeleteZoneRecordResponse, err error) {
recordID, _ := request.RecordId.GetValue64()
var result []pvtz.Record
for _, record := range m.records {
if record.RecordId != recordID {
result = append(result, record)
}
}
m.records = result
response = pvtz.CreateDeleteZoneRecordResponse()
return response, nil
}
func (m *MockAlibabaCloudPrivateZoneAPI) UpdateZoneRecord(request *pvtz.UpdateZoneRecordRequest) (response *pvtz.UpdateZoneRecordResponse, err error) {
recordID, _ := request.RecordId.GetValue64()
ttl, _ := request.Ttl.GetValue()
for i := range m.records {
if m.records[i].RecordId == recordID {
m.records[i].Ttl = ttl
}
}
response = pvtz.CreateUpdateZoneRecordResponse()
return response, nil
}
func (m *MockAlibabaCloudPrivateZoneAPI) DescribeZoneRecords(request *pvtz.DescribeZoneRecordsRequest) (response *pvtz.DescribeZoneRecordsResponse, err error) {
response = pvtz.CreateDescribeZoneRecordsResponse()
response.Records.Record = append(response.Records.Record, m.records...)
return response, nil
}
func (m *MockAlibabaCloudPrivateZoneAPI) DescribeZones(request *pvtz.DescribeZonesRequest) (response *pvtz.DescribeZonesResponse, err error) {
response = pvtz.CreateDescribeZonesResponse()
response.Zones.Zone = append(response.Zones.Zone, m.zone)
return response, nil
}
func (m *MockAlibabaCloudPrivateZoneAPI) DescribeZoneInfo(request *pvtz.DescribeZoneInfoRequest) (response *pvtz.DescribeZoneInfoResponse, err error) {
response = pvtz.CreateDescribeZoneInfoResponse()
response.ZoneId = m.zone.ZoneId
response.ZoneName = m.zone.ZoneName
response.BindVpcs = pvtz.BindVpcs{Vpc: m.zone.Vpcs.Vpc}
return response, nil
}
func newTestAlibabaCloudProvider(private bool) *AlibabaCloudProvider {
cfg := alibabaCloudConfig{
RegionID: "cn-beijing",
AccessKeyID: "xxxxxx",
AccessKeySecret: "xxxxxx",
VPCID: "vpc-xxxxxx",
}
//
//dnsClient, _ := alidns.NewClientWithAccessKey(
// cfg.RegionID,
// cfg.AccessKeyID,
// cfg.AccessKeySecret,
//)
//
//pvtzClient, _ := pvtz.NewClientWithAccessKey(
// "cn-hangzhou",
// cfg.AccessKeyID,
// cfg.AccessKeySecret,
//)
domainFilterTest := endpoint.NewDomainFilter([]string{"container-service.top.", "example.org"})
return &AlibabaCloudProvider{
domainFilter: domainFilterTest,
vpcID: cfg.VPCID,
dryRun: false,
dnsClient: NewMockAlibabaCloudDNSAPI(),
pvtzClient: NewMockAlibabaCloudPrivateZoneAPI(),
privateZone: private,
}
}
func TestAlibabaCloudPrivateProvider_Records(t *testing.T) {
p := newTestAlibabaCloudProvider(true)
endpoints, err := p.Records(context.Background())
if err != nil {
t.Errorf("Failed to get records: %v", err)
} else {
if len(endpoints) != 2 {
t.Errorf("Incorrect number of records: %d", len(endpoints))
}
for _, endpoint := range endpoints {
t.Logf("Endpoint for %++v", *endpoint)
}
}
}
func TestAlibabaCloudProvider_Records(t *testing.T) {
p := newTestAlibabaCloudProvider(false)
endpoints, err := p.Records(context.Background())
if err != nil {
t.Errorf("Failed to get records: %v", err)
} else {
if len(endpoints) != 2 {
t.Errorf("Incorrect number of records: %d", len(endpoints))
}
for _, endpoint := range endpoints {
t.Logf("Endpoint for %++v", *endpoint)
}
}
}
func TestAlibabaCloudProvider_ApplyChanges(t *testing.T) {
p := newTestAlibabaCloudProvider(false)
defaultTtlPlan := &endpoint.Endpoint{
DNSName: "ttl.container-service.top",
RecordType: "A",
RecordTTL: defaultAlibabaCloudRecordTTL,
Targets: endpoint.NewTargets("4.3.2.1"),
}
changes := plan.Changes{
Create: []*endpoint.Endpoint{
{
DNSName: "xyz.container-service.top",
RecordType: "A",
RecordTTL: 300,
Targets: endpoint.NewTargets("4.3.2.1"),
},
defaultTtlPlan,
},
UpdateNew: []*endpoint.Endpoint{
{
DNSName: "abc.container-service.top",
RecordType: "A",
RecordTTL: 500,
Targets: endpoint.NewTargets("1.2.3.4", "5.6.7.8"),
},
},
Delete: []*endpoint.Endpoint{
{
DNSName: "abc.container-service.top",
RecordType: "TXT",
RecordTTL: 300,
Targets: endpoint.NewTargets("\"heritage=external-dns,external-dns/owner=default\""),
},
},
}
ctx := context.Background()
p.ApplyChanges(ctx, &changes)
endpoints, err := p.Records(ctx)
if err != nil {
t.Errorf("Failed to get records: %v", err)
} else {
if len(endpoints) != 3 {
t.Errorf("Incorrect number of records: %d", len(endpoints))
}
for _, endpoint := range endpoints {
t.Logf("Endpoint for %++v", *endpoint)
}
}
for _, ep := range endpoints {
if ep.DNSName == defaultTtlPlan.DNSName {
if ep.RecordTTL != defaultTtlPlan.RecordTTL {
t.Error("default ttl execute error")
}
}
}
}
func TestAlibabaCloudProvider_Records_PrivateZone(t *testing.T) {
p := newTestAlibabaCloudProvider(true)
endpoints, err := p.Records(context.Background())
if err != nil {
t.Errorf("Failed to get records: %v", err)
} else {
if len(endpoints) != 2 {
t.Errorf("Incorrect number of records: %d", len(endpoints))
}
for _, endpoint := range endpoints {
t.Logf("Endpoint for %++v", *endpoint)
}
}
}
func TestAlibabaCloudProvider_ApplyChanges_PrivateZone(t *testing.T) {
p := newTestAlibabaCloudProvider(true)
changes := plan.Changes{
Create: []*endpoint.Endpoint{
{
DNSName: "xyz.container-service.top",
RecordType: "A",
RecordTTL: 300,
Targets: endpoint.NewTargets("4.3.2.1"),
},
},
UpdateNew: []*endpoint.Endpoint{
{
DNSName: "abc.container-service.top",
RecordType: "A",
RecordTTL: 500,
Targets: endpoint.NewTargets("1.2.3.4", "5.6.7.8"),
},
},
Delete: []*endpoint.Endpoint{
{
DNSName: "abc.container-service.top",
RecordType: "TXT",
RecordTTL: 300,
Targets: endpoint.NewTargets("\"heritage=external-dns,external-dns/owner=default\""),
},
},
}
ctx := context.Background()
p.ApplyChanges(ctx, &changes)
endpoints, err := p.Records(ctx)
if err != nil {
t.Errorf("Failed to get records: %v", err)
} else {
if len(endpoints) != 2 {
t.Errorf("Incorrect number of records: %d", len(endpoints))
}
for _, endpoint := range endpoints {
t.Logf("Endpoint for %++v", *endpoint)
}
}
}
func TestAlibabaCloudProvider_splitDNSName(t *testing.T) {
p := newTestAlibabaCloudProvider(false)
endpoint := &endpoint.Endpoint{}
endpoint.DNSName = "www.example.org"
rr, domain := p.splitDNSName(endpoint)
if rr != "www" || domain != "example.org" {
t.Errorf("Failed to splitDNSName for %s: rr=%s, domain=%s", endpoint.DNSName, rr, domain)
}
endpoint.DNSName = ".example.org"
rr, domain = p.splitDNSName(endpoint)
if rr != "@" || domain != "example.org" {
t.Errorf("Failed to splitDNSName for %s: rr=%s, domain=%s", endpoint.DNSName, rr, domain)
}
endpoint.DNSName = "www"
rr, domain = p.splitDNSName(endpoint)
if rr != "www" || domain != "" {
t.Errorf("Failed to splitDNSName for %s: rr=%s, domain=%s", endpoint.DNSName, rr, domain)
}
endpoint.DNSName = ""
rr, domain = p.splitDNSName(endpoint)
if rr != "@" || domain != "" {
t.Errorf("Failed to splitDNSName for %s: rr=%s, domain=%s", endpoint.DNSName, rr, domain)
}
endpoint.DNSName = "_30000._tcp.container-service.top"
rr, domain = p.splitDNSName(endpoint)
if rr != "_30000._tcp" || domain != "container-service.top" {
t.Errorf("Failed to splitDNSName for %s: rr=%s, domain=%s", endpoint.DNSName, rr, domain)
}
endpoint.DNSName = "container-service.top"
rr, domain = p.splitDNSName(endpoint)
if rr != "@" || domain != "container-service.top" {
t.Errorf("Failed to splitDNSName for %s: rr=%s, domain=%s", endpoint.DNSName, rr, domain)
}
endpoint.DNSName = "a.b.container-service.top"
rr, domain = p.splitDNSName(endpoint)
if rr != "a.b" || domain != "container-service.top" {
t.Errorf("Failed to splitDNSName for %s: rr=%s, domain=%s", endpoint.DNSName, rr, domain)
}
endpoint.DNSName = "a.b.c.container-service.top"
rr, domain = p.splitDNSName(endpoint)
if rr != "a.b.c" || domain != "container-service.top" {
t.Errorf("Failed to splitDNSName for %s: rr=%s, domain=%s", endpoint.DNSName, rr, domain)
}
}