2017-09-14 16:13:17 -04:00
package main
import (
"bytes"
"html/template"
"io/ioutil"
"sort"
2020-04-14 16:47:30 -04:00
"github.com/StackExchange/dnscontrol/v3/providers"
_ "github.com/StackExchange/dnscontrol/v3/providers/_all"
2017-09-14 16:13:17 -04: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-10 17:06:15 -05:00
{ "Registrar" , "The provider has registrar capabilities to set nameservers for zones" } ,
2017-09-14 16:13:17 -04:00
{ "ALIAS" , "Provider supports some kind of ALIAS, ANAME or flattened CNAME record type" } ,
2020-02-22 07:09:31 -05:00
{ "AUTODNSSEC" , "Provider can automatically manage DNSSEC" } ,
2017-09-14 16:13:17 -04:00
{ "CAA" , "Provider can manage CAA records" } ,
2018-01-10 17:06:15 -05:00
{ "PTR" , "Provider supports adding PTR records for reverse lookup zones" } ,
2019-03-28 15:40:13 +01:00
{ "NAPTR" , "Provider can manage NAPTR records" } ,
2018-01-10 17:06:15 -05:00
{ "SRV" , "Driver has explicitly implemented SRV record management" } ,
2019-01-28 23:26:20 +01:00
{ "SSHFP" , "Provider can manage SSHFP records" } ,
2017-09-15 09:03:29 -04:00
{ "TLSA" , "Provider can manage TLSA records" } ,
2018-01-10 17:06:15 -05: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 11:53:12 +01:00
{ "R53_ALIAS" , "Provider supports Route 53 limited ALIAS" } ,
2020-03-02 20:25:42 +04:00
{ "AZURE_ALIAS" , "Provider supports Azure DNS limited ALIAS" } ,
2020-05-30 10:40:21 -04:00
{ "DS" , "Provider supports adding DS records" } ,
2017-09-14 16:13:17 -04: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 08:59:18 -05:00
{ "get-zones" , "indicates the dnscontrol get-zones subcommand is implemented." } ,
2017-09-14 16:13:17 -04: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-12 11:24:10 -05:00
fm . SetSimple ( name , true , func ( ) bool { return providers . ProviderHasCapability ( p , cap ) } )
2017-09-14 16:13:17 -04:00
}
2017-09-29 15:44:13 -04:00
setDoc := func ( name string , cap providers . Capability , defaultNo bool ) {
2017-09-14 16:13:17 -04:00
if notes [ cap ] != nil {
fm [ name ] = notes [ cap ]
2017-09-29 15:44:13 -04:00
} else if defaultNo {
fm [ name ] = & providers . DocumentationNote {
HasFeature : false ,
}
2017-09-14 16:13:17 -04:00
}
}
2017-09-29 15:44:13 -04:00
setDoc ( "Official Support" , providers . DocOfficiallySupported , true )
2017-09-14 16:13:17 -04:00
fm . SetSimple ( "DNS Provider" , false , func ( ) bool { return providers . DNSProviderTypes [ p ] != nil } )
2018-01-10 17:06:15 -05:00
fm . SetSimple ( "Registrar" , false , func ( ) bool { return providers . RegistrarTypes [ p ] != nil } )
2017-09-14 16:13:17 -04:00
setCap ( "ALIAS" , providers . CanUseAlias )
2020-02-22 07:09:31 -05:00
setCap ( "AUTODNSSEC" , providers . CanAutoDNSSEC )
2017-09-14 16:13:17 -04:00
setCap ( "CAA" , providers . CanUseCAA )
2019-03-28 15:40:13 +01:00
setCap ( "NAPTR" , providers . CanUseNAPTR )
2019-04-17 16:13:49 -04:00
setCap ( "PTR" , providers . CanUsePTR )
setCap ( "R53_ALIAS" , providers . CanUseRoute53Alias )
2020-03-02 20:25:42 +04:00
setCap ( "AZURE_ALIAS" , providers . CanUseAzureAlias )
2018-01-10 17:06:15 -05:00
setCap ( "SRV" , providers . CanUseSRV )
2019-01-28 23:26:20 +01:00
setCap ( "SSHFP" , providers . CanUseSSHFP )
2017-09-15 09:03:29 -04:00
setCap ( "TLSA" , providers . CanUseTLSA )
2018-01-10 17:06:15 -05:00
setCap ( "TXTMulti" , providers . CanUseTXTMulti )
2020-02-18 08:59:18 -05:00
setCap ( "get-zones" , providers . CanGetZones )
2020-05-30 10:40:21 -04:00
setCap ( "DS" , providers . CanUseDS )
2017-09-29 15:44:13 -04:00
setDoc ( "dual host" , providers . DocDualHost , false )
setDoc ( "create-domains" , providers . DocCreateDomains , true )
2017-09-14 16:13:17 -04:00
// no purge is a freaky double negative
cap := providers . CantUseNOPURGE
if notes [ cap ] != nil {
fm [ "no_purge" ] = notes [ cap ]
} else {
2020-01-12 11:24:10 -05:00
fm . SetSimple ( "no_purge" , false , func ( ) bool { return ! providers . ProviderHasCapability ( p , cap ) } )
2017-09-14 16:13:17 -04: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-09 12:53:16 -05:00
// FeatureDef describes features.
2017-09-14 16:13:17 -04:00
type FeatureDef struct {
Name , Desc string
}
2018-01-09 12:53:16 -05:00
// FeatureMap maps provider names to compliance documentation.
2017-09-14 16:13:17 -04:00
type FeatureMap map [ string ] * providers . DocumentationNote
2018-01-09 12:53:16 -05:00
// SetSimple configures a provider's setting in fm.
2017-09-14 16:13:17 -04:00
func ( fm FeatureMap ) SetSimple ( name string , unknownsAllowed bool , f func ( ) bool ) {
if f ( ) {
fm [ name ] = & providers . DocumentationNote { HasFeature : true }
} else if ! unknownsAllowed {
fm [ name ] = & providers . DocumentationNote { HasFeature : false }
}
}
2018-01-09 12:53:16 -05:00
// FeatureMatrix describes features and which providers support it.
2017-09-14 16:13:17 -04: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 ) } ,
} ) . Parse ( `
{ % comment %}
2017-11-29 20:57:35 +08:00
Matrix generated by build/generate/featureMatrix.go. DO NOT HAND EDIT!
2017-09-14 16:13:17 -04: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 11:53:56 -04:00
<td class=" {{ if $f .HasFeature }} success {{ else if $f .Unimplemented }} info {{ else }} danger {{ end }} "
2017-09-14 16:13:17 -04:00
{{- if $f .Comment }} data-toggle="tooltip" data-container="body" data-placement="top" title=" {{ $f .Comment }} " {{ end }} >
2017-10-03 11:53:56 -04: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-14 16:13:17 -04:00
</td>
{{- else }} <td><i class="fa fa-minus dim"></i></td> {{ end }}
{{ end -}}
</tr>
{{ end -}}
</tbody>
</table>
` ) )