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