mirror of
https://github.com/StackExchange/dnscontrol.git
synced 2024-09-20 06:46:19 +08:00
NEW FEATURE: Moving provider TYPE from dnsconfig.js to creds.json (#1500)
Fixes https://github.com/StackExchange/dnscontrol/issues/1457 * New-style creds.json implememented backwards compatible * Update tests * Update docs * Assume new-style TYPE
This commit is contained in:
parent
bbecce74bd
commit
9e6d642e35
|
@ -22,11 +22,21 @@ var _ = cmd(catUtils, func() *cli.Command {
|
|||
Action: func(ctx *cli.Context) error {
|
||||
if ctx.NArg() < 3 {
|
||||
return cli.Exit("Arguments should be: credskey providername zone(s) (Ex: r53 ROUTE53 example.com)", 1)
|
||||
|
||||
}
|
||||
args.CredName = ctx.Args().Get(0)
|
||||
args.ProviderName = ctx.Args().Get(1)
|
||||
arg1 := ctx.Args().Get(1)
|
||||
args.ProviderName = arg1
|
||||
// In v4.0, skip the first args.ZoneNames if it it equals "-".
|
||||
args.ZoneNames = ctx.Args().Slice()[2:]
|
||||
|
||||
if arg1 != "" && arg1 != "-" {
|
||||
// NB(tlim): In v4.0 this "if" can be removed.
|
||||
fmt.Fprintf(os.Stderr, "WARNING: To retain compatibility in future versions, please change %q to %q. See %q\n",
|
||||
arg1, "-",
|
||||
"https://stackexchange.github.io/dnscontrol/get-zones.html",
|
||||
)
|
||||
}
|
||||
|
||||
return exit(GetZone(args))
|
||||
},
|
||||
Flags: args.flags(),
|
||||
|
@ -73,12 +83,21 @@ var _ = cmd(catUtils, func() *cli.Command {
|
|||
Name: "check-creds",
|
||||
Usage: "Do a small operation to verify credentials (stand-alone)",
|
||||
Action: func(ctx *cli.Context) error {
|
||||
if ctx.NArg() != 2 {
|
||||
return cli.Exit("Arguments should be: credskey providername (Ex: r53 ROUTE53)", 1)
|
||||
|
||||
var arg0, arg1 string
|
||||
// This takes one or two command-line args.
|
||||
// Starting in v3.16: Using it with 2 args will generate a warning.
|
||||
// Starting in v4.0: Using it with 2 args might be an error.
|
||||
if ctx.NArg() == 1 {
|
||||
arg0 = ctx.Args().Get(0)
|
||||
arg1 = ""
|
||||
} else if ctx.NArg() == 2 {
|
||||
arg0 = ctx.Args().Get(0)
|
||||
arg1 = ctx.Args().Get(1)
|
||||
} else {
|
||||
return cli.Exit("Arguments should be: credskey [providername] (Ex: r53 ROUTE53)", 1)
|
||||
}
|
||||
args.CredName = ctx.Args().Get(0)
|
||||
args.ProviderName = ctx.Args().Get(1)
|
||||
args.CredName = arg0
|
||||
args.ProviderName = arg1
|
||||
args.ZoneNames = []string{"all"}
|
||||
args.OutputFormat = "nameonly"
|
||||
return exit(GetZone(args))
|
||||
|
@ -95,8 +114,9 @@ ARGUMENTS:
|
|||
provider: The name of the provider (second parameter to NewDnsProvider() in dnsconfig.js)
|
||||
|
||||
EXAMPLES:
|
||||
dnscontrol get-zones myr53 ROUTE53
|
||||
dnscontrol get-zones --out=/dev/null myr53 ROUTE53`,
|
||||
dnscontrol check-creds myr53 ROUTE53 # Pre v3.16, or pre-v4.0 for backwards-compatibility
|
||||
dnscontrol check-creds myr53
|
||||
dnscontrol check-creds --out=/dev/null myr53 && echo Success`,
|
||||
}
|
||||
}())
|
||||
|
||||
|
@ -104,7 +124,7 @@ EXAMPLES:
|
|||
type GetZoneArgs struct {
|
||||
GetCredentialsArgs // Args related to creds.json
|
||||
CredName string // key in creds.json
|
||||
ProviderName string // provider name: BIND, GANDI_V5, etc or "-"
|
||||
ProviderName string // provider type: BIND, GANDI_V5, etc or "-" (NB(tlim): In 4.0, this field goes away.)
|
||||
ZoneNames []string // The zones to get
|
||||
OutputFormat string // Output format
|
||||
OutputFile string // Filename to send output ("" means stdout)
|
||||
|
@ -144,7 +164,7 @@ func GetZone(args GetZoneArgs) error {
|
|||
}
|
||||
provider, err := providers.CreateDNSProvider(args.ProviderName, providerConfigs[args.CredName], nil)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed GetZone CreateDNSProvider: %w", err)
|
||||
return fmt.Errorf("failed GetZone CDP: %w", err)
|
||||
}
|
||||
|
||||
// decide which zones we need to convert
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
|
||||
|
@ -99,10 +100,6 @@ func run(args PreviewArgs, push bool, interactive bool, out printer.CLI) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
errs := normalize.ValidateAndNormalizeConfig(cfg)
|
||||
if PrintValidationErrors(errs) {
|
||||
return fmt.Errorf("exiting due to validation errors")
|
||||
}
|
||||
providerConfigs, err := credsfile.LoadProviderConfigs(args.CredsFile)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -111,6 +108,11 @@ func run(args PreviewArgs, push bool, interactive bool, out printer.CLI) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
errs := normalize.ValidateAndNormalizeConfig(cfg)
|
||||
if PrintValidationErrors(errs) {
|
||||
return fmt.Errorf("exiting due to validation errors")
|
||||
}
|
||||
anyErrors := false
|
||||
totalCorrections := 0
|
||||
DomainLoop:
|
||||
|
@ -200,6 +202,16 @@ func InitializeProviders(cfg *models.DNSConfig, providerConfigs map[string]map[s
|
|||
isNonDefault[name] = true
|
||||
}
|
||||
}
|
||||
|
||||
// Populate provider type ids based on values from creds.json:
|
||||
msgs, err := populateProviderTypes(cfg, providerConfigs)
|
||||
if len(msgs) != 0 {
|
||||
fmt.Fprintln(os.Stderr, strings.Join(msgs, "\n"))
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
registrars := map[string]providers.Registrar{}
|
||||
dnsProviders := map[string]providers.DNSServiceProvider{}
|
||||
for _, d := range cfg.Domains {
|
||||
|
@ -229,6 +241,200 @@ func InitializeProviders(cfg *models.DNSConfig, providerConfigs map[string]map[s
|
|||
return
|
||||
}
|
||||
|
||||
// providerTypeFieldName is the name of the field in creds.json that specifies the provider type id.
|
||||
const providerTypeFieldName = "TYPE"
|
||||
|
||||
// url is the documentation URL to list in the warnings related to missing provider type ids.
|
||||
const url = "https://stackexchange.github.io/dnscontrol/creds-json"
|
||||
|
||||
// populateProviderTypes scans a DNSConfig for blank provider types and fills them in based on providerConfigs.
|
||||
// That is, if the provider type is "-" or "", we take that as an flag
|
||||
// that means this value should be replaced by the type found in creds.json.
|
||||
func populateProviderTypes(cfg *models.DNSConfig, providerConfigs map[string]map[string]string) ([]string, error) {
|
||||
var msgs []string
|
||||
|
||||
for i := range cfg.Registrars {
|
||||
pType := cfg.Registrars[i].Type
|
||||
pName := cfg.Registrars[i].Name
|
||||
nt, warnMsg, err := refineProviderType(pName, pType, providerConfigs[pName], "NewRegistrar")
|
||||
cfg.Registrars[i].Type = nt
|
||||
if warnMsg != "" {
|
||||
msgs = append(msgs, warnMsg)
|
||||
}
|
||||
if err != nil {
|
||||
return msgs, err
|
||||
}
|
||||
}
|
||||
|
||||
for i := range cfg.DNSProviders {
|
||||
pName := cfg.DNSProviders[i].Name
|
||||
pType := cfg.DNSProviders[i].Type
|
||||
nt, warnMsg, err := refineProviderType(pName, pType, providerConfigs[pName], "NewDnsProvider")
|
||||
cfg.DNSProviders[i].Type = nt
|
||||
if warnMsg != "" {
|
||||
msgs = append(msgs, warnMsg)
|
||||
}
|
||||
if err != nil {
|
||||
return msgs, err
|
||||
}
|
||||
}
|
||||
|
||||
// Update these fields set by // commands/commands.go:preloadProviders().
|
||||
// This is probably a layering violation. That said, the
|
||||
// fundamental problem here is that we're storing the provider
|
||||
// instances by string name, not by a pointer to a struct. We
|
||||
// should clean that up someday.
|
||||
for _, domain := range cfg.Domains { // For each domain..
|
||||
for _, provider := range domain.DNSProviderInstances { // For each provider...
|
||||
pName := provider.ProviderBase.Name
|
||||
pType := provider.ProviderBase.ProviderType
|
||||
nt, warnMsg, err := refineProviderType(pName, pType, providerConfigs[pName], "NewDnsProvider")
|
||||
provider.ProviderBase.ProviderType = nt
|
||||
if warnMsg != "" {
|
||||
msgs = append(msgs, warnMsg)
|
||||
}
|
||||
if err != nil {
|
||||
return msgs, err
|
||||
}
|
||||
}
|
||||
p := domain.RegistrarInstance
|
||||
pName := p.Name
|
||||
pType := p.ProviderType
|
||||
nt, warnMsg, err := refineProviderType(pName, pType, providerConfigs[pName], "NewRegistrar")
|
||||
p.ProviderType = nt
|
||||
if warnMsg != "" {
|
||||
msgs = append(msgs, warnMsg)
|
||||
}
|
||||
if err != nil {
|
||||
return msgs, err
|
||||
}
|
||||
}
|
||||
|
||||
return uniqueStrings(msgs), nil
|
||||
}
|
||||
|
||||
// uniqueStrings takes an unsorted slice of strings and returns the
|
||||
// unique strings, in the order they first appeared in the list.
|
||||
func uniqueStrings(stringSlice []string) []string {
|
||||
keys := make(map[string]bool)
|
||||
list := []string{}
|
||||
for _, entry := range stringSlice {
|
||||
if _, ok := keys[entry]; !ok {
|
||||
keys[entry] = true
|
||||
list = append(list, entry)
|
||||
}
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
func refineProviderType(credEntryName string, t string, credFields map[string]string, source string) (replacementType string, warnMsg string, err error) {
|
||||
|
||||
// t="" and t="-" are processed the same. Standardize on "-" to reduce the number of cases to check.
|
||||
if t == "" {
|
||||
t = "-"
|
||||
}
|
||||
|
||||
// Use cases:
|
||||
//
|
||||
// type credsType
|
||||
// ---- ---------
|
||||
// - or "" GANDI lookup worked. Nothing to say.
|
||||
// - or "" - or "" ERROR "creds.json has invalid or missing data"
|
||||
// GANDI "" WARNING "Working but.... Please fix as follows..."
|
||||
// GANDI GANDI INFO "working but unneeded: clean up as follows..."
|
||||
// GANDI NAMEDOT ERROR "error mismatched: please fix as follows..."
|
||||
|
||||
// ERROR: Invalid.
|
||||
// WARNING: Required change to remain compatible with 4.0
|
||||
// INFO: Post-4.0 cleanups or other non-required changes.
|
||||
|
||||
if t != "-" {
|
||||
// Old-style, dnsconfig.js specifies the type explicitly.
|
||||
// This is supported but we suggest updates for future compatibility.
|
||||
|
||||
// If credFields is nil, that means there was no entry in creds.json:
|
||||
if credFields == nil {
|
||||
// Warn the user to update creds.json in preparation for 4.0:
|
||||
// In 4.0 this should be an error. We could default to a
|
||||
// provider such as "NONE" but I suspect it would be confusing
|
||||
// to users to see references to a provider name that they did
|
||||
// not specify.
|
||||
return t, fmt.Sprintf(`WARNING: For future compatibility, add this entry creds.json: %q: { %q: %q }, (See %s#missing)`,
|
||||
credEntryName, providerTypeFieldName, t,
|
||||
url,
|
||||
), nil
|
||||
}
|
||||
|
||||
switch ct := credFields[providerTypeFieldName]; ct {
|
||||
case "":
|
||||
// Warn the user to update creds.json in preparation for 4.0:
|
||||
// In 4.0 this should be an error.
|
||||
return t, fmt.Sprintf(`WARNING: For future compatibility, update the %q entry in creds.json by adding: %q: %q, (See %s#missing)`,
|
||||
credEntryName,
|
||||
providerTypeFieldName, t,
|
||||
url,
|
||||
), nil
|
||||
case "-":
|
||||
// This should never happen. The user is specifying "-" in a place that it shouldn't be used.
|
||||
return "-", "", fmt.Errorf(`ERROR: creds.json entry %q has invalid %q value %q (See %s#hyphen)`,
|
||||
credEntryName, providerTypeFieldName, ct,
|
||||
url,
|
||||
)
|
||||
case t:
|
||||
// creds.json file is compatible with and dnsconfig.js can be updated.
|
||||
return ct, fmt.Sprintf(`INFO: In dnsconfig.js %s(%q, %q) can be simplified to %s(%q) (See %s#cleanup)`,
|
||||
source, credEntryName, t,
|
||||
source, credEntryName,
|
||||
url,
|
||||
), nil
|
||||
default:
|
||||
// creds.json lists a TYPE but it doesn't match what's in dnsconfig.js!
|
||||
return t, "", fmt.Errorf(`ERROR: Mismatch found! creds.json entry %q has %q set to %q but dnsconfig.js specifies %s(%q, %q) (See %s#mismatch)`,
|
||||
credEntryName,
|
||||
providerTypeFieldName, ct,
|
||||
source, credEntryName, t,
|
||||
url,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// t == "-"
|
||||
// New-style, dnsconfig.js does not specify the type (t == "") or a
|
||||
// command line tool accepted "-" as a positional argument for
|
||||
// backwards compatibility.
|
||||
|
||||
// If credFields is nil, that means there was no entry in creds.json:
|
||||
if credFields == nil {
|
||||
return "", "", fmt.Errorf(`ERROR: creds.json is missing an entry called %q. Suggestion: %q: { %q: %q }, (See %s#missing)`,
|
||||
credEntryName,
|
||||
credEntryName, providerTypeFieldName, "FILL_IN_PROVIDER_TYPE",
|
||||
url,
|
||||
)
|
||||
}
|
||||
|
||||
// New-style, dnsconfig.js doesn't specifies the type. It will be
|
||||
// looked up in creds.json.
|
||||
switch ct := credFields[providerTypeFieldName]; ct {
|
||||
case "":
|
||||
return ct, "", fmt.Errorf(`ERROR: creds.json entry %q is missing: %q: %q, (See %s#fixcreds)`,
|
||||
credEntryName,
|
||||
providerTypeFieldName, "FILL_IN_PROVIDER_TYPE",
|
||||
url,
|
||||
)
|
||||
case "-":
|
||||
// This should never happen. The user is confused and specified "-" in the wrong place!
|
||||
return "-", "", fmt.Errorf(`ERROR: creds.json entry %q has invalid %q value %q (See %s#hyphen)`,
|
||||
credEntryName,
|
||||
providerTypeFieldName, ct,
|
||||
url,
|
||||
)
|
||||
default:
|
||||
// use the value in creds.json (this should be the normal case)
|
||||
return ct, "", nil
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func printOrRunCorrections(domain string, provider string, corrections []*models.Correction, out printer.CLI, push bool, interactive bool, notifier notifications.Notifier) (anyErrors bool) {
|
||||
anyErrors = false
|
||||
if len(corrections) == 0 {
|
||||
|
|
58
commands/previewPush_test.go
Normal file
58
commands/previewPush_test.go
Normal file
|
@ -0,0 +1,58 @@
|
|||
package commands
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_refineProviderType(t *testing.T) {
|
||||
|
||||
var mapEmpty map[string]string
|
||||
mapTypeMissing := map[string]string{"otherfield": "othervalue"}
|
||||
mapTypeFoo := map[string]string{"TYPE": "FOO"}
|
||||
mapTypeBar := map[string]string{"TYPE": "BAR"}
|
||||
mapTypeHyphen := map[string]string{"TYPE": "-"}
|
||||
|
||||
type args struct {
|
||||
t string
|
||||
credFields map[string]string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
wantReplacementType string
|
||||
wantWarnMsgPrefix string
|
||||
wantErr bool
|
||||
}{
|
||||
{"fooEmp", args{"FOO", mapEmpty}, "FOO", "WARN", false}, // 3.x: Provide compatibility suggestion. 4.0: hard error
|
||||
{"fooMis", args{"FOO", mapTypeMissing}, "FOO", "WARN", false}, // 3.x: Provide compatibility suggestion. 4.0: hard error
|
||||
{"fooHyp", args{"FOO", mapTypeHyphen}, "-", "", true}, // Error: Invalid creds.json data.
|
||||
{"fooFoo", args{"FOO", mapTypeFoo}, "FOO", "INFO", false}, // Suggest cleanup.
|
||||
{"fooBar", args{"FOO", mapTypeBar}, "FOO", "", true}, // Error: Mismatched!
|
||||
|
||||
{"hypEmp", args{"-", mapEmpty}, "", "", true}, // Hard error. creds.json entry is missing type.
|
||||
{"hypMis", args{"-", mapTypeMissing}, "", "", true}, // Hard error. creds.json entry is missing type.
|
||||
{"hypHyp", args{"-", mapTypeHyphen}, "-", "", true}, // Hard error: Invalid creds.json data.
|
||||
{"hypFoo", args{"-", mapTypeFoo}, "FOO", "", false}, // normal
|
||||
{"hypBar", args{"-", mapTypeBar}, "BAR", "", false}, // normal
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if tt.wantErr && (tt.wantWarnMsgPrefix != "") {
|
||||
t.Error("refineProviderType() bad test data. Prefix should be \"\" if wantErr is set")
|
||||
}
|
||||
gotReplacementType, gotWarnMsg, err := refineProviderType("foo", tt.args.t, tt.args.credFields, "FOO")
|
||||
if !strings.HasPrefix(gotWarnMsg, tt.wantWarnMsgPrefix) {
|
||||
t.Errorf("refineProviderType() gotWarnMsg = %q, wanted prefix %q", gotWarnMsg, tt.wantWarnMsgPrefix)
|
||||
}
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("refineProviderType() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if gotReplacementType != tt.wantReplacementType {
|
||||
t.Errorf("refineProviderType() gotReplacementType = %q, want %q (warn,msg)=(%q,%s)", gotReplacementType, tt.wantReplacementType, gotWarnMsg, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -19,8 +19,8 @@ Modifier arguments are processed according to type as follows:
|
|||
|
||||
{% capture example %}
|
||||
```js
|
||||
var REGISTRAR = NewRegistrar("name.com", "NAMEDOTCOM");
|
||||
var r53 = NewDnsProvider("R53","ROUTE53");
|
||||
var REGISTRAR = NewRegistrar("name.com");
|
||||
var r53 = NewDnsProvider("R53");
|
||||
|
||||
// simple domain
|
||||
D("example.com", REGISTRAR, DnsProvider(r53),
|
||||
|
@ -60,9 +60,9 @@ To differentiate the different domains, specify the domains as
|
|||
|
||||
{% capture example %}
|
||||
```js
|
||||
var REG = NewRegistrar("Third-Party", "NONE");
|
||||
var DNS_INSIDE = NewDnsProvider("Cloudflare", "CLOUDFLAREAPI");
|
||||
var DNS_OUTSIDE = NewDnsProvider("bind", "BIND");
|
||||
var REG = NewRegistrar("Third-Party");
|
||||
var DNS_INSIDE = NewDnsProvider("Cloudflare");
|
||||
var DNS_OUTSIDE = NewDnsProvider("bind");
|
||||
|
||||
D("example.com!inside", REG, DnsProvider(DNS_INSIDE),
|
||||
A("www", "10.10.10.10")
|
||||
|
|
|
@ -9,7 +9,7 @@ arguments passed as if they were the first modifiers in the argument list.
|
|||
|
||||
{% capture example %}
|
||||
```js
|
||||
var COMMON = NewDnsProvider("foo","BIND");
|
||||
var COMMON = NewDnsProvider("foo");
|
||||
// we want to create backup zone files for all domains, but not actually register them.
|
||||
// also create a default TTL
|
||||
DEFAULTS( DnsProvider(COMMON,0), DefaultTTL(1000));
|
||||
|
|
|
@ -20,8 +20,8 @@ Otherwise the syntax of `FETCH` is the same as `fetch`.
|
|||
|
||||
{% capture example %}
|
||||
```js
|
||||
var REG_NONE = NewRegistrar('none', 'NONE');
|
||||
var DNS_BIND = NewDnsProvider('bind', 'BIND');
|
||||
var REG_NONE = NewRegistrar('none');
|
||||
var DNS_BIND = NewDnsProvider('bind');
|
||||
|
||||
D('example.com', REG_NONE, DnsProvider(DNS_BIND), [
|
||||
A('@', '1.2.3.4'),
|
||||
|
|
|
@ -7,20 +7,36 @@ parameters:
|
|||
return: string
|
||||
---
|
||||
|
||||
NewDnsProvider registers a new DNS Service Provider. The name can be any string value you would like to use.
|
||||
The type must match a valid dns provider type identifier (see [provider page.]({{site.github.url}}/provider-list))
|
||||
NewDnsProvider activates a DNS Service Provider (DSP) specified in creds.json.
|
||||
A DSP stores a DNS zone's records and provides DNS service for the zone (i.e.
|
||||
answers on port 53 to queries related to the zone).
|
||||
|
||||
Metadata is an optional object, that will only be used by certain providers. See [individual provider docs]({{site.github.url}}/provider-list) for specific details.
|
||||
* `name` must match the name of an entry in `creds.json`.
|
||||
* `type` specifies a valid DNS provider type identifier listed on the [provider page.]({{site.github.url}}/provider-list).
|
||||
* Starting with v3.16, the type is optional. If it is absent, the `TYPE` field in `creds.json` is used instead. You can leave it out. (Thanks to JavaScript magic, you can leave it out even when there are more fields).
|
||||
* Starting with v4.0, specifying the type may be an error. Please add the `TYPE` field to `creds.json` and remove this parameter from `dnsconfig.js` to prepare.
|
||||
* `meta` is a way to send additional parameters to the provider. It is optional and only certain providers use it. See the [individual provider docs]({{site.github.url}}/provider-list) for details.
|
||||
|
||||
This function will return the name as a string so that you may assign it to a variable to use inside [D](#D) directives.
|
||||
This function will return an opaque string that should be assigned to a variable name for use in [D](#D) directives.
|
||||
|
||||
Prior to v3.16:
|
||||
|
||||
{% capture example %}
|
||||
```js
|
||||
var REGISTRAR = NewRegistrar("name.com", "NAMEDOTCOM");
|
||||
var R53 = NewDnsProvider("r53", "ROUTE53");
|
||||
var REG_MYNDC = NewRegistrar("mynamedotcom", "NAMEDOTCOM");
|
||||
var DNS_MYAWS = NewDnsProvider("myaws", "ROUTE53");
|
||||
|
||||
D("example.com", REGISTRAR, DnsProvider(R53), A("@","1.2.3.4"));
|
||||
D("example.com", REG_MYNDC, DnsProvider(DNS_MYAWS),
|
||||
A("@","1.2.3.4")
|
||||
);
|
||||
```
|
||||
{% endcapture %}
|
||||
|
||||
{% include example.html content=example %}
|
||||
In v3.16 and later:
|
||||
|
||||
```js
|
||||
var REG_MYNDC = NewRegistrar("mynamedotcom");
|
||||
var DNS_MYAWS = NewDnsProvider("myaws");
|
||||
|
||||
D("example.com", REG_MYNDC, DnsProvider(DNS_MYAWS),
|
||||
A("@","1.2.3.4")
|
||||
);
|
||||
```
|
||||
|
|
|
@ -7,20 +7,36 @@ parameters:
|
|||
return: string
|
||||
---
|
||||
|
||||
NewRegistrar registers a registrar provider. The name can be any string value you would like to use.
|
||||
The type must match a valid registrar provider type identifier (see [provider page.]({{site.github.url}}/provider-list))
|
||||
NewRegistrar activates a Registrar Provider specified in `creds.json`.
|
||||
A registrar maintains the domain's registration and delegation (i.e. the
|
||||
nameservers for the domain). DNSControl only manages the delegation.
|
||||
|
||||
Metadata is an optional object, that will only be used by certain providers. See [individual provider docs]({{site.github.url}}/provider-list) for specific details.
|
||||
* `name` must match the name of an entry in `creds.json`.
|
||||
* `type` specifies a valid DNS provider type identifier listed on the [provider page.]({{site.github.url}}/provider-list).
|
||||
* Starting with v3.16, the type is optional. If it is absent, the `TYPE` field in `creds.json` is used instead. You can leave it out. (Thanks to JavaScript magic, you can leave it out even when there are more fields).
|
||||
* Starting with v4.0, specifying the type may be an error. Please add the `TYPE` field to `creds.json` and remove this parameter from `dnsconfig.js` to prepare.
|
||||
* `meta` is a way to send additional parameters to the provider. It is optional and only certain providers use it. See the [individual provider docs]({{site.github.url}}/provider-list) for details.
|
||||
|
||||
This function will return the name as a string so that you may assign it to a variable to use inside [D](#D) directives.
|
||||
This function will return an opaque string that should be assigned to a variable name for use in [D](#D) directives.
|
||||
|
||||
Prior to v3.16:
|
||||
|
||||
{% capture example %}
|
||||
```js
|
||||
var REGISTRAR = NewRegistrar("name.com", "NAMEDOTCOM");
|
||||
var r53 = NewDnsProvider("R53","ROUTE53");
|
||||
var REG_MYNDC = NewRegistrar("mynamedotcom", "NAMEDOTCOM");
|
||||
var DNS_MYAWS = NewDnsProvider("myaws", "ROUTE53");
|
||||
|
||||
D("example.com", REGISTRAR, DnsProvider(r53), A("@","1.2.3.4"));
|
||||
D("example.com", REG_MYNDC, DnsProvider(DNS_MYAWS),
|
||||
A("@","1.2.3.4")
|
||||
);
|
||||
```
|
||||
{% endcapture %}
|
||||
|
||||
{% include example.html content=example %}
|
||||
In v3.16 and later:
|
||||
|
||||
```js
|
||||
var REG_MYNDC = NewRegistrar("mynamedotcom");
|
||||
var DNS_MYAWS = NewDnsProvider("myaws");
|
||||
|
||||
D("example.com", REG_MYNDC, DnsProvider(DNS_MYAWS),
|
||||
A("@","1.2.3.4")
|
||||
);
|
||||
```
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
{
|
||||
"bind": {
|
||||
"TYPE": "BIND"
|
||||
},
|
||||
"r53_ACCOUNTNAME": {
|
||||
"TYPE": "ROUTE53",
|
||||
"KeyId": "change_to_your_keyid",
|
||||
"SecretKey": "change_to_your_secretkey",
|
||||
"Token": "optional_sts_token"
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
|
||||
// Providers:
|
||||
|
||||
var REG_NONE = NewRegistrar('none', 'NONE'); // No registrar.
|
||||
var DNS_BIND = NewDnsProvider('bind', 'BIND'); // ISC BIND.
|
||||
var REG_NONE = NewRegistrar('none'); // No registrar.
|
||||
var DNS_BIND = NewDnsProvider('bind'); // ISC BIND.
|
||||
|
||||
// Domains:
|
||||
|
||||
|
|
|
@ -8,8 +8,7 @@ title: Check-Creds subcommand
|
|||
This is a stand-alone utility to help verify entries in `creds.json`.
|
||||
|
||||
The command does a trivia operation to verify credentials. If
|
||||
successful, a list of zones will be output. If not, hopefully you see
|
||||
verbose error messages.
|
||||
successful, a list of zones will be output (which may be an empty list). If the credentials or other problems prevent this operation from executing, the exit code will be non-zero and hopefully verbose error messages will be output.
|
||||
|
||||
Syntax:
|
||||
|
||||
|
@ -22,14 +21,23 @@ ARGUMENTS:
|
|||
credkey: The name used in creds.json (first parameter to NewDnsProvider() in dnsconfig.js)
|
||||
provider: The name of the provider (second parameter to NewDnsProvider() in dnsconfig.js)
|
||||
|
||||
Starting in v3.16, "provider" is optional. If it is omitted (or the placeholder value `-` is used), the `TYPE` specified in `creds.json` will be used instead. A warning will be displayed with advice on how to remain compatible with v4.0.
|
||||
|
||||
Starting in v4.0, the "provider" argument is expected to go away.
|
||||
|
||||
EXAMPLES:
|
||||
dnscontrol check-creds myr53 ROUTE53
|
||||
Starting in v3.16:
|
||||
dnscontrol check-creds myr53
|
||||
dnscontrol check-creds myr53 -
|
||||
dnscontrol check-creds myr53 ROUTE53
|
||||
Starting in v4.0:
|
||||
dnscontrol check-creds myr53
|
||||
|
||||
This command is the same as:
|
||||
dnscontrol get-zones --out=/dev/null myr53 ROUTE53
|
||||
This command is the same as `get-zones` with `--format=nameonly`
|
||||
|
||||
# Developer Note
|
||||
|
||||
This command is not implemented for all providers.
|
||||
|
||||
To add this to a provider, implement the get-zones subcommand
|
||||
To add this to a provider, implement the get-zones subcommand.
|
||||
|
|
|
@ -13,14 +13,17 @@ Here's a sample file:
|
|||
```json
|
||||
{
|
||||
"cloudflare_tal": {
|
||||
"TYPE": "CLOUDFLAREAPI",
|
||||
"apikey": "REDACTED",
|
||||
"apiuser": "REDACTED"
|
||||
},
|
||||
"inside": {
|
||||
"TYPE": "BIND",
|
||||
"directory": "inzones",
|
||||
"filenameformat": "db_%T%?_%D"
|
||||
},
|
||||
"hexonet": {
|
||||
"TYPE": "HEXONET",
|
||||
"apilogin": "$HEXONET_APILOGIN",
|
||||
"apipassword": "$HEXONET_APIPASSWORD",
|
||||
"debugmode": "$HEXONET_DEBUGMODE",
|
||||
|
@ -29,7 +32,7 @@ Here's a sample file:
|
|||
}
|
||||
```
|
||||
|
||||
# Format
|
||||
## Format
|
||||
|
||||
* Primary keys: (e.g. `cloudflare_tal`, `inside`, `hexonet`)
|
||||
* ...refer to the first parameter in the `NewRegistrar()` or `NewDnsProvider()` functions in a dnsconfig.js file.
|
||||
|
@ -43,7 +46,130 @@ Here's a sample file:
|
|||
* ...may include any JSON string value including the empty string.
|
||||
* If a subkey starts with `$`, it is taken as an env variable. In the above example, `$HEXONET_APILOGIN` would be replaced by the value of the environment variable `HEXONET_APILOGIN` or the empty string if no such environment variable exists.
|
||||
|
||||
# Using a different name
|
||||
## New in v3.16:
|
||||
|
||||
The special subkey "TYPE" is used to indicate the provider type (NONE,
|
||||
CLOUDFLAREAPI, GCLOUD, etc).
|
||||
|
||||
Prior to v3.16, the provider type is specified as the second argument
|
||||
to `NewRegistrar()` and `NewDnsProvider()` in `dnsconfig.js` or as a
|
||||
command-line argument in tools such as `dnscontrol get-zones`.
|
||||
|
||||
Starting in v3.16, `NewRegistrar()`, and `NewDnsProvider()` no longer
|
||||
require the provider type to be specified. It may be specified for
|
||||
backwards compatibility, but a warning will be generated with a
|
||||
suggestion of how to upgrade to the 4.0 format. Likewise,
|
||||
command-line tools no longer require the provider type to be
|
||||
specified, but for backwards compatibility one may specify `-` since
|
||||
the parameter is positional.
|
||||
|
||||
In 4.0, DNSControl will require the "TYPE" subkey in each `creds.json`
|
||||
entry. Command line tools will have a backwards-incompatible change to
|
||||
remove the provider-type as a positional argument. Prior to 4.0, the
|
||||
various commands will output warnings and suggestions to avoid
|
||||
compatibility issues during the transition.
|
||||
|
||||
## Error messages
|
||||
|
||||
### Missing
|
||||
|
||||
Message: `WARNING: For future compatibility, add this entry creds.json:...`
|
||||
|
||||
Message: `WARNING: For future compatibility, update the ... entry in creds.json by adding:...`
|
||||
|
||||
These messages indicates that this provider is not mentioned in `creds.json`. In v4.0
|
||||
all providers used in `dnsconfig.js` will require an entry in `creds.json`.
|
||||
|
||||
For a smooth transition, please update your `creds.json` file now.
|
||||
|
||||
Here is the minimal entry required:
|
||||
|
||||
```json
|
||||
{
|
||||
"entryName": {
|
||||
"TYPE": "FILL_IN"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### hyphen
|
||||
|
||||
Message: `ERROR: creds.json entry ... has invalid ... value ...`
|
||||
|
||||
This indicates the entry for `creds.json` has a TYPE value that is
|
||||
invalid i.e. it is the empty string or a hyphen (`-`).
|
||||
|
||||
The fix is to correct the `TYPE` parameter in the `creds.json` entry.
|
||||
Change it to one of the all caps identifiers in [the service provider list](https://stackexchange.github.io/dnscontrol/provider-list).
|
||||
|
||||
|
||||
### cleanup
|
||||
|
||||
Message: `INFO: In dnsconfig.js New*(..., ...) can be simplified to New*(...)`
|
||||
|
||||
This message indicates that the same provider name is specified in
|
||||
`dnsconfig.js` and `creds.json` and offers a suggestion for reducing
|
||||
the redundancy.
|
||||
|
||||
The fix is to update `dnsconfig.js` as suggested in the error.
|
||||
Usually this is to simply remove the second parameter to the function.
|
||||
|
||||
Examples:
|
||||
|
||||
|
||||
```
|
||||
OLD: var REG_THING = NewRegistrar("thing", "THING");
|
||||
NEW: var REG_THING = NewRegistrar("thing");
|
||||
|
||||
OLD: var REG_THING = NewRegistrar("thing", "THING", { settings: "value" } );
|
||||
NEW: var REG_THING = NewRegistrar("thing", { settings: "value" } );
|
||||
|
||||
OLD: var DNS_MYGANDI = NewDnsProvider("mygandi", "GANDI_V5");
|
||||
NEW: var DNS_MYGANDI = NewDnsProvider("mygandi");
|
||||
|
||||
OLD: var DNS_MYGANDI = NewDnsProvider("mygandi", "GANDI_V5", { settings: "value" } );
|
||||
NEW: var DNS_MYGANDI = NewDnsProvider("mygandi", { settings: "value" } );
|
||||
```
|
||||
|
||||
Starting with v3.16 use of an OLD format will trigger warnings with suggestions on how to adopt the NEW format.
|
||||
|
||||
Starting with v4.0 support for the OLD format may be reported as an error.
|
||||
|
||||
Please adopt the NEW format when your installation has eliminated any use of DNSControl pre-3.16.
|
||||
|
||||
|
||||
### mismatch
|
||||
|
||||
Message: `ERROR: Mismatch found! creds.json entry ... has ... set to ... but dnsconfig.js specifies New*(..., ...)`
|
||||
|
||||
This indicates that the provider type specifed in `creds.json` does not match the one specifed in `dnsconfig.js` or on the command line.
|
||||
|
||||
The fix is to change one to match the other.
|
||||
|
||||
### fixcreds
|
||||
|
||||
Message: `ERROR: creds.json entry ... is missing ...: ...`
|
||||
|
||||
However no `TYPE` subkey was found in an entry in `creds.json`.
|
||||
In 3.16 forward, it is required if new-style `NewRegistrar()` or `NewDnsProvider()` was used.
|
||||
In 4.0 this is required.
|
||||
|
||||
The fix is to add a `TYPE` subkey to the `creds.json` entry.
|
||||
|
||||
### hyphen
|
||||
|
||||
Message: `ERROR: creds.json entry ... has invalid ... value ...`
|
||||
|
||||
This indicates that the type `-` was specified in a `TYPE` value in
|
||||
`creds.json`. There is no provider named `-` therefore that is
|
||||
invalid. Perhaps you meant to specify a `-` on a command-line tool?
|
||||
|
||||
The fix is to change the `TYPE` subkey entry in `creds.json` from `-` to
|
||||
a valid service provider identifier, as listed
|
||||
in [the service provider list](https://stackexchange.github.io/dnscontrol/provider-list).
|
||||
|
||||
|
||||
## Using a different file name
|
||||
|
||||
The `--creds` flag allows you to specify a different file name.
|
||||
|
||||
|
@ -55,7 +181,7 @@ The `--creds` flag allows you to specify a different file name.
|
|||
* Exceptions: The `x` bit is not checked if the filename ends with `.yaml`, `.yml` or `.json`.
|
||||
* Windows: Executing an external script isn't supported. There's no code that prevents it from trying, but it isn't supported.
|
||||
|
||||
# Don't store secrets in a Git repo!
|
||||
## Don't store secrets in a Git repo!
|
||||
|
||||
Do NOT store secrets in a Git repository. That is not secure. For example,
|
||||
storing the example `cloudflare_tal` is insecure because anyone with access to
|
||||
|
|
|
@ -68,6 +68,10 @@ zones at the provider.
|
|||
provider: The name of the provider (second parameter to NewDnsProvider() in dnsconfig.js)
|
||||
zone: One or more zones (domains) to download; or "all".
|
||||
|
||||
As of v3.16, `provider` can be `-` to indicate that the provider name is listed in `creds.json` in the `TYPE` field. Doing this will be backwards compatible with an (otherwise) breaking change due in v4.0.
|
||||
|
||||
As of v4.0 (BREAKING CHANGE), you must not specify `provider`. That value is found in the `TYPE` field of the credkey's `creds.json` file. For backwards compatibility, if the first `zone` is `-`, it will be skipped.
|
||||
|
||||
FORMATS:
|
||||
--format=js dnsconfig.js format (not perfect, just a decent first draft)
|
||||
--format=djs js with disco commas (leading commas)
|
||||
|
@ -92,12 +96,35 @@ The `--ttl` flag only applies to zone/js/djs formats.
|
|||
dnscontrol get-zones gmain GANDI_V5 example.comn other.com
|
||||
dnscontrol get-zones cfmain CLOUDFLAREAPI all
|
||||
dnscontrol get-zones --format=tsv bind BIND example.com
|
||||
dnscontrol get-zones --format=djs --out=draft.js glcoud GCLOUD example.com`,
|
||||
dnscontrol get-zones --format=djs --out=draft.js glcoud GCLOUD example.com
|
||||
|
||||
As of v3.16:
|
||||
# NOTE: When "-" appears as the 2nd argument, it is assumed that the
|
||||
# creds.json entry has a field TYPE with the provider's type name.
|
||||
dnscontrol get-zones gmain GANDI_V5 example.comn other.com
|
||||
dnscontrol get-zones gmain - example.comn other.com
|
||||
dnscontrol get-zones cfmain CLOUDFLAREAPI all
|
||||
dnscontrol get-zones cfmain - all
|
||||
dnscontrol get-zones --format=tsv bind BIND example.com
|
||||
dnscontrol get-zones --format=tsv bind - example.com
|
||||
dnscontrol get-zones --format=djs --out=draft.js glcoud GCLOUD example.com
|
||||
dnscontrol get-zones --format=djs --out=draft.js glcoud - example.com
|
||||
|
||||
As of v4.0:
|
||||
dnscontrol get-zones gmain example.comn other.com
|
||||
dnscontrol get-zones cfmain all
|
||||
dnscontrol get-zones --format=tsv bind example.com
|
||||
dnscontrol get-zones --format=djs --out=draft.js glcoud example.com
|
||||
# For backwards compatibility, these are valid until at least v5.0
|
||||
dnscontrol get-zones gmain - example.comn other.com
|
||||
dnscontrol get-zones cfmain - all
|
||||
dnscontrol get-zones --format=tsv bind - example.com
|
||||
dnscontrol get-zones --format=djs --out=draft.js glcoud - example.com
|
||||
|
||||
Read a zonefile, generate a JS file, then use the JS file to see how
|
||||
different it is from the zonefile:
|
||||
|
||||
dnscontrol get-zone --format=djs -out=foo.djs bind BIND example.org
|
||||
dnscontrol get-zone --format=djs -out=foo.djs bind - example.org
|
||||
dnscontrol preview --config foo.js
|
||||
|
||||
# Developer Notes
|
||||
|
|
|
@ -9,7 +9,7 @@ title: Getting Started
|
|||
|
||||
## From source
|
||||
|
||||
DNSControl can be built with Go version 1.16 or higher.
|
||||
DNSControl can be built with Go version 1.18 or higher.
|
||||
|
||||
The `go get` command will download the source, compile it, and
|
||||
install `dnscontrol` in your `$GOBIN` directory.
|
||||
|
@ -48,13 +48,6 @@ Create a directory where you'll be storing your configuration files.
|
|||
We highly recommend storing these files in a Git repo, but for
|
||||
simple tests anything will do.
|
||||
|
||||
Note: Do **not** store your creds.json file in Git unencrypted.
|
||||
That is unsafe. Add `creds.json` to your
|
||||
`.gitignore` file as a precaution. This file should be encrypted
|
||||
using something
|
||||
like [git-crypt](https://www.agwa.name/projects/git-crypt) or
|
||||
[Blackbox](https://github.com/StackExchange/blackbox).
|
||||
|
||||
Create a subdirectory called `zones` in the same directory as the
|
||||
configuration files. (`mkdir zones`). `zones` is where the BIND
|
||||
provider writes the zonefiles it creates. Even if you don't
|
||||
|
@ -75,8 +68,8 @@ The file looks like:
|
|||
```js
|
||||
// Providers:
|
||||
|
||||
var REG_NONE = NewRegistrar('none', 'NONE'); // No registrar.
|
||||
var DNS_BIND = NewDnsProvider('bind', 'BIND'); // ISC BIND.
|
||||
var REG_NONE = NewRegistrar('none'); // No registrar.
|
||||
var DNS_BIND = NewDnsProvider('bind'); // ISC BIND.
|
||||
|
||||
// Domains:
|
||||
|
||||
|
@ -85,30 +78,43 @@ D('example.com', REG_NONE, DnsProvider(DNS_BIND),
|
|||
);
|
||||
```
|
||||
|
||||
You may modify this file to match your particular providers and domains. See [the javascript docs]({{site.github.url}}/js) and [the provider docs]({{site.github.url}}/provider-list) for more details.
|
||||
If you are using other providers, you will likely need to make a `creds.json` file with api tokens and other account information. For example, to use both name.com and Cloudflare, you would have:
|
||||
Modify this file to match your particular providers and domains. See [the dnsconfig docs]({{site.github.url}}/js) and [the provider docs]({{site.github.url}}/provider-list) for more details.
|
||||
|
||||
```js
|
||||
Create a file called `creds.json` for storing provider configurations (API tokens and other account information).
|
||||
For example, to use both name.com and Cloudflare, you would have:
|
||||
|
||||
```json
|
||||
{
|
||||
"cloudflare":{ // provider name to be used in dnsconfig.js
|
||||
"apitoken": "token" // API token
|
||||
"cloudflare": { // The provider name used in dnsconfig.js
|
||||
"TYPE": "CLOUDFLAREAPI", // The provider type identifier
|
||||
"accountid": "your-cloudflare-account-id", // credentials
|
||||
"apitoken": "your-cloudflare-api-token" // credentials
|
||||
},
|
||||
"namecom":{ // provider name to be used in dnsconfig.js
|
||||
"apikey": "key", // API Key
|
||||
"apiuser": "username" // username for name.com
|
||||
}
|
||||
"namecom": { // The provider name used in dnsconfig.js
|
||||
"TYPE": "NAMEDOTCOM", // The provider type identifier
|
||||
"apikey": "key", // credentials
|
||||
"apiuser": "username" // credentials
|
||||
},
|
||||
"none": { "TYPE": "NONE" } // The no-op provider
|
||||
}
|
||||
```
|
||||
|
||||
Note: Do **not** store your creds.json file in Git unencrypted.
|
||||
That is unsafe. Add `creds.json` to your
|
||||
`.gitignore` file as a precaution. This file should be encrypted
|
||||
using something
|
||||
like [git-crypt](https://www.agwa.name/projects/git-crypt) or
|
||||
[Blackbox](https://github.com/StackExchange/blackbox).
|
||||
|
||||
There are 2 types of providers:
|
||||
|
||||
A "Registrar" is who you register the domain with. Start with
|
||||
`REG_NONE`, which is a provider that never talks to or updates the
|
||||
`NONE`, which is a provider that never talks to or updates the
|
||||
registrar. You can define your registrar later when you want to
|
||||
use advanced features.
|
||||
|
||||
The `DnsProvider` is the service that actually provides DNS service
|
||||
(port 53) and may be the same or different company. Even if both
|
||||
A "DnsProvider" is the service that actually provides DNS service
|
||||
(port 53) and may be the same or different as the registrar. Even if both
|
||||
your Registrar and DnsProvider are the same company, two different
|
||||
definitions must be included in `dnsconfig.js`.
|
||||
|
||||
|
@ -128,15 +134,17 @@ The file looks like:
|
|||
```js
|
||||
{
|
||||
"bind": {
|
||||
"TYPE": "BIND"
|
||||
},
|
||||
"r53_ACCOUNTNAME": {
|
||||
"r53_accountname": {
|
||||
"TYPE": "ROUTE53",
|
||||
"KeyId": "change_to_your_keyid",
|
||||
"SecretKey": "change_to_your_secretkey"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Ignore the `r53_ACCOUNTNAME` section. It is a placeholder and will be ignored. You
|
||||
Ignore the `r53_accountname` section. It is a placeholder and will be ignored. You
|
||||
can use it later when you define your first set of API credentials.
|
||||
|
||||
Note that `creds.json` is a JSON file. JSON is very strict about commas
|
||||
|
@ -148,7 +156,7 @@ Python:
|
|||
|
||||
jq:
|
||||
|
||||
jq < creds.json
|
||||
jq . < creds.json
|
||||
|
||||
FYI: `creds.json` fields can be read from an environment variable. The field must begin with a `$` followed by the variable name. No other text. For example:
|
||||
|
||||
|
|
|
@ -20,20 +20,20 @@ All the examples use the variables. Substitute your own.
|
|||
// ========== Registrars:
|
||||
|
||||
// A typical registrar.
|
||||
var REG_NAMECOM = NewRegistrar("namedotcom_main", "NAMEDOTCOM");
|
||||
var REG_NAMECOM = NewRegistrar("namedotcom_main");
|
||||
|
||||
// The "NONE" registrar is a "fake" registrar.
|
||||
// This is useful if the registrar is not supported by DNSControl,
|
||||
// or if you don't want to control the domain's delegation.
|
||||
var REG_THIRDPARTY = NewRegistrar("ThirdParty", "NONE");
|
||||
var REG_THIRDPARTY = NewRegistrar("ThirdParty");
|
||||
|
||||
// ========== DNS Providers:
|
||||
|
||||
var DNS_NAMECOM = NewDnsProvider("namedotcom_main", "NAMEDOTCOM");
|
||||
var DNS_AWS = NewDnsProvider("aws_main", "ROUTE53");
|
||||
var DNS_GOOGLE = NewDnsProvider("gcp_main", "GCLOUD");
|
||||
var DNS_CLOUDFLARE = NewDnsProvider("cloudflare_main", "CLOUDFLAREAPI");
|
||||
var DNS_BIND = NewDnsProvider("bind", "BIND");
|
||||
var DNS_NAMECOM = NewDnsProvider("namedotcom_main");
|
||||
var DNS_AWS = NewDnsProvider("aws_main");
|
||||
var DNS_GOOGLE = NewDnsProvider("gcp_main");
|
||||
var DNS_CLOUDFLARE = NewDnsProvider("cloudflare_main");
|
||||
var DNS_BIND = NewDnsProvider("bind");
|
||||
```
|
||||
|
||||
# Typical Delegations
|
||||
|
@ -226,7 +226,7 @@ Sometimes you just want to know if something changes!
|
|||
See the <a href="{{site.github.url}}/providers/doh">DNS-over-HTTPS Provider</a> documentation for more info.
|
||||
|
||||
```js
|
||||
var REG_MONITOR = NewRegistrar('DNS-over-HTTPS', 'DNSOVERHTTPS');
|
||||
var REG_MONITOR = NewRegistrar('DNS-over-HTTPS');
|
||||
|
||||
D("example1.com", REG_MONITOR,
|
||||
NAMESERVER("ns1.example1.com."),
|
||||
|
|
220
docs/v316.md
Normal file
220
docs/v316.md
Normal file
|
@ -0,0 +1,220 @@
|
|||
---
|
||||
layout: default
|
||||
title: Converting to v3.16
|
||||
---
|
||||
|
||||
# creds.json file format change
|
||||
|
||||
**Feel free to skip to "How do I convert?" if you don't care about the details.**
|
||||
|
||||
Starting in v3.16 the "provider type identifier" (PTI) will be located in
|
||||
`creds.json` instead of `dnsconfig.js`. The PTI is the all caps string like
|
||||
`ROUTE53` or `CLOUDFLAREAPI` used to identify a provider's type.
|
||||
|
||||
V3.16 will enable a syntax that is backwards and forwards compatible. The old
|
||||
syntax will be removed in v4.0. There's no planned release date for v4.0 but
|
||||
it is expected to be after Dec 31, 2022.
|
||||
|
||||
The change was discussed
|
||||
in [Request for Comments: Include the provider type in creds.json, remove it from dnsconfig.js](https://github.com/StackExchange/dnscontrol/issues/1457) where we decided "Plan A" would be selected.
|
||||
|
||||
# What does this mean to you?
|
||||
|
||||
In a nutshell, `NewRegistrar()` and `NewDnsProvider()` will lose the 2nd
|
||||
parameter:
|
||||
|
||||
OLD dnsconfig.js:
|
||||
|
||||
```js
|
||||
var REG_GANDI = NewRegistrar("gandi", "GANDI_V5");
|
||||
var DSP_CF = NewDnsProvider("cloudflare_tal", "CLOUDFLAREAPI");
|
||||
```
|
||||
|
||||
NEW dnsconfig.js:
|
||||
|
||||
```js
|
||||
var REG_GANDI = NewRegistrar("gandi");
|
||||
var DSP_CF = NewDnsProvider("cloudflare_tal");
|
||||
```
|
||||
|
||||
The second paramter (`GANDI_V5` and `CLOUDFLAREAPI` in the
|
||||
above examples) has moved to `creds.json` instead. It will be in a `TYPE`
|
||||
field, which all providers have. It can appear in both places for backwards compatibility for now.
|
||||
|
||||
NEW creds.json:
|
||||
|
||||
```json
|
||||
{
|
||||
"gandi": {
|
||||
"TYPE": "GANDI_V5", << NEW
|
||||
"apikey": "reacted"
|
||||
},
|
||||
"cloudflare_tal": {
|
||||
"TYPE": "CLOUDFLAREAPI", << NEW
|
||||
"apikey": "reacted",
|
||||
"apiuser": "reacted"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
In the past, a provider didn't need an entry in `creds.json` if there were no credentials to be stored. Starting in v4.0 all providers must have an entry in `creds.json`. To aid the transition, starting in v3.16 warnings will appear on stdout that direct you to convert to the new format.
|
||||
|
||||
Also to help in the conversion, if no provider named "none" or "bind" exist, ones will be added for you. They look like this:
|
||||
|
||||
```json
|
||||
{
|
||||
"none": { "TYPE": "NONE" },
|
||||
"bind": { "TYPE": "BIND" }
|
||||
}
|
||||
```
|
||||
|
||||
# Command line tools
|
||||
|
||||
How does this affect command line tools?
|
||||
|
||||
The following subcommands require the PTI a parameter on the command line:
|
||||
|
||||
* `get-zone`
|
||||
* `get-zones`
|
||||
* `check-creds`
|
||||
|
||||
In 3.16, that parameter can be changed to `-` as a placeholder, or removed
|
||||
entirely if it is the last parameter on the command line. When you omit this
|
||||
parameter, DNSControl will look find the value in `creds.json` instead.
|
||||
|
||||
In 4.0, that parameter will be removed, though a `-` is permitted for backwards compatibility.
|
||||
|
||||
In other words, if you add the `TYPE` field to `creds.json`, you no longer need
|
||||
to specify it on the command line. You can specify `-` instead, or leave it
|
||||
out entirely starting in v4.0.
|
||||
|
||||
For check-creds:
|
||||
|
||||
```
|
||||
Starting in v3.16 these forms are valid:
|
||||
dnscontrol check-creds myr53
|
||||
dnscontrol check-creds myr53 -
|
||||
dnscontrol check-creds myr53 ROUTE53
|
||||
Starting in v4.0 this is the only valid form:
|
||||
dnscontrol check-creds myr53
|
||||
# For backwards compatibility, these are valid until at least v5.0:
|
||||
dnscontrol check-creds myr53 -
|
||||
```
|
||||
|
||||
For get-zones/get-zone:
|
||||
|
||||
```
|
||||
Starting in v3.16 these forms are valid:
|
||||
dnscontrol get-zones gmain GANDI_V5 example.comn other.com
|
||||
dnscontrol get-zones gmain - example.comn other.com
|
||||
dnscontrol get-zones cfmain CLOUDFLAREAPI all
|
||||
dnscontrol get-zones cfmain - all
|
||||
dnscontrol get-zones --format=tsv bind BIND example.com
|
||||
dnscontrol get-zones --format=tsv bind - example.com
|
||||
dnscontrol get-zones --format=djs --out=draft.js glcoud GCLOUD example.com
|
||||
dnscontrol get-zones --format=djs --out=draft.js glcoud - example.com
|
||||
Starting in v4.0 these forms are valid:
|
||||
dnscontrol get-zones gmain example.comn other.com
|
||||
dnscontrol get-zones cfmain all
|
||||
dnscontrol get-zones --format=tsv bind example.com
|
||||
dnscontrol get-zones --format=djs --out=draft.js glcoud example.com
|
||||
# For backwards compatibility, these are valid until at least v5.0:
|
||||
dnscontrol get-zones gmain - example.comn other.com
|
||||
dnscontrol get-zones cfmain - all
|
||||
dnscontrol get-zones --format=tsv bind - example.com
|
||||
dnscontrol get-zones --format=djs --out=draft.js glcoud - example.com
|
||||
```
|
||||
|
||||
# How do I convert?
|
||||
|
||||
## Step 1: Upgrade
|
||||
|
||||
Upgrade to v3.16 or later. If DNSControl is used in many places, do not
|
||||
continue until they are all at v3.16 or later.
|
||||
|
||||
## Step 2: Edit creds.json
|
||||
|
||||
Now that all uses of DNSControl are on v3.16 or later...
|
||||
|
||||
For each `creds.json` entry, add a field "TYPE" set to the provider type
|
||||
identifier. This is the all-caps name such as `ROUTE53`, `GCLOUD`, or
|
||||
`CLOUDFLAREAPI`.
|
||||
|
||||
For example, here is a new-style `creds.json` file with `TYPE` fields added:
|
||||
|
||||
```json
|
||||
{
|
||||
"bind_inside": {
|
||||
"TYPE": "BIND", << ADDED
|
||||
"directory": "inzones"
|
||||
},
|
||||
"cloudflare_tal": {
|
||||
"TYPE": "CLOUDFLAREAPI", << ADDED
|
||||
"apikey": "redacted",
|
||||
"apiuser": "redacted"
|
||||
},
|
||||
"gandi": {
|
||||
"TYPE": "GANDI_V5", << ADDED
|
||||
"apikey": "redacted"
|
||||
},
|
||||
```
|
||||
|
||||
## Step 3: Cross-check
|
||||
|
||||
Run `dnscontrol preview` as one normally would. Fix any errors, warnings, or informational messages that appear on stdout.
|
||||
|
||||
Here are some examples:
|
||||
|
||||
```
|
||||
WARNING: For future compatibility, update the "namedotcom_main" entry in `creds.json` by adding: "TYPE": "NAMEDOTCOM", (See https://stackexchange.github.io/dnscontrol/creds-json#missing)
|
||||
```
|
||||
|
||||
```
|
||||
ERROR: Mismatch found! creds.json entry "namedotcom_main" has "TYPE" set to "ROUTE53" but dnsconfig.js specifies New*("namedotcom_main", "NAMEDOTCOM") (See https://stackexchange.github.io/dnscontrol/creds-json#mismatch)
|
||||
```
|
||||
|
||||
After you correct some warnings, you may receive information messages like:
|
||||
|
||||
```
|
||||
INFO: In dnsconfig.js New*("namedotcom_main", "NAMEDOTCOM") can be simplified to New*("namedotcom_main") (See https://stackexchange.github.io/dnscontrol/creds-json#cleanup)
|
||||
```
|
||||
|
||||
Those messages will disappear as you update `dnsconfig.js` in the next step.
|
||||
|
||||
## Step 4: Edit dnsconfig.js
|
||||
|
||||
Remove the 2nd parameter to any NewDnsProvider() or NewRegistrar() functions.
|
||||
|
||||
OLD:
|
||||
|
||||
```js
|
||||
var REG_NAMEDOTCOM_TAL = NewRegistrar("namedotcom_tal", "NAMEDOTCOM");
|
||||
var DNS_GANDI_TAL = NewDnsProvider("gandi_v5_tal", "GANDI_V5");
|
||||
```
|
||||
|
||||
NEW:
|
||||
|
||||
```js
|
||||
var REG_NAMEDOTCOM_TAL = NewRegistrar("namedotcom_tal");
|
||||
var DNS_GANDI_TAL = NewDnsProvider("gandi_v5_tal");
|
||||
```
|
||||
|
||||
Again, run `dnscontrol preview` to verify you setup still works as expected.
|
||||
|
||||
## Step 5: Update any shell scripts
|
||||
|
||||
Any shell scripts or documentation that uses the subcommands `get-zone`,
|
||||
`get-zones` or `check-creds` should be updated. The "provider type" parameter
|
||||
should be changed to `-`. If it is the last parameter on the command, it can
|
||||
be removed.
|
||||
|
||||
It's unlikely you have scripts that use these commands. However you may have
|
||||
documentation that refers to them and needs to be updated.
|
||||
|
||||
## Step 4: Test
|
||||
|
||||
Run `dnscontrol preview` as one normally would. Fix any errors, warnings, or informational messages that appear on stdout.
|
||||
|
||||
## Step 5: Done!
|
||||
|
||||
That's it!
|
|
@ -14,7 +14,6 @@ import (
|
|||
|
||||
"github.com/DisposaBoy/JsonConfigReader"
|
||||
"github.com/TomOnTime/utfutil"
|
||||
"golang.org/x/exp/maps"
|
||||
)
|
||||
|
||||
func quotedList(l []string) string {
|
||||
|
@ -76,13 +75,16 @@ func LoadProviderConfigs(fname string) (map[string]map[string]string, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
ckeys := keysWithColons(maps.Keys(results))
|
||||
if len(ckeys) != 0 {
|
||||
fmt.Printf(`WARNING: In the future, colons in cred entry names will have meaning.`+
|
||||
` Our best advice is to remove the colons for now to avoid future compatibility issues.`+
|
||||
` Specifically these keys: %v`+"\n",
|
||||
quotedList(ckeys))
|
||||
// For backwards compatibility, insert NONE and BIND entries if
|
||||
// they do not exist. These are the only providers that previously
|
||||
// did not require entries in creds.json prior to v4.0.
|
||||
if _, ok := results["none"]; !ok {
|
||||
results["none"] = map[string]string{"TYPE": "NONE"}
|
||||
}
|
||||
if _, ok := results["bind"]; !ok {
|
||||
results["bind"] = map[string]string{"TYPE": "BIND"}
|
||||
}
|
||||
|
||||
return results, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
'use strict';
|
||||
|
||||
// If you edit this file, you must run `go generate` to embed this
|
||||
// file in the source code.
|
||||
|
||||
// If you are heavily debugging this code, the "-dev" flag will
|
||||
// read this file directly instead of using the output of
|
||||
// `go generate`. You'll still need to run `go generate` before
|
||||
|
@ -36,7 +33,27 @@ function getConfiguredDomains() {
|
|||
return conf.domain_names;
|
||||
}
|
||||
|
||||
function NewRegistrar(name, type, meta) {
|
||||
// NewRegistrar returns an registrar object.
|
||||
// For backwards compatibility, it accepts (name), (name, meta),
|
||||
// (name, type), (name, type, meta).
|
||||
function NewRegistrar() {
|
||||
// For backwards compatibility, this is a wrapper around the legacy
|
||||
// version of this function.
|
||||
switch (arguments.length) {
|
||||
case 1:
|
||||
return oldNewRegistrar(arguments[0], "-")
|
||||
case 2:
|
||||
// x = NewRegistrar("myThing", "THING")
|
||||
// x = NewRegistrar("myThing", { metakey: metavalue } )
|
||||
if (typeof arguments[1] === 'object') {
|
||||
return oldNewRegistrar(arguments[0], "-", arguments[1])
|
||||
}
|
||||
break;
|
||||
default: // do nothing
|
||||
}
|
||||
return oldNewRegistrar.apply(null, arguments)
|
||||
}
|
||||
function oldNewRegistrar(name, type, meta) {
|
||||
if (type) {
|
||||
type == 'MANUAL';
|
||||
}
|
||||
|
@ -46,6 +63,23 @@ function NewRegistrar(name, type, meta) {
|
|||
}
|
||||
|
||||
function NewDnsProvider(name, type, meta) {
|
||||
// For backwards compatibility, this is a wrapper around the legacy
|
||||
// version of this function.
|
||||
switch (arguments.length) {
|
||||
case 1:
|
||||
return oldNewDnsProvider(arguments[0], "-")
|
||||
case 2:
|
||||
// x = NewDnsProvider("myThing", "THING")
|
||||
// x = NewDnsProvider("myThing", { metakey: metavalue } )
|
||||
if (typeof arguments[1] === 'object') {
|
||||
return oldNewDnsProvider(arguments[0], "-", arguments[1])
|
||||
}
|
||||
break;
|
||||
default: // do nothing
|
||||
}
|
||||
return oldNewDnsProvider.apply(null, arguments)
|
||||
}
|
||||
function oldNewDnsProvider(name, type, meta) {
|
||||
if (typeof meta === 'object' && 'ip_conversions' in meta) {
|
||||
meta.ip_conversions = format_tt(meta.ip_conversions);
|
||||
}
|
||||
|
|
|
@ -54,6 +54,13 @@ func TestParsedFiles(t *testing.T) {
|
|||
// Initialize any DNS providers mentioned.
|
||||
for _, dProv := range conf.DNSProviders {
|
||||
var pcfg = map[string]string{}
|
||||
|
||||
if dProv.Type == "-" {
|
||||
// Pretend any "look up provider type in creds.json" results
|
||||
// in a provider type that actually exists.
|
||||
dProv.Type = "CLOUDFLAREAPI"
|
||||
}
|
||||
|
||||
// Fake out any provider's validation tests.
|
||||
switch dProv.Type {
|
||||
case "CLOUDFLAREAPI":
|
||||
|
|
31
pkg/js/parse_tests/041-newstyleproviders.js
Executable file
31
pkg/js/parse_tests/041-newstyleproviders.js
Executable file
|
@ -0,0 +1,31 @@
|
|||
// Test old-style and new-style New*() functions.
|
||||
|
||||
var REG1 = NewRegistrar("foo1");
|
||||
var CF1 = NewDnsProvider("dns1");
|
||||
|
||||
var REG2a = NewRegistrar("foo2a", "NONE");
|
||||
var CF2a = NewDnsProvider("dns2a", "CLOUDFLAREAPI");
|
||||
|
||||
var REG2b = NewRegistrar("foo2b", {
|
||||
regmetakey: "reg2b"
|
||||
});
|
||||
var CF2b = NewDnsProvider("dns2b", {
|
||||
dnsmetakey: "dns2b"
|
||||
});
|
||||
|
||||
var REG3 = NewRegistrar("foo3", "MANUAL", {
|
||||
regmetakey: "reg3"
|
||||
});
|
||||
var CF3 = NewDnsProvider("dns3", "CLOUDFLAREAPI", {
|
||||
dnsmetakey: "dns3"
|
||||
});
|
||||
|
||||
var REG1h = NewRegistrar("foo1h", "-");
|
||||
var CF1h = NewDnsProvider("dns1h", "-");
|
||||
|
||||
var REG2bh = NewRegistrar("foo2bh", "-", {
|
||||
regmetakey: "reg2bh"
|
||||
});
|
||||
var CF2bh = NewDnsProvider("dns2bh", "-", {
|
||||
dnsmetakey: "dns2bh"
|
||||
});
|
19
pkg/js/parse_tests/041-newstyleproviders.json
Normal file
19
pkg/js/parse_tests/041-newstyleproviders.json
Normal file
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"dns_providers": [
|
||||
{ "name": "dns1", "type": "CLOUDFLAREAPI" },
|
||||
{ "name": "dns2a", "type": "CLOUDFLAREAPI" },
|
||||
{ "name": "dns2b", "type": "CLOUDFLAREAPI", "meta": { "dnsmetakey": "dns2b" } },
|
||||
{ "name": "dns3", "type": "CLOUDFLAREAPI", "meta": { "dnsmetakey": "dns3" } },
|
||||
{ "name": "dns1h", "type": "CLOUDFLAREAPI" },
|
||||
{ "name": "dns2bh", "type": "CLOUDFLAREAPI", "meta": { "dnsmetakey": "dns2bh" } }
|
||||
],
|
||||
"domains": [],
|
||||
"registrars": [
|
||||
{ "name": "foo1", "type": "-" },
|
||||
{ "name": "foo2a", "type": "NONE" },
|
||||
{ "name": "foo2b", "type": "-", "meta": { "regmetakey": "reg2b" } },
|
||||
{ "name": "foo3", "type": "MANUAL", "meta": { "regmetakey": "reg3" } },
|
||||
{ "name": "foo1h", "type": "-" },
|
||||
{ "name": "foo2bh", "type": "-", "meta": { "regmetakey": "reg2bh" } }
|
||||
]
|
||||
}
|
|
@ -464,7 +464,7 @@ func ValidateAndNormalizeConfig(config *models.DNSConfig) (errs []error) {
|
|||
|
||||
// At this point we've munged anything that needs to be munged, and
|
||||
// validated anything that can be globally validated.
|
||||
// Let's ask // the provider if there are any records they can't handle.
|
||||
// Let's ask the provider if there are any records they can't handle.
|
||||
for _, domain := range config.Domains { // For each domain..
|
||||
for _, provider := range domain.DNSProviderInstances { // For each provider...
|
||||
if err := providers.AuditRecords(provider.ProviderBase.ProviderType, domain.Records); err != nil {
|
||||
|
|
|
@ -57,7 +57,7 @@ var DNSProviderTypes = map[string]DspFuncs{}
|
|||
// RegisterRegistrarType adds a registrar type to the registry by providing a suitable initialization function.
|
||||
func RegisterRegistrarType(name string, init RegistrarInitializer, pm ...ProviderMetadata) {
|
||||
if _, ok := RegistrarTypes[name]; ok {
|
||||
log.Fatalf("Cannot register registrar type %s multiple times", name)
|
||||
log.Fatalf("Cannot register registrar type %q multiple times", name)
|
||||
}
|
||||
RegistrarTypes[name] = init
|
||||
unwrapProviderCapabilities(name, pm)
|
||||
|
@ -66,7 +66,7 @@ func RegisterRegistrarType(name string, init RegistrarInitializer, pm ...Provide
|
|||
// RegisterDomainServiceProviderType adds a dsp to the registry with the given initialization function.
|
||||
func RegisterDomainServiceProviderType(name string, fns DspFuncs, pm ...ProviderMetadata) {
|
||||
if _, ok := DNSProviderTypes[name]; ok {
|
||||
log.Fatalf("Cannot register registrar type %s multiple times", name)
|
||||
log.Fatalf("Cannot register registrar type %q multiple times", name)
|
||||
}
|
||||
DNSProviderTypes[name] = fns
|
||||
unwrapProviderCapabilities(name, pm)
|
||||
|
@ -74,30 +74,71 @@ func RegisterDomainServiceProviderType(name string, fns DspFuncs, pm ...Provider
|
|||
|
||||
// CreateRegistrar initializes a registrar instance from given credentials.
|
||||
func CreateRegistrar(rType string, config map[string]string) (Registrar, error) {
|
||||
var err error
|
||||
rType, err = beCompatible(rType, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
initer, ok := RegistrarTypes[rType]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("registrar type %s not declared", rType)
|
||||
return nil, fmt.Errorf("No such registrar type: %q", rType)
|
||||
}
|
||||
return initer(config)
|
||||
}
|
||||
|
||||
// CreateDNSProvider initializes a dns provider instance from given credentials.
|
||||
func CreateDNSProvider(dType string, config map[string]string, meta json.RawMessage) (DNSServiceProvider, error) {
|
||||
p, ok := DNSProviderTypes[dType]
|
||||
func CreateDNSProvider(providerTypeName string, config map[string]string, meta json.RawMessage) (DNSServiceProvider, error) {
|
||||
var err error
|
||||
providerTypeName, err = beCompatible(providerTypeName, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
p, ok := DNSProviderTypes[providerTypeName]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("DSP type %s not declared", dType)
|
||||
return nil, fmt.Errorf("No such DNS service provider: %q", providerTypeName)
|
||||
}
|
||||
return p.Initializer(config, meta)
|
||||
}
|
||||
|
||||
// beCompatible looks up
|
||||
func beCompatible(n string, config map[string]string) (string, error) {
|
||||
// Pre 4.0: If n is a placeholder, substitute the TYPE from creds.json.
|
||||
// 4.0: Require TYPE from creds.json.
|
||||
|
||||
ct := config["TYPE"]
|
||||
// If a placeholder value was specified...
|
||||
if n == "" || n == "-" {
|
||||
// But no TYPE exists in creds.json...
|
||||
if ct == "" {
|
||||
return "-", fmt.Errorf("creds.json entry missing TYPE field")
|
||||
}
|
||||
// Otherwise, use the value from creds.json.
|
||||
return ct, nil
|
||||
}
|
||||
|
||||
// Pre 4.0: The user specified the name manually.
|
||||
// Cross check to detect user-error.
|
||||
if ct != "" && n != ct {
|
||||
return "", fmt.Errorf("creds.json entry mismatch: specified=%q TYPE=%q", n, ct)
|
||||
}
|
||||
// Seems like the user did it the right way. Return the original value.
|
||||
return n, nil
|
||||
|
||||
// NB(tlim): My hope is that in 4.0 this entire function will simply be the
|
||||
// following, but I may be wrong:
|
||||
//return config["TYPE"], nil
|
||||
}
|
||||
|
||||
// AuditRecords calls the RecordAudit function for a provider.
|
||||
func AuditRecords(dType string, rcs models.Records) error {
|
||||
p, ok := DNSProviderTypes[dType]
|
||||
if !ok {
|
||||
return fmt.Errorf("DSP type %s not declared", dType)
|
||||
return fmt.Errorf("Unknown DNS service provider type: %q", dType)
|
||||
}
|
||||
if p.RecordAuditor == nil {
|
||||
return fmt.Errorf("DSP type %s has no RecordAuditor", dType)
|
||||
return fmt.Errorf("DNS service provider type %q has no RecordAuditor", dType)
|
||||
}
|
||||
return p.RecordAuditor(rcs)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue