2017-09-15 04:13:17 +08:00
package main
import (
"bytes"
"html/template"
"io/ioutil"
"sort"
2020-04-15 04:47:30 +08:00
"github.com/StackExchange/dnscontrol/v3/providers"
_ "github.com/StackExchange/dnscontrol/v3/providers/_all"
2017-09-15 04:13:17 +08:00
)
func generateFeatureMatrix ( ) error {
allNames := map [ string ] bool { }
for n := range providers . RegistrarTypes {
allNames [ n ] = true
}
for n := range providers . DNSProviderTypes {
allNames [ n ] = true
}
providerTypes := [ ] string { }
for n := range allNames {
providerTypes = append ( providerTypes , n )
}
sort . Strings ( providerTypes )
matrix := & FeatureMatrix {
Providers : map [ string ] FeatureMap { } ,
Features : [ ] FeatureDef {
{ "Official Support" , "This means the provider is actively used at Stack Exchange, bugs are more likely to be fixed, and failing integration tests will block a release. See below for details" } ,
{ "DNS Provider" , "Can manage and serve DNS zones" } ,
2018-01-11 06:06:15 +08:00
{ "Registrar" , "The provider has registrar capabilities to set nameservers for zones" } ,
2017-09-15 04:13:17 +08:00
{ "ALIAS" , "Provider supports some kind of ALIAS, ANAME or flattened CNAME record type" } ,
2020-02-22 20:09:31 +08:00
{ "AUTODNSSEC" , "Provider can automatically manage DNSSEC" } ,
2017-09-15 04:13:17 +08:00
{ "CAA" , "Provider can manage CAA records" } ,
2018-01-11 06:06:15 +08:00
{ "PTR" , "Provider supports adding PTR records for reverse lookup zones" } ,
2019-03-28 22:40:13 +08:00
{ "NAPTR" , "Provider can manage NAPTR records" } ,
2021-05-05 03:47:26 +08:00
{ "SOA" , "Provider can manage SOA records" } ,
2018-01-11 06:06:15 +08:00
{ "SRV" , "Driver has explicitly implemented SRV record management" } ,
2019-01-29 06:26:20 +08:00
{ "SSHFP" , "Provider can manage SSHFP records" } ,
2017-09-15 21:03:29 +08:00
{ "TLSA" , "Provider can manage TLSA records" } ,
2018-01-11 06:06:15 +08:00
{ "TXTMulti" , "Provider can manage TXT records with multiple strings" } ,
ROUTE53: Support Route53's ALIAS record type (#239) (#301)
* Stable comparison of metadata (#239)
Iterating over a map in Go never produces twice the same ordering.
Thus when comparing two metadata map with more than one key, the
`differ` is always finding differences.
To properly compare records metadata, we need to iterate the maps
in a deterministic way.
Signed-off-by: Brice Figureau <brice@daysofwonder.com>
* Support for Route53 ALIAS record type (#239)
Route53 ALIAS doesn't behave like a regular ALIAS, and is much more
limited as its target can only be some specific AWS resources or
another record in the same zone.
According to #239, this change adds a new directive R53_ALIAS which
implements this specific alias. This record type can only be used
with the Route53 provider.
This directive usage looks like this:
```js
D("example.com", REGISTRAR, DnsProvider("ROUTE53"),
R53_ALIAS("foo1", "A", "bar") // record in same zone
R53_ALIAS("foo2", "A",
"blahblah.elasticloadbalancing.us-west-1.amazonaws.com",
R53_ZONE('Z368ELLRRE2KJ0')) // ELB in us-west-1
```
Unfortunately, Route53 requires indicating the hosted zone id
where the target is defined (those are listed in AWS documentation,
see the R53_ALIAS documentation for links).
2018-01-16 18:53:12 +08:00
{ "R53_ALIAS" , "Provider supports Route 53 limited ALIAS" } ,
2020-03-03 00:25:42 +08:00
{ "AZURE_ALIAS" , "Provider supports Azure DNS limited ALIAS" } ,
2020-05-30 22:40:21 +08:00
{ "DS" , "Provider supports adding DS records" } ,
2021-07-22 04:10:53 +08:00
{ "AKAMAICDN" , "Provider supports adding AKAMAICDN records" } ,
2017-09-15 04:13:17 +08:00
{ "dual host" , "This provider is recommended for use in 'dual hosting' scenarios. Usually this means the provider allows full control over the apex NS records" } ,
{ "create-domains" , "This means the provider can automatically create domains that do not currently exist on your account. The 'dnscontrol create-domains' command will initialize any missing domains" } ,
{ "no_purge" , "indicates you can use NO_PURGE macro to prevent deleting records not managed by dnscontrol. A few providers that generate the entire zone from scratch have a problem implementing this." } ,
2020-02-18 21:59:18 +08:00
{ "get-zones" , "indicates the dnscontrol get-zones subcommand is implemented." } ,
2017-09-15 04:13:17 +08:00
} ,
}
for _ , p := range providerTypes {
if p == "NONE" {
continue
}
fm := FeatureMap { }
notes := providers . Notes [ p ]
if notes == nil {
notes = providers . DocumentationNotes { }
}
setCap := func ( name string , cap providers . Capability ) {
if notes [ cap ] != nil {
fm [ name ] = notes [ cap ]
return
}
2020-01-13 00:24:10 +08:00
fm . SetSimple ( name , true , func ( ) bool { return providers . ProviderHasCapability ( p , cap ) } )
2017-09-15 04:13:17 +08:00
}
2017-09-30 03:44:13 +08:00
setDoc := func ( name string , cap providers . Capability , defaultNo bool ) {
2017-09-15 04:13:17 +08:00
if notes [ cap ] != nil {
fm [ name ] = notes [ cap ]
2017-09-30 03:44:13 +08:00
} else if defaultNo {
fm [ name ] = & providers . DocumentationNote {
HasFeature : false ,
}
2017-09-15 04:13:17 +08:00
}
}
2017-09-30 03:44:13 +08:00
setDoc ( "Official Support" , providers . DocOfficiallySupported , true )
2021-03-08 02:19:22 +08:00
fm . SetSimple ( "DNS Provider" , false , func ( ) bool { return providers . DNSProviderTypes [ p ] . Initializer != nil } )
2018-01-11 06:06:15 +08:00
fm . SetSimple ( "Registrar" , false , func ( ) bool { return providers . RegistrarTypes [ p ] != nil } )
2022-03-03 00:19:15 +08:00
setCap ( "AKAMAICDN" , providers . CanUseAKAMAICDN )
2017-09-15 04:13:17 +08:00
setCap ( "ALIAS" , providers . CanUseAlias )
2020-02-22 20:09:31 +08:00
setCap ( "AUTODNSSEC" , providers . CanAutoDNSSEC )
2022-03-03 00:19:15 +08:00
setCap ( "AZURE_ALIAS" , providers . CanUseAzureAlias )
2017-09-15 04:13:17 +08:00
setCap ( "CAA" , providers . CanUseCAA )
2022-03-03 00:19:15 +08:00
setCap ( "DS" , providers . CanUseDS )
2019-03-28 22:40:13 +08:00
setCap ( "NAPTR" , providers . CanUseNAPTR )
2019-04-18 04:13:49 +08:00
setCap ( "PTR" , providers . CanUsePTR )
setCap ( "R53_ALIAS" , providers . CanUseRoute53Alias )
2021-05-05 03:47:26 +08:00
setCap ( "SOA" , providers . CanUseSOA )
2018-01-11 06:06:15 +08:00
setCap ( "SRV" , providers . CanUseSRV )
2019-01-29 06:26:20 +08:00
setCap ( "SSHFP" , providers . CanUseSSHFP )
2017-09-15 21:03:29 +08:00
setCap ( "TLSA" , providers . CanUseTLSA )
2020-02-18 21:59:18 +08:00
setCap ( "get-zones" , providers . CanGetZones )
2017-09-30 03:44:13 +08:00
setDoc ( "create-domains" , providers . DocCreateDomains , true )
2022-03-03 00:19:15 +08:00
setDoc ( "dual host" , providers . DocDualHost , false )
2017-09-15 04:13:17 +08:00
// no purge is a freaky double negative
cap := providers . CantUseNOPURGE
if notes [ cap ] != nil {
fm [ "no_purge" ] = notes [ cap ]
} else {
2020-01-13 00:24:10 +08:00
fm . SetSimple ( "no_purge" , false , func ( ) bool { return ! providers . ProviderHasCapability ( p , cap ) } )
2017-09-15 04:13:17 +08:00
}
matrix . Providers [ p ] = fm
}
buf := & bytes . Buffer { }
err := tmpl . Execute ( buf , matrix )
if err != nil {
return err
}
return ioutil . WriteFile ( "docs/_includes/matrix.html" , buf . Bytes ( ) , 0644 )
}
2018-01-10 01:53:16 +08:00
// FeatureDef describes features.
2017-09-15 04:13:17 +08:00
type FeatureDef struct {
Name , Desc string
}
2018-01-10 01:53:16 +08:00
// FeatureMap maps provider names to compliance documentation.
2017-09-15 04:13:17 +08:00
type FeatureMap map [ string ] * providers . DocumentationNote
2018-01-10 01:53:16 +08:00
// SetSimple configures a provider's setting in fm.
2017-09-15 04:13:17 +08:00
func ( fm FeatureMap ) SetSimple ( name string , unknownsAllowed bool , f func ( ) bool ) {
if f ( ) {
fm [ name ] = & providers . DocumentationNote { HasFeature : true }
} else if ! unknownsAllowed {
f m [ name ] = & providers . DocumentationNote { HasFeature : false }
}
}
2018-01-10 01:53:16 +08:00
// FeatureMatrix describes features and which providers support it.
2017-09-15 04:13:17 +08:00
type FeatureMatrix struct {
Features [ ] FeatureDef
Providers map [ string ] FeatureMap
}
var tmpl = template . Must ( template . New ( "" ) . Funcs ( template . FuncMap {
"safe" : func ( s string ) template . HTML { return template . HTML ( s ) } ,
2022-04-05 02:55:35 +08:00
} ) . Parse ( ` { % comment % }
2017-11-29 20:57:35 +08:00
Matrix generated by build / generate / featureMatrix . go . DO NOT HAND EDIT !
2017-09-15 04:13:17 +08:00
{ % endcomment % } { { $ providers := . Providers } }
< table class = "table-header-rotated" >
< thead >
< tr >
< th > < / th >
{ { range $ key , $ val := $ providers } } < th class = "rotate" > < div > < span > { { $ key } } < / span > < / div > < / th >
{ { end - } }
< / tr >
< / thead >
< tbody >
{ { range . Features } } { { $ name := . Name } } < tr >
< th class = "row-header" style = "text-decoration: underline;" data - toggle = "tooltip" data - container = "body" data - placement = "top" title = "{{.Desc}}" > { { $ name } } < / th >
{ { range $ pname , $ features := $ providers } } { { $ f := index $ features $ name } } { { if $ f - } }
2017-10-03 23:53:56 +08:00
< td class = "{{if $f.HasFeature}}success{{else if $f.Unimplemented}}info{{else}}danger{{end}}"
2017-09-15 04:13:17 +08:00
{ { - if $ f . Comment } } data - toggle = "tooltip" data - container = "body" data - placement = "top" title = "{{$f.Comment}}" { { end } } >
2017-10-03 23:53:56 +08:00
{ { if $ f . Link } } < a href = "{{$f.Link}}" > { { end } } < i class = " fa { { if and $ f . Comment ( not $ f . Unimplemented ) } } has - tooltip { { end } }
{ { - if $ f . HasFeature } } fa - check text - success { { else if $ f . Unimplemented } } fa - circle - o text - info { { else } } fa - times text - danger { { end } } " aria-hidden=" true " > < / i > { { if $ f . Link } } < / a > { { end } }
2017-09-15 04:13:17 +08:00
< / td >
{ { - else } } < td > < i class = "fa fa-minus dim" > < / i > < / td > { { end } }
{ { end - } }
< / tr >
{ { end - } }
< / tbody >
< / table >
` ) )