mirror of
https://github.com/kubernetes-sigs/external-dns.git
synced 2025-08-06 09:36:58 +02:00
Refactor and clean up akamai provider
refactor: remove dns api logic and use dns api library enhancement: add additional args for auth credential retieval cleanup: simplify, organize processing logic test: update automation and validate
This commit is contained in:
parent
65087c4e02
commit
75429cc504
2
go.mod
2
go.mod
@ -10,7 +10,7 @@ require (
|
||||
github.com/Azure/go-autorest/autorest/adal v0.9.5
|
||||
github.com/Azure/go-autorest/autorest/azure/auth v0.5.3
|
||||
github.com/Azure/go-autorest/autorest/to v0.4.0
|
||||
github.com/akamai/AkamaiOPEN-edgegrid-golang v0.9.11
|
||||
github.com/akamai/AkamaiOPEN-edgegrid-golang v1.0.0
|
||||
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
|
||||
|
2
go.sum
2
go.sum
@ -60,6 +60,8 @@ github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4Rq
|
||||
github.com/ahmetb/gen-crd-api-reference-docs v0.1.5/go.mod h1:P/XzJ+c2+khJKNKABcm2biRwk2QAuwbLf8DlXuaL7WM=
|
||||
github.com/akamai/AkamaiOPEN-edgegrid-golang v0.9.11 h1:QGjNHMwoPYxE5NpOAc8kpd2KTY293/oFk5BWdjkza+k=
|
||||
github.com/akamai/AkamaiOPEN-edgegrid-golang v0.9.11/go.mod h1:L+HB2uBoDgi3+r1pJEJcbGwyyHhd2QXaGsKLbDwtm8Q=
|
||||
github.com/akamai/AkamaiOPEN-edgegrid-golang v1.0.0 h1:FJF58TWBaQnGqTIcziIP5/z3TTqWUn8fh26z03oZE2c=
|
||||
github.com/akamai/AkamaiOPEN-edgegrid-golang v1.0.0/go.mod h1:kX6YddBkXqqywAe8c9LyvgTCyFuZCTMF4cRPQhc3Fy8=
|
||||
github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38 h1:smF2tmSOzy2Mm+0dGI2AIUHY+w0BUc+4tn40djz7+6U=
|
||||
github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38/go.mod h1:r7bzyVFMNntcxPZXK3/+KdruV1H5KSlyVY0gc+NgInI=
|
||||
github.com/alecthomas/colour v0.1.0 h1:nOE9rJm6dsZ66RGWYSFrXw461ZIt9A6+nHgL7FRrDUk=
|
||||
|
7
main.go
7
main.go
@ -151,7 +151,7 @@ func main() {
|
||||
var p provider.Provider
|
||||
switch cfg.Provider {
|
||||
case "akamai":
|
||||
p = akamai.NewAkamaiProvider(
|
||||
p, err = akamai.NewAkamaiProvider(
|
||||
akamai.AkamaiConfig{
|
||||
DomainFilter: domainFilter,
|
||||
ZoneIDFilter: zoneIDFilter,
|
||||
@ -159,9 +159,10 @@ func main() {
|
||||
ClientToken: cfg.AkamaiClientToken,
|
||||
ClientSecret: cfg.AkamaiClientSecret,
|
||||
AccessToken: cfg.AkamaiAccessToken,
|
||||
EdgercPath: cfg.AkamaiEdgercPath,
|
||||
EdgercSection: cfg.AkamaiEdgercSection,
|
||||
DryRun: cfg.DryRun,
|
||||
},
|
||||
)
|
||||
}, nil)
|
||||
case "alibabacloud":
|
||||
p, err = alibabacloud.NewAlibabaCloudProvider(cfg.AlibabaCloudConfigFile, domainFilter, zoneIDFilter, cfg.AlibabaCloudZoneType, cfg.DryRun)
|
||||
case "aws":
|
||||
|
@ -88,6 +88,8 @@ type Config struct {
|
||||
AkamaiClientToken string
|
||||
AkamaiClientSecret string
|
||||
AkamaiAccessToken string
|
||||
AkamaiEdgercPath string
|
||||
AkamaiEdgercSection string
|
||||
InfobloxGridHost string
|
||||
InfobloxWapiPort int
|
||||
InfobloxWapiUsername string
|
||||
@ -194,6 +196,8 @@ var defaultConfig = &Config{
|
||||
AkamaiClientToken: "",
|
||||
AkamaiClientSecret: "",
|
||||
AkamaiAccessToken: "",
|
||||
AkamaiEdgercSection: "",
|
||||
AkamaiEdgercPath: "",
|
||||
InfobloxGridHost: "",
|
||||
InfobloxWapiPort: 443,
|
||||
InfobloxWapiUsername: "admin",
|
||||
@ -353,10 +357,12 @@ func (cfg *Config) ParseFlags(args []string) error {
|
||||
app.Flag("cloudflare-proxied", "When using the Cloudflare provider, specify if the proxy mode must be enabled (default: disabled)").BoolVar(&cfg.CloudflareProxied)
|
||||
app.Flag("cloudflare-zones-per-page", "When using the Cloudflare provider, specify how many zones per page listed, max. possible 50 (default: 50)").Default(strconv.Itoa(defaultConfig.CloudflareZonesPerPage)).IntVar(&cfg.CloudflareZonesPerPage)
|
||||
app.Flag("coredns-prefix", "When using the CoreDNS provider, specify the prefix name").Default(defaultConfig.CoreDNSPrefix).StringVar(&cfg.CoreDNSPrefix)
|
||||
app.Flag("akamai-serviceconsumerdomain", "When using the Akamai provider, specify the base URL (required when --provider=akamai)").Default(defaultConfig.AkamaiServiceConsumerDomain).StringVar(&cfg.AkamaiServiceConsumerDomain)
|
||||
app.Flag("akamai-client-token", "When using the Akamai provider, specify the client token (required when --provider=akamai)").Default(defaultConfig.AkamaiClientToken).StringVar(&cfg.AkamaiClientToken)
|
||||
app.Flag("akamai-client-secret", "When using the Akamai provider, specify the client secret (required when --provider=akamai)").Default(defaultConfig.AkamaiClientSecret).StringVar(&cfg.AkamaiClientSecret)
|
||||
app.Flag("akamai-access-token", "When using the Akamai provider, specify the access token (required when --provider=akamai)").Default(defaultConfig.AkamaiAccessToken).StringVar(&cfg.AkamaiAccessToken)
|
||||
app.Flag("akamai-serviceconsumerdomain", "When using the Akamai provider, specify the base URL (required when --provider=akamai and edgerc-path not specified)").Default(defaultConfig.AkamaiServiceConsumerDomain).StringVar(&cfg.AkamaiServiceConsumerDomain)
|
||||
app.Flag("akamai-client-token", "When using the Akamai provider, specify the client token (required when --provider=akamai and edgerc-path not specified)").Default(defaultConfig.AkamaiClientToken).StringVar(&cfg.AkamaiClientToken)
|
||||
app.Flag("akamai-client-secret", "When using the Akamai provider, specify the client secret (required when --provider=akamai and edgerc-path not specified)").Default(defaultConfig.AkamaiClientSecret).StringVar(&cfg.AkamaiClientSecret)
|
||||
app.Flag("akamai-access-token", "When using the Akamai provider, specify the access token (required when --provider=akamai and edgerc-path not specified)").Default(defaultConfig.AkamaiAccessToken).StringVar(&cfg.AkamaiAccessToken)
|
||||
app.Flag("akamai-edgerc-path", "When using the Akamai provider, specify the .edgerc file path. Path must be reachable form invocation environment. (required when --provider=akamai and *-token, secret serviceconsumerdomain not specified)").Default(defaultConfig.AkamaiEdgercPath).StringVar(&cfg.AkamaiEdgercPath)
|
||||
app.Flag("akamai-edgerc-section", "When using the Akamai provider, specify the .edgerc file path (Optional when edgerc-path is specified)").Default(defaultConfig.AkamaiEdgercSection).StringVar(&cfg.AkamaiEdgercSection)
|
||||
app.Flag("infoblox-grid-host", "When using the Infoblox provider, specify the Grid Manager host (required when --provider=infoblox)").Default(defaultConfig.InfobloxGridHost).StringVar(&cfg.InfobloxGridHost)
|
||||
app.Flag("infoblox-wapi-port", "When using the Infoblox provider, specify the WAPI port (default: 443)").Default(strconv.Itoa(defaultConfig.InfobloxWapiPort)).IntVar(&cfg.InfobloxWapiPort)
|
||||
app.Flag("infoblox-wapi-username", "When using the Infoblox provider, specify the WAPI username (default: admin)").Default(defaultConfig.InfobloxWapiUsername).StringVar(&cfg.InfobloxWapiUsername)
|
||||
|
@ -66,6 +66,8 @@ var (
|
||||
AkamaiClientToken: "",
|
||||
AkamaiClientSecret: "",
|
||||
AkamaiAccessToken: "",
|
||||
AkamaiEdgercPath: "",
|
||||
AkamaiEdgercSection: "",
|
||||
InfobloxGridHost: "",
|
||||
InfobloxWapiPort: 443,
|
||||
InfobloxWapiUsername: "admin",
|
||||
@ -144,6 +146,8 @@ var (
|
||||
AkamaiClientToken: "o184671d5307a388180fbf7f11dbdf46",
|
||||
AkamaiClientSecret: "o184671d5307a388180fbf7f11dbdf46",
|
||||
AkamaiAccessToken: "o184671d5307a388180fbf7f11dbdf46",
|
||||
AkamaiEdgercPath: "/home/test/.edgerc",
|
||||
AkamaiEdgercSection: "default",
|
||||
InfobloxGridHost: "127.0.0.1",
|
||||
InfobloxWapiPort: 8443,
|
||||
InfobloxWapiUsername: "infoblox",
|
||||
@ -235,6 +239,8 @@ func TestParseFlags(t *testing.T) {
|
||||
"--akamai-client-token=o184671d5307a388180fbf7f11dbdf46",
|
||||
"--akamai-client-secret=o184671d5307a388180fbf7f11dbdf46",
|
||||
"--akamai-access-token=o184671d5307a388180fbf7f11dbdf46",
|
||||
"--akamai-edgerc-path=/home/test/.edgerc",
|
||||
"--akamai-edgerc-section=default",
|
||||
"--infoblox-grid-host=127.0.0.1",
|
||||
"--infoblox-wapi-port=8443",
|
||||
"--infoblox-wapi-username=infoblox",
|
||||
@ -328,6 +334,8 @@ func TestParseFlags(t *testing.T) {
|
||||
"EXTERNAL_DNS_AKAMAI_CLIENT_TOKEN": "o184671d5307a388180fbf7f11dbdf46",
|
||||
"EXTERNAL_DNS_AKAMAI_CLIENT_SECRET": "o184671d5307a388180fbf7f11dbdf46",
|
||||
"EXTERNAL_DNS_AKAMAI_ACCESS_TOKEN": "o184671d5307a388180fbf7f11dbdf46",
|
||||
"EXTERNAL_DNS_AKAMAI_EDGERC_PATH": "/home/test/.edgerc",
|
||||
"EXTERNAL_DNS_AKAMAI_EDGERC_SECTION": "default",
|
||||
"EXTERNAL_DNS_INFOBLOX_GRID_HOST": "127.0.0.1",
|
||||
"EXTERNAL_DNS_INFOBLOX_WAPI_PORT": "8443",
|
||||
"EXTERNAL_DNS_INFOBLOX_WAPI_USERNAME": "infoblox",
|
||||
|
@ -45,16 +45,20 @@ func ValidateConfig(cfg *externaldns.Config) error {
|
||||
|
||||
// Akamai provider specific validations
|
||||
if cfg.Provider == "akamai" {
|
||||
if cfg.AkamaiServiceConsumerDomain == "" {
|
||||
edgerc := false
|
||||
if cfg.AkamaiEdgercPath != "" {
|
||||
edgerc = true
|
||||
}
|
||||
if cfg.AkamaiServiceConsumerDomain == "" && !edgerc {
|
||||
return errors.New("no Akamai ServiceConsumerDomain specified")
|
||||
}
|
||||
if cfg.AkamaiClientToken == "" {
|
||||
if cfg.AkamaiClientToken == "" && !edgerc {
|
||||
return errors.New("no Akamai client token specified")
|
||||
}
|
||||
if cfg.AkamaiClientSecret == "" {
|
||||
if cfg.AkamaiClientSecret == "" && !edgerc {
|
||||
return errors.New("no Akamai client secret specified")
|
||||
}
|
||||
if cfg.AkamaiAccessToken == "" {
|
||||
if cfg.AkamaiAccessToken == "" && !edgerc {
|
||||
return errors.New("no Akamai access token specified")
|
||||
}
|
||||
}
|
||||
|
@ -17,15 +17,13 @@ limitations under the License.
|
||||
package akamai
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
c "github.com/akamai/AkamaiOPEN-edgegrid-golang/client-v1"
|
||||
dns "github.com/akamai/AkamaiOPEN-edgegrid-golang/configdns-v2"
|
||||
"github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
@ -34,22 +32,23 @@ import (
|
||||
"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)
|
||||
const (
|
||||
// Default Record TTL
|
||||
edgeDNSRecordTTL = 600
|
||||
maxUint = ^uint(0)
|
||||
maxInt = int(maxUint >> 1)
|
||||
)
|
||||
|
||||
// edgeDNSClient is a proxy interface of the Akamai edgegrid configdns-v2 package that can be stubbed for testing.
|
||||
type AkamaiDNSService interface {
|
||||
ListZones(queryArgs dns.ZoneListQueryArgs) (*dns.ZoneListResponse, error)
|
||||
GetRecordsets(zone string, queryArgs dns.RecordsetQueryArgs) (*dns.RecordSetResponse, error)
|
||||
GetRecord(zone string, name string, recordtype string) (*dns.RecordBody, error)
|
||||
DeleteRecord(record *dns.RecordBody, zone string, recLock bool) error
|
||||
UpdateRecord(record *dns.RecordBody, zone string, recLock bool) error
|
||||
CreateRecordsets(recordsets *dns.Recordsets, zone string, recLock bool) 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
|
||||
@ -57,17 +56,25 @@ type AkamaiConfig struct {
|
||||
ClientToken string
|
||||
ClientSecret string
|
||||
AccessToken string
|
||||
EdgercPath string
|
||||
EdgercSection string
|
||||
MaxBody int
|
||||
AccountKey string
|
||||
DryRun bool
|
||||
}
|
||||
|
||||
// AkamaiProvider implements the DNS provider for Akamai.
|
||||
type AkamaiProvider struct {
|
||||
provider.BaseProvider
|
||||
// Edgedns zones to filter on
|
||||
domainFilter endpoint.DomainFilter
|
||||
// Contract Ids to filter on
|
||||
zoneIDFilter provider.ZoneIDFilter
|
||||
config edgegrid.Config
|
||||
dryRun bool
|
||||
client akamaiClient
|
||||
// Edgegrid library configuration
|
||||
config *edgegrid.Config
|
||||
dryRun bool
|
||||
// Defines client. Allows for mocking.
|
||||
client AkamaiDNSService
|
||||
}
|
||||
|
||||
type akamaiZones struct {
|
||||
@ -79,84 +86,126 @@ type akamaiZone struct {
|
||||
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,
|
||||
func NewAkamaiProvider(akamaiConfig AkamaiConfig, akaService AkamaiDNSService) (provider.Provider, error) {
|
||||
var edgeGridConfig edgegrid.Config
|
||||
|
||||
/*
|
||||
log.Debugf("Host: %s", akamaiConfig.ServiceConsumerDomain)
|
||||
log.Debugf("ClientToken: %s", akamaiConfig.ClientToken)
|
||||
log.Debugf("ClientSecret: %s", akamaiConfig.ClientSecret)
|
||||
log.Debugf("AccessToken: %s", akamaiConfig.AccessToken)
|
||||
log.Debugf("EdgePath: %s", akamaiConfig.EdgercPath)
|
||||
log.Debugf("EdgeSection: %s", akamaiConfig.EdgercSection)
|
||||
*/
|
||||
// environment overrides edgerc file but config needs to be complete
|
||||
if akamaiConfig.ServiceConsumerDomain == "" || akamaiConfig.ClientToken == "" || akamaiConfig.ClientSecret == "" || akamaiConfig.AccessToken == "" {
|
||||
// Kubernetes config incomplete or non existent. Can't mix and match.
|
||||
// Look for Akamai environment or .edgerd creds
|
||||
var err error
|
||||
edgeGridConfig, err = edgegrid.Init(akamaiConfig.EdgercPath, akamaiConfig.EdgercSection) // use default .edgerc location and section
|
||||
if err != nil {
|
||||
log.Errorf("Edgegrid Init Failed")
|
||||
return &AkamaiProvider{}, err // return empty provider for backward compatibility
|
||||
}
|
||||
edgeGridConfig.HeaderToSign = append(edgeGridConfig.HeaderToSign, "X-External-DNS")
|
||||
} else {
|
||||
// Use external-dns config
|
||||
edgeGridConfig = edgegrid.Config{
|
||||
Host: akamaiConfig.ServiceConsumerDomain,
|
||||
ClientToken: akamaiConfig.ClientToken,
|
||||
ClientSecret: akamaiConfig.ClientSecret,
|
||||
AccessToken: akamaiConfig.AccessToken,
|
||||
MaxBody: 131072, // same default val as used by Edgegrid
|
||||
HeaderToSign: []string{
|
||||
"X-External-DNS",
|
||||
},
|
||||
Debug: false,
|
||||
}
|
||||
// Check for edgegrid overrides
|
||||
if envval, ok := os.LookupEnv("AKAMAI_MAX_BODY"); ok {
|
||||
if i, err := strconv.Atoi(envval); err == nil {
|
||||
edgeGridConfig.MaxBody = i
|
||||
log.Debugf("Edgegrid maxbody set to %s", envval)
|
||||
}
|
||||
}
|
||||
if envval, ok := os.LookupEnv("AKAMAI_ACCOUNT_KEY"); ok {
|
||||
edgeGridConfig.AccountKey = envval
|
||||
log.Debugf("Edgegrid applying account key %s", envval)
|
||||
}
|
||||
if envval, ok := os.LookupEnv("AKAMAI_DEBUG"); ok {
|
||||
if dbgval, err := strconv.ParseBool(envval); err == nil {
|
||||
edgeGridConfig.Debug = dbgval
|
||||
log.Debugf("Edgegrid debug set to %s", envval)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
provider := &AkamaiProvider{
|
||||
domainFilter: akamaiConfig.DomainFilter,
|
||||
zoneIDFilter: akamaiConfig.ZoneIDFilter,
|
||||
config: edgeGridConfig,
|
||||
config: &edgeGridConfig,
|
||||
dryRun: akamaiConfig.DryRun,
|
||||
client: &akamaiOpenClient{},
|
||||
}
|
||||
return provider
|
||||
if akaService != nil {
|
||||
log.Debugf("Using STUB")
|
||||
provider.client = akaService
|
||||
} else {
|
||||
provider.client = provider
|
||||
}
|
||||
|
||||
// Init library for direct endpoint calls
|
||||
dns.Init(edgeGridConfig)
|
||||
|
||||
return provider, nil
|
||||
}
|
||||
|
||||
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
|
||||
func (p AkamaiProvider) ListZones(queryArgs dns.ZoneListQueryArgs) (*dns.ZoneListResponse, error) {
|
||||
return dns.ListZones(queryArgs)
|
||||
}
|
||||
|
||||
//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)
|
||||
func (p AkamaiProvider) GetRecordsets(zone string, queryArgs dns.RecordsetQueryArgs) (*dns.RecordSetResponse, error) {
|
||||
return dns.GetRecordsets(zone, queryArgs)
|
||||
}
|
||||
|
||||
func (p AkamaiProvider) CreateRecordsets(recordsets *dns.Recordsets, zone string, reclock bool) error {
|
||||
return recordsets.Save(zone, reclock)
|
||||
}
|
||||
|
||||
func (p AkamaiProvider) GetRecord(zone string, name string, recordtype string) (*dns.RecordBody, error) {
|
||||
return dns.GetRecord(zone, name, recordtype)
|
||||
}
|
||||
|
||||
func (p AkamaiProvider) DeleteRecord(record *dns.RecordBody, zone string, recLock bool) error {
|
||||
return record.Delete(zone, recLock)
|
||||
}
|
||||
|
||||
func (p AkamaiProvider) UpdateRecord(record *dns.RecordBody, zone string, recLock bool) error {
|
||||
return record.Update(zone, recLock)
|
||||
}
|
||||
|
||||
// Fetch zones using Edgegrid DNS v2 API
|
||||
func (p AkamaiProvider) fetchZones() (akamaiZones, error) {
|
||||
log.Debugf("Fetching Akamai Edge DNS zones")
|
||||
filteredZones := akamaiZones{Zones: make([]akamaiZone, 0)}
|
||||
queryArgs := dns.ZoneListQueryArgs{Types: "primary", ShowAll: true}
|
||||
// filter based on contractIds
|
||||
if len(p.zoneIDFilter.ZoneIDs) > 0 {
|
||||
queryArgs.ContractIds = strings.Join(p.zoneIDFilter.ZoneIDs, ",")
|
||||
}
|
||||
resp, err := p.client.ListZones(queryArgs) // don't worry about paged results
|
||||
|
||||
if err != nil {
|
||||
log.Errorf("Failed to fetch zones from Akamai")
|
||||
return zones, err
|
||||
return filteredZones, 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
|
||||
for _, zone := range resp.Zones {
|
||||
//log.Debugf("Evaluating zone: %s", zone.Zone)
|
||||
if p.domainFilter.Match(zone.Zone) || !p.domainFilter.IsConfigured() {
|
||||
filteredZones.Zones = append(filteredZones.Zones, akamaiZone{ContractID: zone.ContractId, Zone: zone.Zone})
|
||||
log.Debugf("Fetched zone: '%s' (ZoneID: %s)", zone.Zone, zone.ContractId)
|
||||
}
|
||||
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 {
|
||||
@ -168,53 +217,45 @@ func (p *AkamaiProvider) fetchZones() (zones akamaiZones, err error) {
|
||||
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()
|
||||
func (p AkamaiProvider) Records(context.Context) (endpoints []*endpoint.Endpoint, err error) {
|
||||
log.Debugf("Entering Records function")
|
||||
if p.config == nil {
|
||||
log.Errorf("Akamai provider failed initialization!")
|
||||
return endpoints, fmt.Errorf("edge dns provider is not initialized")
|
||||
}
|
||||
|
||||
zones, err := p.fetchZones() // returns a filtered set of zones
|
||||
if err != nil {
|
||||
log.Warnf("No zones to fetch endpoints from!")
|
||||
log.Warnf("Failed to identify target zones! Error: %s", err.Error())
|
||||
return endpoints, err
|
||||
}
|
||||
for _, zone := range zones.Zones {
|
||||
records, err := p.fetchRecordSet(zone.Zone)
|
||||
recordsets, err := p.client.GetRecordsets(zone.Zone, dns.RecordsetQueryArgs{})
|
||||
if err != nil {
|
||||
log.Warnf("No recordsets could be fetched for zone: '%s'!", zone.Zone)
|
||||
log.Errorf("Recordsets retrieval for zone: '%s' failed! %s", zone.Zone, err.Error())
|
||||
continue
|
||||
}
|
||||
if len(recordsets.Recordsets) == 0 {
|
||||
log.Warnf("Zone %s contains no recordsets", zone.Zone)
|
||||
}
|
||||
|
||||
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)
|
||||
for _, recordset := range recordsets.Recordsets {
|
||||
if !provider.SupportedRecordType(recordset.Type) {
|
||||
log.Debugf("Skipping endpoint DNSName: '%s' RecordType: '%s'. Record type not supported.", recordset.Name, recordset.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)
|
||||
if !p.domainFilter.Match(recordset.Name) {
|
||||
log.Debugf("Skipping endpoint. Record name %s doesn't match containing zone %s.", recordset.Name, zone)
|
||||
continue
|
||||
}
|
||||
var temp interface{} = int64(recordset.TTL)
|
||||
var ttl endpoint.TTL = endpoint.TTL(temp.(int64)) //endpoint.TTL)
|
||||
endpoints = append(endpoints, endpoint.NewEndpointWithTTL(recordset.Name,
|
||||
recordset.Type,
|
||||
ttl,
|
||||
trimTxtRdata(recordset.Rdata, recordset.Type)...))
|
||||
log.Debugf("Fetched endpoint DNSName: '%s' RecordType: '%s' Rdata: '%s')", recordset.Name, recordset.Type, recordset.Rdata)
|
||||
}
|
||||
}
|
||||
lenEndpoints := len(endpoints)
|
||||
@ -222,161 +263,247 @@ func (p *AkamaiProvider) Records(context.Context) (endpoints []*endpoint.Endpoin
|
||||
log.Warnf("No endpoints could be fetched")
|
||||
} else {
|
||||
log.Debugf("Fetched '%d' endpoints from Akamai", lenEndpoints)
|
||||
log.Debugf("Endpoints [%v]", endpoints)
|
||||
}
|
||||
|
||||
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 {
|
||||
func (p AkamaiProvider) ApplyChanges(ctx context.Context, changes *plan.Changes) error {
|
||||
log.Debugf("Entering ApplyChanges")
|
||||
|
||||
if p.config == nil {
|
||||
log.Errorf("Akamai provider failed initialization!")
|
||||
return fmt.Errorf("edge dns provider failed initialization")
|
||||
}
|
||||
|
||||
zoneNameIDMapper := provider.ZoneIDName{}
|
||||
zones, err := p.fetchZones()
|
||||
if err != nil {
|
||||
log.Warnf("No zones to fetch endpoints from!")
|
||||
return nil
|
||||
log.Errorf("Failed to fetch zones from Akamai")
|
||||
return err
|
||||
}
|
||||
|
||||
for _, z := range zones.Zones {
|
||||
zoneNameIDMapper[z.Zone] = z.Zone
|
||||
}
|
||||
log.Debugf("Processing zones: [%v]", zoneNameIDMapper)
|
||||
|
||||
_, 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)
|
||||
// Create recodsets
|
||||
log.Debugf("Create Changes requested [%v]", changes.Create)
|
||||
if err := p.createRecordsets(zoneNameIDMapper, changes.Create); err != nil {
|
||||
return err
|
||||
}
|
||||
// Delete recordsets
|
||||
log.Debugf("Delete Changes requested [%v]", changes.Delete)
|
||||
if err := p.deleteRecordsets(zoneNameIDMapper, changes.Delete); err != nil {
|
||||
return err
|
||||
}
|
||||
// Update recordsets
|
||||
log.Debugf("Update Changes requested [%v]", changes.UpdateNew)
|
||||
if err := p.updateNewRecordsets(zoneNameIDMapper, changes.UpdateNew); err != nil {
|
||||
return err
|
||||
}
|
||||
// Check that all old endpoints were accounted for
|
||||
revRecs := changes.Delete
|
||||
revRecs = append(revRecs, changes.UpdateNew...)
|
||||
for _, rec := range changes.UpdateOld {
|
||||
found := false
|
||||
for _, r := range revRecs {
|
||||
if rec.DNSName == r.DNSName {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_, 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)
|
||||
if !found {
|
||||
log.Warnf("UpdateOld endpoint '%s' is not accounted for in UpdateNew|Delete endpoint list", rec.DNSName)
|
||||
}
|
||||
}
|
||||
|
||||
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{
|
||||
// Create DNS Recordset
|
||||
func newAkamaiRecordset(dnsName, recordType string, ttl int, targets []string) dns.Recordset {
|
||||
return dns.Recordset{
|
||||
Name: strings.TrimSuffix(dnsName, "."),
|
||||
Rdata: cleanTargets,
|
||||
Rdata: targets,
|
||||
Type: recordType,
|
||||
TTL: 300,
|
||||
TTL: ttl,
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
// cleanTargets preps recordset rdata if necessary for EdgeDNS
|
||||
func cleanTargets(rtype string, targets ...string) []string {
|
||||
log.Debugf("Targets to clean: [%v]", targets)
|
||||
//var targets []string = tgts
|
||||
if rtype == "CNAME" || rtype == "SRV" {
|
||||
for idx, target := range targets {
|
||||
targets[idx] = strings.TrimSuffix(target, ".")
|
||||
}
|
||||
} else if rtype == "TXT" {
|
||||
for idx, target := range targets {
|
||||
log.Debugf("TXT data to clean: [%s]", target)
|
||||
// need to embed text data in quotes. Make sure not piling on
|
||||
target = strings.Trim(target, "\"")
|
||||
// bug in DNS API with embedded quotes.
|
||||
if strings.Contains(target, "owner") && strings.Contains(target, "\"") {
|
||||
target = strings.ReplaceAll(target, "\"", "`")
|
||||
}
|
||||
targets[idx] = "\"" + target + "\""
|
||||
}
|
||||
}
|
||||
log.Debugf("Clean targets: [%v]", targets)
|
||||
|
||||
return targets
|
||||
}
|
||||
|
||||
// trimTxtRdata removes surrounding quotes for received TXT rdata
|
||||
func trimTxtRdata(rdata []string, rtype string) []string {
|
||||
if rtype == "TXT" {
|
||||
for idx, d := range rdata {
|
||||
//rdata[idx] = strings.Trim(d, "\"")
|
||||
if strings.Contains(d, "`") {
|
||||
rdata[idx] = strings.ReplaceAll(d, "`", "\"")
|
||||
}
|
||||
}
|
||||
}
|
||||
log.Debugf("Trimmed data: [%v]", rdata)
|
||||
|
||||
return rdata
|
||||
}
|
||||
|
||||
func ttlAsInt(src endpoint.TTL) int {
|
||||
var temp interface{} = int64(src)
|
||||
var temp64 = temp.(int64)
|
||||
var ttl int = edgeDNSRecordTTL // int
|
||||
if temp64 > 0 && temp64 <= int64(maxInt) {
|
||||
ttl = int(temp64)
|
||||
}
|
||||
|
||||
return ttl
|
||||
}
|
||||
|
||||
// Create Endpoint Recordsets
|
||||
func (p AkamaiProvider) createRecordsets(zoneNameIDMapper provider.ZoneIDName, endpoints []*endpoint.Endpoint) error {
|
||||
if len(endpoints) == 0 {
|
||||
log.Info("No endpoints to create")
|
||||
return nil
|
||||
}
|
||||
|
||||
endpointsByZone := edgeChangesByZone(zoneNameIDMapper, endpoints)
|
||||
|
||||
// create all recordsets by zone
|
||||
for zone, endpoints := range endpointsByZone {
|
||||
recordsets := &dns.Recordsets{Recordsets: make([]dns.Recordset, 0)}
|
||||
for _, endpoint := range endpoints {
|
||||
newrec := newAkamaiRecordset(endpoint.DNSName,
|
||||
endpoint.RecordType,
|
||||
ttlAsInt(endpoint.RecordTTL),
|
||||
cleanTargets(endpoint.RecordType, endpoint.Targets...))
|
||||
logfields := log.Fields{
|
||||
"record": newrec.Name,
|
||||
"type": newrec.Type,
|
||||
"ttl": newrec.TTL,
|
||||
"target": fmt.Sprintf("%v", newrec.Rdata),
|
||||
"zone": zone,
|
||||
}
|
||||
log.WithFields(logfields).Info("Creating recordsets")
|
||||
recordsets.Recordsets = append(recordsets.Recordsets, newrec)
|
||||
}
|
||||
|
||||
if p.dryRun {
|
||||
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)
|
||||
// Create recordsets all at once
|
||||
err := p.client.CreateRecordsets(recordsets, zone, true)
|
||||
if err != nil {
|
||||
log.Errorf("Failed to create endpoints for DNS zone %s. Error: %s", zone, err.Error())
|
||||
return err
|
||||
}
|
||||
}
|
||||
return created, failed
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *AkamaiProvider) deleteRecords(zoneNameIDMapper provider.ZoneIDName, endpoints []*endpoint.Endpoint) (deleted []*endpoint.Endpoint, failed []*endpoint.Endpoint) {
|
||||
func (p AkamaiProvider) deleteRecordsets(zoneNameIDMapper provider.ZoneIDName, endpoints []*endpoint.Endpoint) error {
|
||||
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)
|
||||
zoneName, _ := zoneNameIDMapper.FindZone(endpoint.DNSName)
|
||||
if zoneName == "" {
|
||||
log.Debugf("Skipping Akamai Edge DNS endpoint deletion: '%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)
|
||||
log.Infof("Akamai Edge DNS recordset deletion- 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)
|
||||
if p.dryRun {
|
||||
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
|
||||
recName := strings.TrimSuffix(endpoint.DNSName, ".")
|
||||
rec, err := p.client.GetRecord(zoneName, recName, endpoint.RecordType)
|
||||
if err != nil {
|
||||
// error not found?
|
||||
if _, ok := err.(*dns.RecordError); !ok {
|
||||
return fmt.Errorf("endpoint deletion. record validation failed. error: %s", err.Error())
|
||||
}
|
||||
|
||||
_, 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)
|
||||
log.Infof("Endpoint deletion. Record doesn't exist. Name: %s, Type: %s", recName, endpoint.RecordType)
|
||||
continue
|
||||
}
|
||||
if err := p.client.DeleteRecord(rec, zoneName, true); err != nil {
|
||||
log.Errorf("edge dns recordset deletion failed. error: %s", err.Error())
|
||||
return err
|
||||
}
|
||||
}
|
||||
return updated, failed
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Update endpoint recordsets
|
||||
func (p AkamaiProvider) updateNewRecordsets(zoneNameIDMapper provider.ZoneIDName, endpoints []*endpoint.Endpoint) error {
|
||||
for _, endpoint := range endpoints {
|
||||
zoneName, _ := zoneNameIDMapper.FindZone(endpoint.DNSName)
|
||||
if zoneName == "" {
|
||||
log.Debugf("Skipping Akamai Edge DNS endpoint update: '%s' type: '%s', it does not match against Domain filters", endpoint.DNSName, endpoint.RecordType)
|
||||
continue
|
||||
}
|
||||
log.Infof("Akamai Edge DNS recordset update - Zone: '%s', DNSName: '%s', RecordType: '%s', Targets: '%+v'", zoneName, endpoint.DNSName, endpoint.RecordType, endpoint.Targets)
|
||||
|
||||
if p.dryRun {
|
||||
continue
|
||||
}
|
||||
|
||||
recName := strings.TrimSuffix(endpoint.DNSName, ".")
|
||||
rec, err := p.client.GetRecord(zoneName, recName, endpoint.RecordType)
|
||||
if err != nil {
|
||||
log.Errorf("Endpoint update. Record validation failed. Error: %s", err.Error())
|
||||
return err
|
||||
}
|
||||
rec.TTL = ttlAsInt(endpoint.RecordTTL)
|
||||
rec.Target = cleanTargets(endpoint.RecordType, endpoint.Targets...)
|
||||
if err := p.client.UpdateRecord(rec, zoneName, true); err != nil {
|
||||
log.Errorf("Akamai Edge DNS recordset update failed. Error: %s", err.Error())
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// edgeChangesByZone separates a multi-zone change into a single change per zone.
|
||||
func edgeChangesByZone(zoneMap provider.ZoneIDName, endpoints []*endpoint.Endpoint) map[string][]*endpoint.Endpoint {
|
||||
createsByZone := make(map[string][]*endpoint.Endpoint, len(zoneMap))
|
||||
for _, z := range zoneMap {
|
||||
createsByZone[z] = make([]*endpoint.Endpoint, 0)
|
||||
}
|
||||
for _, ep := range endpoints {
|
||||
zone, _ := zoneMap.FindZone(ep.DNSName)
|
||||
if zone != "" {
|
||||
createsByZone[zone] = append(createsByZone[zone], ep)
|
||||
continue
|
||||
}
|
||||
log.Debugf("Skipping Akamai Edge DNS creation of endpoint: '%s' type: '%s', it does not match against Domain filters", ep.DNSName, ep.RecordType)
|
||||
}
|
||||
|
||||
return createsByZone
|
||||
}
|
||||
|
@ -17,148 +17,208 @@ limitations under the License.
|
||||
package akamai
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"testing"
|
||||
|
||||
"github.com/akamai/AkamaiOPEN-edgegrid-golang/edgegrid"
|
||||
dns "github.com/akamai/AkamaiOPEN-edgegrid-golang/configdns-v2"
|
||||
"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
|
||||
type edgednsStubData struct {
|
||||
objType string // zone, record, recordsets
|
||||
output []interface{}
|
||||
updateRecords []interface{}
|
||||
createRecords []interface{}
|
||||
}
|
||||
|
||||
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
|
||||
type edgednsStub struct {
|
||||
stubData map[string]edgednsStubData
|
||||
}
|
||||
|
||||
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 }"
|
||||
func newStub() *edgednsStub {
|
||||
return &edgednsStub{
|
||||
stubData: make(map[string]edgednsStubData),
|
||||
}
|
||||
w := httptest.NewRecorder()
|
||||
err := handler(w, req)
|
||||
resp := w.Result()
|
||||
}
|
||||
|
||||
if err == true {
|
||||
resp.StatusCode = 400
|
||||
func createAkamaiStubProvider(stub *edgednsStub, domfilter endpoint.DomainFilter, idfilter provider.ZoneIDFilter) (*AkamaiProvider, error) {
|
||||
|
||||
akamaiConfig := AkamaiConfig{
|
||||
DomainFilter: domfilter,
|
||||
ZoneIDFilter: idfilter,
|
||||
ServiceConsumerDomain: "testzone.com",
|
||||
ClientToken: "test_token",
|
||||
ClientSecret: "test_client_secret",
|
||||
AccessToken: "test_access_token",
|
||||
}
|
||||
|
||||
prov, err := NewAkamaiProvider(akamaiConfig, stub)
|
||||
aprov := prov.(*AkamaiProvider)
|
||||
return aprov, err
|
||||
}
|
||||
|
||||
func (r *edgednsStub) createStubDataEntry(objtype string) {
|
||||
|
||||
log.Debugf("Creating stub data entry")
|
||||
if _, exists := r.stubData[objtype]; !exists {
|
||||
r.stubData[objtype] = edgednsStubData{objType: objtype}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (r *edgednsStub) setOutput(objtype string, output []interface{}) {
|
||||
|
||||
log.Debugf("Setting output to %v", output)
|
||||
r.createStubDataEntry(objtype)
|
||||
stubdata := r.stubData[objtype]
|
||||
stubdata.output = output
|
||||
r.stubData[objtype] = stubdata
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (r *edgednsStub) setUpdateRecords(objtype string, records []interface{}) {
|
||||
|
||||
log.Debugf("Setting updaterecords to %v", records)
|
||||
r.createStubDataEntry(objtype)
|
||||
stubdata := r.stubData[objtype]
|
||||
stubdata.updateRecords = records
|
||||
r.stubData[objtype] = stubdata
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (r *edgednsStub) setCreateRecords(objtype string, records []interface{}) {
|
||||
|
||||
log.Debugf("Setting createrecords to %v", records)
|
||||
r.createStubDataEntry(objtype)
|
||||
stubdata := r.stubData[objtype]
|
||||
stubdata.createRecords = records
|
||||
r.stubData[objtype] = stubdata
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (r *edgednsStub) ListZones(queryArgs dns.ZoneListQueryArgs) (*dns.ZoneListResponse, error) {
|
||||
|
||||
log.Debugf("Entering ListZones")
|
||||
// Ignore Metadata`
|
||||
resp := &dns.ZoneListResponse{}
|
||||
zones := make([]*dns.ZoneResponse, 0)
|
||||
for _, zname := range r.stubData["zone"].output {
|
||||
log.Debugf("Processing output: %v", zname)
|
||||
zn := &dns.ZoneResponse{Zone: zname.(string), ContractId: "contract"}
|
||||
log.Debugf("Created Zone Object: %v", zn)
|
||||
zones = append(zones, zn)
|
||||
}
|
||||
resp.Zones = zones
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (r *edgednsStub) GetRecordsets(zone string, queryArgs dns.RecordsetQueryArgs) (*dns.RecordSetResponse, error) {
|
||||
|
||||
log.Debugf("Entering GetRecordsets")
|
||||
// Ignore Metadata`
|
||||
|
||||
resp := &dns.RecordSetResponse{}
|
||||
sets := make([]dns.Recordset, 0)
|
||||
for _, rec := range r.stubData["recordset"].output {
|
||||
rset := rec.(dns.Recordset)
|
||||
sets = append(sets, rset)
|
||||
}
|
||||
resp.Recordsets = sets
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func TestRequestError(t *testing.T) {
|
||||
config := AkamaiConfig{}
|
||||
func (r *edgednsStub) CreateRecordsets(recordsets *dns.Recordsets, zone string, reclock bool) error {
|
||||
|
||||
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)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *edgednsStub) GetRecord(zone string, name string, record_type string) (*dns.RecordBody, error) {
|
||||
|
||||
resp := &dns.RecordBody{}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (r *edgednsStub) DeleteRecord(record *dns.RecordBody, zone string, recLock bool) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *edgednsStub) UpdateRecord(record *dns.RecordBody, zone string, recLock bool) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Test FetchZones
|
||||
func TestFetchZonesZoneIDFilter(t *testing.T) {
|
||||
config := AkamaiConfig{
|
||||
ZoneIDFilter: provider.NewZoneIDFilter([]string{"Test"}),
|
||||
}
|
||||
|
||||
client := &mockAkamaiClient{}
|
||||
c := NewAkamaiProvider(config)
|
||||
c.client = client
|
||||
stub := newStub()
|
||||
domfilter := endpoint.DomainFilter{}
|
||||
idfilter := provider.NewZoneIDFilter([]string{"Test"})
|
||||
c, err := createAkamaiStubProvider(stub, domfilter, idfilter)
|
||||
assert.Nil(t, err)
|
||||
stub.setOutput("zone", []interface{}{"test1.testzone.com", "test2.testzone.com"})
|
||||
|
||||
x, _ := c.fetchZones()
|
||||
y, _ := json.Marshal(x)
|
||||
if assert.NotNil(t, y) {
|
||||
assert.Equal(t, "{\"zones\":[{\"contractId\":\"Test\",\"zone\":\"example.com\"}]}", string(y))
|
||||
assert.Equal(t, "{\"zones\":[{\"contractId\":\"contract\",\"zone\":\"test1.testzone.com\"},{\"contractId\":\"contract\",\"zone\":\"test2.testzone.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
|
||||
stub := newStub()
|
||||
domfilter := endpoint.NewDomainFilter([]string{"Nonexistent"})
|
||||
idfilter := provider.NewZoneIDFilter([]string{"Nonexistent"})
|
||||
c, err := createAkamaiStubProvider(stub, domfilter, idfilter)
|
||||
assert.Nil(t, err)
|
||||
stub.setOutput("zone", []interface{}{})
|
||||
|
||||
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))
|
||||
assert.Equal(t, "{\"zones\":[]}", string(y))
|
||||
}
|
||||
}
|
||||
|
||||
// TestAkamaiRecords tests record endpoint
|
||||
func TestAkamaiRecords(t *testing.T) {
|
||||
config := AkamaiConfig{}
|
||||
|
||||
client := &mockAkamaiClient{}
|
||||
c := NewAkamaiProvider(config)
|
||||
c.client = client
|
||||
|
||||
stub := newStub()
|
||||
domfilter := endpoint.DomainFilter{}
|
||||
idfilter := provider.ZoneIDFilter{}
|
||||
c, err := createAkamaiStubProvider(stub, domfilter, idfilter)
|
||||
assert.Nil(t, err)
|
||||
stub.setOutput("zone", []interface{}{"test1.testzone.com"})
|
||||
recordsets := make([]interface{}, 0)
|
||||
recordsets = append(recordsets, dns.Recordset{
|
||||
Name: "www.example.com",
|
||||
Type: endpoint.RecordTypeA,
|
||||
Rdata: []string{"10.0.0.2", "10.0.0.3"},
|
||||
})
|
||||
recordsets = append(recordsets, dns.Recordset{
|
||||
Name: "www.example.com",
|
||||
Type: endpoint.RecordTypeTXT,
|
||||
Rdata: []string{"heritage=external-dns,external-dns/owner=default"},
|
||||
})
|
||||
recordsets = append(recordsets, dns.Recordset{
|
||||
Name: "www.exclude.me",
|
||||
Type: endpoint.RecordTypeA,
|
||||
Rdata: []string{"192.168.0.1", "192.168.0.2"},
|
||||
})
|
||||
stub.setOutput("recordset", recordsets)
|
||||
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"))
|
||||
@ -170,29 +230,43 @@ func TestAkamaiRecords(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
func TestAkamaiRecordsEmpty(t *testing.T) {
|
||||
config := AkamaiConfig{
|
||||
ZoneIDFilter: provider.NewZoneIDFilter([]string{"Nonexistent"}),
|
||||
}
|
||||
|
||||
client := &mockAkamaiClient{}
|
||||
c := NewAkamaiProvider(config)
|
||||
c.client = client
|
||||
stub := newStub()
|
||||
domfilter := endpoint.DomainFilter{}
|
||||
idfilter := provider.NewZoneIDFilter([]string{"Nonexistent"})
|
||||
c, err := createAkamaiStubProvider(stub, domfilter, idfilter)
|
||||
assert.Nil(t, err)
|
||||
stub.setOutput("zone", []interface{}{"test1.testzone.com"})
|
||||
recordsets := make([]interface{}, 0)
|
||||
stub.setOutput("recordset", recordsets)
|
||||
|
||||
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
|
||||
|
||||
stub := newStub()
|
||||
domfilter := endpoint.NewDomainFilter([]string{"www.exclude.me"})
|
||||
idfilter := provider.ZoneIDFilter{}
|
||||
c, err := createAkamaiStubProvider(stub, domfilter, idfilter)
|
||||
assert.Nil(t, err)
|
||||
stub.setOutput("zone", []interface{}{"www.exclude.me"})
|
||||
recordsets := make([]interface{}, 0)
|
||||
recordsets = append(recordsets, dns.Recordset{
|
||||
Name: "www.example.com",
|
||||
Type: endpoint.RecordTypeA,
|
||||
Rdata: []string{"10.0.0.2", "10.0.0.3"},
|
||||
})
|
||||
recordsets = append(recordsets, dns.Recordset{
|
||||
Name: "www.exclude.me",
|
||||
Type: endpoint.RecordTypeA,
|
||||
Rdata: []string{"192.168.0.1", "192.168.0.2"},
|
||||
})
|
||||
stub.setOutput("recordset", recordsets)
|
||||
endpoints := make([]*endpoint.Endpoint, 0)
|
||||
endpoints = append(endpoints, endpoint.NewEndpoint("www.exclude.me", endpoint.RecordTypeA, "192.168.0.1", "192.168.0.2"))
|
||||
|
||||
@ -202,32 +276,32 @@ func TestAkamaiRecordsFilters(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestCreateRecords tests create function
|
||||
// (p AkamaiProvider) createRecordsets(zoneNameIDMapper provider.ZoneIDName, endpoints []*endpoint.Endpoint) error
|
||||
func TestCreateRecords(t *testing.T) {
|
||||
config := AkamaiConfig{}
|
||||
|
||||
client := &mockAkamaiClient{}
|
||||
c := NewAkamaiProvider(config)
|
||||
c.client = client
|
||||
stub := newStub()
|
||||
domfilter := endpoint.DomainFilter{}
|
||||
idfilter := provider.ZoneIDFilter{}
|
||||
c, err := createAkamaiStubProvider(stub, domfilter, idfilter)
|
||||
assert.Nil(t, err)
|
||||
|
||||
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)
|
||||
}
|
||||
err = c.createRecordsets(zoneNameIDMapper, endpoints)
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
|
||||
func TestCreateRecordsDomainFilter(t *testing.T) {
|
||||
config := AkamaiConfig{
|
||||
DomainFilter: endpoint.NewDomainFilter([]string{"example.com"}),
|
||||
}
|
||||
|
||||
client := &mockAkamaiClient{}
|
||||
c := NewAkamaiProvider(config)
|
||||
c.client = client
|
||||
stub := newStub()
|
||||
domfilter := endpoint.DomainFilter{}
|
||||
idfilter := provider.ZoneIDFilter{}
|
||||
c, err := createAkamaiStubProvider(stub, domfilter, idfilter)
|
||||
assert.Nil(t, err)
|
||||
|
||||
zoneNameIDMapper := provider.ZoneIDName{"example.com": "example.com"}
|
||||
endpoints := make([]*endpoint.Endpoint, 0)
|
||||
@ -235,38 +309,36 @@ func TestCreateRecordsDomainFilter(t *testing.T) {
|
||||
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)
|
||||
}
|
||||
err = c.createRecordsets(zoneNameIDMapper, exclude)
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
|
||||
// TestDeleteRecords validate delete
|
||||
func TestDeleteRecords(t *testing.T) {
|
||||
config := AkamaiConfig{}
|
||||
|
||||
client := &mockAkamaiClient{}
|
||||
c := NewAkamaiProvider(config)
|
||||
c.client = client
|
||||
stub := newStub()
|
||||
domfilter := endpoint.DomainFilter{}
|
||||
idfilter := provider.ZoneIDFilter{}
|
||||
c, err := createAkamaiStubProvider(stub, domfilter, idfilter)
|
||||
assert.Nil(t, err)
|
||||
|
||||
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)
|
||||
}
|
||||
err = c.deleteRecordsets(zoneNameIDMapper, endpoints)
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
|
||||
//
|
||||
func TestDeleteRecordsDomainFilter(t *testing.T) {
|
||||
config := AkamaiConfig{
|
||||
DomainFilter: endpoint.NewDomainFilter([]string{"example.com"}),
|
||||
}
|
||||
|
||||
client := &mockAkamaiClient{}
|
||||
c := NewAkamaiProvider(config)
|
||||
c.client = client
|
||||
stub := newStub()
|
||||
domfilter := endpoint.NewDomainFilter([]string{"example.com"})
|
||||
idfilter := provider.ZoneIDFilter{}
|
||||
c, err := createAkamaiStubProvider(stub, domfilter, idfilter)
|
||||
assert.Nil(t, err)
|
||||
|
||||
zoneNameIDMapper := provider.ZoneIDName{"example.com": "example.com"}
|
||||
endpoints := make([]*endpoint.Endpoint, 0)
|
||||
@ -274,38 +346,36 @@ func TestDeleteRecordsDomainFilter(t *testing.T) {
|
||||
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)
|
||||
}
|
||||
err = c.deleteRecordsets(zoneNameIDMapper, exclude)
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
|
||||
// Test record update func
|
||||
func TestUpdateRecords(t *testing.T) {
|
||||
config := AkamaiConfig{}
|
||||
|
||||
client := &mockAkamaiClient{}
|
||||
c := NewAkamaiProvider(config)
|
||||
c.client = client
|
||||
stub := newStub()
|
||||
domfilter := endpoint.DomainFilter{}
|
||||
idfilter := provider.ZoneIDFilter{}
|
||||
c, err := createAkamaiStubProvider(stub, domfilter, idfilter)
|
||||
assert.Nil(t, err)
|
||||
|
||||
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)
|
||||
}
|
||||
err = c.updateNewRecordsets(zoneNameIDMapper, endpoints)
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
|
||||
//
|
||||
func TestUpdateRecordsDomainFilter(t *testing.T) {
|
||||
config := AkamaiConfig{
|
||||
DomainFilter: endpoint.NewDomainFilter([]string{"example.com"}),
|
||||
}
|
||||
|
||||
client := &mockAkamaiClient{}
|
||||
c := NewAkamaiProvider(config)
|
||||
c.client = client
|
||||
stub := newStub()
|
||||
domfilter := endpoint.NewDomainFilter([]string{"example.com"})
|
||||
idfilter := provider.ZoneIDFilter{}
|
||||
c, err := createAkamaiStubProvider(stub, domfilter, idfilter)
|
||||
assert.Nil(t, err)
|
||||
|
||||
zoneNameIDMapper := provider.ZoneIDName{"example.com": "example.com"}
|
||||
endpoints := make([]*endpoint.Endpoint, 0)
|
||||
@ -313,19 +383,19 @@ func TestUpdateRecordsDomainFilter(t *testing.T) {
|
||||
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)
|
||||
}
|
||||
err = c.updateNewRecordsets(zoneNameIDMapper, exclude)
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
|
||||
func TestAkamaiApplyChanges(t *testing.T) {
|
||||
config := AkamaiConfig{}
|
||||
|
||||
client := &mockAkamaiClient{}
|
||||
c := NewAkamaiProvider(config)
|
||||
c.client = client
|
||||
stub := newStub()
|
||||
domfilter := endpoint.NewDomainFilter([]string{"example.com"})
|
||||
idfilter := provider.ZoneIDFilter{}
|
||||
c, err := createAkamaiStubProvider(stub, domfilter, idfilter)
|
||||
assert.Nil(t, err)
|
||||
|
||||
stub.setOutput("zone", []interface{}{"example.com"})
|
||||
changes := &plan.Changes{}
|
||||
changes.Create = []*endpoint.Endpoint{
|
||||
{DNSName: "www.example.com", RecordType: "A", Targets: endpoint.Targets{"target"}, RecordTTL: 300},
|
||||
|
Loading…
Reference in New Issue
Block a user