Skip to content

Commit

Permalink
ORACLE: Abide by 429-style rate limits, fix Nameserver update bug (#3090
Browse files Browse the repository at this point in the history
)

Co-authored-by: Tom Limoncelli <tlimoncelli@stackoverflow.com>
  • Loading branch information
fabienmazieres and tlimoncelli authored Aug 23, 2024
1 parent 8bb5df9 commit 0de789f
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 8 deletions.
12 changes: 12 additions & 0 deletions documentation/provider/oracle.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,11 @@ Example:
{% endcode %}

## Metadata

This provider does not recognize any special metadata fields unique to Oracle Cloud.

## Usage

An example configuration:

{% code title="dnsconfig.js" %}
Expand All @@ -42,3 +44,13 @@ D("example.com", REG_NONE, DnsProvider(DSP_ORACLE),
END);
```
{% endcode %}

## Notes for developers

Integration does not have the capability to set the TTL set differently when Oracle is the provider being tested.
You will see an error message behind displayed, such as below, but it can be safely ignored.

```Text
=== RUN TestDNSProviders/example.co.uk/Clean_Slate:Empty
WARNING: Oracle Cloud forces TTL=86400 for NS records. Ignoring configured TTL of 300 for ns1.p201.dns.oraclecloud.net.
```
13 changes: 11 additions & 2 deletions providers/oracle/auditrecords.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,19 @@
package oracle

import "github.com/StackExchange/dnscontrol/v4/models"
import (
"github.com/StackExchange/dnscontrol/v4/models"
"github.com/StackExchange/dnscontrol/v4/pkg/rejectif"
)

// AuditRecords returns a list of errors corresponding to the records
// that aren't supported by this provider. If all records are
// supported, an empty list is returned.
func AuditRecords(records []*models.RecordConfig) []error {
return nil
a := rejectif.Auditor{}

a.Add("TXT", rejectif.TxtIsEmpty) // Last verified 2024-08-21
a.Add("TXT", rejectif.TxtHasBackslash) // Last verified 2024-08-21
a.Add("TXT", rejectif.TxtHasDoubleQuotes) // Last verified 2024-08-21

return a.Audit(records)
}
71 changes: 65 additions & 6 deletions providers/oracle/oracleProvider.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package oracle
import (
"context"
"encoding/json"
"net/http"
"strings"
"time"

Expand Down Expand Up @@ -75,10 +76,15 @@ func (o *oracleProvider) ListZones() ([]string, error) {
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
defer cancel()

waitTime = 1
retry:
listResp, err := o.client.ListZones(ctx, dns.ListZonesRequest{
CompartmentId: &o.compartment,
})
if err != nil {
if pauseAndRetry(listResp.HTTPResponse()) {
goto retry
}
return nil, err
}

Expand All @@ -94,40 +100,59 @@ func (o *oracleProvider) EnsureZoneExists(domain string) error {
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
defer cancel()

waitTime = 1
retryFirstGetZone:
getResp, err := o.client.GetZone(ctx, dns.GetZoneRequest{
ZoneNameOrId: &domain,
CompartmentId: &o.compartment,
})
if err == nil {
return nil
}
if getResp.RawResponse.StatusCode != 404 {
return err
if err != nil {
if pauseAndRetry(getResp.HTTPResponse()) {
goto retryFirstGetZone
}
if getResp.RawResponse.StatusCode != 404 {
return err
}
}

_, err = o.client.CreateZone(ctx, dns.CreateZoneRequest{
waitTime = 1
retryCreate:
createResp, err := o.client.CreateZone(ctx, dns.CreateZoneRequest{
CreateZoneDetails: dns.CreateZoneDetails{
CompartmentId: &o.compartment,
Name: &domain,
ZoneType: dns.CreateZoneDetailsZoneTypePrimary,
},
})
if err != nil {
if pauseAndRetry(createResp.HTTPResponse()) {
goto retryCreate
}
return err
}

waitTime = 1
retrySecondGetZone:
// poll until the zone is ready
pollUntilAvailable := func(r common.OCIOperationResponse) bool {
if converted, ok := r.Response.(dns.GetZoneResponse); ok {
return converted.LifecycleState != dns.ZoneLifecycleStateActive
}
return true
}
_, err = o.client.GetZone(ctx, dns.GetZoneRequest{
getResp, err = o.client.GetZone(ctx, dns.GetZoneRequest{
ZoneNameOrId: &domain,
CompartmentId: &o.compartment,
RequestMetadata: helpers.GetRequestMetadataWithCustomizedRetryPolicy(pollUntilAvailable),
})
if err != nil {
if pauseAndRetry(createResp.HTTPResponse()) {
goto retrySecondGetZone
}
}

return err
}
Expand All @@ -136,11 +161,16 @@ func (o *oracleProvider) GetNameservers(domain string) ([]*models.Nameserver, er
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
defer cancel()

waitTime = 1
retry:
getResp, err := o.client.GetZone(ctx, dns.GetZoneRequest{
ZoneNameOrId: &domain,
CompartmentId: &o.compartment,
})
if err != nil {
if pauseAndRetry(getResp.HTTPResponse()) {
goto retry
}
return nil, err
}

Expand All @@ -149,7 +179,7 @@ func (o *oracleProvider) GetNameservers(domain string) ([]*models.Nameserver, er
nss[i] = *ns.Hostname
}

return models.ToNameservers(nss)
return models.ToNameserversStripTD(nss)
}

func (o *oracleProvider) GetZoneRecords(zone string, meta map[string]string) (models.Records, error) {
Expand All @@ -164,8 +194,13 @@ func (o *oracleProvider) GetZoneRecords(zone string, meta map[string]string) (mo
}

for {
waitTime = 1
retry:
getResp, err := o.client.GetZoneRecords(ctx, request)
if err != nil {
if pauseAndRetry(getResp.HTTPResponse()) {
goto retry
}
return nil, err
}

Expand Down Expand Up @@ -309,8 +344,14 @@ func (o *oracleProvider) patch(createRecords, deleteRecords models.Records, doma
batchEnd = len(ops)
}
patchReq.Items = ops[batchStart:batchEnd]
_, err := o.client.PatchZoneRecords(ctx, patchReq)

waitTime = 1
retry:
response, err := o.client.PatchZoneRecords(ctx, patchReq)
if err != nil {
if pauseAndRetry(response.HTTPResponse()) {
goto retry
}
return err
}
}
Expand Down Expand Up @@ -339,3 +380,21 @@ func convertToRecordOperation(rec *models.RecordConfig, op dns.RecordOperationOp
Operation: op,
}
}

// waitTime is the amount of time to sleep if a 429 is received.
// Must be reset before every query
var waitTime = 1

func pauseAndRetry(resp *http.Response) bool {
if resp.StatusCode == 429 {
waitTime = waitTime * 2
if waitTime > 300 {
printer.Printf("Oracle: max wait for rate-limit reached.\n")
return false
}
printer.Printf("Oracle: API rate-limit hit, pause for %v seconds.\n", waitTime)
time.Sleep(time.Duration(waitTime+1) * time.Second)
return true
}
return false
}

0 comments on commit 0de789f

Please sign in to comment.