mirror of
https://github.com/StackExchange/dnscontrol.git
synced 2025-12-09 13:46:07 +08:00
RP works FromStruct but hardcoding needs to be removed
This commit is contained in:
parent
a3ed1dc6b2
commit
cbbb396026
10 changed files with 157 additions and 120 deletions
|
|
@ -11,5 +11,33 @@ dlv test github.com/StackExchange/dnscontrol/v4/pkg/diff2 -- -test.run Test_anal
|
|||
Debug the integration tests:
|
||||
|
||||
```shell
|
||||
dlv test github.com/StackExchange/dnscontrol/v4/integrationTest -- -test.v -test.run ^TestDNSProviders -verbose -profile NAMEDOTCOM -start 1 -end 1
|
||||
dlv test github.com/StackExchange/dnscontrol/v4/integrationTest -- -test.v -test.run ^TestDNSProviders -verbose -profile BIND -start 7 -end 7
|
||||
```
|
||||
|
||||
If you are using VSCode, the equivalent configuration is:
|
||||
|
||||
```
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Debug Integration Test",
|
||||
"type": "go",
|
||||
"request": "launch",
|
||||
"mode": "test",
|
||||
"program": "${workspaceFolder}/integrationTest",
|
||||
"args": [
|
||||
"-test.v",
|
||||
"-test.run",
|
||||
"^TestDNSProviders",
|
||||
"-verbose",
|
||||
"-profile",
|
||||
"BIND",
|
||||
"-start",
|
||||
"7",
|
||||
"-end",
|
||||
"7"
|
||||
],
|
||||
"buildFlags": "",
|
||||
"env": {},
|
||||
"showLog": true
|
||||
},
|
||||
```
|
||||
|
|
|
|||
|
|
@ -343,7 +343,7 @@ func cfSingleRedirectEnabled() bool {
|
|||
}
|
||||
|
||||
func cfSingleRedirect(name string, code any, when, then string) *models.RecordConfig {
|
||||
rec, err := rtypecontrol.NewRecordConfigFromRaw("CLOUDFLAREAPI_SINGLE_REDIRECT", []any{name, code, when, then}, globalDC)
|
||||
rec, err := rtypecontrol.NewRecordConfigFromRaw("CLOUDFLAREAPI_SINGLE_REDIRECT", 1, []any{name, code, when, then}, globalDC)
|
||||
panicOnErr(err)
|
||||
return rec
|
||||
}
|
||||
|
|
@ -355,13 +355,13 @@ func cfWorkerRoute(pattern, target string) *models.RecordConfig {
|
|||
}
|
||||
|
||||
func cfRedir(pattern, target string) *models.RecordConfig {
|
||||
rec, err := rtypecontrol.NewRecordConfigFromRaw("CF_REDIRECT", []any{pattern, target}, globalDC)
|
||||
rec, err := rtypecontrol.NewRecordConfigFromRaw("CF_REDIRECT", 1, []any{pattern, target}, globalDC)
|
||||
panicOnErr(err)
|
||||
return rec
|
||||
}
|
||||
|
||||
func cfRedirTemp(pattern, target string) *models.RecordConfig {
|
||||
rec, err := rtypecontrol.NewRecordConfigFromRaw("CF_TEMP_REDIRECT", []any{pattern, target}, globalDC)
|
||||
rec, err := rtypecontrol.NewRecordConfigFromRaw("CF_TEMP_REDIRECT", 1, []any{pattern, target}, globalDC)
|
||||
panicOnErr(err)
|
||||
return rec
|
||||
}
|
||||
|
|
@ -487,7 +487,7 @@ func r53alias(name, aliasType, target, evalTargetHealth string) *models.RecordCo
|
|||
}
|
||||
|
||||
func rp(name string, m, t string) *models.RecordConfig {
|
||||
rec, err := rtypecontrol.NewRecordConfigFromRaw("RP", []any{name, m, t}, globalDC)
|
||||
rec, err := rtypecontrol.NewRecordConfigFromRaw("RP", 300, []any{name, m, t}, globalDC)
|
||||
panicOnErr(err)
|
||||
return rec
|
||||
}
|
||||
|
|
|
|||
|
|
@ -174,9 +174,9 @@ func makeTests() []*TestGroup {
|
|||
),
|
||||
|
||||
testgroup("RP",
|
||||
tc("Create RP", rp("foo", "usr@example.com", "bar.com")),
|
||||
tc("Create RP", rp("foo", "other@example.com", "bar.com")),
|
||||
tc("Create RP", rp("foo", "other@example.com", "example.com")),
|
||||
tc("Create RP", rp("foo", "user.example.com.", "bar.com.")),
|
||||
tc("Create RP", rp("foo", "other.example.com.", "bar.com.")),
|
||||
tc("Create RP", rp("foo", "other.example.com.", "example.com.")),
|
||||
),
|
||||
|
||||
// TXT
|
||||
|
|
|
|||
43
pkg/rtype/rp.go
Normal file
43
pkg/rtype/rp.go
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
package rtype
|
||||
|
||||
import (
|
||||
"github.com/StackExchange/dnscontrol/v4/models"
|
||||
"github.com/StackExchange/dnscontrol/v4/pkg/rtypecontrol"
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
func init() {
|
||||
rtypecontrol.Register(&RP{})
|
||||
}
|
||||
|
||||
// RP RR. See RFC 1138, Section 2.2.
|
||||
type RP struct {
|
||||
dns.RP
|
||||
}
|
||||
|
||||
func (handle *RP) Name() string {
|
||||
return "RP"
|
||||
}
|
||||
|
||||
func (handle *RP) FromArgs(dc *models.DomainConfig, rec *models.RecordConfig, args []any) error {
|
||||
if err := rtypecontrol.PaveArgs(args[1:], "ss"); err != nil {
|
||||
return err
|
||||
}
|
||||
rec.F = &RP{
|
||||
dns.RP{
|
||||
Mbox: args[1].(string),
|
||||
Txt: args[2].(string),
|
||||
},
|
||||
}
|
||||
|
||||
// TODO: Generate friendly Comparable and ZonefilePartial values.
|
||||
rec.Comparable = rec.F.(*RP).Mbox + " " + rec.F.(*RP).Txt
|
||||
rec.ZonefilePartial = rec.Comparable
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (handle *RP) CopyToLegacyFields(rec *models.RecordConfig) {
|
||||
rp := rec.F.(*RP)
|
||||
_ = rec.SetTarget(rp.Mbox + " " + rp.Txt)
|
||||
}
|
||||
|
|
@ -5,6 +5,7 @@ import (
|
|||
|
||||
"github.com/StackExchange/dnscontrol/v4/models"
|
||||
"github.com/StackExchange/dnscontrol/v4/pkg/domaintags"
|
||||
"github.com/miekg/dns"
|
||||
"github.com/miekg/dns/dnsutil"
|
||||
)
|
||||
|
||||
|
|
@ -14,7 +15,7 @@ func ImportRawRecords(domains []*models.DomainConfig) error {
|
|||
for _, dc := range domains {
|
||||
for _, rawRec := range dc.RawRecords {
|
||||
|
||||
rec, err := NewRecordConfigFromRaw(rawRec.Type, rawRec.Args, dc)
|
||||
rec, err := NewRecordConfigFromRaw(rawRec.Type, rawRec.TTL, rawRec.Args, dc)
|
||||
rec.FilePos = models.FixPosition(rawRec.FilePos)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s: %w", rec.FilePos, err)
|
||||
|
|
@ -32,25 +33,22 @@ func ImportRawRecords(domains []*models.DomainConfig) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func NewRecordConfigFromRaw(t string, args []any, dc *models.DomainConfig) (*models.RecordConfig, error) {
|
||||
//fmt.Printf("DEBUG: NewRecordConfigFromRaw t=%q args=%+v\n", t, args)
|
||||
func NewRecordConfigFromRaw(t string, ttl uint32, args []any, dc *models.DomainConfig) (*models.RecordConfig, error) {
|
||||
if _, ok := Func[t]; !ok {
|
||||
return nil, fmt.Errorf("record type %q is not supported", t)
|
||||
}
|
||||
if t == "" {
|
||||
panic("rtypecontrol: NewRecordConfigFromRaw: empty record type")
|
||||
}
|
||||
|
||||
// Create as much of the RecordConfig as we can now. Allow New() to fill in the reset.
|
||||
rec := &models.RecordConfig{
|
||||
Type: t,
|
||||
Name: args[0].(string), // May be fixed later.
|
||||
TTL: ttl,
|
||||
Metadata: map[string]string{},
|
||||
}
|
||||
|
||||
setRecordNames(rec, dc, args[0].(string))
|
||||
|
||||
if rec.Type == "" {
|
||||
panic("rtypecontrol: NewRecordConfigFromRaw: empty record type")
|
||||
}
|
||||
|
||||
// Fill in the .F/.Fields* fields.
|
||||
err := Func[t].FromArgs(dc, rec, args)
|
||||
if err != nil {
|
||||
|
|
@ -60,19 +58,30 @@ func NewRecordConfigFromRaw(t string, args []any, dc *models.DomainConfig) (*mod
|
|||
return rec, nil
|
||||
}
|
||||
|
||||
// func stringifyMetas(metas []map[string]any) map[string]string {
|
||||
// result := make(map[string]string)
|
||||
// for _, m := range metas {
|
||||
// for mk, mv := range m {
|
||||
// if v, ok := mv.(string); ok {
|
||||
// result[mk] = v // Already a string. No new malloc.
|
||||
// } else {
|
||||
// result[mk] = fmt.Sprintf("%v", mv)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return result
|
||||
// }
|
||||
func NewRecordConfigFromStruct(name string, ttl uint32, t string, fields any, dc *models.DomainConfig) (*models.RecordConfig, error) {
|
||||
if _, ok := Func[t]; !ok {
|
||||
return nil, fmt.Errorf("record type %q is not supported", t)
|
||||
}
|
||||
if t == "" {
|
||||
panic("rtypecontrol: NewRecordConfigFromStruct: empty record type")
|
||||
}
|
||||
|
||||
// Create as much of the RecordConfig as we can now. Allow New() to fill in the reset.
|
||||
rec := &models.RecordConfig{
|
||||
Type: t,
|
||||
TTL: ttl,
|
||||
Metadata: map[string]string{},
|
||||
}
|
||||
setRecordNames(rec, dc, name)
|
||||
|
||||
// Fill in the .F/.Fields* fields.
|
||||
err := Func[t].FromArgs(dc, rec, []any{name, fields.(*dns.RP).Mbox, fields.(*dns.RP).Txt})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return rec, nil
|
||||
}
|
||||
|
||||
func setRecordNames(rec *models.RecordConfig, dc *models.DomainConfig, n string) {
|
||||
|
||||
|
|
@ -87,9 +96,9 @@ func setRecordNames(rec *models.RecordConfig, dc *models.DomainConfig, n string)
|
|||
rec.NameRaw = n
|
||||
rec.NameUnicode = domaintags.EfficientToUnicode(n)
|
||||
}
|
||||
rec.NameFQDN = dnsutil.AddOrigin(rec.Name, dc.Name)
|
||||
rec.NameFQDNRaw = dnsutil.AddOrigin(rec.NameRaw, dc.NameRaw)
|
||||
rec.NameFQDNUnicode = dnsutil.AddOrigin(rec.NameUnicode, dc.NameUnicode)
|
||||
rec.NameFQDN = dc.Name
|
||||
rec.NameFQDNRaw = dc.NameRaw
|
||||
rec.NameFQDNUnicode = dc.NameUnicode
|
||||
} else {
|
||||
// _EXTEND() mode:
|
||||
// FIXME(tlim): Not implemented.
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import (
|
|||
"github.com/StackExchange/dnscontrol/v4/pkg/domaintags"
|
||||
"github.com/StackExchange/dnscontrol/v4/pkg/prettyzone"
|
||||
"github.com/StackExchange/dnscontrol/v4/pkg/printer"
|
||||
"github.com/StackExchange/dnscontrol/v4/pkg/rtypecontrol"
|
||||
"github.com/StackExchange/dnscontrol/v4/providers"
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
|
@ -204,10 +205,31 @@ func ParseZoneContents(content string, zoneName string, zonefileName string) (mo
|
|||
|
||||
foundRecords := models.Records{}
|
||||
for rr, ok := zp.Next(); ok; rr, ok = zp.Next() {
|
||||
rec, err := models.RRtoRCTxtBug(rr, zoneName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
var rec models.RecordConfig
|
||||
var prec *models.RecordConfig
|
||||
var err error
|
||||
|
||||
// Modern types:
|
||||
rtype := rr.Header().Rrtype
|
||||
switch rtype {
|
||||
case dns.TypeRP:
|
||||
name := rr.Header().Name
|
||||
name = strings.TrimSuffix(name, ".")
|
||||
prec, err = rtypecontrol.NewRecordConfigFromStruct(name, rr.Header().Ttl, "RP", rr, models.MakeFakeDomainConfig(zoneName))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rec = *prec
|
||||
rec.TTL = rr.Header().Ttl
|
||||
fmt.Printf("DEBUG: RP record parsed as %+v\n", rec)
|
||||
default:
|
||||
// Legacy types:
|
||||
rec, err = models.RRtoRCTxtBug(rr, zoneName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
foundRecords = append(foundRecords, &rec)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -509,58 +509,6 @@ func (c *cloudflareProvider) preprocessConfig(dc *models.DomainConfig) error {
|
|||
}
|
||||
}
|
||||
|
||||
// // CF_REDIRECT record types:
|
||||
// if rec.Type == "CF_REDIRECT" || rec.Type == "CF_TEMP_REDIRECT" {
|
||||
// if !c.manageRedirects && !c.manageSingleRedirects {
|
||||
// return errors.New("you must add 'manage_single_redirects: true' metadata to cloudflare provider to use CF_REDIRECT/CF_TEMP_REDIRECT records")
|
||||
// }
|
||||
// code := uint16(301)
|
||||
// if rec.Type == "CF_TEMP_REDIRECT" {
|
||||
// code = 302
|
||||
// }
|
||||
|
||||
// part := strings.SplitN(rec.GetTargetField(), ",", 2)
|
||||
// prWhen, prThen := part[0], part[1]
|
||||
// prPriority++
|
||||
|
||||
// // Convert this record to a PAGE_RULE.
|
||||
// if err := cfsingleredirect.MakePageRule(rec, prPriority, code, prWhen, prThen); err != nil {
|
||||
// return err
|
||||
// }
|
||||
// rec.SetLabel("@", dc.Name)
|
||||
|
||||
// if c.manageRedirects && !c.manageSingleRedirects {
|
||||
// // Old-Style only. No additional work needed.
|
||||
// } else if !c.manageRedirects && c.manageSingleRedirects {
|
||||
// // New-Style only. Convert PAGE_RULE to SINGLEREDIRECT.
|
||||
// if err := cfsingleredirect.TranscodePRtoSR(rec); err != nil {
|
||||
// return err
|
||||
// }
|
||||
// if err := c.LogTranscode(dc.Name, rec.CloudflareRedirect); err != nil {
|
||||
// return err
|
||||
// }
|
||||
// } else {
|
||||
// // Both old-style and new-style enabled!
|
||||
// // Retain the PAGE_RULE and append an additional SINGLEREDIRECT.
|
||||
|
||||
// // make a copy:
|
||||
// newRec, err := rec.Copy()
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
// // The copy becomes the CF SingleRedirect
|
||||
// if err := cfsingleredirect.TranscodePRtoSR(rec); err != nil {
|
||||
// return err
|
||||
// }
|
||||
// if err := c.LogTranscode(dc.Name, rec.CloudflareRedirect); err != nil {
|
||||
// return err
|
||||
// }
|
||||
// // Append the copy to the end of the list.
|
||||
// dc.Records = append(dc.Records, newRec)
|
||||
|
||||
// // The original PAGE_RULE remains untouched.
|
||||
// }
|
||||
// } else
|
||||
if rec.Type == "CLOUDFLAREAPI_SINGLE_REDIRECT" {
|
||||
// SINGLEREDIRECT record types. Verify they are enabled.
|
||||
if !c.manageSingleRedirects {
|
||||
|
|
@ -797,18 +745,6 @@ func uint16Zero(value interface{}) uint16 {
|
|||
return 0
|
||||
}
|
||||
|
||||
// // intZero converts value to uint16 or returns 0.
|
||||
// func intZero(value interface{}) uint16 {
|
||||
// switch v := value.(type) {
|
||||
// case float64:
|
||||
// return uint16(v)
|
||||
// case int:
|
||||
// return uint16(v)
|
||||
// case nil:
|
||||
// }
|
||||
// return 0
|
||||
// }
|
||||
|
||||
// stringDefault returns the value as a string or returns the default value if nil.
|
||||
func stringDefault(value interface{}, def string) string {
|
||||
switch v := value.(type) {
|
||||
|
|
|
|||
|
|
@ -299,6 +299,7 @@ func (c *cloudflareProvider) getSingleRedirects(id string, domain string) ([]*mo
|
|||
|
||||
rec, err := rtypecontrol.NewRecordConfigFromRaw(
|
||||
"CLOUDFLAREAPI_SINGLE_REDIRECT",
|
||||
1,
|
||||
[]any{srName, code, srWhen, srThen},
|
||||
models.MakeFakeDomainConfig(domain))
|
||||
if err != nil {
|
||||
|
|
@ -434,17 +435,3 @@ func (c *cloudflareProvider) createWorkerRoute(domainID string, target string) e
|
|||
_, err := c.cfClient.CreateWorkerRoute(context.Background(), cloudflare.ZoneIdentifier(domainID), wr)
|
||||
return err
|
||||
}
|
||||
|
||||
// https://github.com/dominikh/go-tools/issues/1137 which is a dup of
|
||||
// https://github.com/dominikh/go-tools/issues/810
|
||||
//
|
||||
//lint:ignore U1000 false positive due to
|
||||
// type pageRuleConstraint struct {
|
||||
// Operator string `json:"operator"`
|
||||
// Value string `json:"value"`
|
||||
// }
|
||||
|
||||
// type pageRuleFwdInfo struct {
|
||||
// URL string `json:"url"`
|
||||
// StatusCode uint16 `json:"status_code"`
|
||||
// }
|
||||
|
|
|
|||
|
|
@ -24,6 +24,10 @@ func (handle *CfRedirect) FromArgs(dc *models.DomainConfig, rec *models.RecordCo
|
|||
return FromArgs_helper(dc, rec, args, 301)
|
||||
}
|
||||
|
||||
// func (handle *CfRedirect) FromStruct(dc *models.DomainConfig, rec *models.RecordConfig, fields any) error {
|
||||
// panic("CF_REDIRECT: FromStruct not implemented")
|
||||
// }
|
||||
|
||||
func (handle *CfRedirect) CopyToLegacyFields(rec *models.RecordConfig) {
|
||||
// Nothing needs to be copied. The CLOUDFLAREAPI_SINGLE_REDIRECT FromArgs copies everything needed.
|
||||
}
|
||||
|
|
@ -39,6 +43,10 @@ func (handle *CfTempRedirect) FromArgs(dc *models.DomainConfig, rec *models.Reco
|
|||
return FromArgs_helper(dc, rec, args, 302)
|
||||
}
|
||||
|
||||
// func (handle *CfTempRedirect) FromStruct(dc *models.DomainConfig, rec *models.RecordConfig, fields any) error {
|
||||
// panic("CF_TEMP_REDIRECT: FromStruct not implemented")
|
||||
// }
|
||||
|
||||
func (handle *CfTempRedirect) CopyToLegacyFields(rec *models.RecordConfig) {
|
||||
// Nothing needs to be copied. The CLOUDFLAREAPI_SINGLE_REDIRECT FromArgs copies everything needed.
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,12 +17,12 @@ type SingleRedirectConfig struct {
|
|||
Code uint16 `json:"code,omitempty"` // 301 or 302
|
||||
//
|
||||
// SR == SingleRedirect
|
||||
SRName string `json:"sr_name,omitempty"` // How is this displayed to the user
|
||||
SRWhen string `json:"sr_when,omitempty"`
|
||||
SRThen string `json:"sr_then,omitempty"`
|
||||
SRRRulesetID string `json:"sr_rulesetid,omitempty"`
|
||||
SRRRulesetRuleID string `json:"sr_rulesetruleid,omitempty"`
|
||||
SRDisplay string `json:"sr_display,omitempty"` // How is this displayed to the user (SetTarget) for CF_SINGLE_REDIRECT
|
||||
SRName string `json:"sr_name,omitempty"` // How is this displayed to the user
|
||||
SRWhen string `json:"sr_when,omitempty"` // Condition for redirect
|
||||
SRThen string `json:"sr_then,omitempty"` // Formula for redirect
|
||||
SRRRulesetID string `json:"sr_rulesetid,omitempty"` // ID of the ruleset containing this rule (populated by API)
|
||||
SRRRulesetRuleID string `json:"sr_rulesetruleid,omitempty"` // ID of this rule within the ruleset (populated by API)
|
||||
SRDisplay string `json:"sr_display,omitempty"` // How is this displayed to the user (SetTarget) for CF_SINGLE_REDIRECT
|
||||
}
|
||||
|
||||
// Name returns the text (all caps) name of the rtype.
|
||||
|
|
@ -76,6 +76,10 @@ func (handle *SingleRedirectConfig) FromArgs(dc *models.DomainConfig, rec *model
|
|||
return nil
|
||||
}
|
||||
|
||||
// func (handle *SingleRedirectConfig) FromStruct(dc *models.DomainConfig, rec *models.RecordConfig, fields any) error {
|
||||
// panic("CLOUDFLAREAPI_SINGLE_REDIRECT: FromStruct not implemented")
|
||||
// }
|
||||
|
||||
// targetFromRaw create the display text used for a normal Redirect.
|
||||
func targetFromRaw(name string, code uint16, when, then string) string {
|
||||
return fmt.Sprintf("name=(%s) code=(%03d) when=(%s) then=(%s)",
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue