github.com/philhug/dnscontrol@v0.2.4-0.20180625181521-921fa9849001/providers/octodns/octodnsProvider.go (about)

     1  package octodns
     2  
     3  /*
     4  
     5  octodns -
     6    Generate zonefiles suitiable for OctoDNS.
     7  
     8  	The zonefiles are read and written to the directory octoconfig
     9  
    10  	If the old octoconfig files are readable, we read them to determine
    11  	if an update is actually needed.
    12  
    13  	The YAML input and output code is extremely complicated because
    14  	the format does not fit well with a statically typed language.
    15  	The YAML format changes drastically if the label has single
    16  	or multiple rtypes associated with it, and if there is a single
    17  	or multiple rtype data.
    18  
    19  */
    20  
    21  import (
    22  	"bytes"
    23  	"encoding/json"
    24  	"fmt"
    25  	"log"
    26  	"os"
    27  	"path/filepath"
    28  	"strings"
    29  
    30  	"github.com/StackExchange/dnscontrol/models"
    31  	"github.com/StackExchange/dnscontrol/providers"
    32  	"github.com/StackExchange/dnscontrol/providers/diff"
    33  	"github.com/StackExchange/dnscontrol/providers/octodns/octoyaml"
    34  	"github.com/pkg/errors"
    35  )
    36  
    37  var features = providers.DocumentationNotes{
    38  	//providers.CanUseCAA: providers.Can(),
    39  	providers.CanUsePTR: providers.Can(),
    40  	providers.CanUseSRV: providers.Can(),
    41  	//providers.CanUseTXTMulti:   providers.Can(),
    42  	providers.DocCreateDomains: providers.Cannot("Driver just maintains list of OctoDNS config files. You must manually create the master config files that refer these."),
    43  	providers.DocDualHost:      providers.Cannot("Research is needed."),
    44  }
    45  
    46  func initProvider(config map[string]string, providermeta json.RawMessage) (providers.DNSServiceProvider, error) {
    47  	// config -- the key/values from creds.json
    48  	// meta -- the json blob from NewReq('name', 'TYPE', meta)
    49  	api := &Provider{
    50  		directory: config["directory"],
    51  	}
    52  	if api.directory == "" {
    53  		api.directory = "config"
    54  	}
    55  	if len(providermeta) != 0 {
    56  		err := json.Unmarshal(providermeta, api)
    57  		if err != nil {
    58  			return nil, err
    59  		}
    60  	}
    61  	//api.nameservers = models.StringsToNameservers(api.DefaultNS)
    62  	return api, nil
    63  }
    64  
    65  func init() {
    66  	providers.RegisterDomainServiceProviderType("OCTODNS", initProvider, features)
    67  }
    68  
    69  // Provider is the provider handle for the OctoDNS driver.
    70  type Provider struct {
    71  	//DefaultNS   []string `json:"default_ns"`
    72  	//DefaultSoa  SoaInfo  `json:"default_soa"`
    73  	//nameservers []*models.Nameserver
    74  	directory string
    75  }
    76  
    77  // GetNameservers returns the nameservers for a domain.
    78  func (c *Provider) GetNameservers(string) ([]*models.Nameserver, error) {
    79  	return nil, nil
    80  }
    81  
    82  // GetDomainCorrections returns a list of corrections to update a domain.
    83  func (c *Provider) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
    84  	dc.Punycode()
    85  	// Phase 1: Copy everything to []*models.RecordConfig:
    86  	//    expectedRecords < dc.Records[i]
    87  	//    foundRecords < zonefile
    88  	//
    89  	// Phase 2: Do any manipulations:
    90  	// add NS
    91  	// manipulate SOA
    92  	//
    93  	// Phase 3: Convert to []diff.Records and compare:
    94  	// expectedDiffRecords < expectedRecords
    95  	// foundDiffRecords < foundRecords
    96  	// diff.Inc...(foundDiffRecords, expectedDiffRecords )
    97  
    98  	// Read foundRecords:
    99  	var foundRecords models.Records
   100  	zoneFileFound := true
   101  	zoneFileName := filepath.Join(c.directory, strings.Replace(strings.ToLower(dc.Name), "/", "_", -1)+".yaml")
   102  	foundFH, err := os.Open(zoneFileName)
   103  	if err != nil {
   104  		if os.IsNotExist(err) {
   105  			zoneFileFound = false
   106  		} else {
   107  			return nil, errors.Wrapf(err, "can't open %s:", zoneFileName)
   108  		}
   109  	} else {
   110  		foundRecords, err = octoyaml.ReadYaml(foundFH, dc.Name)
   111  		if err != nil {
   112  			return nil, errors.Wrapf(err, "can not get corrections")
   113  		}
   114  	}
   115  
   116  	// Normalize
   117  	models.PostProcessRecords(foundRecords)
   118  
   119  	differ := diff.New(dc)
   120  	_, create, del, mod := differ.IncrementalDiff(foundRecords)
   121  
   122  	buf := &bytes.Buffer{}
   123  	// Print a list of changes. Generate an actual change that is the zone
   124  	changes := false
   125  	for _, i := range create {
   126  		changes = true
   127  		fmt.Fprintln(buf, i)
   128  	}
   129  	for _, i := range del {
   130  		changes = true
   131  		fmt.Fprintln(buf, i)
   132  	}
   133  	for _, i := range mod {
   134  		changes = true
   135  		fmt.Fprintln(buf, i)
   136  	}
   137  	msg := fmt.Sprintf("GENERATE_CONFIGFILE: %s", dc.Name)
   138  	if zoneFileFound {
   139  		msg += "\n"
   140  		msg += buf.String()
   141  	} else {
   142  		msg += fmt.Sprintf(" (%d records)\n", len(create))
   143  	}
   144  	corrections := []*models.Correction{}
   145  	if changes {
   146  		corrections = append(corrections,
   147  			&models.Correction{
   148  				Msg: msg,
   149  				F: func() error {
   150  					fmt.Printf("CREATING CONFIGFILE: %v\n", zoneFileName)
   151  					zf, err := os.Create(zoneFileName)
   152  					if err != nil {
   153  						log.Fatalf("Could not create zonefile: %v", err)
   154  					}
   155  					//err = WriteZoneFile(zf, dc.Records, dc.Name)
   156  					err = octoyaml.WriteYaml(zf, dc.Records, dc.Name)
   157  					if err != nil {
   158  						log.Fatalf("WriteZoneFile error: %v\n", err)
   159  					}
   160  					err = zf.Close()
   161  					if err != nil {
   162  						log.Fatalf("Closing: %v", err)
   163  					}
   164  					return nil
   165  				},
   166  			})
   167  	}
   168  
   169  	return corrections, nil
   170  }