github.com/teknogeek/dnscontrol/v2@v2.10.1-0.20200227202244-ae299b55ba42/build/generate/featureMatrix.go (about)

     1  package main
     2  
     3  import (
     4  	"bytes"
     5  	"html/template"
     6  	"io/ioutil"
     7  	"sort"
     8  
     9  	"github.com/StackExchange/dnscontrol/v2/providers"
    10  	_ "github.com/StackExchange/dnscontrol/v2/providers/_all"
    11  )
    12  
    13  func generateFeatureMatrix() error {
    14  	allNames := map[string]bool{}
    15  	for n := range providers.RegistrarTypes {
    16  		allNames[n] = true
    17  	}
    18  	for n := range providers.DNSProviderTypes {
    19  		allNames[n] = true
    20  	}
    21  	providerTypes := []string{}
    22  	for n := range allNames {
    23  		providerTypes = append(providerTypes, n)
    24  	}
    25  	sort.Strings(providerTypes)
    26  	matrix := &FeatureMatrix{
    27  		Providers: map[string]FeatureMap{},
    28  		Features: []FeatureDef{
    29  			{"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"},
    30  			{"DNS Provider", "Can manage and serve DNS zones"},
    31  			{"Registrar", "The provider has registrar capabilities to set nameservers for zones"},
    32  			{"ALIAS", "Provider supports some kind of ALIAS, ANAME or flattened CNAME record type"},
    33  			{"AUTODNSSEC", "Provider can automatically manage DNSSEC"},
    34  			{"CAA", "Provider can manage CAA records"},
    35  			{"PTR", "Provider supports adding PTR records for reverse lookup zones"},
    36  			{"NAPTR", "Provider can manage NAPTR records"},
    37  			{"SRV", "Driver has explicitly implemented SRV record management"},
    38  			{"SSHFP", "Provider can manage SSHFP records"},
    39  			{"TLSA", "Provider can manage TLSA records"},
    40  			{"TXTMulti", "Provider can manage TXT records with multiple strings"},
    41  			{"R53_ALIAS", "Provider supports Route 53 limited ALIAS"},
    42  
    43  			{"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"},
    44  			{"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"},
    45  			{"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."},
    46  			{"get-zones", "indicates the dnscontrol get-zones subcommand is implemented."},
    47  		},
    48  	}
    49  	for _, p := range providerTypes {
    50  		if p == "NONE" {
    51  			continue
    52  		}
    53  		fm := FeatureMap{}
    54  		notes := providers.Notes[p]
    55  		if notes == nil {
    56  			notes = providers.DocumentationNotes{}
    57  		}
    58  		setCap := func(name string, cap providers.Capability) {
    59  			if notes[cap] != nil {
    60  				fm[name] = notes[cap]
    61  				return
    62  			}
    63  			fm.SetSimple(name, true, func() bool { return providers.ProviderHasCapability(p, cap) })
    64  		}
    65  		setDoc := func(name string, cap providers.Capability, defaultNo bool) {
    66  			if notes[cap] != nil {
    67  				fm[name] = notes[cap]
    68  			} else if defaultNo {
    69  				fm[name] = &providers.DocumentationNote{
    70  					HasFeature: false,
    71  				}
    72  			}
    73  		}
    74  		setDoc("Official Support", providers.DocOfficiallySupported, true)
    75  		fm.SetSimple("DNS Provider", false, func() bool { return providers.DNSProviderTypes[p] != nil })
    76  		fm.SetSimple("Registrar", false, func() bool { return providers.RegistrarTypes[p] != nil })
    77  		setCap("ALIAS", providers.CanUseAlias)
    78  		setCap("AUTODNSSEC", providers.CanAutoDNSSEC)
    79  		setCap("CAA", providers.CanUseCAA)
    80  		setCap("NAPTR", providers.CanUseNAPTR)
    81  		setCap("PTR", providers.CanUsePTR)
    82  		setCap("R53_ALIAS", providers.CanUseRoute53Alias)
    83  		setCap("SRV", providers.CanUseSRV)
    84  		setCap("SSHFP", providers.CanUseSSHFP)
    85  		setCap("TLSA", providers.CanUseTLSA)
    86  		setCap("TXTMulti", providers.CanUseTXTMulti)
    87  		setCap("get-zones", providers.CanGetZones)
    88  		setDoc("dual host", providers.DocDualHost, false)
    89  		setDoc("create-domains", providers.DocCreateDomains, true)
    90  
    91  		// no purge is a freaky double negative
    92  		cap := providers.CantUseNOPURGE
    93  		if notes[cap] != nil {
    94  			fm["no_purge"] = notes[cap]
    95  		} else {
    96  			fm.SetSimple("no_purge", false, func() bool { return !providers.ProviderHasCapability(p, cap) })
    97  		}
    98  		matrix.Providers[p] = fm
    99  	}
   100  	buf := &bytes.Buffer{}
   101  	err := tmpl.Execute(buf, matrix)
   102  	if err != nil {
   103  		return err
   104  	}
   105  	return ioutil.WriteFile("docs/_includes/matrix.html", buf.Bytes(), 0644)
   106  }
   107  
   108  // FeatureDef describes features.
   109  type FeatureDef struct {
   110  	Name, Desc string
   111  }
   112  
   113  // FeatureMap maps provider names to compliance documentation.
   114  type FeatureMap map[string]*providers.DocumentationNote
   115  
   116  // SetSimple configures a provider's setting in fm.
   117  func (fm FeatureMap) SetSimple(name string, unknownsAllowed bool, f func() bool) {
   118  	if f() {
   119  		fm[name] = &providers.DocumentationNote{HasFeature: true}
   120  	} else if !unknownsAllowed {
   121  		fm[name] = &providers.DocumentationNote{HasFeature: false}
   122  	}
   123  }
   124  
   125  // FeatureMatrix describes features and which providers support it.
   126  type FeatureMatrix struct {
   127  	Features  []FeatureDef
   128  	Providers map[string]FeatureMap
   129  }
   130  
   131  var tmpl = template.Must(template.New("").Funcs(template.FuncMap{
   132  	"safe": func(s string) template.HTML { return template.HTML(s) },
   133  }).Parse(`
   134  	{% comment %}
   135      Matrix generated by build/generate/featureMatrix.go. DO NOT HAND EDIT!
   136  {% endcomment %}{{$providers := .Providers}}
   137  <table class="table-header-rotated">
   138  <thead>
   139  	<tr>
   140  	<th></th>
   141  	{{range $key,$val := $providers}}<th class="rotate"><div><span>{{$key}}</span></div></th>
   142  	{{end -}}
   143  	</tr>
   144  </thead>
   145  <tbody>
   146  	{{range .Features}}{{$name := .Name}}<tr>
   147  		<th class="row-header" style="text-decoration: underline;" data-toggle="tooltip" data-container="body" data-placement="top" title="{{.Desc}}">{{$name}}</th>
   148  		{{range $pname, $features := $providers}}{{$f := index $features $name}}{{if $f -}}
   149  		<td class="{{if $f.HasFeature}}success{{else if $f.Unimplemented}}info{{else}}danger{{end}}"
   150  			{{- if $f.Comment}} data-toggle="tooltip" data-container="body" data-placement="top" title="{{$f.Comment}}"{{end}}>
   151  			{{if $f.Link}}<a href="{{$f.Link}}">{{end}}<i class="fa {{if and $f.Comment (not $f.Unimplemented)}}has-tooltip {{end}}
   152  				{{- 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}}
   153  		</td>
   154  		{{- else}}<td><i class="fa fa-minus dim"></i></td>{{end}}
   155  		{{end -}}
   156  	</tr>
   157  	{{end -}}
   158  </tbody>
   159  </table>
   160  `))