mirror of
https://github.com/kubernetes-sigs/external-dns.git
synced 2025-08-06 09:36:58 +02:00
Added new provider: Akamai FastDNS
This commit is contained in:
parent
4be51a9445
commit
3d821d74ce
2
go.mod
2
go.mod
@ -9,6 +9,7 @@ require (
|
|||||||
github.com/Azure/go-autorest/autorest/adal v0.6.0
|
github.com/Azure/go-autorest/autorest/adal v0.6.0
|
||||||
github.com/Azure/go-autorest/autorest/azure/auth v0.0.0-00010101000000-000000000000
|
github.com/Azure/go-autorest/autorest/azure/auth v0.0.0-00010101000000-000000000000
|
||||||
github.com/Azure/go-autorest/autorest/to v0.3.0
|
github.com/Azure/go-autorest/autorest/to v0.3.0
|
||||||
|
github.com/akamai/AkamaiOPEN-edgegrid-golang v0.9.5
|
||||||
github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38 // indirect
|
github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38 // indirect
|
||||||
github.com/alecthomas/colour v0.1.0 // indirect
|
github.com/alecthomas/colour v0.1.0 // indirect
|
||||||
github.com/alecthomas/kingpin v2.2.5+incompatible
|
github.com/alecthomas/kingpin v2.2.5+incompatible
|
||||||
@ -64,6 +65,7 @@ replace (
|
|||||||
github.com/Azure/go-autorest/autorest/adal => github.com/Azure/go-autorest/autorest/adal v0.6.0
|
github.com/Azure/go-autorest/autorest/adal => github.com/Azure/go-autorest/autorest/adal v0.6.0
|
||||||
github.com/Azure/go-autorest/autorest/azure/auth => github.com/Azure/go-autorest/autorest/azure/auth v0.3.0
|
github.com/Azure/go-autorest/autorest/azure/auth => github.com/Azure/go-autorest/autorest/azure/auth v0.3.0
|
||||||
github.com/golang/glog => github.com/kubermatic/glog-logrus v0.0.0-20180829085450-3fa5b9870d1d
|
github.com/golang/glog => github.com/kubermatic/glog-logrus v0.0.0-20180829085450-3fa5b9870d1d
|
||||||
|
github.com/h2non/gock => gopkg.in/h2non/gock.v1 v1.0.14
|
||||||
istio.io/api => istio.io/api v0.0.0-20190820204432-483f2547d882
|
istio.io/api => istio.io/api v0.0.0-20190820204432-483f2547d882
|
||||||
istio.io/istio => istio.io/istio v0.0.0-20190911205955-c2bd59595ce6
|
istio.io/istio => istio.io/istio v0.0.0-20190911205955-c2bd59595ce6
|
||||||
k8s.io/api => k8s.io/api v0.0.0-20190817221950-ebce17126a01
|
k8s.io/api => k8s.io/api v0.0.0-20190817221950-ebce17126a01
|
||||||
|
12
go.sum
12
go.sum
@ -60,6 +60,8 @@ github.com/SAP/go-hdb v0.14.1/go.mod h1:7fdQLVC2lER3urZLjZCm0AuMQfApof92n3aylBPE
|
|||||||
github.com/SermoDigital/jose v0.9.1/go.mod h1:ARgCUhI1MHQH+ONky/PAtmVHQrP5JlGY0F3poXOp/fA=
|
github.com/SermoDigital/jose v0.9.1/go.mod h1:ARgCUhI1MHQH+ONky/PAtmVHQrP5JlGY0F3poXOp/fA=
|
||||||
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
|
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
|
||||||
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
|
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
|
||||||
|
github.com/akamai/AkamaiOPEN-edgegrid-golang v0.9.5 h1:6/ofsc2djpS+bsyOG10cDJI1ftigCiulAfIZpxSua6k=
|
||||||
|
github.com/akamai/AkamaiOPEN-edgegrid-golang v0.9.5/go.mod h1:L3YOfsK9Dzvjxj1/Q5OG58SDCGGOwtzgi734Kpdc03c=
|
||||||
github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38 h1:smF2tmSOzy2Mm+0dGI2AIUHY+w0BUc+4tn40djz7+6U=
|
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/assert v0.0.0-20170929043011-405dbfeb8e38/go.mod h1:r7bzyVFMNntcxPZXK3/+KdruV1H5KSlyVY0gc+NgInI=
|
||||||
github.com/alecthomas/colour v0.1.0 h1:nOE9rJm6dsZ66RGWYSFrXw461ZIt9A6+nHgL7FRrDUk=
|
github.com/alecthomas/colour v0.1.0 h1:nOE9rJm6dsZ66RGWYSFrXw461ZIt9A6+nHgL7FRrDUk=
|
||||||
@ -192,6 +194,8 @@ github.com/garyburd/redigo v1.6.0/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05
|
|||||||
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
|
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
|
||||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||||
github.com/go-ini/ini v1.33.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
|
github.com/go-ini/ini v1.33.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
|
||||||
|
github.com/go-ini/ini v1.44.0 h1:8+SRbfpRFlIunpSum4BEf1ClTtVjOgKzgBv9pHFkI6w=
|
||||||
|
github.com/go-ini/ini v1.44.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
|
||||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||||
@ -292,6 +296,7 @@ github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgf
|
|||||||
github.com/grpc-ecosystem/grpc-gateway v1.8.5 h1:2+KSC78XiO6Qy0hIjfc1OD9H+hsaJdJlb8Kqsd41CTE=
|
github.com/grpc-ecosystem/grpc-gateway v1.8.5 h1:2+KSC78XiO6Qy0hIjfc1OD9H+hsaJdJlb8Kqsd41CTE=
|
||||||
github.com/grpc-ecosystem/grpc-gateway v1.8.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
github.com/grpc-ecosystem/grpc-gateway v1.8.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||||
github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20171214222146-0e7658f8ee99/go.mod h1:6iZfnjpejD4L/4DwD7NryNaJyCQdzwWwH2MWhCA90Kw=
|
github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20171214222146-0e7658f8ee99/go.mod h1:6iZfnjpejD4L/4DwD7NryNaJyCQdzwWwH2MWhCA90Kw=
|
||||||
|
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI=
|
||||||
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4=
|
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4=
|
||||||
github.com/hashicorp/consul v1.3.0/go.mod h1:mFrjN1mfidgJfYP1xrJCF+AfRhr6Eaqhb2+sfyn/OOI=
|
github.com/hashicorp/consul v1.3.0/go.mod h1:mFrjN1mfidgJfYP1xrJCF+AfRhr6Eaqhb2+sfyn/OOI=
|
||||||
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
|
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
|
||||||
@ -413,6 +418,7 @@ github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3Rllmb
|
|||||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||||
github.com/natefinch/lumberjack v2.0.0+incompatible h1:4QJd3OLAMgj7ph+yZTuX13Ld4UpgHp07nNdFX7mqFfM=
|
github.com/natefinch/lumberjack v2.0.0+incompatible h1:4QJd3OLAMgj7ph+yZTuX13Ld4UpgHp07nNdFX7mqFfM=
|
||||||
github.com/natefinch/lumberjack v2.0.0+incompatible/go.mod h1:Wi9p2TTF5DG5oU+6YfsmYQpsTIOm0B1VNzQg9Mw6nPk=
|
github.com/natefinch/lumberjack v2.0.0+incompatible/go.mod h1:Wi9p2TTF5DG5oU+6YfsmYQpsTIOm0B1VNzQg9Mw6nPk=
|
||||||
|
github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms=
|
||||||
github.com/nesv/go-dynect v0.6.0 h1:Ow/DiSm4LAISwnFku/FITSQHnU6pBvhQMsUE5Gu6Oq4=
|
github.com/nesv/go-dynect v0.6.0 h1:Ow/DiSm4LAISwnFku/FITSQHnU6pBvhQMsUE5Gu6Oq4=
|
||||||
github.com/nesv/go-dynect v0.6.0/go.mod h1:GHRBRKzTwjAMhosHJQq/KrZaFkXIFyJ5zRE7thGXXrs=
|
github.com/nesv/go-dynect v0.6.0/go.mod h1:GHRBRKzTwjAMhosHJQq/KrZaFkXIFyJ5zRE7thGXXrs=
|
||||||
github.com/nic-at/rc0go v1.1.0 h1:k6/Bru/npTjmCSFw65ulYRw/b3ycIS30t6/YM4r42V4=
|
github.com/nic-at/rc0go v1.1.0 h1:k6/Bru/npTjmCSFw65ulYRw/b3ycIS30t6/YM4r42V4=
|
||||||
@ -549,6 +555,9 @@ github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4A
|
|||||||
github.com/urfave/cli v1.21.0/go.mod h1:lxDj6qX9Q6lWQxIrbrT0nwecwUtRnhVZAJjJZrVUZZQ=
|
github.com/urfave/cli v1.21.0/go.mod h1:lxDj6qX9Q6lWQxIrbrT0nwecwUtRnhVZAJjJZrVUZZQ=
|
||||||
github.com/vinyldns/go-vinyldns v0.0.0-20190611170422-7119fe55ed92 h1:Q76MzqJu++vAfhj0mVf7t0F4xHUbg+V/d/Uk5PBQjRU=
|
github.com/vinyldns/go-vinyldns v0.0.0-20190611170422-7119fe55ed92 h1:Q76MzqJu++vAfhj0mVf7t0F4xHUbg+V/d/Uk5PBQjRU=
|
||||||
github.com/vinyldns/go-vinyldns v0.0.0-20190611170422-7119fe55ed92/go.mod h1:AZuEfReFWdvtU0LatbLpo70t3lqdLvph2D5mqFP0bkA=
|
github.com/vinyldns/go-vinyldns v0.0.0-20190611170422-7119fe55ed92/go.mod h1:AZuEfReFWdvtU0LatbLpo70t3lqdLvph2D5mqFP0bkA=
|
||||||
|
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||||
|
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
|
||||||
|
github.com/xeipuuv/gojsonschema v1.1.0/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs=
|
||||||
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos=
|
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos=
|
||||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8=
|
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8=
|
||||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||||
@ -726,9 +735,12 @@ gopkg.in/d4l3k/messagediff.v1 v1.2.1/go.mod h1:EUzikiKadqXWcD1AzJLagx0j/BeeWGtn+
|
|||||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||||
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
|
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
|
||||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||||
|
gopkg.in/h2non/gock.v1 v1.0.14/go.mod h1:sX4zAkdYX1TRGJ2JY156cFspQn4yRWn6p9EMdODlynE=
|
||||||
|
gopkg.in/h2non/gock.v1 v1.0.15/go.mod h1:sX4zAkdYX1TRGJ2JY156cFspQn4yRWn6p9EMdODlynE=
|
||||||
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
|
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
|
||||||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||||
gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
|
gopkg.in/ini.v1 v1.44.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
gopkg.in/logfmt.v0 v0.3.0/go.mod h1:mRLMcMLrml5h2Ux/H+4zccFOlVCiRvOvndsolsJoU8Q=
|
gopkg.in/logfmt.v0 v0.3.0/go.mod h1:mRLMcMLrml5h2Ux/H+4zccFOlVCiRvOvndsolsJoU8Q=
|
||||||
gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
|
gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
|
||||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
|
gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
|
||||||
|
12
main.go
12
main.go
@ -111,6 +111,18 @@ func main() {
|
|||||||
|
|
||||||
var p provider.Provider
|
var p provider.Provider
|
||||||
switch cfg.Provider {
|
switch cfg.Provider {
|
||||||
|
case "akamai":
|
||||||
|
p = provider.NewAkamaiProvider(
|
||||||
|
provider.AkamaiConfig{
|
||||||
|
DomainFilter: domainFilter,
|
||||||
|
ZoneIDFilter: zoneIDFilter,
|
||||||
|
ServiceConsumerDomain: cfg.AkamaiServiceConsumerDomain,
|
||||||
|
ClientToken: cfg.AkamaiClientToken,
|
||||||
|
ClientSecret: cfg.AkamaiClientSecret,
|
||||||
|
AccessToken: cfg.AkamaiAccessToken,
|
||||||
|
DryRun: cfg.DryRun,
|
||||||
|
},
|
||||||
|
)
|
||||||
case "alibabacloud":
|
case "alibabacloud":
|
||||||
p, err = provider.NewAlibabaCloudProvider(cfg.AlibabaCloudConfigFile, domainFilter, zoneIDFilter, cfg.AlibabaCloudZoneType, cfg.DryRun)
|
p, err = provider.NewAlibabaCloudProvider(cfg.AlibabaCloudConfigFile, domainFilter, zoneIDFilter, cfg.AlibabaCloudZoneType, cfg.DryRun)
|
||||||
case "aws":
|
case "aws":
|
||||||
|
@ -77,6 +77,10 @@ type Config struct {
|
|||||||
CloudflareZonesPerPage int
|
CloudflareZonesPerPage int
|
||||||
CoreDNSPrefix string
|
CoreDNSPrefix string
|
||||||
RcodezeroTXTEncrypt bool
|
RcodezeroTXTEncrypt bool
|
||||||
|
AkamaiServiceConsumerDomain string
|
||||||
|
AkamaiClientToken string
|
||||||
|
AkamaiClientSecret string
|
||||||
|
AkamaiAccessToken string
|
||||||
InfobloxGridHost string
|
InfobloxGridHost string
|
||||||
InfobloxWapiPort int
|
InfobloxWapiPort int
|
||||||
InfobloxWapiUsername string
|
InfobloxWapiUsername string
|
||||||
@ -169,6 +173,10 @@ var defaultConfig = &Config{
|
|||||||
CloudflareZonesPerPage: 50,
|
CloudflareZonesPerPage: 50,
|
||||||
CoreDNSPrefix: "/skydns/",
|
CoreDNSPrefix: "/skydns/",
|
||||||
RcodezeroTXTEncrypt: false,
|
RcodezeroTXTEncrypt: false,
|
||||||
|
AkamaiServiceConsumerDomain: "",
|
||||||
|
AkamaiClientToken: "",
|
||||||
|
AkamaiClientSecret: "",
|
||||||
|
AkamaiAccessToken: "",
|
||||||
InfobloxGridHost: "",
|
InfobloxGridHost: "",
|
||||||
InfobloxWapiPort: 443,
|
InfobloxWapiPort: 443,
|
||||||
InfobloxWapiUsername: "admin",
|
InfobloxWapiUsername: "admin",
|
||||||
@ -289,7 +297,7 @@ func (cfg *Config) ParseFlags(args []string) error {
|
|||||||
app.Flag("service-type-filter", "The service types to take care about (default: all, expected: ClusterIP, NodePort, LoadBalancer or ExternalName)").StringsVar(&cfg.ServiceTypeFilter)
|
app.Flag("service-type-filter", "The service types to take care about (default: all, expected: ClusterIP, NodePort, LoadBalancer or ExternalName)").StringsVar(&cfg.ServiceTypeFilter)
|
||||||
|
|
||||||
// Flags related to providers
|
// Flags related to providers
|
||||||
app.Flag("provider", "The DNS provider where the DNS records will be created (required, options: aws, aws-sd, google, azure, azure-dns, azure-private-dns, cloudflare, rcodezero, digitalocean, dnsimple, infoblox, dyn, designate, coredns, skydns, inmemory, pdns, oci, exoscale, linode, rfc2136, ns1, transip, vinyldns, rdns)").Required().PlaceHolder("provider").EnumVar(&cfg.Provider, "aws", "aws-sd", "google", "azure", "azure-dns", "azure-private-dns", "alibabacloud", "cloudflare", "rcodezero", "digitalocean", "dnsimple", "infoblox", "dyn", "designate", "coredns", "skydns", "inmemory", "pdns", "oci", "exoscale", "linode", "rfc2136", "ns1", "transip", "vinyldns", "rdns")
|
app.Flag("provider", "The DNS provider where the DNS records will be created (required, options: aws, aws-sd, google, azure, azure-dns, azure-private-dns, cloudflare, rcodezero, digitalocean, dnsimple, akamai, infoblox, dyn, designate, coredns, skydns, inmemory, pdns, oci, exoscale, linode, rfc2136, ns1, transip, vinyldns, rdns)").Required().PlaceHolder("provider").EnumVar(&cfg.Provider, "aws", "aws-sd", "google", "azure", "azure-dns", "azure-private-dns", "alibabacloud", "cloudflare", "rcodezero", "digitalocean", "dnsimple", "akamai", "infoblox", "dyn", "designate", "coredns", "skydns", "inmemory", "pdns", "oci", "exoscale", "linode", "rfc2136", "ns1", "transip", "vinyldns", "rdns")
|
||||||
app.Flag("domain-filter", "Limit possible target zones by a domain suffix; specify multiple times for multiple domains (optional)").Default("").StringsVar(&cfg.DomainFilter)
|
app.Flag("domain-filter", "Limit possible target zones by a domain suffix; specify multiple times for multiple domains (optional)").Default("").StringsVar(&cfg.DomainFilter)
|
||||||
app.Flag("exclude-domains", "Exclude subdomains (optional)").Default("").StringsVar(&cfg.ExcludeDomains)
|
app.Flag("exclude-domains", "Exclude subdomains (optional)").Default("").StringsVar(&cfg.ExcludeDomains)
|
||||||
app.Flag("zone-id-filter", "Filter target zones by hosted zone id; specify multiple times for multiple zones (optional)").Default("").StringsVar(&cfg.ZoneIDFilter)
|
app.Flag("zone-id-filter", "Filter target zones by hosted zone id; specify multiple times for multiple zones (optional)").Default("").StringsVar(&cfg.ZoneIDFilter)
|
||||||
@ -313,6 +321,10 @@ 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-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("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("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("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-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-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)
|
app.Flag("infoblox-wapi-username", "When using the Infoblox provider, specify the WAPI username (default: admin)").Default(defaultConfig.InfobloxWapiUsername).StringVar(&cfg.InfobloxWapiUsername)
|
||||||
|
@ -29,140 +29,148 @@ import (
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
minimalConfig = &Config{
|
minimalConfig = &Config{
|
||||||
Master: "",
|
Master: "",
|
||||||
KubeConfig: "",
|
KubeConfig: "",
|
||||||
RequestTimeout: time.Second * 30,
|
RequestTimeout: time.Second * 30,
|
||||||
ContourLoadBalancerService: "heptio-contour/contour",
|
ContourLoadBalancerService: "heptio-contour/contour",
|
||||||
Sources: []string{"service"},
|
Sources: []string{"service"},
|
||||||
Namespace: "",
|
Namespace: "",
|
||||||
FQDNTemplate: "",
|
FQDNTemplate: "",
|
||||||
Compatibility: "",
|
Compatibility: "",
|
||||||
Provider: "google",
|
Provider: "google",
|
||||||
GoogleProject: "",
|
GoogleProject: "",
|
||||||
GoogleBatchChangeSize: 1000,
|
GoogleBatchChangeSize: 1000,
|
||||||
GoogleBatchChangeInterval: time.Second,
|
GoogleBatchChangeInterval: time.Second,
|
||||||
DomainFilter: []string{""},
|
DomainFilter: []string{""},
|
||||||
ExcludeDomains: []string{""},
|
ExcludeDomains: []string{""},
|
||||||
ZoneIDFilter: []string{""},
|
ZoneIDFilter: []string{""},
|
||||||
AlibabaCloudConfigFile: "/etc/kubernetes/alibaba-cloud.json",
|
AlibabaCloudConfigFile: "/etc/kubernetes/alibaba-cloud.json",
|
||||||
AWSZoneType: "",
|
AWSZoneType: "",
|
||||||
AWSZoneTagFilter: []string{""},
|
AWSZoneTagFilter: []string{""},
|
||||||
AWSAssumeRole: "",
|
AWSAssumeRole: "",
|
||||||
AWSBatchChangeSize: 1000,
|
AWSBatchChangeSize: 1000,
|
||||||
AWSBatchChangeInterval: time.Second,
|
AWSBatchChangeInterval: time.Second,
|
||||||
AWSEvaluateTargetHealth: true,
|
AWSEvaluateTargetHealth: true,
|
||||||
AWSAPIRetries: 3,
|
AWSAPIRetries: 3,
|
||||||
AWSPreferCNAME: false,
|
AWSPreferCNAME: false,
|
||||||
AzureConfigFile: "/etc/kubernetes/azure.json",
|
AzureConfigFile: "/etc/kubernetes/azure.json",
|
||||||
AzureResourceGroup: "",
|
AzureResourceGroup: "",
|
||||||
AzureSubscriptionID: "",
|
AzureSubscriptionID: "",
|
||||||
CloudflareProxied: false,
|
CloudflareProxied: false,
|
||||||
CloudflareZonesPerPage: 50,
|
CloudflareZonesPerPage: 50,
|
||||||
CoreDNSPrefix: "/skydns/",
|
CoreDNSPrefix: "/skydns/",
|
||||||
InfobloxGridHost: "",
|
AkamaiServiceConsumerDomain: "",
|
||||||
InfobloxWapiPort: 443,
|
AkamaiClientToken: "",
|
||||||
InfobloxWapiUsername: "admin",
|
AkamaiClientSecret: "",
|
||||||
InfobloxWapiPassword: "",
|
AkamaiAccessToken: "",
|
||||||
InfobloxWapiVersion: "2.3.1",
|
InfobloxGridHost: "",
|
||||||
InfobloxView: "",
|
InfobloxWapiPort: 443,
|
||||||
InfobloxSSLVerify: true,
|
InfobloxWapiUsername: "admin",
|
||||||
InfobloxMaxResults: 0,
|
InfobloxWapiPassword: "",
|
||||||
OCIConfigFile: "/etc/kubernetes/oci.yaml",
|
InfobloxWapiVersion: "2.3.1",
|
||||||
InMemoryZones: []string{""},
|
InfobloxView: "",
|
||||||
PDNSServer: "http://localhost:8081",
|
InfobloxSSLVerify: true,
|
||||||
PDNSAPIKey: "",
|
InfobloxMaxResults: 0,
|
||||||
Policy: "sync",
|
OCIConfigFile: "/etc/kubernetes/oci.yaml",
|
||||||
Registry: "txt",
|
InMemoryZones: []string{""},
|
||||||
TXTOwnerID: "default",
|
PDNSServer: "http://localhost:8081",
|
||||||
TXTPrefix: "",
|
PDNSAPIKey: "",
|
||||||
TXTCacheInterval: 0,
|
Policy: "sync",
|
||||||
Interval: time.Minute,
|
Registry: "txt",
|
||||||
Once: false,
|
TXTOwnerID: "default",
|
||||||
DryRun: false,
|
TXTPrefix: "",
|
||||||
LogFormat: "text",
|
TXTCacheInterval: 0,
|
||||||
MetricsAddress: ":7979",
|
Interval: time.Minute,
|
||||||
LogLevel: logrus.InfoLevel.String(),
|
Once: false,
|
||||||
ConnectorSourceServer: "localhost:8080",
|
DryRun: false,
|
||||||
ExoscaleEndpoint: "https://api.exoscale.ch/dns",
|
LogFormat: "text",
|
||||||
ExoscaleAPIKey: "",
|
MetricsAddress: ":7979",
|
||||||
ExoscaleAPISecret: "",
|
LogLevel: logrus.InfoLevel.String(),
|
||||||
CRDSourceAPIVersion: "externaldns.k8s.io/v1alpha1",
|
ConnectorSourceServer: "localhost:8080",
|
||||||
CRDSourceKind: "DNSEndpoint",
|
ExoscaleEndpoint: "https://api.exoscale.ch/dns",
|
||||||
RcodezeroTXTEncrypt: false,
|
ExoscaleAPIKey: "",
|
||||||
TransIPAccountName: "",
|
ExoscaleAPISecret: "",
|
||||||
TransIPPrivateKeyFile: "",
|
CRDSourceAPIVersion: "externaldns.k8s.io/v1alpha1",
|
||||||
|
CRDSourceKind: "DNSEndpoint",
|
||||||
|
RcodezeroTXTEncrypt: false,
|
||||||
|
TransIPAccountName: "",
|
||||||
|
TransIPPrivateKeyFile: "",
|
||||||
}
|
}
|
||||||
|
|
||||||
overriddenConfig = &Config{
|
overriddenConfig = &Config{
|
||||||
Master: "http://127.0.0.1:8080",
|
Master: "http://127.0.0.1:8080",
|
||||||
KubeConfig: "/some/path",
|
KubeConfig: "/some/path",
|
||||||
RequestTimeout: time.Second * 77,
|
RequestTimeout: time.Second * 77,
|
||||||
ContourLoadBalancerService: "heptio-contour-other/contour-other",
|
ContourLoadBalancerService: "heptio-contour-other/contour-other",
|
||||||
Sources: []string{"service", "ingress", "connector"},
|
Sources: []string{"service", "ingress", "connector"},
|
||||||
Namespace: "namespace",
|
Namespace: "namespace",
|
||||||
IgnoreHostnameAnnotation: true,
|
IgnoreHostnameAnnotation: true,
|
||||||
FQDNTemplate: "{{.Name}}.service.example.com",
|
FQDNTemplate: "{{.Name}}.service.example.com",
|
||||||
Compatibility: "mate",
|
Compatibility: "mate",
|
||||||
Provider: "google",
|
Provider: "google",
|
||||||
GoogleProject: "project",
|
GoogleProject: "project",
|
||||||
GoogleBatchChangeSize: 100,
|
GoogleBatchChangeSize: 100,
|
||||||
GoogleBatchChangeInterval: time.Second * 2,
|
GoogleBatchChangeInterval: time.Second * 2,
|
||||||
DomainFilter: []string{"example.org", "company.com"},
|
DomainFilter: []string{"example.org", "company.com"},
|
||||||
ExcludeDomains: []string{"xapi.example.org", "xapi.company.com"},
|
ExcludeDomains: []string{"xapi.example.org", "xapi.company.com"},
|
||||||
ZoneIDFilter: []string{"/hostedzone/ZTST1", "/hostedzone/ZTST2"},
|
ZoneIDFilter: []string{"/hostedzone/ZTST1", "/hostedzone/ZTST2"},
|
||||||
AlibabaCloudConfigFile: "/etc/kubernetes/alibaba-cloud.json",
|
AlibabaCloudConfigFile: "/etc/kubernetes/alibaba-cloud.json",
|
||||||
AWSZoneType: "private",
|
AWSZoneType: "private",
|
||||||
AWSZoneTagFilter: []string{"tag=foo"},
|
AWSZoneTagFilter: []string{"tag=foo"},
|
||||||
AWSAssumeRole: "some-other-role",
|
AWSAssumeRole: "some-other-role",
|
||||||
AWSBatchChangeSize: 100,
|
AWSBatchChangeSize: 100,
|
||||||
AWSBatchChangeInterval: time.Second * 2,
|
AWSBatchChangeInterval: time.Second * 2,
|
||||||
AWSEvaluateTargetHealth: false,
|
AWSEvaluateTargetHealth: false,
|
||||||
AWSAPIRetries: 13,
|
AWSAPIRetries: 13,
|
||||||
AWSPreferCNAME: true,
|
AWSPreferCNAME: true,
|
||||||
AzureConfigFile: "azure.json",
|
AzureConfigFile: "azure.json",
|
||||||
AzureResourceGroup: "arg",
|
AzureResourceGroup: "arg",
|
||||||
AzureSubscriptionID: "arg",
|
AzureSubscriptionID: "arg",
|
||||||
CloudflareProxied: true,
|
CloudflareProxied: true,
|
||||||
CloudflareZonesPerPage: 20,
|
CloudflareZonesPerPage: 20,
|
||||||
CoreDNSPrefix: "/coredns/",
|
CoreDNSPrefix: "/coredns/",
|
||||||
InfobloxGridHost: "127.0.0.1",
|
AkamaiServiceConsumerDomain: "oooo-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx.luna.akamaiapis.net",
|
||||||
InfobloxWapiPort: 8443,
|
AkamaiClientToken: "o184671d5307a388180fbf7f11dbdf46",
|
||||||
InfobloxWapiUsername: "infoblox",
|
AkamaiClientSecret: "o184671d5307a388180fbf7f11dbdf46",
|
||||||
InfobloxWapiPassword: "infoblox",
|
AkamaiAccessToken: "o184671d5307a388180fbf7f11dbdf46",
|
||||||
InfobloxWapiVersion: "2.6.1",
|
InfobloxGridHost: "127.0.0.1",
|
||||||
InfobloxView: "internal",
|
InfobloxWapiPort: 8443,
|
||||||
InfobloxSSLVerify: false,
|
InfobloxWapiUsername: "infoblox",
|
||||||
InfobloxMaxResults: 2000,
|
InfobloxWapiPassword: "infoblox",
|
||||||
OCIConfigFile: "oci.yaml",
|
InfobloxWapiVersion: "2.6.1",
|
||||||
InMemoryZones: []string{"example.org", "company.com"},
|
InfobloxView: "internal",
|
||||||
PDNSServer: "http://ns.example.com:8081",
|
InfobloxSSLVerify: false,
|
||||||
PDNSAPIKey: "some-secret-key",
|
InfobloxMaxResults: 2000,
|
||||||
PDNSTLSEnabled: true,
|
OCIConfigFile: "oci.yaml",
|
||||||
TLSCA: "/path/to/ca.crt",
|
InMemoryZones: []string{"example.org", "company.com"},
|
||||||
TLSClientCert: "/path/to/cert.pem",
|
PDNSServer: "http://ns.example.com:8081",
|
||||||
TLSClientCertKey: "/path/to/key.pem",
|
PDNSAPIKey: "some-secret-key",
|
||||||
Policy: "upsert-only",
|
PDNSTLSEnabled: true,
|
||||||
Registry: "noop",
|
TLSCA: "/path/to/ca.crt",
|
||||||
TXTOwnerID: "owner-1",
|
TLSClientCert: "/path/to/cert.pem",
|
||||||
TXTPrefix: "associated-txt-record",
|
TLSClientCertKey: "/path/to/key.pem",
|
||||||
TXTCacheInterval: 12 * time.Hour,
|
Policy: "upsert-only",
|
||||||
Interval: 10 * time.Minute,
|
Registry: "noop",
|
||||||
Once: true,
|
TXTOwnerID: "owner-1",
|
||||||
DryRun: true,
|
TXTPrefix: "associated-txt-record",
|
||||||
LogFormat: "json",
|
TXTCacheInterval: 12 * time.Hour,
|
||||||
MetricsAddress: "127.0.0.1:9099",
|
Interval: 10 * time.Minute,
|
||||||
LogLevel: logrus.DebugLevel.String(),
|
Once: true,
|
||||||
ConnectorSourceServer: "localhost:8081",
|
DryRun: true,
|
||||||
ExoscaleEndpoint: "https://api.foo.ch/dns",
|
LogFormat: "json",
|
||||||
ExoscaleAPIKey: "1",
|
MetricsAddress: "127.0.0.1:9099",
|
||||||
ExoscaleAPISecret: "2",
|
LogLevel: logrus.DebugLevel.String(),
|
||||||
CRDSourceAPIVersion: "test.k8s.io/v1alpha1",
|
ConnectorSourceServer: "localhost:8081",
|
||||||
CRDSourceKind: "Endpoint",
|
ExoscaleEndpoint: "https://api.foo.ch/dns",
|
||||||
RcodezeroTXTEncrypt: true,
|
ExoscaleAPIKey: "1",
|
||||||
NS1Endpoint: "https://api.example.com/v1",
|
ExoscaleAPISecret: "2",
|
||||||
NS1IgnoreSSL: true,
|
CRDSourceAPIVersion: "test.k8s.io/v1alpha1",
|
||||||
TransIPAccountName: "transip",
|
CRDSourceKind: "Endpoint",
|
||||||
TransIPPrivateKeyFile: "/path/to/transip.key",
|
RcodezeroTXTEncrypt: true,
|
||||||
|
NS1Endpoint: "https://api.example.com/v1",
|
||||||
|
NS1IgnoreSSL: true,
|
||||||
|
TransIPAccountName: "transip",
|
||||||
|
TransIPPrivateKeyFile: "/path/to/transip.key",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -206,6 +214,10 @@ func TestParseFlags(t *testing.T) {
|
|||||||
"--cloudflare-proxied",
|
"--cloudflare-proxied",
|
||||||
"--cloudflare-zones-per-page=20",
|
"--cloudflare-zones-per-page=20",
|
||||||
"--coredns-prefix=/coredns/",
|
"--coredns-prefix=/coredns/",
|
||||||
|
"--akamai-serviceconsumerdomain=oooo-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx.luna.akamaiapis.net",
|
||||||
|
"--akamai-client-token=o184671d5307a388180fbf7f11dbdf46",
|
||||||
|
"--akamai-client-secret=o184671d5307a388180fbf7f11dbdf46",
|
||||||
|
"--akamai-access-token=o184671d5307a388180fbf7f11dbdf46",
|
||||||
"--infoblox-grid-host=127.0.0.1",
|
"--infoblox-grid-host=127.0.0.1",
|
||||||
"--infoblox-wapi-port=8443",
|
"--infoblox-wapi-port=8443",
|
||||||
"--infoblox-wapi-username=infoblox",
|
"--infoblox-wapi-username=infoblox",
|
||||||
@ -286,6 +298,10 @@ func TestParseFlags(t *testing.T) {
|
|||||||
"EXTERNAL_DNS_CLOUDFLARE_PROXIED": "1",
|
"EXTERNAL_DNS_CLOUDFLARE_PROXIED": "1",
|
||||||
"EXTERNAL_DNS_CLOUDFLARE_ZONES_PER_PAGE": "20",
|
"EXTERNAL_DNS_CLOUDFLARE_ZONES_PER_PAGE": "20",
|
||||||
"EXTERNAL_DNS_COREDNS_PREFIX": "/coredns/",
|
"EXTERNAL_DNS_COREDNS_PREFIX": "/coredns/",
|
||||||
|
"EXTERNAL_DNS_AKAMAI_SERVICECONSUMERDOMAIN": "oooo-xxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx.luna.akamaiapis.net",
|
||||||
|
"EXTERNAL_DNS_AKAMAI_CLIENT_TOKEN": "o184671d5307a388180fbf7f11dbdf46",
|
||||||
|
"EXTERNAL_DNS_AKAMAI_CLIENT_SECRET": "o184671d5307a388180fbf7f11dbdf46",
|
||||||
|
"EXTERNAL_DNS_AKAMAI_ACCESS_TOKEN": "o184671d5307a388180fbf7f11dbdf46",
|
||||||
"EXTERNAL_DNS_INFOBLOX_GRID_HOST": "127.0.0.1",
|
"EXTERNAL_DNS_INFOBLOX_GRID_HOST": "127.0.0.1",
|
||||||
"EXTERNAL_DNS_INFOBLOX_WAPI_PORT": "8443",
|
"EXTERNAL_DNS_INFOBLOX_WAPI_PORT": "8443",
|
||||||
"EXTERNAL_DNS_INFOBLOX_WAPI_USERNAME": "infoblox",
|
"EXTERNAL_DNS_INFOBLOX_WAPI_USERNAME": "infoblox",
|
||||||
|
@ -43,6 +43,22 @@ func ValidateConfig(cfg *externaldns.Config) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Akamai provider specific validations
|
||||||
|
if cfg.Provider == "akamai" {
|
||||||
|
if cfg.AkamaiServiceConsumerDomain == "" {
|
||||||
|
return errors.New("no Akamai ServiceConsumerDomain specified")
|
||||||
|
}
|
||||||
|
if cfg.AkamaiClientToken == "" {
|
||||||
|
return errors.New("no Akamai client token specified")
|
||||||
|
}
|
||||||
|
if cfg.AkamaiClientSecret == "" {
|
||||||
|
return errors.New("no Akamai client secret specified")
|
||||||
|
}
|
||||||
|
if cfg.AkamaiAccessToken == "" {
|
||||||
|
return errors.New("no Akamai access token specified")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Infoblox provider specific validations
|
// Infoblox provider specific validations
|
||||||
if cfg.Provider == "infoblox" {
|
if cfg.Provider == "infoblox" {
|
||||||
if cfg.InfobloxGridHost == "" {
|
if cfg.InfobloxGridHost == "" {
|
||||||
|
414
provider/akamai.go
Normal file
414
provider/akamai.go
Normal file
@ -0,0 +1,414 @@
|
|||||||
|
/*
|
||||||
|
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 provider
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"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"
|
||||||
|
)
|
||||||
|
|
||||||
|
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 DomainFilter
|
||||||
|
ZoneIDFilter ZoneIDFilter
|
||||||
|
ServiceConsumerDomain string
|
||||||
|
ClientToken string
|
||||||
|
ClientSecret string
|
||||||
|
AccessToken string
|
||||||
|
DryRun bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// AkamaiProvider implements the DNS provider for Akamai.
|
||||||
|
type AkamaiProvider struct {
|
||||||
|
domainFilter DomainFilter
|
||||||
|
zoneIDFilter ZoneIDFilter
|
||||||
|
config edgegrid.Config
|
||||||
|
dryRun bool
|
||||||
|
client akamaiClient
|
||||||
|
}
|
||||||
|
|
||||||
|
type akamaiError struct {
|
||||||
|
Title string `json:"title"`
|
||||||
|
Status int `json:"status"`
|
||||||
|
Detail string `json:"detail"`
|
||||||
|
RequestID string `json:"requestId"`
|
||||||
|
}
|
||||||
|
|
||||||
|
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) ([]byte, 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
|
||||||
|
}
|
||||||
|
|
||||||
|
//204 means no body on success by choice
|
||||||
|
if resp.StatusCode == 204 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
defer resp.Body.Close()
|
||||||
|
byt, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("ioutil failed to read the response-body of the request to Akamai")
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
//catch authentication errors here, they aren't handled very well by the client
|
||||||
|
akamaiError := akamaiError{}
|
||||||
|
err = json.Unmarshal([]byte(byt), &akamaiError)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Failed to unmarshal the response-body of the request to Akamai")
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if akamaiError.Status >= 300 {
|
||||||
|
log.Errorf("Received an error from Akamai!\ntitle: %s \nstatus: %v \ndetail: %s \nrequestId: %s", akamaiError.Title, akamaiError.Status, akamaiError.Detail, akamaiError.RequestID)
|
||||||
|
return nil, errors.New("AkamaiError")
|
||||||
|
}
|
||||||
|
|
||||||
|
return byt, 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")
|
||||||
|
res, 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.Unmarshal([]byte(res), &zones)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Could not unmarshal json response from Akamai on zone request")
|
||||||
|
return zones, err
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
res, 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
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.Unmarshal([]byte(res), &recordSet)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Could not unmarshal 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, _ := p.fetchRecordSet(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)
|
||||||
|
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 := 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) newAkamaiRecordsets(dnsName, recordType string, targets ...string) *akamaiRecordsets {
|
||||||
|
akamaiRecords := make([]akamaiRecord, 0)
|
||||||
|
akamaiRecord := p.newAkamaiRecord(dnsName, recordType, targets...)
|
||||||
|
akamaiRecords = append(akamaiRecords, *akamaiRecord)
|
||||||
|
|
||||||
|
return &akamaiRecordsets{
|
||||||
|
Recordsets: akamaiRecords,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *AkamaiProvider) createRecords(zoneNameIDMapper 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 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 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
|
||||||
|
}
|
336
provider/akamai_test.go
Normal file
336
provider/akamai_test.go
Normal file
@ -0,0 +1,336 @@
|
|||||||
|
/*
|
||||||
|
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 provider
|
||||||
|
|
||||||
|
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"
|
||||||
|
)
|
||||||
|
|
||||||
|
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\"}"))
|
||||||
|
}
|
||||||
|
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) {
|
||||||
|
b, _ := ioutil.ReadAll(r.Body)
|
||||||
|
io.WriteString(w, string(b))
|
||||||
|
}
|
||||||
|
w := httptest.NewRecorder()
|
||||||
|
handler(w, req)
|
||||||
|
|
||||||
|
resp := w.Result()
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRequestError(t *testing.T) {
|
||||||
|
config := AkamaiConfig{}
|
||||||
|
|
||||||
|
client := &mockAkamaiClient{}
|
||||||
|
c := NewAkamaiProvider(config)
|
||||||
|
c.client = client
|
||||||
|
|
||||||
|
m := "GET"
|
||||||
|
p := ""
|
||||||
|
b := "{\"title\": \"MockError\", \"status\": 404, \"detail\": \"MockError\", \"requestId\": \"1234\"}"
|
||||||
|
x, _ := c.request(m, p, bytes.NewReader([]byte(b)))
|
||||||
|
assert.Nil(t, x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFetchZonesZoneIDFilter(t *testing.T) {
|
||||||
|
config := AkamaiConfig{
|
||||||
|
ZoneIDFilter: 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: NewDomainFilter([]string{"Nonexistent"}),
|
||||||
|
ZoneIDFilter: 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: 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: NewDomainFilter([]string{"www.exclude.me"}),
|
||||||
|
ZoneIDFilter: 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 := 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: NewDomainFilter([]string{"example.com"}),
|
||||||
|
}
|
||||||
|
|
||||||
|
client := &mockAkamaiClient{}
|
||||||
|
c := NewAkamaiProvider(config)
|
||||||
|
c.client = client
|
||||||
|
|
||||||
|
zoneNameIDMapper := 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 := 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: NewDomainFilter([]string{"example.com"}),
|
||||||
|
}
|
||||||
|
|
||||||
|
client := &mockAkamaiClient{}
|
||||||
|
c := NewAkamaiProvider(config)
|
||||||
|
c.client = client
|
||||||
|
|
||||||
|
zoneNameIDMapper := 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 := 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: NewDomainFilter([]string{"example.com"}),
|
||||||
|
}
|
||||||
|
|
||||||
|
client := &mockAkamaiClient{}
|
||||||
|
c := NewAkamaiProvider(config)
|
||||||
|
c.client = client
|
||||||
|
|
||||||
|
zoneNameIDMapper := 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)
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user