github.com/kurthockenbury/dnscontrol@v0.2.8/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 }