mirror of
https://github.com/StackExchange/dnscontrol.git
synced 2024-05-11 05:55:12 +00:00
Create a dynamic provider features matrix (#201)
* adding simple provider feature matrix generator * filling out matrix * clean output * dead code * explanatory text * explanatory text * typo * move stuff around * clean * editing
This commit is contained in:
137
build/generate/featureMatrix.go
Normal file
137
build/generate/featureMatrix.go
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"html/template"
|
||||||
|
"io/ioutil"
|
||||||
|
"sort"
|
||||||
|
|
||||||
|
"github.com/StackExchange/dnscontrol/providers"
|
||||||
|
_ "github.com/StackExchange/dnscontrol/providers/_all"
|
||||||
|
)
|
||||||
|
|
||||||
|
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"},
|
||||||
|
{"Registrar", "The provider has registrar capabilities to set nameservers for zones"},
|
||||||
|
{"DNS Provider", "Can manage and serve DNS zones"},
|
||||||
|
{"ALIAS", "Provider supports some kind of ALIAS, ANAME or flattened CNAME record type"},
|
||||||
|
{"SRV", "Driver has explicitly implemented SRV record management"},
|
||||||
|
{"PTR", "Provider supports adding PTR records for reverse lookup zones"},
|
||||||
|
{"CAA", "Provider can manage CAA records"},
|
||||||
|
|
||||||
|
{"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."},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
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
|
||||||
|
}
|
||||||
|
fm.SetSimple(name, true, func() bool { return providers.ProviderHasCabability(p, cap) })
|
||||||
|
}
|
||||||
|
setDoc := func(name string, cap providers.Capability) {
|
||||||
|
if notes[cap] != nil {
|
||||||
|
fm[name] = notes[cap]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setDoc("Official Support", providers.DocOfficiallySupported)
|
||||||
|
fm.SetSimple("Registrar", false, func() bool { return providers.RegistrarTypes[p] != nil })
|
||||||
|
fm.SetSimple("DNS Provider", false, func() bool { return providers.DNSProviderTypes[p] != nil })
|
||||||
|
setCap("ALIAS", providers.CanUseAlias)
|
||||||
|
setCap("SRV", providers.CanUseSRV)
|
||||||
|
setCap("PTR", providers.CanUsePTR)
|
||||||
|
setCap("CAA", providers.CanUseCAA)
|
||||||
|
setDoc("dual host", providers.DocDualHost)
|
||||||
|
setDoc("create-domains", providers.DocCreateDomains)
|
||||||
|
|
||||||
|
// no purge is a freaky double negative
|
||||||
|
cap := providers.CantUseNOPURGE
|
||||||
|
if notes[cap] != nil {
|
||||||
|
fm["no_purge"] = notes[cap]
|
||||||
|
} else {
|
||||||
|
fm.SetSimple("no_purge", false, func() bool { return !providers.ProviderHasCabability(p, cap) })
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
type FeatureDef struct {
|
||||||
|
Name, Desc string
|
||||||
|
}
|
||||||
|
type FeatureMap map[string]*providers.DocumentationNote
|
||||||
|
|
||||||
|
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}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 %}
|
||||||
|
Matrix generated by build/generate/featureMatrix.go. DO NOT HAND EDIT!
|
||||||
|
{% 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 -}}
|
||||||
|
<td class="{{if $f.HasFeature}}success{{else}}danger{{end}}"
|
||||||
|
{{- if $f.Comment}} data-toggle="tooltip" data-container="body" data-placement="top" title="{{$f.Comment}}"{{end}}>
|
||||||
|
<i class="fa {{if $f.Comment}}has-tooltip {{end}}
|
||||||
|
{{- if $f.HasFeature}}fa-check text-success{{else}}fa-times text-danger{{end}}" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
{{- else}}<td><i class="fa fa-minus dim"></i></td>{{end}}
|
||||||
|
{{end -}}
|
||||||
|
</tr>
|
||||||
|
{{end -}}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
`))
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"log"
|
||||||
|
|
||||||
"github.com/mjibson/esc/embed"
|
"github.com/mjibson/esc/embed"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -14,4 +16,8 @@ func main() {
|
|||||||
Files: []string{`pkg/js/helpers.js`},
|
Files: []string{`pkg/js/helpers.js`},
|
||||||
}
|
}
|
||||||
embed.Run(conf)
|
embed.Run(conf)
|
||||||
|
|
||||||
|
if err := generateFeatureMatrix(); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
334
docs/_includes/matrix.html
Normal file
334
docs/_includes/matrix.html
Normal file
@@ -0,0 +1,334 @@
|
|||||||
|
|
||||||
|
{% comment %}
|
||||||
|
Matrix generated by build/generate/featureMatrix.go. DO NOT HAND EDIT!
|
||||||
|
{% endcomment %}
|
||||||
|
<table class="table-header-rotated">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th></th>
|
||||||
|
<th class="rotate"><div><span>ACTIVEDIRECTORY_PS</span></div></th>
|
||||||
|
<th class="rotate"><div><span>BIND</span></div></th>
|
||||||
|
<th class="rotate"><div><span>CLOUDFLAREAPI</span></div></th>
|
||||||
|
<th class="rotate"><div><span>DIGITALOCEAN</span></div></th>
|
||||||
|
<th class="rotate"><div><span>DNSIMPLE</span></div></th>
|
||||||
|
<th class="rotate"><div><span>GANDI</span></div></th>
|
||||||
|
<th class="rotate"><div><span>GCLOUD</span></div></th>
|
||||||
|
<th class="rotate"><div><span>NAMECHEAP</span></div></th>
|
||||||
|
<th class="rotate"><div><span>NAMEDOTCOM</span></div></th>
|
||||||
|
<th class="rotate"><div><span>NS1</span></div></th>
|
||||||
|
<th class="rotate"><div><span>ROUTE53</span></div></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<th class="row-header" style="text-decoration: underline;" data-toggle="tooltip" data-container="body" data-placement="top" title="This means the provider is actively used at stack exchange, and we offer a stronger guarantee it will work">Official Support</th>
|
||||||
|
<td class="success">
|
||||||
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
<td class="success">
|
||||||
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
<td class="success">
|
||||||
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
<td class="danger">
|
||||||
|
<i class="fa fa-times text-danger" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
<td class="danger">
|
||||||
|
<i class="fa fa-times text-danger" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
<td class="danger">
|
||||||
|
<i class="fa fa-times text-danger" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
<td class="success">
|
||||||
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
<td class="danger">
|
||||||
|
<i class="fa fa-times text-danger" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
<td class="success">
|
||||||
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
<td class="danger">
|
||||||
|
<i class="fa fa-times text-danger" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
<td class="success">
|
||||||
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th class="row-header" style="text-decoration: underline;" data-toggle="tooltip" data-container="body" data-placement="top" title="The provider has registrar capabilities to set nameservers for zones">Registrar</th>
|
||||||
|
<td class="danger">
|
||||||
|
<i class="fa fa-times text-danger" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
<td class="danger">
|
||||||
|
<i class="fa fa-times text-danger" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
<td class="danger">
|
||||||
|
<i class="fa fa-times text-danger" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
<td class="danger">
|
||||||
|
<i class="fa fa-times text-danger" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
<td class="success">
|
||||||
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
<td class="danger">
|
||||||
|
<i class="fa fa-times text-danger" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
<td class="danger">
|
||||||
|
<i class="fa fa-times text-danger" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
<td class="success">
|
||||||
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
<td class="success">
|
||||||
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
<td class="danger">
|
||||||
|
<i class="fa fa-times text-danger" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
<td class="success">
|
||||||
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th class="row-header" style="text-decoration: underline;" data-toggle="tooltip" data-container="body" data-placement="top" title="Can manage and serve DNS zones">DNS Provider</th>
|
||||||
|
<td class="success">
|
||||||
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
<td class="success">
|
||||||
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
<td class="success">
|
||||||
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
<td class="success">
|
||||||
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
<td class="success">
|
||||||
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
<td class="success">
|
||||||
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
<td class="success">
|
||||||
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
<td class="danger">
|
||||||
|
<i class="fa fa-times text-danger" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
<td class="success">
|
||||||
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
<td class="success">
|
||||||
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
<td class="success">
|
||||||
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th class="row-header" style="text-decoration: underline;" data-toggle="tooltip" data-container="body" data-placement="top" title="Provider supports some kind of ALIAS,ANAME or flattened CNAME record type">ALIAS</th>
|
||||||
|
<td class="danger">
|
||||||
|
<i class="fa fa-times text-danger" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
<td><i class="fa fa-minus dim"></i></td>
|
||||||
|
<td class="success" data-toggle="tooltip" data-container="body" data-placement="top" title="CF automatically flattens CNAME records into A records dynamically">
|
||||||
|
<i class="fa has-tooltip fa-check text-success" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
<td><i class="fa fa-minus dim"></i></td>
|
||||||
|
<td><i class="fa fa-minus dim"></i></td>
|
||||||
|
<td><i class="fa fa-minus dim"></i></td>
|
||||||
|
<td><i class="fa fa-minus dim"></i></td>
|
||||||
|
<td><i class="fa fa-minus dim"></i></td>
|
||||||
|
<td class="success">
|
||||||
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
<td><i class="fa fa-minus dim"></i></td>
|
||||||
|
<td><i class="fa fa-minus dim"></i></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th class="row-header" style="text-decoration: underline;" data-toggle="tooltip" data-container="body" data-placement="top" title="Driver has explicitly implemented SRV record management">SRV</th>
|
||||||
|
<td class="danger">
|
||||||
|
<i class="fa fa-times text-danger" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
<td class="success">
|
||||||
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
<td class="success">
|
||||||
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
<td class="success">
|
||||||
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
<td><i class="fa fa-minus dim"></i></td>
|
||||||
|
<td class="success">
|
||||||
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
<td class="success">
|
||||||
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
<td><i class="fa fa-minus dim"></i></td>
|
||||||
|
<td class="success">
|
||||||
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
<td><i class="fa fa-minus dim"></i></td>
|
||||||
|
<td class="success">
|
||||||
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th class="row-header" style="text-decoration: underline;" data-toggle="tooltip" data-container="body" data-placement="top" title="Provider supports adding PTR records for reverse lookup zones">PTR</th>
|
||||||
|
<td class="danger">
|
||||||
|
<i class="fa fa-times text-danger" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
<td class="success">
|
||||||
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
<td><i class="fa fa-minus dim"></i></td>
|
||||||
|
<td><i class="fa fa-minus dim"></i></td>
|
||||||
|
<td class="success">
|
||||||
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
<td class="success">
|
||||||
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
<td class="success">
|
||||||
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
<td><i class="fa fa-minus dim"></i></td>
|
||||||
|
<td class="danger" data-toggle="tooltip" data-container="body" data-placement="top" title="PTR records are not supported https://www.name.com/support/articles/205188508-Reverse-DNS-records (2017-05-08)">
|
||||||
|
<i class="fa has-tooltip fa-times text-danger" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
<td><i class="fa fa-minus dim"></i></td>
|
||||||
|
<td class="success">
|
||||||
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th class="row-header" style="text-decoration: underline;" data-toggle="tooltip" data-container="body" data-placement="top" title="Provider can manage CAA records">CAA</th>
|
||||||
|
<td class="danger">
|
||||||
|
<i class="fa fa-times text-danger" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
<td class="success">
|
||||||
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
<td><i class="fa fa-minus dim"></i></td>
|
||||||
|
<td><i class="fa fa-minus dim"></i></td>
|
||||||
|
<td><i class="fa fa-minus dim"></i></td>
|
||||||
|
<td><i class="fa fa-minus dim"></i></td>
|
||||||
|
<td class="success">
|
||||||
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
<td><i class="fa fa-minus dim"></i></td>
|
||||||
|
<td><i class="fa fa-minus dim"></i></td>
|
||||||
|
<td><i class="fa fa-minus dim"></i></td>
|
||||||
|
<td class="success">
|
||||||
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th class="row-header" style="text-decoration: underline;" data-toggle="tooltip" data-container="body" data-placement="top" title="This provider is recommended for use in 'dual hosting' scenarios. Usually this means the provider allows full control over the apex NS records">dual host</th>
|
||||||
|
<td class="danger" data-toggle="tooltip" data-container="body" data-placement="top" title="This driver does not manage NS records, so should not be used for dual-host scenarios">
|
||||||
|
<i class="fa has-tooltip fa-times text-danger" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
<td class="success">
|
||||||
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
<td class="danger" data-toggle="tooltip" data-container="body" data-placement="top" title="Cloudflare will not work well in situations where it is not the only DNS server">
|
||||||
|
<i class="fa has-tooltip fa-times text-danger" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
<td><i class="fa fa-minus dim"></i></td>
|
||||||
|
<td class="danger" data-toggle="tooltip" data-container="body" data-placement="top" title="DNSimple does not allow sufficient control over the apex NS records">
|
||||||
|
<i class="fa has-tooltip fa-times text-danger" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
<td><i class="fa fa-minus dim"></i></td>
|
||||||
|
<td class="success">
|
||||||
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
<td><i class="fa fa-minus dim"></i></td>
|
||||||
|
<td class="danger" data-toggle="tooltip" data-container="body" data-placement="top" title="Apex NS records not editable">
|
||||||
|
<i class="fa has-tooltip fa-times text-danger" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
<td class="success">
|
||||||
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
<td class="success">
|
||||||
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th class="row-header" style="text-decoration: underline;" data-toggle="tooltip" data-container="body" data-placement="top" title="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">create-domains</th>
|
||||||
|
<td class="danger" data-toggle="tooltip" data-container="body" data-placement="top" title="AD depends on the zone already existing on the dns server">
|
||||||
|
<i class="fa has-tooltip fa-times text-danger" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
<td class="success" data-toggle="tooltip" data-container="body" data-placement="top" title="Driver just maintains list of zone files. It should automatically add missing ones.">
|
||||||
|
<i class="fa has-tooltip fa-check text-success" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
<td class="success">
|
||||||
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
<td class="success">
|
||||||
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
<td class="danger">
|
||||||
|
<i class="fa fa-times text-danger" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
<td class="danger" data-toggle="tooltip" data-container="body" data-placement="top" title="Can only manage domains registered through their service">
|
||||||
|
<i class="fa has-tooltip fa-times text-danger" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
<td class="success">
|
||||||
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
<td class="danger" data-toggle="tooltip" data-container="body" data-placement="top" title="Requires domain registered through their service">
|
||||||
|
<i class="fa has-tooltip fa-times text-danger" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
<td class="danger" data-toggle="tooltip" data-container="body" data-placement="top" title="New domains require registration">
|
||||||
|
<i class="fa has-tooltip fa-times text-danger" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
<td class="danger">
|
||||||
|
<i class="fa fa-times text-danger" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
<td class="success">
|
||||||
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th class="row-header" style="text-decoration: underline;" data-toggle="tooltip" data-container="body" data-placement="top" title="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.">no_purge</th>
|
||||||
|
<td class="success">
|
||||||
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
<td class="danger">
|
||||||
|
<i class="fa fa-times text-danger" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
<td class="success">
|
||||||
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
<td class="success">
|
||||||
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
<td class="success">
|
||||||
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
<td class="danger">
|
||||||
|
<i class="fa fa-times text-danger" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
<td class="success">
|
||||||
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
<td class="success">
|
||||||
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
<td class="success">
|
||||||
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
<td class="success">
|
||||||
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
<td class="success">
|
||||||
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
@@ -5,11 +5,11 @@
|
|||||||
crossorigin="anonymous">
|
crossorigin="anonymous">
|
||||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap-theme.min.css" integrity="sha384-fLW2N01lMqjakBkx3l/M9EahuwpSfeNvV63J5ezn3uZzapT0u7EYsXMjQV+0En5r"
|
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap-theme.min.css" integrity="sha384-fLW2N01lMqjakBkx3l/M9EahuwpSfeNvV63J5ezn3uZzapT0u7EYsXMjQV+0En5r"
|
||||||
crossorigin="anonymous">
|
crossorigin="anonymous">
|
||||||
|
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
|
||||||
<script src="https://code.jquery.com/jquery-2.1.4.min.js" integrity="sha384-R4/ztc4ZlRqWjqIuvf6RX5yb/v90qNGx6fS48N0tRxiGkqveZETq72KgDVJCp2TC"
|
<script src="https://code.jquery.com/jquery-2.1.4.min.js" integrity="sha384-R4/ztc4ZlRqWjqIuvf6RX5yb/v90qNGx6fS48N0tRxiGkqveZETq72KgDVJCp2TC"
|
||||||
crossorigin="anonymous"></script>
|
crossorigin="anonymous"></script>
|
||||||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js" integrity="sha384-0mSbJDEHialfmuBBQP6A4Qrprq5OVfW37PRR3j5ELqxss1yVqOtnepnHVP9aJ7xS"
|
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js" integrity="sha384-0mSbJDEHialfmuBBQP6A4Qrprq5OVfW37PRR3j5ELqxss1yVqOtnepnHVP9aJ7xS"
|
||||||
crossorigin="anonymous"></script>
|
crossorigin="anonymous"></script>
|
||||||
<script src="https://use.fontawesome.com/03614296b7.js"></script>
|
|
||||||
<link rel="stylesheet" href="{{site.github.url}}/css/site.css">
|
<link rel="stylesheet" href="{{site.github.url}}/css/site.css">
|
||||||
<link rel="stylesheet" href="{{site.github.url}}/css/syntax.css">
|
<link rel="stylesheet" href="{{site.github.url}}/css/syntax.css">
|
||||||
|
|
||||||
@@ -45,9 +45,6 @@
|
|||||||
{{ content}}
|
{{ content}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% comment %} Live reload script. Dev mode only {% endcomment %} {% unless site.github %}
|
|
||||||
<script>document.write('<script src="http://' + (location.host || 'localhost').split(':')[0] + ':35729/livereload.js?snipver=1"></' + 'script>')</script>
|
|
||||||
{% endunless %}
|
|
||||||
{% comment %} This script makes the examples collapse appropriately {% endcomment %}
|
{% comment %} This script makes the examples collapse appropriately {% endcomment %}
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@@ -56,6 +53,9 @@
|
|||||||
$(this).parent().next().collapse('toggle');
|
$(this).parent().next().collapse('toggle');
|
||||||
$(this).toggleClass('expanded')
|
$(this).toggleClass('expanded')
|
||||||
});
|
});
|
||||||
|
$(function () {
|
||||||
|
$('[data-toggle="tooltip"]').tooltip()
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
|
|||||||
@@ -12,4 +12,65 @@
|
|||||||
|
|
||||||
body {
|
body {
|
||||||
padding-bottom: 50px;
|
padding-bottom: 50px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.table-header-rotated {
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-header-rotated td {
|
||||||
|
width: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-header-rotated th {
|
||||||
|
padding: 5px 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-header-rotated td {
|
||||||
|
text-align: center;
|
||||||
|
padding: 10px 5px;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-header-rotated th.rotate {
|
||||||
|
height: 140px;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-header-rotated th.rotate>div {
|
||||||
|
-webkit-transform: translate(25px, 51px) rotate(315deg);
|
||||||
|
-ms-transform: translate(25px, 51px) rotate(315deg);
|
||||||
|
transform: translate(25px, 51px) rotate(315deg);
|
||||||
|
width: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-header-rotated th.rotate>div>span {
|
||||||
|
border-bottom: 1px solid #ccc;
|
||||||
|
padding: 5px 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-header-rotated th.row-header {
|
||||||
|
padding: 0 10px;
|
||||||
|
border-bottom: 1px solid #ccc;
|
||||||
|
}
|
||||||
|
.success {
|
||||||
|
background-color: #dff0d8;
|
||||||
|
}
|
||||||
|
.warning {
|
||||||
|
background-color: #faf2cc;
|
||||||
|
}
|
||||||
|
.danger {
|
||||||
|
background-color: #f2dede;
|
||||||
|
}
|
||||||
|
.info {
|
||||||
|
background-color: #d9edf7;
|
||||||
|
}
|
||||||
|
.fa {
|
||||||
|
font-size: 150%;
|
||||||
|
}
|
||||||
|
.has-tooltip:before{
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
.dim {
|
||||||
|
color: #eeeeee
|
||||||
|
}
|
||||||
@@ -36,3 +36,4 @@ Dnscontrol is a platform for seamlessly managing your dns configuration across a
|
|||||||
### [Writing Providers]({{site.github.url}}/writing-providers)
|
### [Writing Providers]({{site.github.url}}/writing-providers)
|
||||||
|
|
||||||
### [Adding new DNS record types]({{site.github.url}}/adding-new-rtypes)
|
### [Adding new DNS record types]({{site.github.url}}/adding-new-rtypes)
|
||||||
|
|
||||||
|
|||||||
@@ -16,17 +16,26 @@ layout: default
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
<h2> Provider Features </h2>
|
||||||
|
|
||||||
|
<p>The table below shows various features supported, or not supported by DNSControl providers.
|
||||||
|
Underlined items have tooltips for more detailed explanation. This table is automatically generated
|
||||||
|
from metadata supplied by the provider when they register themselves inside dnscontrol.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
An empty space may indicate the feature is not supported by a provider, or it may simply mean
|
||||||
|
the feature has not been investigated and implemented yet. If a feature you need is missing from
|
||||||
|
a provider that supports it, we'd love your contribution to ensure it works correctly and add it to this matrix.
|
||||||
|
</p>
|
||||||
|
<p>If a feature is definitively not supported for whatever reason, we would also like a PR to clarify why it is not supported, and fill in this entire matrix.</p>
|
||||||
|
<br/>
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
{% include matrix.html %}
|
||||||
|
|
||||||
|
|
||||||
### Providers with "official support"
|
### Providers with "official support"
|
||||||
|
|
||||||
The following providers have official support:
|
|
||||||
|
|
||||||
* ACTIVEDIRECTORY_PS
|
|
||||||
* BIND
|
|
||||||
* CLOUDFLAREAPI
|
|
||||||
* GCLOUD
|
|
||||||
* NAMEDOTCOM
|
|
||||||
* ROUTE53
|
|
||||||
|
|
||||||
Official support means:
|
Official support means:
|
||||||
|
|
||||||
* New releases will block if any of these providers do not pass integration tests.
|
* New releases will block if any of these providers do not pass integration tests.
|
||||||
@@ -50,10 +59,11 @@ provided to help community members support their code independently.
|
|||||||
|
|
||||||
Maintainers of contributed providers:
|
Maintainers of contributed providers:
|
||||||
|
|
||||||
* digital ocean @Deraen
|
* digital ocean @Deraen
|
||||||
* dnsimple @aeden
|
* dnsimple @aeden
|
||||||
* gandi @TomOnTime
|
* gandi @TomOnTime
|
||||||
* namecheap @captncraig
|
* namecheap @captncraig
|
||||||
|
* ns1 @captncraig
|
||||||
* OVH @Oprax
|
* OVH @Oprax
|
||||||
|
|
||||||
### Requested providers
|
### Requested providers
|
||||||
@@ -62,7 +72,6 @@ We have received requests for the following providers. If you would like to cont
|
|||||||
code to support this provider, please re-open the issue. We'd be glad to help in any way.
|
code to support this provider, please re-open the issue. We'd be glad to help in any way.
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
<li>AWS R53 (DNS works. Request is to add Registrar support) (<a href="https://github.com/StackExchange/dnscontrol/issues/68">#68</a>)</li>
|
|
||||||
<li>Azure (<a href="https://github.com/StackExchange/dnscontrol/issues/42">#42</a>)</li>
|
<li>Azure (<a href="https://github.com/StackExchange/dnscontrol/issues/42">#42</a>)</li>
|
||||||
<li>ClouDNS (<a href="https://github.com/StackExchange/dnscontrol/issues/114">#114</a>)</li>
|
<li>ClouDNS (<a href="https://github.com/StackExchange/dnscontrol/issues/114">#114</a>)</li>
|
||||||
<li>Dyn (<a href="https://github.com/StackExchange/dnscontrol/issues/61">#61</a>)</li>
|
<li>Dyn (<a href="https://github.com/StackExchange/dnscontrol/issues/61">#61</a>)</li>
|
||||||
@@ -71,5 +80,4 @@ code to support this provider, please re-open the issue. We'd be glad to help in
|
|||||||
<li>Hurricane Electric (dns.he.net) (<a href="https://github.com/StackExchange/dnscontrol/issues/118">#118</a>)</li>
|
<li>Hurricane Electric (dns.he.net) (<a href="https://github.com/StackExchange/dnscontrol/issues/118">#118</a>)</li>
|
||||||
<li>Linode (<a href="https://github.com/StackExchange/dnscontrol/issues/121">#121</a>)</li>
|
<li>Linode (<a href="https://github.com/StackExchange/dnscontrol/issues/121">#121</a>)</li>
|
||||||
<li>OVH (<a href="https://github.com/StackExchange/dnscontrol/issues/143">#143</a>)</li>
|
<li>OVH (<a href="https://github.com/StackExchange/dnscontrol/issues/143">#143</a>)</li>
|
||||||
</ul>
|
</ul>
|
||||||
</ul>
|
|
||||||
2
main.go
2
main.go
@@ -10,7 +10,7 @@ import (
|
|||||||
_ "github.com/StackExchange/dnscontrol/providers/_all"
|
_ "github.com/StackExchange/dnscontrol/providers/_all"
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:generate go run build/generate/generate.go
|
//go:generate go run build/generate/generate.go build/generate/featureMatrix.go
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
log.SetFlags(log.LstdFlags | log.Lshortfile)
|
log.SetFlags(log.LstdFlags | log.Lshortfile)
|
||||||
|
|||||||
@@ -16,10 +16,20 @@ type adProvider struct {
|
|||||||
psLog string
|
psLog string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var docNotes = providers.DocumentationNotes{
|
||||||
|
providers.DocDualHost: providers.Cannot("This driver does not manage NS records, so should not be used for dual-host scenarios"),
|
||||||
|
providers.DocCreateDomains: providers.Cannot("AD depends on the zone already existing on the dns server"),
|
||||||
|
providers.DocOfficiallySupported: providers.Can(),
|
||||||
|
providers.CanUseAlias: providers.Cannot(),
|
||||||
|
providers.CanUseSRV: providers.Cannot(),
|
||||||
|
providers.CanUsePTR: providers.Cannot(),
|
||||||
|
providers.CanUseCAA: providers.Cannot(),
|
||||||
|
}
|
||||||
|
|
||||||
// Register with the dnscontrol system.
|
// Register with the dnscontrol system.
|
||||||
// This establishes the name (all caps), and the function to call to initialize it.
|
// This establishes the name (all caps), and the function to call to initialize it.
|
||||||
func init() {
|
func init() {
|
||||||
providers.RegisterDomainServiceProviderType("ACTIVEDIRECTORY_PS", newDNS)
|
providers.RegisterDomainServiceProviderType("ACTIVEDIRECTORY_PS", newDNS, docNotes)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newDNS(config map[string]string, metadata json.RawMessage) (providers.DNSServiceProvider, error) {
|
func newDNS(config map[string]string, metadata json.RawMessage) (providers.DNSServiceProvider, error) {
|
||||||
|
|||||||
@@ -30,6 +30,12 @@ import (
|
|||||||
"github.com/StackExchange/dnscontrol/providers/diff"
|
"github.com/StackExchange/dnscontrol/providers/diff"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var docNotes = providers.DocumentationNotes{
|
||||||
|
providers.DocDualHost: providers.Can(),
|
||||||
|
providers.DocCreateDomains: providers.Can("Driver just maintains list of zone files. It should automatically add missing ones."),
|
||||||
|
providers.DocOfficiallySupported: providers.Can(),
|
||||||
|
}
|
||||||
|
|
||||||
func initBind(config map[string]string, providermeta json.RawMessage) (providers.DNSServiceProvider, error) {
|
func initBind(config map[string]string, providermeta json.RawMessage) (providers.DNSServiceProvider, error) {
|
||||||
// config -- the key/values from creds.json
|
// config -- the key/values from creds.json
|
||||||
// meta -- the json blob from NewReq('name', 'TYPE', meta)
|
// meta -- the json blob from NewReq('name', 'TYPE', meta)
|
||||||
@@ -50,7 +56,8 @@ func initBind(config map[string]string, providermeta json.RawMessage) (providers
|
|||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
providers.RegisterDomainServiceProviderType("BIND", initBind, providers.CanUsePTR, providers.CanUseSRV, providers.CanUseCAA, providers.CantUseNOPURGE)
|
providers.RegisterDomainServiceProviderType("BIND", initBind, providers.CanUsePTR,
|
||||||
|
providers.CanUseSRV, providers.CanUseCAA, providers.CantUseNOPURGE, docNotes)
|
||||||
}
|
}
|
||||||
|
|
||||||
type SoaInfo struct {
|
type SoaInfo struct {
|
||||||
|
|||||||
97
providers/capabilities.go
Normal file
97
providers/capabilities.go
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
package providers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
//Capability is a bitmasked set of "features" that a provider supports. Only use constants from this package.
|
||||||
|
type Capability uint32
|
||||||
|
|
||||||
|
const (
|
||||||
|
// CanUseAlias indicates the provider support ALIAS records (or flattened CNAMES). Up to the provider to translate them to the appropriate record type.
|
||||||
|
// If you add something to this list, you probably want to add it to pkg/normalize/validate.go checkProviderCapabilities() or somewhere near there.
|
||||||
|
CanUseAlias Capability = iota
|
||||||
|
// CanUsePTR indicates the provider can handle PTR records
|
||||||
|
CanUsePTR
|
||||||
|
// CanUseSRV indicates the provider can handle SRV records
|
||||||
|
CanUseSRV
|
||||||
|
// CanUseCAA indicates the provider can handle CAA records
|
||||||
|
CanUseCAA
|
||||||
|
// CantUseNOPURGE indicates NO_PURGE is broken for this provider. To make it
|
||||||
|
// work would require complex emulation of an incremental update mechanism,
|
||||||
|
// so it is easier to simply mark this feature as not working for this
|
||||||
|
// provider.
|
||||||
|
CantUseNOPURGE
|
||||||
|
|
||||||
|
// DocOfficiallySupported means it is actively used and maintained by stack exchange
|
||||||
|
DocOfficiallySupported
|
||||||
|
// DocDualHost means provider allows full management of apex NS records, so we can safely dual-host with anothe provider
|
||||||
|
DocDualHost
|
||||||
|
// DocCreateDomains means provider can add domains with the `dnscontrol create-domains` command
|
||||||
|
DocCreateDomains
|
||||||
|
)
|
||||||
|
|
||||||
|
var providerCapabilities = map[string]map[Capability]bool{}
|
||||||
|
|
||||||
|
func ProviderHasCabability(pType string, cap Capability) bool {
|
||||||
|
if providerCapabilities[pType] == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return providerCapabilities[pType][cap]
|
||||||
|
}
|
||||||
|
|
||||||
|
// DocumentationNote is a way for providers to give more detail about what features they support.
|
||||||
|
type DocumentationNote struct {
|
||||||
|
HasFeature bool
|
||||||
|
Comment string
|
||||||
|
}
|
||||||
|
|
||||||
|
// DocumentationNotes is a full list of notes for a single provider
|
||||||
|
type DocumentationNotes map[Capability]*DocumentationNote
|
||||||
|
|
||||||
|
// ProviderMetadata is a common interface for DocumentationNotes and Capability to be used interchangably
|
||||||
|
type ProviderMetadata interface{}
|
||||||
|
|
||||||
|
// Notes is a collection of all documentation notes, keyed by provider type
|
||||||
|
var Notes = map[string]DocumentationNotes{}
|
||||||
|
|
||||||
|
func unwrapProviderCapabilities(pName string, meta []ProviderMetadata) {
|
||||||
|
for _, pm := range meta {
|
||||||
|
switch x := pm.(type) {
|
||||||
|
case Capability:
|
||||||
|
if providerCapabilities[pName] == nil {
|
||||||
|
providerCapabilities[pName] = map[Capability]bool{}
|
||||||
|
}
|
||||||
|
providerCapabilities[pName][x] = true
|
||||||
|
case DocumentationNotes:
|
||||||
|
if Notes[pName] == nil {
|
||||||
|
Notes[pName] = DocumentationNotes{}
|
||||||
|
}
|
||||||
|
for k, v := range x {
|
||||||
|
Notes[pName][k] = v
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
log.Fatalf("Unrecognized ProviderMetadata type: %T", pm)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Can is a small helper for concisely creating Documentation Notes
|
||||||
|
// comments are variadic for easy ommission, so you generally should pass 0 or 1 only.
|
||||||
|
func Can(comments ...string) *DocumentationNote {
|
||||||
|
return &DocumentationNote{
|
||||||
|
HasFeature: true,
|
||||||
|
Comment: strings.Join(comments, " "),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cannot is a small helper for concisely creating Documentation Notes
|
||||||
|
// comments are variadic for easy ommission, so you generally should pass 0 or 1 only.
|
||||||
|
func Cannot(comments ...string) *DocumentationNote {
|
||||||
|
return &DocumentationNote{
|
||||||
|
HasFeature: false,
|
||||||
|
Comment: strings.Join(comments, " "),
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -33,8 +33,15 @@ Domain level metadata available:
|
|||||||
- ip_conversions
|
- ip_conversions
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
var docNotes = providers.DocumentationNotes{
|
||||||
|
providers.DocDualHost: providers.Cannot("Cloudflare will not work well in situations where it is not the only DNS server"),
|
||||||
|
providers.DocCreateDomains: providers.Can(),
|
||||||
|
providers.DocOfficiallySupported: providers.Can(),
|
||||||
|
providers.CanUseAlias: providers.Can("CF automatically flattens CNAME records into A records dynamically"),
|
||||||
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
providers.RegisterDomainServiceProviderType("CLOUDFLAREAPI", newCloudflare, providers.CanUseSRV, providers.CanUseAlias)
|
providers.RegisterDomainServiceProviderType("CLOUDFLAREAPI", newCloudflare, providers.CanUseSRV, providers.CanUseAlias, docNotes)
|
||||||
providers.RegisterCustomRecordType("CF_REDIRECT", "CLOUDFLAREAPI", "")
|
providers.RegisterCustomRecordType("CF_REDIRECT", "CLOUDFLAREAPI", "")
|
||||||
providers.RegisterCustomRecordType("CF_TEMP_REDIRECT", "CLOUDFLAREAPI", "")
|
providers.RegisterCustomRecordType("CF_TEMP_REDIRECT", "CLOUDFLAREAPI", "")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,8 +60,13 @@ func newDo(m map[string]string, metadata json.RawMessage) (providers.DNSServiceP
|
|||||||
return api, nil
|
return api, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var docNotes = providers.DocumentationNotes{
|
||||||
|
providers.DocCreateDomains: providers.Can(),
|
||||||
|
providers.DocOfficiallySupported: providers.Cannot(),
|
||||||
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
providers.RegisterDomainServiceProviderType("DIGITALOCEAN", newDo, providers.CanUseSRV)
|
providers.RegisterDomainServiceProviderType("DIGITALOCEAN", newDo, providers.CanUseSRV, docNotes)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *DoApi) EnsureDomainExists(domain string) error {
|
func (api *DoApi) EnsureDomainExists(domain string) error {
|
||||||
|
|||||||
@@ -15,6 +15,17 @@ import (
|
|||||||
dnsimpleapi "github.com/dnsimple/dnsimple-go/dnsimple"
|
dnsimpleapi "github.com/dnsimple/dnsimple-go/dnsimple"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var docNotes = providers.DocumentationNotes{
|
||||||
|
providers.DocDualHost: providers.Cannot("DNSimple does not allow sufficient control over the apex NS records"),
|
||||||
|
providers.DocCreateDomains: providers.Cannot(),
|
||||||
|
providers.DocOfficiallySupported: providers.Cannot(),
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
providers.RegisterRegistrarType("DNSIMPLE", newReg)
|
||||||
|
providers.RegisterDomainServiceProviderType("DNSIMPLE", newDsp, providers.CanUsePTR, docNotes)
|
||||||
|
}
|
||||||
|
|
||||||
const stateRegistered = "registered"
|
const stateRegistered = "registered"
|
||||||
|
|
||||||
var defaultNameServerNames = []string{
|
var defaultNameServerNames = []string{
|
||||||
@@ -313,11 +324,6 @@ func newProvider(m map[string]string, metadata json.RawMessage) (*DnsimpleApi, e
|
|||||||
return api, nil
|
return api, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
|
||||||
providers.RegisterRegistrarType("DNSIMPLE", newReg)
|
|
||||||
providers.RegisterDomainServiceProviderType("DNSIMPLE", newDsp, providers.CanUsePTR)
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove all non-dnsimple NS records from our desired state.
|
// remove all non-dnsimple NS records from our desired state.
|
||||||
// if any are found, print a warning
|
// if any are found, print a warning
|
||||||
func removeOtherNS(dc *models.DomainConfig) {
|
func removeOtherNS(dc *models.DomainConfig) {
|
||||||
|
|||||||
@@ -25,6 +25,16 @@ Info required in `creds.json`:
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
var docNotes = providers.DocumentationNotes{
|
||||||
|
providers.DocCreateDomains: providers.Cannot("Can only manage domains registered through their service"),
|
||||||
|
providers.DocOfficiallySupported: providers.Cannot(),
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
providers.RegisterDomainServiceProviderType("GANDI", newGandi, providers.CanUsePTR,
|
||||||
|
providers.CanUseSRV, docNotes, providers.CantUseNOPURGE)
|
||||||
|
}
|
||||||
|
|
||||||
type GandiApi struct {
|
type GandiApi struct {
|
||||||
ApiKey string
|
ApiKey string
|
||||||
domainIndex map[string]int64 // Map of domainname to index
|
domainIndex map[string]int64 // Map of domainname to index
|
||||||
@@ -145,7 +155,3 @@ func newGandi(m map[string]string, metadata json.RawMessage) (providers.DNSServi
|
|||||||
|
|
||||||
return api, nil
|
return api, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
|
||||||
providers.RegisterDomainServiceProviderType("GANDI", newGandi, providers.CanUsePTR, providers.CanUseSRV)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -14,8 +14,14 @@ import (
|
|||||||
"github.com/StackExchange/dnscontrol/providers/diff"
|
"github.com/StackExchange/dnscontrol/providers/diff"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var docNotes = providers.DocumentationNotes{
|
||||||
|
providers.DocDualHost: providers.Can(),
|
||||||
|
providers.DocCreateDomains: providers.Can(),
|
||||||
|
providers.DocOfficiallySupported: providers.Can(),
|
||||||
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
providers.RegisterDomainServiceProviderType("GCLOUD", New, providers.CanUsePTR, providers.CanUseSRV, providers.CanUseCAA)
|
providers.RegisterDomainServiceProviderType("GCLOUD", New, providers.CanUsePTR, providers.CanUseSRV, providers.CanUseCAA, docNotes)
|
||||||
}
|
}
|
||||||
|
|
||||||
type gcloud struct {
|
type gcloud struct {
|
||||||
|
|||||||
@@ -16,8 +16,13 @@ type Namecheap struct {
|
|||||||
client *nc.Client
|
client *nc.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var docNotes = providers.DocumentationNotes{
|
||||||
|
providers.DocCreateDomains: providers.Cannot("Requires domain registered through their service"),
|
||||||
|
providers.DocOfficiallySupported: providers.Cannot(),
|
||||||
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
providers.RegisterRegistrarType("NAMECHEAP", newReg)
|
providers.RegisterRegistrarType("NAMECHEAP", newReg, docNotes)
|
||||||
// NOTE(tlim): If in the future the DNS Service Provider is implemented,
|
// NOTE(tlim): If in the future the DNS Service Provider is implemented,
|
||||||
// most likely it will require providers.CantUseNOPURGE.
|
// most likely it will require providers.CantUseNOPURGE.
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,13 @@ type nameDotCom struct {
|
|||||||
APIKey string `json:"apikey"`
|
APIKey string `json:"apikey"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var docNotes = providers.DocumentationNotes{
|
||||||
|
providers.DocDualHost: providers.Cannot("Apex NS records not editable"),
|
||||||
|
providers.DocCreateDomains: providers.Cannot("New domains require registration"),
|
||||||
|
providers.DocOfficiallySupported: providers.Can(),
|
||||||
|
providers.CanUsePTR: providers.Cannot("PTR records are not supported https://www.name.com/support/articles/205188508-Reverse-DNS-records (2017-05-08)"),
|
||||||
|
}
|
||||||
|
|
||||||
func newReg(conf map[string]string) (providers.Registrar, error) {
|
func newReg(conf map[string]string) (providers.Registrar, error) {
|
||||||
return newProvider(conf)
|
return newProvider(conf)
|
||||||
}
|
}
|
||||||
@@ -41,8 +48,7 @@ func newProvider(conf map[string]string) (*nameDotCom, error) {
|
|||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
providers.RegisterRegistrarType("NAMEDOTCOM", newReg)
|
providers.RegisterRegistrarType("NAMEDOTCOM", newReg)
|
||||||
providers.RegisterDomainServiceProviderType("NAMEDOTCOM", newDsp, providers.CanUseAlias, providers.CanUseSRV)
|
providers.RegisterDomainServiceProviderType("NAMEDOTCOM", newDsp, providers.CanUseAlias, providers.CanUseSRV, docNotes)
|
||||||
// PTR records are not supported https://www.name.com/support/articles/205188508-Reverse-DNS-records (2017-05-08)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
|
|||||||
@@ -18,8 +18,14 @@ import (
|
|||||||
"gopkg.in/ns1/ns1-go.v2/rest/model/dns"
|
"gopkg.in/ns1/ns1-go.v2/rest/model/dns"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var docNotes = providers.DocumentationNotes{
|
||||||
|
providers.DocCreateDomains: providers.Cannot(),
|
||||||
|
providers.DocOfficiallySupported: providers.Cannot(),
|
||||||
|
providers.DocDualHost: providers.Can(),
|
||||||
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
providers.RegisterDomainServiceProviderType("NS1", newProvider)
|
providers.RegisterDomainServiceProviderType("NS1", newProvider, docNotes)
|
||||||
}
|
}
|
||||||
|
|
||||||
type nsone struct {
|
type nsone struct {
|
||||||
|
|||||||
@@ -28,61 +28,33 @@ type DomainCreator interface {
|
|||||||
//RegistrarInitializer is a function to create a registrar. Function will be passed the unprocessed json payload from the configuration file for the given provider.
|
//RegistrarInitializer is a function to create a registrar. Function will be passed the unprocessed json payload from the configuration file for the given provider.
|
||||||
type RegistrarInitializer func(map[string]string) (Registrar, error)
|
type RegistrarInitializer func(map[string]string) (Registrar, error)
|
||||||
|
|
||||||
var registrarTypes = map[string]RegistrarInitializer{}
|
var RegistrarTypes = map[string]RegistrarInitializer{}
|
||||||
|
|
||||||
//DspInitializer is a function to create a DNS service provider. Function will be passed the unprocessed json payload from the configuration file for the given provider.
|
//DspInitializer is a function to create a DNS service provider. Function will be passed the unprocessed json payload from the configuration file for the given provider.
|
||||||
type DspInitializer func(map[string]string, json.RawMessage) (DNSServiceProvider, error)
|
type DspInitializer func(map[string]string, json.RawMessage) (DNSServiceProvider, error)
|
||||||
|
|
||||||
var dspTypes = map[string]DspInitializer{}
|
var DNSProviderTypes = map[string]DspInitializer{}
|
||||||
var dspCapabilities = map[string]Capability{}
|
|
||||||
|
|
||||||
//Capability is a bitmasked set of "features" that a provider supports. Only use constants from this package.
|
|
||||||
type Capability uint32
|
|
||||||
|
|
||||||
const (
|
|
||||||
// CanUseAlias indicates the provider support ALIAS records (or flattened CNAMES). Up to the provider to translate them to the appropriate record type.
|
|
||||||
// If you add something to this list, you probably want to add it to pkg/normalize/validate.go checkProviderCapabilities() or somewhere near there.
|
|
||||||
CanUseAlias Capability = 1 << iota
|
|
||||||
// CanUsePTR indicates the provider can handle PTR records
|
|
||||||
CanUsePTR
|
|
||||||
// CanUseSRV indicates the provider can handle SRV records
|
|
||||||
CanUseSRV
|
|
||||||
// CanUseCAA indicates the provider can handle CAA records
|
|
||||||
CanUseCAA
|
|
||||||
// CantUseNOPURGE indicates NO_PURGE is broken for this provider. To make it
|
|
||||||
// work would require complex emulation of an incremental update mechanism,
|
|
||||||
// so it is easier to simply mark this feature as not working for this
|
|
||||||
// provider.
|
|
||||||
CantUseNOPURGE
|
|
||||||
)
|
|
||||||
|
|
||||||
func ProviderHasCabability(pType string, cap Capability) bool {
|
|
||||||
return dspCapabilities[pType]&cap != 0
|
|
||||||
}
|
|
||||||
|
|
||||||
//RegisterRegistrarType adds a registrar type to the registry by providing a suitable initialization function.
|
//RegisterRegistrarType adds a registrar type to the registry by providing a suitable initialization function.
|
||||||
func RegisterRegistrarType(name string, init RegistrarInitializer) {
|
func RegisterRegistrarType(name string, init RegistrarInitializer, pm ...ProviderMetadata) {
|
||||||
if _, ok := registrarTypes[name]; ok {
|
if _, ok := RegistrarTypes[name]; ok {
|
||||||
log.Fatalf("Cannot register registrar type %s multiple times", name)
|
log.Fatalf("Cannot register registrar type %s multiple times", name)
|
||||||
}
|
}
|
||||||
registrarTypes[name] = init
|
RegistrarTypes[name] = init
|
||||||
|
unwrapProviderCapabilities(name, pm)
|
||||||
}
|
}
|
||||||
|
|
||||||
//RegisterDomainServiceProviderType adds a dsp to the registry with the given initialization function.
|
//RegisterDomainServiceProviderType adds a dsp to the registry with the given initialization function.
|
||||||
func RegisterDomainServiceProviderType(name string, init DspInitializer, caps ...Capability) {
|
func RegisterDomainServiceProviderType(name string, init DspInitializer, pm ...ProviderMetadata) {
|
||||||
if _, ok := dspTypes[name]; ok {
|
if _, ok := DNSProviderTypes[name]; ok {
|
||||||
log.Fatalf("Cannot register registrar type %s multiple times", name)
|
log.Fatalf("Cannot register registrar type %s multiple times", name)
|
||||||
}
|
}
|
||||||
var abilities Capability
|
DNSProviderTypes[name] = init
|
||||||
for _, c := range caps {
|
unwrapProviderCapabilities(name, pm)
|
||||||
abilities |= c
|
|
||||||
}
|
|
||||||
dspTypes[name] = init
|
|
||||||
dspCapabilities[name] = abilities
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func createRegistrar(rType string, config map[string]string) (Registrar, error) {
|
func createRegistrar(rType string, config map[string]string) (Registrar, error) {
|
||||||
initer, ok := registrarTypes[rType]
|
initer, ok := RegistrarTypes[rType]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("Registrar type %s not declared.", rType)
|
return nil, fmt.Errorf("Registrar type %s not declared.", rType)
|
||||||
}
|
}
|
||||||
@@ -90,7 +62,7 @@ func createRegistrar(rType string, config map[string]string) (Registrar, error)
|
|||||||
}
|
}
|
||||||
|
|
||||||
func CreateDNSProvider(dType string, config map[string]string, meta json.RawMessage) (DNSServiceProvider, error) {
|
func CreateDNSProvider(dType string, config map[string]string, meta json.RawMessage) (DNSServiceProvider, error) {
|
||||||
initer, ok := dspTypes[dType]
|
initer, ok := DNSProviderTypes[dType]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("DSP type %s not declared", dType)
|
return nil, fmt.Errorf("DSP type %s not declared", dType)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,8 +56,14 @@ func newRoute53(m map[string]string, metadata json.RawMessage) (*route53Provider
|
|||||||
return api, nil
|
return api, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var docNotes = providers.DocumentationNotes{
|
||||||
|
providers.DocDualHost: providers.Can(),
|
||||||
|
providers.DocCreateDomains: providers.Can(),
|
||||||
|
providers.DocOfficiallySupported: providers.Can(),
|
||||||
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
providers.RegisterDomainServiceProviderType("ROUTE53", newRoute53Dsp, providers.CanUsePTR, providers.CanUseSRV, providers.CanUseCAA)
|
providers.RegisterDomainServiceProviderType("ROUTE53", newRoute53Dsp, providers.CanUsePTR, providers.CanUseSRV, providers.CanUseCAA, docNotes)
|
||||||
providers.RegisterRegistrarType("ROUTE53", newRoute53Reg)
|
providers.RegisterRegistrarType("ROUTE53", newRoute53Reg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user