mirror of
https://github.com/StackExchange/dnscontrol.git
synced 2024-05-11 05:55:12 +00:00
NEW PROVIDER: Gcore DNS (#1816)
This commit is contained in:
1
OWNERS
1
OWNERS
@ -15,6 +15,7 @@ providers/domainnameshop @SimenBai
|
|||||||
providers/easyname @tresni
|
providers/easyname @tresni
|
||||||
providers/exoscale @pierre-emmanuelJ
|
providers/exoscale @pierre-emmanuelJ
|
||||||
providers/gandi_v5 @TomOnTime
|
providers/gandi_v5 @TomOnTime
|
||||||
|
providers/gcore @xddxdd
|
||||||
providers/gcloud @riyadhalnur
|
providers/gcloud @riyadhalnur
|
||||||
providers/hedns @rblenkinsopp
|
providers/hedns @rblenkinsopp
|
||||||
providers/hetzner @das7pad
|
providers/hetzner @das7pad
|
||||||
|
@ -34,6 +34,7 @@ Currently supported DNS providers:
|
|||||||
- Domainnameshop (Domeneshop)
|
- Domainnameshop (Domeneshop)
|
||||||
- Exoscale
|
- Exoscale
|
||||||
- Gandi
|
- Gandi
|
||||||
|
- Gcore
|
||||||
- Google DNS
|
- Google DNS
|
||||||
- Hetzner
|
- Hetzner
|
||||||
- HEXONET
|
- HEXONET
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
<th class="rotate"><div><span>EXOSCALE</span></div></th>
|
<th class="rotate"><div><span>EXOSCALE</span></div></th>
|
||||||
<th class="rotate"><div><span>GANDI_V5</span></div></th>
|
<th class="rotate"><div><span>GANDI_V5</span></div></th>
|
||||||
<th class="rotate"><div><span>GCLOUD</span></div></th>
|
<th class="rotate"><div><span>GCLOUD</span></div></th>
|
||||||
|
<th class="rotate"><div><span>GCORE</span></div></th>
|
||||||
<th class="rotate"><div><span>HEDNS</span></div></th>
|
<th class="rotate"><div><span>HEDNS</span></div></th>
|
||||||
<th class="rotate"><div><span>HETZNER</span></div></th>
|
<th class="rotate"><div><span>HETZNER</span></div></th>
|
||||||
<th class="rotate"><div><span>HEXONET</span></div></th>
|
<th class="rotate"><div><span>HEXONET</span></div></th>
|
||||||
@ -111,6 +112,9 @@
|
|||||||
<td class="danger">
|
<td class="danger">
|
||||||
<i class="fa fa-times text-danger" aria-hidden="true"></i>
|
<i class="fa fa-times text-danger" aria-hidden="true"></i>
|
||||||
</td>
|
</td>
|
||||||
|
<td class="danger">
|
||||||
|
<i class="fa fa-times text-danger" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
<td class="danger" data-toggle="tooltip" data-container="body" data-placement="top" title="Actively maintained provider module.">
|
<td class="danger" data-toggle="tooltip" data-container="body" data-placement="top" title="Actively maintained provider module.">
|
||||||
<i class="fa has-tooltip fa-times text-danger" aria-hidden="true"></i>
|
<i class="fa has-tooltip fa-times text-danger" aria-hidden="true"></i>
|
||||||
</td>
|
</td>
|
||||||
@ -243,6 +247,9 @@
|
|||||||
<td class="success">
|
<td class="success">
|
||||||
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
</td>
|
</td>
|
||||||
|
<td class="success">
|
||||||
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
<td class="danger">
|
<td class="danger">
|
||||||
<i class="fa fa-times text-danger" aria-hidden="true"></i>
|
<i class="fa fa-times text-danger" aria-hidden="true"></i>
|
||||||
</td>
|
</td>
|
||||||
@ -363,6 +370,9 @@
|
|||||||
<td class="danger">
|
<td class="danger">
|
||||||
<i class="fa fa-times text-danger" aria-hidden="true"></i>
|
<i class="fa fa-times text-danger" aria-hidden="true"></i>
|
||||||
</td>
|
</td>
|
||||||
|
<td class="danger">
|
||||||
|
<i class="fa fa-times text-danger" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
<td class="success">
|
<td class="success">
|
||||||
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
</td>
|
</td>
|
||||||
@ -469,6 +479,9 @@
|
|||||||
<i class="fa has-tooltip fa-check text-success" aria-hidden="true"></i>
|
<i class="fa has-tooltip fa-check text-success" aria-hidden="true"></i>
|
||||||
</td>
|
</td>
|
||||||
<td><i class="fa fa-minus dim"></i></td>
|
<td><i class="fa fa-minus dim"></i></td>
|
||||||
|
<td class="danger">
|
||||||
|
<i class="fa fa-times text-danger" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
<td class="success">
|
<td class="success">
|
||||||
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
</td>
|
</td>
|
||||||
@ -560,6 +573,9 @@
|
|||||||
<td class="danger">
|
<td class="danger">
|
||||||
<i class="fa fa-times text-danger" aria-hidden="true"></i>
|
<i class="fa fa-times text-danger" aria-hidden="true"></i>
|
||||||
</td>
|
</td>
|
||||||
|
<td class="danger">
|
||||||
|
<i class="fa fa-times text-danger" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
<td><i class="fa fa-minus dim"></i></td>
|
<td><i class="fa fa-minus dim"></i></td>
|
||||||
<td><i class="fa fa-minus dim"></i></td>
|
<td><i class="fa fa-minus dim"></i></td>
|
||||||
<td class="info" data-toggle="tooltip" data-container="body" data-placement="top" title="Supported but not implemented yet.">
|
<td class="info" data-toggle="tooltip" data-container="body" data-placement="top" title="Supported but not implemented yet.">
|
||||||
@ -624,8 +640,8 @@
|
|||||||
<td class="success">
|
<td class="success">
|
||||||
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
</td>
|
</td>
|
||||||
<td class="success" data-toggle="tooltip" data-container="body" data-placement="top" title="Semicolons not supported in issue/issuewild fields.">
|
<td class="success">
|
||||||
<a href="https://www.digitalocean.com/docs/networking/dns/how-to/create-caa-records"><i class="fa has-tooltip fa-check text-success" aria-hidden="true"></i></a>
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
</td>
|
</td>
|
||||||
<td class="success">
|
<td class="success">
|
||||||
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
@ -659,6 +675,9 @@
|
|||||||
<td class="success">
|
<td class="success">
|
||||||
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
</td>
|
</td>
|
||||||
|
<td class="success">
|
||||||
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
<td><i class="fa fa-minus dim"></i></td>
|
<td><i class="fa fa-minus dim"></i></td>
|
||||||
<td class="success">
|
<td class="success">
|
||||||
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
@ -753,6 +772,9 @@
|
|||||||
<td class="success">
|
<td class="success">
|
||||||
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
</td>
|
</td>
|
||||||
|
<td class="danger">
|
||||||
|
<i class="fa fa-times text-danger" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
<td class="success">
|
<td class="success">
|
||||||
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
</td>
|
</td>
|
||||||
@ -847,6 +869,9 @@
|
|||||||
<td><i class="fa fa-minus dim"></i></td>
|
<td><i class="fa fa-minus dim"></i></td>
|
||||||
<td><i class="fa fa-minus dim"></i></td>
|
<td><i class="fa fa-minus dim"></i></td>
|
||||||
<td><i class="fa fa-minus dim"></i></td>
|
<td><i class="fa fa-minus dim"></i></td>
|
||||||
|
<td class="danger">
|
||||||
|
<i class="fa fa-times text-danger" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
<td class="success">
|
<td class="success">
|
||||||
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
</td>
|
</td>
|
||||||
@ -938,6 +963,7 @@
|
|||||||
<td><i class="fa fa-minus dim"></i></td>
|
<td><i class="fa fa-minus dim"></i></td>
|
||||||
<td><i class="fa fa-minus dim"></i></td>
|
<td><i class="fa fa-minus dim"></i></td>
|
||||||
<td><i class="fa fa-minus dim"></i></td>
|
<td><i class="fa fa-minus dim"></i></td>
|
||||||
|
<td><i class="fa fa-minus dim"></i></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th class="row-header" style="text-decoration: underline;" data-toggle="tooltip" data-container="body" data-placement="top" title="Driver has explicitly implemented SRV record management">SRV</th>
|
<th class="row-header" style="text-decoration: underline;" data-toggle="tooltip" data-container="body" data-placement="top" title="Driver has explicitly implemented SRV record management">SRV</th>
|
||||||
@ -991,6 +1017,9 @@
|
|||||||
<td class="success">
|
<td class="success">
|
||||||
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
</td>
|
</td>
|
||||||
|
<td class="success" data-toggle="tooltip" data-container="body" data-placement="top" title="G-Core doesn't support SRV records with empty targets">
|
||||||
|
<i class="fa has-tooltip fa-check text-success" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
<td class="success">
|
<td class="success">
|
||||||
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
</td>
|
</td>
|
||||||
@ -1101,6 +1130,9 @@
|
|||||||
<td class="success">
|
<td class="success">
|
||||||
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
</td>
|
</td>
|
||||||
|
<td class="danger">
|
||||||
|
<i class="fa fa-times text-danger" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
<td class="success">
|
<td class="success">
|
||||||
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
</td>
|
</td>
|
||||||
@ -1199,6 +1231,9 @@
|
|||||||
<td class="danger">
|
<td class="danger">
|
||||||
<i class="fa fa-times text-danger" aria-hidden="true"></i>
|
<i class="fa fa-times text-danger" aria-hidden="true"></i>
|
||||||
</td>
|
</td>
|
||||||
|
<td class="danger">
|
||||||
|
<i class="fa fa-times text-danger" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
<td class="success">
|
<td class="success">
|
||||||
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
</td>
|
</td>
|
||||||
@ -1286,6 +1321,7 @@
|
|||||||
<td><i class="fa fa-minus dim"></i></td>
|
<td><i class="fa fa-minus dim"></i></td>
|
||||||
<td><i class="fa fa-minus dim"></i></td>
|
<td><i class="fa fa-minus dim"></i></td>
|
||||||
<td><i class="fa fa-minus dim"></i></td>
|
<td><i class="fa fa-minus dim"></i></td>
|
||||||
|
<td><i class="fa fa-minus dim"></i></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th class="row-header" style="text-decoration: underline;" data-toggle="tooltip" data-container="body" data-placement="top" title="Provider supports Route 53 limited ALIAS">R53_ALIAS</th>
|
<th class="row-header" style="text-decoration: underline;" data-toggle="tooltip" data-container="body" data-placement="top" title="Provider supports Route 53 limited ALIAS">R53_ALIAS</th>
|
||||||
@ -1309,6 +1345,7 @@
|
|||||||
<td><i class="fa fa-minus dim"></i></td>
|
<td><i class="fa fa-minus dim"></i></td>
|
||||||
<td><i class="fa fa-minus dim"></i></td>
|
<td><i class="fa fa-minus dim"></i></td>
|
||||||
<td><i class="fa fa-minus dim"></i></td>
|
<td><i class="fa fa-minus dim"></i></td>
|
||||||
|
<td><i class="fa fa-minus dim"></i></td>
|
||||||
<td class="danger" data-toggle="tooltip" data-container="body" data-placement="top" title="Using ALIAS is possible through our extended DNS (X-DNS) service. Feel free to get in touch with us.">
|
<td class="danger" data-toggle="tooltip" data-container="body" data-placement="top" title="Using ALIAS is possible through our extended DNS (X-DNS) service. Feel free to get in touch with us.">
|
||||||
<i class="fa has-tooltip fa-times text-danger" aria-hidden="true"></i>
|
<i class="fa has-tooltip fa-times text-danger" aria-hidden="true"></i>
|
||||||
</td>
|
</td>
|
||||||
@ -1362,6 +1399,7 @@
|
|||||||
<td><i class="fa fa-minus dim"></i></td>
|
<td><i class="fa fa-minus dim"></i></td>
|
||||||
<td><i class="fa fa-minus dim"></i></td>
|
<td><i class="fa fa-minus dim"></i></td>
|
||||||
<td><i class="fa fa-minus dim"></i></td>
|
<td><i class="fa fa-minus dim"></i></td>
|
||||||
|
<td><i class="fa fa-minus dim"></i></td>
|
||||||
<td class="danger">
|
<td class="danger">
|
||||||
<i class="fa fa-times text-danger" aria-hidden="true"></i>
|
<i class="fa fa-times text-danger" aria-hidden="true"></i>
|
||||||
</td>
|
</td>
|
||||||
@ -1431,6 +1469,9 @@
|
|||||||
<td class="danger">
|
<td class="danger">
|
||||||
<i class="fa fa-times text-danger" aria-hidden="true"></i>
|
<i class="fa fa-times text-danger" aria-hidden="true"></i>
|
||||||
</td>
|
</td>
|
||||||
|
<td class="danger">
|
||||||
|
<i class="fa fa-times text-danger" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
<td><i class="fa fa-minus dim"></i></td>
|
<td><i class="fa fa-minus dim"></i></td>
|
||||||
<td class="success">
|
<td class="success">
|
||||||
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
@ -1514,6 +1555,7 @@
|
|||||||
<td><i class="fa fa-minus dim"></i></td>
|
<td><i class="fa fa-minus dim"></i></td>
|
||||||
<td><i class="fa fa-minus dim"></i></td>
|
<td><i class="fa fa-minus dim"></i></td>
|
||||||
<td><i class="fa fa-minus dim"></i></td>
|
<td><i class="fa fa-minus dim"></i></td>
|
||||||
|
<td><i class="fa fa-minus dim"></i></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th class="row-header" style="text-decoration: underline;" data-toggle="tooltip" data-container="body" data-placement="top" title="This provider is recommended for use in 'dual hosting' scenarios. Usually this means the provider allows full control over the apex NS records">dual host</th>
|
<th class="row-header" style="text-decoration: underline;" data-toggle="tooltip" data-container="body" data-placement="top" title="This provider is recommended for use in 'dual hosting' scenarios. Usually this means the provider allows full control over the apex NS records">dual host</th>
|
||||||
@ -1573,6 +1615,9 @@
|
|||||||
<td class="success">
|
<td class="success">
|
||||||
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
</td>
|
</td>
|
||||||
|
<td class="success">
|
||||||
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
<td><i class="fa fa-minus dim"></i></td>
|
<td><i class="fa fa-minus dim"></i></td>
|
||||||
<td class="success">
|
<td class="success">
|
||||||
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
@ -1689,6 +1734,9 @@
|
|||||||
<td class="success">
|
<td class="success">
|
||||||
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
</td>
|
</td>
|
||||||
|
<td class="success">
|
||||||
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
<td class="danger">
|
<td class="danger">
|
||||||
<i class="fa fa-times text-danger" aria-hidden="true"></i>
|
<i class="fa fa-times text-danger" aria-hidden="true"></i>
|
||||||
</td>
|
</td>
|
||||||
@ -1827,6 +1875,9 @@
|
|||||||
<td class="success">
|
<td class="success">
|
||||||
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
</td>
|
</td>
|
||||||
|
<td class="success">
|
||||||
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
<td class="danger">
|
<td class="danger">
|
||||||
<i class="fa fa-times text-danger" aria-hidden="true"></i>
|
<i class="fa fa-times text-danger" aria-hidden="true"></i>
|
||||||
</td>
|
</td>
|
||||||
@ -1931,6 +1982,9 @@
|
|||||||
<td class="success">
|
<td class="success">
|
||||||
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
</td>
|
</td>
|
||||||
|
<td class="success">
|
||||||
|
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||||
|
</td>
|
||||||
<td class="info">
|
<td class="info">
|
||||||
<i class="fa fa-circle-o text-info" aria-hidden="true"></i>
|
<i class="fa fa-circle-o text-info" aria-hidden="true"></i>
|
||||||
</td>
|
</td>
|
||||||
|
43
docs/_providers/gcore.md
Normal file
43
docs/_providers/gcore.md
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
---
|
||||||
|
name: Gcore
|
||||||
|
title: Gcore Provider
|
||||||
|
layout: default
|
||||||
|
jsId: GCORE
|
||||||
|
---
|
||||||
|
# Gcore Provider
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
To use this provider, add an entry to `creds.json` with `TYPE` set to `GCORE`
|
||||||
|
along with a Gcore account API token.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"gcore": {
|
||||||
|
"TYPE": "GCORE",
|
||||||
|
"api-key": "your-gcore-api-key"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Metadata
|
||||||
|
This provider does not recognize any special metadata fields unique to Gcore.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
An example `dnsconfig.js` configuration:
|
||||||
|
|
||||||
|
```js
|
||||||
|
var REG_NONE = NewRegistrar("none"); // No registrar.
|
||||||
|
var DSP_GCORE = NewDnsProvider("gcore"); // Gcore
|
||||||
|
|
||||||
|
D("example.tld", REG_NONE, DnsProvider(DSP_GCORE),
|
||||||
|
A("test", "1.2.3.4")
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
## Activation
|
||||||
|
|
||||||
|
DNSControl depends on a Gcore account API token.
|
||||||
|
|
||||||
|
You can obtain your API token on this page: <https://accounts.gcore.com/profile/api-tokens>
|
@ -85,6 +85,7 @@ Providers in this category and their maintainers are:
|
|||||||
* `EASYNAME` @tresni
|
* `EASYNAME` @tresni
|
||||||
* `EXOSCALE` @pierre-emmanuelJ
|
* `EXOSCALE` @pierre-emmanuelJ
|
||||||
* `GANDI_V5` @TomOnTime
|
* `GANDI_V5` @TomOnTime
|
||||||
|
* `GCORE` @xddxdd
|
||||||
* `HEDNS` @rblenkinsopp
|
* `HEDNS` @rblenkinsopp
|
||||||
* `HETZNER` @das7pad
|
* `HETZNER` @das7pad
|
||||||
* `HEXONET` @papakai
|
* `HEXONET` @papakai
|
||||||
|
2
go.mod
2
go.mod
@ -60,6 +60,7 @@ require (
|
|||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/G-Core/gcore-dns-sdk-go v0.2.3
|
||||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
|
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
|
||||||
github.com/mattn/go-isatty v0.0.16
|
github.com/mattn/go-isatty v0.0.16
|
||||||
github.com/vultr/govultr/v2 v2.17.2
|
github.com/vultr/govultr/v2 v2.17.2
|
||||||
@ -152,6 +153,7 @@ require (
|
|||||||
go.uber.org/atomic v1.9.0 // indirect
|
go.uber.org/atomic v1.9.0 // indirect
|
||||||
golang.org/x/crypto v0.1.0 // indirect
|
golang.org/x/crypto v0.1.0 // indirect
|
||||||
golang.org/x/mod v0.6.0 // indirect
|
golang.org/x/mod v0.6.0 // indirect
|
||||||
|
golang.org/x/sync v0.1.0 // indirect
|
||||||
golang.org/x/sys v0.1.0 // indirect
|
golang.org/x/sys v0.1.0 // indirect
|
||||||
golang.org/x/text v0.4.0 // indirect
|
golang.org/x/text v0.4.0 // indirect
|
||||||
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af // indirect
|
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af // indirect
|
||||||
|
3
go.sum
3
go.sum
@ -19,6 +19,8 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03
|
|||||||
github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
|
github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
|
||||||
github.com/DisposaBoy/JsonConfigReader v0.0.0-20201129172854-99cf318d67e7 h1:AJKJCKcb/psppPl/9CUiQQnTG+Bce0/cIweD5w5Q7aQ=
|
github.com/DisposaBoy/JsonConfigReader v0.0.0-20201129172854-99cf318d67e7 h1:AJKJCKcb/psppPl/9CUiQQnTG+Bce0/cIweD5w5Q7aQ=
|
||||||
github.com/DisposaBoy/JsonConfigReader v0.0.0-20201129172854-99cf318d67e7/go.mod h1:GCzqZQHydohgVLSIqRKZeTt8IGb1Y4NaFfim3H40uUI=
|
github.com/DisposaBoy/JsonConfigReader v0.0.0-20201129172854-99cf318d67e7/go.mod h1:GCzqZQHydohgVLSIqRKZeTt8IGb1Y4NaFfim3H40uUI=
|
||||||
|
github.com/G-Core/gcore-dns-sdk-go v0.2.3 h1:WODi+qWlZyF7E7SH8rq/DCACa/Zhsuhu1h0DuFJc2Yg=
|
||||||
|
github.com/G-Core/gcore-dns-sdk-go v0.2.3/go.mod h1:TM+VaDvBPObF+x085lS3i0kc2OPAkuW2c4Leg7Pe6jI=
|
||||||
github.com/PuerkitoBio/goquery v1.8.0 h1:PJTF7AmFCFKk1N6V6jmKfrNH9tV5pNE6lZMkG0gta/U=
|
github.com/PuerkitoBio/goquery v1.8.0 h1:PJTF7AmFCFKk1N6V6jmKfrNH9tV5pNE6lZMkG0gta/U=
|
||||||
github.com/PuerkitoBio/goquery v1.8.0/go.mod h1:ypIiRMtY7COPGk+I/YbZLbxsxn9g5ejnI2HSMtkjZvI=
|
github.com/PuerkitoBio/goquery v1.8.0/go.mod h1:ypIiRMtY7COPGk+I/YbZLbxsxn9g5ejnI2HSMtkjZvI=
|
||||||
github.com/TomOnTime/utfutil v0.0.0-20210710122150-437f72b26edf h1:+GdVyvpzTy3UFAS1+hbTqm9Mk0U1Xrocm28s/E2GWz0=
|
github.com/TomOnTime/utfutil v0.0.0-20210710122150-437f72b26edf h1:+GdVyvpzTy3UFAS1+hbTqm9Mk0U1Xrocm28s/E2GWz0=
|
||||||
@ -573,6 +575,7 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ
|
|||||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
|
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
|
||||||
|
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
@ -94,6 +94,10 @@
|
|||||||
"project_id": "$GCLOUD_PROJECT",
|
"project_id": "$GCLOUD_PROJECT",
|
||||||
"type": "$GCLOUD_TYPE"
|
"type": "$GCLOUD_TYPE"
|
||||||
},
|
},
|
||||||
|
"GCORE": {
|
||||||
|
"api-key": "$GCORE_API_KEY",
|
||||||
|
"domain": "$GCORE_DOMAIN"
|
||||||
|
},
|
||||||
"HEDNS": {
|
"HEDNS": {
|
||||||
"domain": "$HEDNS_DOMAIN",
|
"domain": "$HEDNS_DOMAIN",
|
||||||
"password": "$HEDNS_PASSWORD",
|
"password": "$HEDNS_PASSWORD",
|
||||||
|
@ -21,6 +21,7 @@ import (
|
|||||||
_ "github.com/StackExchange/dnscontrol/v3/providers/exoscale"
|
_ "github.com/StackExchange/dnscontrol/v3/providers/exoscale"
|
||||||
_ "github.com/StackExchange/dnscontrol/v3/providers/gandiv5"
|
_ "github.com/StackExchange/dnscontrol/v3/providers/gandiv5"
|
||||||
_ "github.com/StackExchange/dnscontrol/v3/providers/gcloud"
|
_ "github.com/StackExchange/dnscontrol/v3/providers/gcloud"
|
||||||
|
_ "github.com/StackExchange/dnscontrol/v3/providers/gcore"
|
||||||
_ "github.com/StackExchange/dnscontrol/v3/providers/hedns"
|
_ "github.com/StackExchange/dnscontrol/v3/providers/hedns"
|
||||||
_ "github.com/StackExchange/dnscontrol/v3/providers/hetzner"
|
_ "github.com/StackExchange/dnscontrol/v3/providers/hetzner"
|
||||||
_ "github.com/StackExchange/dnscontrol/v3/providers/hexonet"
|
_ "github.com/StackExchange/dnscontrol/v3/providers/hexonet"
|
||||||
|
15
providers/gcore/auditrecords.go
Normal file
15
providers/gcore/auditrecords.go
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package gcore
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/StackExchange/dnscontrol/v3/models"
|
||||||
|
"github.com/StackExchange/dnscontrol/v3/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 {
|
||||||
|
a := rejectif.Auditor{}
|
||||||
|
a.Add("SRV", rejectif.SrvHasNullTarget)
|
||||||
|
return a.Audit(records)
|
||||||
|
}
|
107
providers/gcore/convert.go
Normal file
107
providers/gcore/convert.go
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
package gcore
|
||||||
|
|
||||||
|
// Convert the provider's native record description to models.RecordConfig.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
dnssdk "github.com/G-Core/gcore-dns-sdk-go"
|
||||||
|
"github.com/StackExchange/dnscontrol/v3/models"
|
||||||
|
"github.com/StackExchange/dnscontrol/v3/pkg/printer"
|
||||||
|
)
|
||||||
|
|
||||||
|
// nativeToRecord takes a DNS record from G-Core and returns a native RecordConfig struct.
|
||||||
|
func nativeToRecords(n dnssdk.RRSet, zoneName string, recName string, recType string) ([]*models.RecordConfig, error) {
|
||||||
|
var rcs []*models.RecordConfig
|
||||||
|
|
||||||
|
// Split G-Core's RRset into individual records
|
||||||
|
for _, value := range n.Records {
|
||||||
|
rc := &models.RecordConfig{
|
||||||
|
TTL: uint32(n.TTL),
|
||||||
|
Original: n,
|
||||||
|
}
|
||||||
|
rc.SetLabelFromFQDN(recName, zoneName)
|
||||||
|
switch recType {
|
||||||
|
case "CAA": // G-Core API don't need quotes around CAA with whitespace
|
||||||
|
if len(value.Content) != 3 {
|
||||||
|
return nil, errors.New("incorrect number of fields in G-Core's CAA record")
|
||||||
|
}
|
||||||
|
|
||||||
|
parts := make([]string, len(value.Content))
|
||||||
|
for i := range value.Content {
|
||||||
|
parts[i] = fmt.Sprint(value.Content[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
flag, tag, target := parts[0], parts[1], parts[2]
|
||||||
|
if err := rc.SetTargetCAAStrings(flag, tag, target); err != nil {
|
||||||
|
return nil, fmt.Errorf("unparsable record received from G-Core: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
default: // "A", "AAAA", "CAA", "NS", "CNAME", "MX", "PTR", "SRV", "TXT"
|
||||||
|
if err := rc.PopulateFromString(recType, value.ContentToString(), zoneName); err != nil {
|
||||||
|
return nil, fmt.Errorf("unparsable record received from G-Core: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rcs = append(rcs, rc)
|
||||||
|
}
|
||||||
|
|
||||||
|
return rcs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func recordsToNative(rcs []*models.RecordConfig, expectedKey models.RecordKey) *dnssdk.RRSet {
|
||||||
|
// Merge DNSControl records into G-Core RRsets
|
||||||
|
|
||||||
|
var result *dnssdk.RRSet
|
||||||
|
|
||||||
|
for _, r := range rcs {
|
||||||
|
label := r.GetLabel()
|
||||||
|
if label == "@" {
|
||||||
|
label = ""
|
||||||
|
}
|
||||||
|
key := r.Key()
|
||||||
|
|
||||||
|
if key != expectedKey {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
var rr dnssdk.ResourceRecord
|
||||||
|
switch key.Type {
|
||||||
|
case "CAA": // G-Core API don't need quotes around CAA with whitespace
|
||||||
|
rr = dnssdk.ResourceRecord{
|
||||||
|
Content: []interface{}{
|
||||||
|
int64(r.CaaFlag),
|
||||||
|
r.CaaTag,
|
||||||
|
r.GetTargetField(),
|
||||||
|
},
|
||||||
|
Meta: nil,
|
||||||
|
Enabled: true,
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
rr = dnssdk.ResourceRecord{
|
||||||
|
Content: dnssdk.ContentFromValue(key.Type, r.GetTargetCombined()),
|
||||||
|
Meta: nil,
|
||||||
|
Enabled: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if result == nil {
|
||||||
|
result = &dnssdk.RRSet{
|
||||||
|
TTL: int(r.TTL),
|
||||||
|
Filters: nil,
|
||||||
|
Records: []dnssdk.ResourceRecord{rr},
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result.Records = append(result.Records, rr)
|
||||||
|
|
||||||
|
if int(r.TTL) != result.TTL {
|
||||||
|
printer.Warnf("All TTLs for a rrset (%v) must be the same. Using smaller of %v and %v.\n", key, r.TTL, result.TTL)
|
||||||
|
if int(r.TTL) < result.TTL {
|
||||||
|
result.TTL = int(r.TTL)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
236
providers/gcore/gcoreProvider.go
Normal file
236
providers/gcore/gcoreProvider.go
Normal file
@ -0,0 +1,236 @@
|
|||||||
|
package gcore
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/StackExchange/dnscontrol/v3/models"
|
||||||
|
"github.com/StackExchange/dnscontrol/v3/pkg/diff"
|
||||||
|
"github.com/StackExchange/dnscontrol/v3/providers"
|
||||||
|
|
||||||
|
dnssdk "github.com/G-Core/gcore-dns-sdk-go"
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
G-Core API DNS provider:
|
||||||
|
Info required in `creds.json`:
|
||||||
|
- api-key
|
||||||
|
*/
|
||||||
|
|
||||||
|
type gcoreProvider struct {
|
||||||
|
provider *dnssdk.Client
|
||||||
|
ctx context.Context
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewGCore creates the provider.
|
||||||
|
func NewGCore(m map[string]string, metadata json.RawMessage) (providers.DNSServiceProvider, error) {
|
||||||
|
if m["api-key"] == "" {
|
||||||
|
return nil, fmt.Errorf("missing G-Core API key")
|
||||||
|
}
|
||||||
|
|
||||||
|
c := &gcoreProvider{
|
||||||
|
provider: dnssdk.NewClient(dnssdk.PermanentAPIKeyAuth(m["api-key"])),
|
||||||
|
ctx: context.TODO(),
|
||||||
|
}
|
||||||
|
|
||||||
|
return c, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var features = providers.DocumentationNotes{
|
||||||
|
providers.CanAutoDNSSEC: providers.Cannot(),
|
||||||
|
providers.CanGetZones: providers.Can(),
|
||||||
|
providers.CanUseAlias: providers.Cannot(),
|
||||||
|
providers.CanUseCAA: providers.Can(),
|
||||||
|
providers.CanUseDS: providers.Cannot(),
|
||||||
|
providers.CanUseNAPTR: providers.Cannot(),
|
||||||
|
providers.CanUsePTR: providers.Cannot(),
|
||||||
|
providers.CanUseSRV: providers.Can("G-Core doesn't support SRV records with empty targets"),
|
||||||
|
providers.CanUseSSHFP: providers.Cannot(),
|
||||||
|
providers.CanUseTLSA: providers.Cannot(),
|
||||||
|
providers.DocCreateDomains: providers.Can(),
|
||||||
|
providers.DocDualHost: providers.Can(),
|
||||||
|
providers.DocOfficiallySupported: providers.Cannot(),
|
||||||
|
}
|
||||||
|
|
||||||
|
var defaultNameServerNames = []string{
|
||||||
|
"ns1.gcorelabs.net",
|
||||||
|
"ns2.gcdn.services",
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
fns := providers.DspFuncs{
|
||||||
|
Initializer: NewGCore,
|
||||||
|
RecordAuditor: AuditRecords,
|
||||||
|
}
|
||||||
|
providers.RegisterDomainServiceProviderType("GCORE", fns, features)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetNameservers returns the nameservers for a domain.
|
||||||
|
func (c *gcoreProvider) GetNameservers(domain string) ([]*models.Nameserver, error) {
|
||||||
|
return models.ToNameservers(defaultNameServerNames)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *gcoreProvider) GetDomainCorrections(dc *models.DomainConfig) ([]*models.Correction, error) {
|
||||||
|
existing, err := c.GetZoneRecords(dc.Name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
models.PostProcessRecords(existing)
|
||||||
|
clean := PrepFoundRecords(existing)
|
||||||
|
PrepDesiredRecords(dc)
|
||||||
|
return c.GenerateDomainCorrections(dc, clean)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetZoneRecords gets the records of a zone and returns them in RecordConfig format.
|
||||||
|
func (c *gcoreProvider) GetZoneRecords(domain string) (models.Records, error) {
|
||||||
|
zone, err := c.provider.Zone(c.ctx, domain)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert RRsets to DNSControl format on the fly
|
||||||
|
existingRecords := []*models.RecordConfig{}
|
||||||
|
|
||||||
|
// We cannot directly use Zone's ShortAnswers
|
||||||
|
// they aren't complete for CAA & SRV
|
||||||
|
for _, rec := range zone.Records {
|
||||||
|
rrset, err := c.provider.RRSet(c.ctx, zone.Name, rec.Name, rec.Type)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
nativeRecords, err := nativeToRecords(rrset, zone.Name, rec.Name, rec.Type)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
existingRecords = append(existingRecords, nativeRecords...)
|
||||||
|
}
|
||||||
|
|
||||||
|
return existingRecords, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// EnsureDomainExists returns an error if domain doesn't exist.
|
||||||
|
func (c *gcoreProvider) EnsureDomainExists(domain string) error {
|
||||||
|
zones, err := c.provider.Zones(c.ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, zone := range zones {
|
||||||
|
if zone.Name == domain {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = c.provider.CreateZone(c.ctx, domain)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// PrepFoundRecords munges any records to make them compatible with
|
||||||
|
// this provider. Usually this is a no-op.
|
||||||
|
func PrepFoundRecords(recs models.Records) models.Records {
|
||||||
|
// If there are records that need to be modified, removed, etc. we
|
||||||
|
// do it here. Usually this is a no-op.
|
||||||
|
return recs
|
||||||
|
}
|
||||||
|
|
||||||
|
// PrepDesiredRecords munges any records to best suit this provider.
|
||||||
|
func PrepDesiredRecords(dc *models.DomainConfig) {
|
||||||
|
dc.Punycode()
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateChangeMsg(updates []string) string {
|
||||||
|
return strings.Join(updates, "\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
// GenerateDomainCorrections takes the desired and existing records
|
||||||
|
// and produces a Correction list. The correction list is simply
|
||||||
|
// a list of functions to call to actually make the desired
|
||||||
|
// correction, and a message to output to the user when the change is
|
||||||
|
// made.
|
||||||
|
func (c *gcoreProvider) GenerateDomainCorrections(dc *models.DomainConfig, existing models.Records) ([]*models.Correction, error) {
|
||||||
|
|
||||||
|
var corrections = []*models.Correction{}
|
||||||
|
|
||||||
|
// diff existing vs. current.
|
||||||
|
differ := diff.New(dc)
|
||||||
|
keysToUpdate, err := differ.ChangedGroups(existing)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(keysToUpdate) == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
desiredRecords := dc.Records.GroupedByKey()
|
||||||
|
existingRecords := existing.GroupedByKey()
|
||||||
|
|
||||||
|
// First pass: delete records to avoid coexisting of conflicting types
|
||||||
|
for label := range keysToUpdate {
|
||||||
|
if _, ok := desiredRecords[label]; !ok {
|
||||||
|
// record deleted in update
|
||||||
|
// Copy all params to avoid overwrites
|
||||||
|
zone := dc.Name
|
||||||
|
name := label.NameFQDN
|
||||||
|
typ := label.Type
|
||||||
|
msg := generateChangeMsg(keysToUpdate[label])
|
||||||
|
corrections = append(corrections, &models.Correction{
|
||||||
|
Msg: msg,
|
||||||
|
F: func() error {
|
||||||
|
return c.provider.DeleteRRSet(c.ctx, zone, name, typ)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Second pass: create and update records
|
||||||
|
for label := range keysToUpdate {
|
||||||
|
if _, ok := desiredRecords[label]; !ok {
|
||||||
|
// record deleted in update
|
||||||
|
// do nothing here
|
||||||
|
|
||||||
|
} else if _, ok := existingRecords[label]; !ok {
|
||||||
|
// record created in update
|
||||||
|
record := recordsToNative(desiredRecords[label], label)
|
||||||
|
if record == nil {
|
||||||
|
panic("No records matching label")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy all params to avoid overwrites
|
||||||
|
zone := dc.Name
|
||||||
|
name := label.NameFQDN
|
||||||
|
typ := label.Type
|
||||||
|
rec := *record
|
||||||
|
msg := generateChangeMsg(keysToUpdate[label])
|
||||||
|
corrections = append(corrections, &models.Correction{
|
||||||
|
Msg: msg,
|
||||||
|
F: func() error {
|
||||||
|
return c.provider.CreateRRSet(c.ctx, zone, name, typ, rec)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// record modified in update
|
||||||
|
record := recordsToNative(desiredRecords[label], label)
|
||||||
|
if record == nil {
|
||||||
|
panic("No records matching label")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy all params to avoid overwrites
|
||||||
|
zone := dc.Name
|
||||||
|
name := label.NameFQDN
|
||||||
|
typ := label.Type
|
||||||
|
rec := *record
|
||||||
|
msg := generateChangeMsg(keysToUpdate[label])
|
||||||
|
corrections = append(corrections, &models.Correction{
|
||||||
|
Msg: msg,
|
||||||
|
F: func() error {
|
||||||
|
return c.provider.UpdateRRSet(c.ctx, zone, name, typ, rec)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return corrections, nil
|
||||||
|
}
|
Reference in New Issue
Block a user