diff --git a/docs/_providers/ovh.md b/docs/_providers/ovh.md index f38f76d8e..e0e83da23 100644 --- a/docs/_providers/ovh.md +++ b/docs/_providers/ovh.md @@ -119,14 +119,13 @@ control panel manually. ## Dual providers scenario -Since OVH doesn't allow to host DNS for a domain that is not registered in their registrar, some dual providers -scenario are not possible: +OVH now allows to host DNS zone for a domain that is not registered in their registrar (see: https://www.ovh.com/manager/web/#/zone). The following dual providers scenario are supported: | registrar | zone | working? | |:---------:|:-----------:|:--------:| | OVH | other | √ | | OVH | OVH + other | √ | -| other | OVH | X | +| other | OVH | √ | ## Caveat diff --git a/providers/ovh/ovhProvider.go b/providers/ovh/ovhProvider.go index 8b2c2d976..bc6f4fe1a 100644 --- a/providers/ovh/ovhProvider.go +++ b/providers/ovh/ovhProvider.go @@ -68,7 +68,7 @@ func (c *ovhProvider) GetNameservers(domain string) ([]*models.Nameserver, error return nil, fmt.Errorf("'%s' not a zone in ovh account", domain) } - ns, err := c.fetchRegistrarNS(domain) + ns, err := c.fetchNS(domain) if err != nil { return nil, err } diff --git a/providers/ovh/protocol.go b/providers/ovh/protocol.go index fed9e0da7..b6b520c2c 100644 --- a/providers/ovh/protocol.go +++ b/providers/ovh/protocol.go @@ -1,10 +1,13 @@ package ovh import ( + "errors" "fmt" + "strings" + "github.com/StackExchange/dnscontrol/v3/models" "github.com/miekg/dns/dnsutil" - "strings" + "github.com/ovh/go-ovh/ovh" ) // Void an empty structure. @@ -164,7 +167,7 @@ func (c *ovhProvider) refreshZone(fqdn string) error { // fetch the NS OVH attributed to this zone (which is distinct from fetchRealNS which // get the exact NS stored at the registrar -func (c *ovhProvider) fetchNS(fqdn string) ([]string, error) { +func (c *ovhProvider) fetchZoneNS(fqdn string) ([]string, error) { zone, err := c.fetchZone(fqdn) if err != nil { return nil, err @@ -173,6 +176,22 @@ func (c *ovhProvider) fetchNS(fqdn string) ([]string, error) { return zone.NameServers, nil } +// Fetch first the registrar NS, if none found, return the zone defined NS +func (c *ovhProvider) fetchNS(fqdn string) ([]string, error) { + ns, err := c.fetchRegistrarNS(fqdn) + if err != nil { + return nil, err + } + + if len(ns) == 0 { + ns, err = c.fetchZoneNS(fqdn) + if err != nil { + return nil, err + } + } + return ns, nil +} + // CurrentNameServer stores information about nameservers. type CurrentNameServer struct { ToDelete bool `json:"toDelete,omitempty"` @@ -187,6 +206,10 @@ func (c *ovhProvider) fetchRegistrarNS(fqdn string) ([]string, error) { var nameServersID []int err := c.client.CallAPI("GET", "/domain/"+fqdn+"/nameServer", nil, &nameServersID, true) if err != nil { + var apiError *ovh.APIError + if errors.As(err, &apiError) && apiError.Code == 404 { + return []string{}, nil + } return nil, err }