github.com/philhug/dnscontrol@v0.2.4-0.20180625181521-921fa9849001/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/providers"
    10  	_ "github.com/StackExchange/dnscontrol/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  			{"CAA", "Provider can manage CAA records"},
    34  			{"PTR", "Provider supports adding PTR records for reverse lookup zones"},
    35  			{"SRV", "Driver has explicitly implemented SRV record management"},
    36  			{"TLSA", "Provider can manage TLSA records"},
    37  			{"TXTMulti", "Provider can manage TXT records with multiple strings"},
    38  			{"R53_ALIAS", "Provider supports Route 53 limited ALIAS"},
    39  
    40  			{"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"},
    41  			{"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"},
    42  			{"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."},
    43  		},
    44  	}
    45  	for _, p := range providerTypes {
    46  		if p == "NONE" {
    47  			continue
    48  		}
    49  		fm := FeatureMap{}
    50  		notes := providers.Notes[p]
    51  		if notes == nil {
    52  			notes = providers.DocumentationNotes{}
    53  		}
    54  		setCap := func(name string, cap providers.Capability) {
    55  			if notes[cap] != nil {
    56  				fm[name] = notes[cap]
    57  				return
    58  			}
    59  			fm.SetSimple(name, true, func() bool { return providers.ProviderHasCabability(p, cap) })
    60  		}
    61  		setDoc := func(name string, cap providers.Capability, defaultNo bool) {
    62  			if notes[cap] != nil {
    63  				fm[name] = notes[cap]
    64  			} else if defaultNo {
    65  				fm[name] = &providers.DocumentationNote{
    66  					HasFeature: false,
    67  				}
    68  			}
    69  		}
    70  		setDoc("Official Support", providers.DocOfficiallySupported, true)
    71  		fm.SetSimple("DNS Provider", false, func() bool { return providers.DNSProviderTypes[p] != nil })
    72  		fm.SetSimple("Registrar", false, func() bool { return providers.RegistrarTypes[p] != nil })
    73  		setCap("ALIAS", providers.CanUseAlias)
    74  		setCap("CAA", providers.CanUseCAA)
    75  		setCap("PTR", providers.CanUsePTR)
    76  		setCap("SRV", providers.CanUseSRV)
    77  		setCap("TLSA", providers.CanUseTLSA)
    78  		setCap("TXTMulti", providers.CanUseTXTMulti)
    79  		setCap("R53_ALIAS", providers.CanUseRoute53Alias)
    80  		setDoc("dual host", providers.DocDualHost, false)
    81  		setDoc("create-domains", providers.DocCreateDomains, true)
    82  
    83  		// no purge is a freaky double negative
    84  		cap := providers.CantUseNOPURGE
    85  		if notes[cap] != nil {
    86  			fm["no_purge"] = notes[cap]
    87  		} else {
    88  			fm.SetSimple("no_purge", false, func() bool { return !providers.ProviderHasCabability(p, cap) })
    89  		}
    90  		matrix.Providers[p] = fm
    91  	}
    92  	buf := &bytes.Buffer{}
    93  	err := tmpl.Execute(buf, matrix)
    94  	if err != nil {
    95  		return err
    96  	}
    97  	return ioutil.WriteFile("docs/_includes/matrix.html", buf.Bytes(), 0644)
    98  }
    99  
   100  // FeatureDef describes features.
   101  type FeatureDef struct {
   102  	Name, Desc string
   103  }
   104  
   105  // FeatureMap maps provider names to compliance documentation.
   106  type FeatureMap map[string]*providers.DocumentationNote
   107  
   108  // SetSimple configures a provider's setting in fm.
   109  func (fm FeatureMap) SetSimple(name string, unknownsAllowed bool, f func() bool) {
   110  	if f() {
   111  		fm[name] = &providers.DocumentationNote{HasFeature: true}
   112  	} else if !unknownsAllowed {
   113  		fm[name] = &providers.DocumentationNote{HasFeature: false}
   114  	}
   115  }
   116  
   117  // FeatureMatrix describes features and which providers support it.
   118  type FeatureMatrix struct {
   119  	Features  []FeatureDef
   120  	Providers map[string]FeatureMap
   121  }
   122  
   123  var tmpl = template.Must(template.New("").Funcs(template.FuncMap{
   124  	"safe": func(s string) template.HTML { return template.HTML(s) },
   125  }).Parse(`
   126  	{% comment %}
   127      Matrix generated by build/generate/featureMatrix.go. DO NOT HAND EDIT!
   128  {% endcomment %}{{$providers := .Providers}}
   129  <table class="table-header-rotated">
   130  <thead>
   131  	<tr>
   132  	<th></th>
   133  	{{range $key,$val := $providers}}<th class="rotate"><div><span>{{$key}}</span></div></th>
   134  	{{end -}}
   135  	</tr>
   136  </thead>
   137  <tbody>
   138  	{{range .Features}}{{$name := .Name}}<tr>
   139  		<th class="row-header" style="text-decoration: underline;" data-toggle="tooltip" data-container="body" data-placement="top" title="{{.Desc}}">{{$name}}</th>
   140  		{{range $pname, $features := $providers}}{{$f := index $features $name}}{{if $f -}}
   141  		<td class="{{if $f.HasFeature}}success{{else if $f.Unimplemented}}info{{else}}danger{{end}}"
   142  			{{- if $f.Comment}} data-toggle="tooltip" data-container="body" data-placement="top" title="{{$f.Comment}}"{{end}}>
   143  			{{if $f.Link}}<a href="{{$f.Link}}">{{end}}<i class="fa {{if and $f.Comment (not $f.Unimplemented)}}has-tooltip {{end}}
   144  				{{- 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}}
   145  		</td>
   146  		{{- else}}<td><i class="fa fa-minus dim"></i></td>{{end}}
   147  		{{end -}}
   148  	</tr>
   149  	{{end -}}
   150  </tbody>
   151  </table>
   152  `))