mirror of
https://github.com/StackExchange/dnscontrol.git
synced 2025-12-09 13:46:07 +08:00
Merge branch 'main' into branch_allrecs
This commit is contained in:
commit
8c140c0b3b
16 changed files with 409 additions and 37 deletions
5
.github/workflows/pr_integration_tests.yml
vendored
5
.github/workflows/pr_integration_tests.yml
vendored
|
|
@ -52,7 +52,7 @@ jobs:
|
|||
Write-Host "Integration test providers: $Providers"
|
||||
echo "integration_test_providers=$(ConvertTo-Json -InputObject $Providers -Compress)" >> $env:GITHUB_OUTPUT
|
||||
env:
|
||||
PROVIDERS: "['AXFRDDNS', 'AXFRDDNS_DNSSEC', 'AZURE_DNS','BIND','BUNNY_DNS','CLOUDFLAREAPI','CLOUDNS','CNR','DIGITALOCEAN','FORTIGATE','GANDI_V5','GCLOUD','HEDNS','HEXONET','HUAWEICLOUD','INWX','JOKER','MYTHICBEASTS', 'NAMEDOTCOM','NS1','POWERDNS','ROUTE53','SAKURACLOUD','TRANSIP']"
|
||||
PROVIDERS: "['AXFRDDNS', 'AXFRDDNS_DNSSEC', 'AZURE_DNS','BIND','BUNNY_DNS','CLOUDFLAREAPI','CLOUDNS','CNR','DIGITALOCEAN','FORTIGATE','GANDI_V5','GCLOUD','HEDNS','HETZNER_V2','HEXONET','HUAWEICLOUD','INWX','JOKER','MYTHICBEASTS', 'NAMEDOTCOM','NS1','POWERDNS','ROUTE53','SAKURACLOUD','TRANSIP']"
|
||||
ENV_CONTEXT: ${{ toJson(env) }}
|
||||
VARS_CONTEXT: ${{ toJson(vars) }}
|
||||
SECRETS_CONTEXT: ${{ toJson(secrets) }}
|
||||
|
|
@ -87,6 +87,7 @@ jobs:
|
|||
GANDI_V5_DOMAIN: ${{ vars.GANDI_V5_DOMAIN }}
|
||||
GCLOUD_DOMAIN: ${{ vars.GCLOUD_DOMAIN }}
|
||||
HEDNS_DOMAIN: ${{ vars.HEDNS_DOMAIN }}
|
||||
HETZNER_V2_DOMAIN: ${{ vars.HETZNER_V2_DOMAIN }}
|
||||
HEXONET_DOMAIN: ${{ vars.HEXONET_DOMAIN }}
|
||||
HUAWEICLOUD_DOMAIN: ${{ vars.HUAWEICLOUD_DOMAIN }}
|
||||
JOKER_DOMAIN: ${{ vars.JOKER_DOMAIN }}
|
||||
|
|
@ -154,6 +155,8 @@ jobs:
|
|||
HEDNS_TOTP_SECRET: ${{ secrets.HEDNS_TOTP_SECRET }}
|
||||
HEDNS_USERNAME: ${{ secrets.HEDNS_USERNAME }}
|
||||
#
|
||||
HETZNER_V2_API_TOKEN: ${{ secrets.HETZNER_V2_API_TOKEN }}
|
||||
#
|
||||
HEXONET_ENTITY: ${{ secrets.HEXONET_ENTITY }}
|
||||
HEXONET_PW: ${{ secrets.HEXONET_PW }}
|
||||
HEXONET_UID: ${{ secrets.HEXONET_UID }}
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ changelog:
|
|||
regexp: "(?i)^.*(major|new provider|feature)[(\\w)]*:+.*$"
|
||||
order: 1
|
||||
- title: 'Provider-specific changes:'
|
||||
regexp: "(?i)((adguardhome|akamaiedge|autodns|axfrd|azure|azure_private_dns|bind|bunnydns|cloudflare|cloudflareapi_old|cloudns|cnr|cscglobal|desec|digitalocean|dnsimple|dnsmadeeasy|doh|domainnameshop|dynadot|easyname|exoscale|fortigate|gandi|gcloud|gcore|hedns|hetzner|hexonet|hostingde|huaweicloud|inwx|joker|linode|loopia|luadns|mythicbeasts|namecheap|namedotcom|netcup|netlify|ns1|opensrs|oracle|ovh|packetframe|porkbun|powerdns|realtimeregister|route53|rwth|sakuracloud|softlayer|transip|vultr).*:)+.*"
|
||||
regexp: "(?i)((adguardhome|akamaiedge|autodns|axfrd|azure|azure_private_dns|bind|bunnydns|cloudflare|cloudflareapi_old|cloudns|cnr|cscglobal|desec|digitalocean|dnsimple|dnsmadeeasy|doh|domainnameshop|dynadot|easyname|exoscale|fortigate|gandi|gcloud|gcore|hedns|hetzner|hetznerv2|hexonet|hostingde|huaweicloud|inwx|joker|linode|loopia|luadns|mythicbeasts|namecheap|namedotcom|netcup|netlify|ns1|opensrs|oracle|ovh|packetframe|porkbun|powerdns|realtimeregister|route53|rwth|sakuracloud|softlayer|transip|vultr).*:)+.*"
|
||||
order: 2
|
||||
- title: 'Documentation:'
|
||||
regexp: "(?i)^.*(docs)[(\\w)]*:+.*$"
|
||||
|
|
|
|||
1
OWNERS
1
OWNERS
|
|
@ -25,6 +25,7 @@ providers/gcloud @riyadhalnur
|
|||
providers/gcore @xddxdd
|
||||
providers/hedns @rblenkinsopp
|
||||
providers/hetzner @das7pad
|
||||
providers/hetznerv2 @das7pad
|
||||
providers/hexonet @KaiSchwarz-cnic
|
||||
providers/hostingde @juliusrickert
|
||||
providers/huaweicloud @huihuimoe
|
||||
|
|
|
|||
|
|
@ -137,7 +137,8 @@
|
|||
* [Gandi_v5](provider/gandi_v5.md)
|
||||
* [Gcore](provider/gcore.md)
|
||||
* [Google Cloud DNS](provider/gcloud.md)
|
||||
* [Hetzner DNS Console](provider/hetzner.md)
|
||||
* [Hetzner DNS API](provider/hetzner_v2.md)
|
||||
* [Hetzner DNS Console (legacy)](provider/hetzner.md)
|
||||
* [HEXONET](provider/hexonet.md)
|
||||
* [hosting.de](provider/hostingde.md)
|
||||
* [Huawei Cloud DNS](provider/huaweicloud.md)
|
||||
|
|
|
|||
54
documentation/provider/hetzner_v2.md
Normal file
54
documentation/provider/hetzner_v2.md
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
## Configuration
|
||||
|
||||
To use this provider, add an entry to `creds.json` with `TYPE` set to `HETZNER_V2`
|
||||
along with a [Hetzner API Token](https://docs.hetzner.cloud/reference/cloud#getting-started).
|
||||
|
||||
Example:
|
||||
|
||||
{% code title="creds.json" %}
|
||||
```json
|
||||
{
|
||||
"hetzner_v2": {
|
||||
"TYPE": "HETZNER_V2",
|
||||
"api_token": "your-api-token"
|
||||
}
|
||||
}
|
||||
```
|
||||
{% endcode %}
|
||||
|
||||
## Metadata
|
||||
|
||||
This provider does not recognize any special metadata fields unique to Hetzner DNS API.
|
||||
|
||||
## Usage
|
||||
|
||||
An example configuration:
|
||||
|
||||
{% code title="dnsconfig.js" %}
|
||||
```javascript
|
||||
var REG_NONE = NewRegistrar("none");
|
||||
var DSP_HETZNER = NewDnsProvider("hetzner_v2");
|
||||
|
||||
D("example.com", REG_NONE, DnsProvider(DSP_HETZNER),
|
||||
A("test", "1.2.3.4"),
|
||||
);
|
||||
```
|
||||
{% endcode %}
|
||||
|
||||
## Activation
|
||||
|
||||
Create a new API Key in the
|
||||
[Hetzner Console](https://docs.hetzner.cloud/reference/cloud#getting-started).
|
||||
|
||||
## Caveats
|
||||
|
||||
### NS
|
||||
|
||||
Removing the Hetzner provided NS records at the root is not possible.
|
||||
|
||||
### SOA
|
||||
|
||||
Hetzner DNS API does not allow changing the SOA record via their API.
|
||||
There is an alternative method using an import of a full BIND file, but this
|
||||
approach does not play nice with incremental changes or ignored records.
|
||||
At this time you cannot update SOA records via DNSControl.
|
||||
|
|
@ -52,6 +52,7 @@ Jump to a table:
|
|||
| [`GCORE`](gcore.md) | ❌ | ✅ | ❌ |
|
||||
| [`HEDNS`](hedns.md) | ❌ | ✅ | ❌ |
|
||||
| [`HETZNER`](hetzner.md) | ❌ | ✅ | ❌ |
|
||||
| [`HETZNER_V2`](hetzner_v2.md) | ❌ | ✅ | ❌ |
|
||||
| [`HEXONET`](hexonet.md) | ❌ | ✅ | ✅ |
|
||||
| [`HOSTINGDE`](hostingde.md) | ❌ | ✅ | ✅ |
|
||||
| [`HUAWEICLOUD`](huaweicloud.md) | ❌ | ✅ | ❌ |
|
||||
|
|
@ -112,6 +113,7 @@ Jump to a table:
|
|||
| [`GCORE`](gcore.md) | ✅ | ✅ | ✅ | ✅ |
|
||||
| [`HEDNS`](hedns.md) | ❔ | ✅ | ✅ | ✅ |
|
||||
| [`HETZNER`](hetzner.md) | ✅ | ✅ | ✅ | ✅ |
|
||||
| [`HETZNER_V2`](hetzner_v2.md) | ✅ | ✅ | ✅ | ✅ |
|
||||
| [`HEXONET`](hexonet.md) | ❔ | ✅ | ✅ | ❔ |
|
||||
| [`HOSTINGDE`](hostingde.md) | ❔ | ✅ | ✅ | ✅ |
|
||||
| [`HUAWEICLOUD`](huaweicloud.md) | ❔ | ✅ | ✅ | ✅ |
|
||||
|
|
@ -169,6 +171,7 @@ Jump to a table:
|
|||
| [`GCORE`](gcore.md) | ✅ | ❔ | ❌ | ✅ | ❔ |
|
||||
| [`HEDNS`](hedns.md) | ✅ | ❔ | ✅ | ✅ | ❌ |
|
||||
| [`HETZNER`](hetzner.md) | ❌ | ❔ | ❌ | ❌ | ❌ |
|
||||
| [`HETZNER_V2`](hetzner_v2.md) | ❌ | ❔ | ❌ | ✅ | ❌ |
|
||||
| [`HEXONET`](hexonet.md) | ❌ | ❔ | ❔ | ✅ | ❔ |
|
||||
| [`HOSTINGDE`](hostingde.md) | ✅ | ❔ | ❌ | ✅ | ✅ |
|
||||
| [`HUAWEICLOUD`](huaweicloud.md) | ❌ | ❔ | ❌ | ❌ | ❌ |
|
||||
|
|
@ -223,6 +226,7 @@ Jump to a table:
|
|||
| [`GCORE`](gcore.md) | ❔ | ❌ | ✅ | ✅ |
|
||||
| [`HEDNS`](hedns.md) | ❔ | ✅ | ✅ | ✅ |
|
||||
| [`HETZNER`](hetzner.md) | ❔ | ❌ | ✅ | ❔ |
|
||||
| [`HETZNER_V2`](hetzner_v2.md) | ❔ | ❌ | ✅ | ✅ |
|
||||
| [`HEXONET`](hexonet.md) | ❔ | ❔ | ✅ | ❔ |
|
||||
| [`HOSTINGDE`](hostingde.md) | ❔ | ❌ | ✅ | ❔ |
|
||||
| [`HUAWEICLOUD`](huaweicloud.md) | ❔ | ❌ | ✅ | ❌ |
|
||||
|
|
@ -276,6 +280,7 @@ Jump to a table:
|
|||
| [`GCORE`](gcore.md) | ✅ | ✅ | ❔ | ❌ | ❌ |
|
||||
| [`HEDNS`](hedns.md) | ✅ | ✅ | ❔ | ✅ | ❌ |
|
||||
| [`HETZNER`](hetzner.md) | ✅ | ❔ | ❔ | ❌ | ✅ |
|
||||
| [`HETZNER_V2`](hetzner_v2.md) | ✅ | ✅ | ❔ | ❌ | ✅ |
|
||||
| [`HEXONET`](hexonet.md) | ✅ | ❔ | ❔ | ❔ | ✅ |
|
||||
| [`HOSTINGDE`](hostingde.md) | ✅ | ❔ | ❔ | ✅ | ✅ |
|
||||
| [`HUAWEICLOUD`](huaweicloud.md) | ✅ | ❌ | ❔ | ❌ | ❌ |
|
||||
|
|
@ -320,6 +325,7 @@ Jump to a table:
|
|||
| [`GCORE`](gcore.md) | ✅ | ❔ | ❌ |
|
||||
| [`HEDNS`](hedns.md) | ❌ | ❔ | ❌ |
|
||||
| [`HETZNER`](hetzner.md) | ❌ | ❔ | ✅ |
|
||||
| [`HETZNER_V2`](hetzner_v2.md) | ❌ | ❔ | ✅ |
|
||||
| [`HOSTINGDE`](hostingde.md) | ✅ | ❔ | ✅ |
|
||||
| [`HUAWEICLOUD`](huaweicloud.md) | ❔ | ❔ | ❌ |
|
||||
| [`INWX`](inwx.md) | ✅ | ❔ | ❔ |
|
||||
|
|
|
|||
11
go.mod
11
go.mod
|
|
@ -38,7 +38,7 @@ require (
|
|||
github.com/miekg/dns v1.1.68
|
||||
github.com/mittwald/go-powerdns v0.6.7
|
||||
github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04
|
||||
github.com/nrdcg/goinwx v0.11.0
|
||||
github.com/nrdcg/goinwx v0.12.0
|
||||
github.com/ovh/go-ovh v1.9.0
|
||||
github.com/philhug/opensrs-go v0.0.0-20171126225031-9dfa7433020d
|
||||
github.com/pkg/errors v0.9.1
|
||||
|
|
@ -66,6 +66,7 @@ require (
|
|||
github.com/fbiville/markdown-table-formatter v0.3.0
|
||||
github.com/google/go-cmp v0.7.0
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
|
||||
github.com/hetznercloud/hcloud-go/v2 v2.30.0
|
||||
github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.174
|
||||
github.com/kylelemons/godebug v1.1.0
|
||||
github.com/luadns/luadns-go v0.3.0
|
||||
|
|
@ -97,8 +98,10 @@ require (
|
|||
github.com/aws/aws-sdk-go-v2/service/sso v1.30.1 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.5 // indirect
|
||||
github.com/aws/smithy-go v1.23.2 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/bits-and-blooms/bitset v1.24.0 // indirect
|
||||
github.com/boombuler/barcode v1.0.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/deepmap/oapi-codegen v1.9.1 // indirect
|
||||
|
|
@ -126,10 +129,15 @@ require (
|
|||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
|
||||
github.com/peterhellberg/link v1.2.0 // indirect
|
||||
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
github.com/prometheus/client_golang v1.23.2 // indirect
|
||||
github.com/prometheus/client_model v0.6.2 // indirect
|
||||
github.com/prometheus/common v0.66.1 // indirect
|
||||
github.com/prometheus/procfs v0.16.1 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/sergi/go-diff v1.2.0 // indirect
|
||||
github.com/shopspring/decimal v1.4.0 // indirect
|
||||
|
|
@ -147,6 +155,7 @@ require (
|
|||
go.opentelemetry.io/otel v1.37.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.37.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.37.0 // indirect
|
||||
go.yaml.in/yaml/v2 v2.4.2 // indirect
|
||||
golang.org/x/mod v0.29.0 // indirect
|
||||
golang.org/x/sync v0.18.0 // indirect
|
||||
golang.org/x/sys v0.38.0 // indirect
|
||||
|
|
|
|||
26
go.sum
26
go.sum
|
|
@ -78,6 +78,8 @@ github.com/aws/smithy-go v1.23.2 h1:Crv0eatJUQhaManss33hS5r40CG3ZFH+21XSkqMrIUM=
|
|||
github.com/aws/smithy-go v1.23.2/go.mod h1:LEj2LM3rBRQJxPZTB4KuzZkaZYnZPnvgIhb4pu07mx0=
|
||||
github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6 h1:4NNbNM2Iq/k57qEu7WfL67UrbPq1uFWxW4qODCohi+0=
|
||||
github.com/babolivier/go-doh-client v0.0.0-20201028162107-a76cff4cb8b6/go.mod h1:J29hk+f9lJrblVIfiJOtTFk+OblBawmib4uz/VdKzlg=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/billputer/go-namecheap v0.0.0-20210108011502-994a912fb7f9 h1:2vQTbEJvFsyd1VefzZ34GUkUD6TkJleYYJh9/25WBE4=
|
||||
github.com/billputer/go-namecheap v0.0.0-20210108011502-994a912fb7f9/go.mod h1:bqqNsI2akL+lLWyApkYY0cxquWPKwEBU0Wd3chi3TEg=
|
||||
github.com/bits-and-blooms/bitset v1.24.0 h1:H4x4TuulnokZKvHLfzVRTHJfFfnHEeSYJizujEZvmAM=
|
||||
|
|
@ -90,6 +92,8 @@ github.com/centralnicgroup-opensource/rtldev-middleware-go-sdk/v4 v4.0.7 h1:Jk7u
|
|||
github.com/centralnicgroup-opensource/rtldev-middleware-go-sdk/v4 v4.0.7/go.mod h1:FnQtD0+Q/1NZxi0eEWN+3ZRyMsE9vzSB3YjyunkbKD0=
|
||||
github.com/centralnicgroup-opensource/rtldev-middleware-go-sdk/v5 v5.0.18 h1:RvyTDU0VmnUBd3Qm2i6irEXtCR2KRIxnRlD8l+5z/DY=
|
||||
github.com/centralnicgroup-opensource/rtldev-middleware-go-sdk/v5 v5.0.18/go.mod h1:a6n4wXFHbMW0iJFxHIJR4PkgG5krP52nOVCBU0m+Obw=
|
||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ=
|
||||
github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
|
|
@ -229,6 +233,8 @@ github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB1
|
|||
github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
|
||||
github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU=
|
||||
github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk=
|
||||
github.com/hetznercloud/hcloud-go/v2 v2.30.0 h1:fgAUtCCw4PbJNSs9XPLHVu0//dTNMbPq8P/48ovmdG8=
|
||||
github.com/hetznercloud/hcloud-go/v2 v2.30.0/go.mod h1:zv7x2kM7xyJ5mW/+y4HbfxQYhk8TE57ypTa1hofsYdw=
|
||||
github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.174 h1:FBlx7E5rl8doUTbizt+DXR0zU05Mu2oEYvc/2GMB7pc=
|
||||
github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.174/go.mod h1:M+yna96Fx9o5GbIUnF3OvVvQGjgfVSyeJbV9Yb1z/wI=
|
||||
github.com/influxdata/tdigest v0.0.1 h1:XpFptwYmnEKUqmkcDjrzffswZ3nvNeevbUSLPP/ZzIY=
|
||||
|
|
@ -246,6 +252,8 @@ github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfV
|
|||
github.com/keybase/go-keychain v0.0.1 h1:way+bWYa6lDppZoZcgMbYsvC7GxljxrskdNInRtuthU=
|
||||
github.com/keybase/go-keychain v0.0.1/go.mod h1:PdEILRW3i9D8JcdM+FmY6RwkHGnhHxXwkPPMeUgOK1k=
|
||||
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
||||
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
|
||||
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
|
||||
github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b h1:udzkj9S/zlT5X367kqJis0QP7YMxobob6zhzq6Yre00=
|
||||
github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b/go.mod h1:pcaDhQK0/NJZEvtCO0qQPPropqV0sJOJ6YW7X+9kRwM=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
|
|
@ -300,6 +308,8 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN
|
|||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||
github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04 h1:o6uBwrhM5C8Ll3MAAxrQxRHEu7FkapwTuI2WmL1rw4g=
|
||||
github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04/go.mod h1:5sN+Lt1CaY4wsPvgQH/jsuJi4XO2ssZbdsIizr4CVC8=
|
||||
github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms=
|
||||
|
|
@ -307,8 +317,8 @@ github.com/nicholas-fedor/shoutrrr v0.12.0 h1:8mwJdfU+uBEybSymwQJMGl/grG7lvVUKbV
|
|||
github.com/nicholas-fedor/shoutrrr v0.12.0/go.mod h1:WYiRalR4C43Qmd2zhPWGIFIxu633NB1hDM6Ap/DQcsA=
|
||||
github.com/nozzle/throttler v0.0.0-20180817012639-2ea982251481 h1:Up6+btDp321ZG5/zdSLo48H9Iaq0UQGthrhWC6pCxzE=
|
||||
github.com/nozzle/throttler v0.0.0-20180817012639-2ea982251481/go.mod h1:yKZQO8QE2bHlgozqWDiRVqTFlLQSj30K/6SAK8EeYFw=
|
||||
github.com/nrdcg/goinwx v0.11.0 h1:GER0SE3POub7rxARt3Y3jRy1OON1hwF1LRxHz5xsFBw=
|
||||
github.com/nrdcg/goinwx v0.11.0/go.mod h1:0BXSC0FxVtU4aTjX0Zw3x0DK32tjugLzeNIAGtwXvPQ=
|
||||
github.com/nrdcg/goinwx v0.12.0 h1:ujdUqDBnaRSFwzVnImvPHYw3w3m9XgmGImNUw1GyMb4=
|
||||
github.com/nrdcg/goinwx v0.12.0/go.mod h1:IrVKd3ZDbFiMjdPgML4CSxZAY9wOoqLvH44zv3NodJ0=
|
||||
github.com/onsi/ginkgo/v2 v2.27.2 h1:LzwLj0b89qtIy6SSASkzlNvX6WktqurSHwkk2ipF/Ns=
|
||||
github.com/onsi/ginkgo/v2 v2.27.2/go.mod h1:ArE1D/XhNXBXCBkKOLkbsb2c81dQHCRcF5zwn/ykDRo=
|
||||
github.com/onsi/gomega v1.38.2 h1:eZCjf2xjZAqe+LeWvKb5weQ+NcPwX84kqJ0cZNxok2A=
|
||||
|
|
@ -333,7 +343,15 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI
|
|||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pquerna/otp v1.5.0 h1:NMMR+WrmaqXU4EzdGJEE1aUUI0AMRzsp96fFFWNPwxs=
|
||||
github.com/pquerna/otp v1.5.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg=
|
||||
github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o=
|
||||
github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
|
||||
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
|
||||
github.com/prometheus/common v0.66.1 h1:h5E0h5/Y8niHc5DlaLlWLArTQI7tMrsfQjHV+d9ZoGs=
|
||||
github.com/prometheus/common v0.66.1/go.mod h1:gcaUsgf3KfRSwHY4dIMXLPV0K/Wg1oZ8+SbZk/HH/dA=
|
||||
github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg=
|
||||
github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is=
|
||||
github.com/qdm12/reprint v0.0.0-20200326205758-722754a53494 h1:wSmWgpuccqS2IOfmYrbRiUgv+g37W5suLLLxwwniTSc=
|
||||
github.com/qdm12/reprint v0.0.0-20200326205758-722754a53494/go.mod h1:yipyliwI08eQ6XwDm1fEwKPdF/xdbkiHtrU+1Hg+vc4=
|
||||
github.com/robertkrimen/otto v0.0.0-20200922221731-ef014fd054ac/go.mod h1:xvqspoSXJTIpemEonrMDFq6XzwHYYgToXWj5eRX1OtY=
|
||||
|
|
@ -426,6 +444,10 @@ go.opentelemetry.io/otel/sdk/metric v1.37.0 h1:90lI228XrB9jCMuSdA0673aubgRobVZFh
|
|||
go.opentelemetry.io/otel/sdk/metric v1.37.0/go.mod h1:cNen4ZWfiD37l5NhS+Keb5RXVWZWpRE+9WyVCpbo5ps=
|
||||
go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4=
|
||||
go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI=
|
||||
go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU=
|
||||
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
|
||||
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
|
|
|
|||
|
|
@ -176,6 +176,11 @@
|
|||
"api_key": "$HETZNER_API_KEY",
|
||||
"domain": "$HETZNER_DOMAIN"
|
||||
},
|
||||
"HETZNER_V2": {
|
||||
"TYPE": "HETZNER_V2",
|
||||
"api_token": "$HETZNER_V2_API_TOKEN",
|
||||
"domain": "$HETZNER_V2_DOMAIN"
|
||||
},
|
||||
"HEXONET": {
|
||||
"TYPE": "HEXONET",
|
||||
"apientity": "$HEXONET_ENTITY",
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ func CorrectZoneRecords(driver models.DNSProvider, dc *models.DomainConfig) ([]*
|
|||
models.CanonicalizeTargets(existingRecords, dc.Name)
|
||||
models.CanonicalizeTargets(dc.Records, dc.Name)
|
||||
|
||||
// Copy dc so that any corrections code that wants to
|
||||
// Copy dc so that any correction code that wants to
|
||||
// modify the records may. For example, if the provider only
|
||||
// supports certain TTL values, it will adjust the ones in
|
||||
// dc.Records.
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ import (
|
|||
_ "github.com/StackExchange/dnscontrol/v4/providers/gcore"
|
||||
_ "github.com/StackExchange/dnscontrol/v4/providers/hedns"
|
||||
_ "github.com/StackExchange/dnscontrol/v4/providers/hetzner"
|
||||
_ "github.com/StackExchange/dnscontrol/v4/providers/hetznerv2"
|
||||
_ "github.com/StackExchange/dnscontrol/v4/providers/hexonet"
|
||||
_ "github.com/StackExchange/dnscontrol/v4/providers/hostingde"
|
||||
_ "github.com/StackExchange/dnscontrol/v4/providers/huaweicloud"
|
||||
|
|
|
|||
12
providers/hetznerv2/auditrecords.go
Normal file
12
providers/hetznerv2/auditrecords.go
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
package hetznerv2
|
||||
|
||||
import (
|
||||
"github.com/StackExchange/dnscontrol/v4/models"
|
||||
)
|
||||
|
||||
// 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(_ []*models.RecordConfig) []error {
|
||||
return nil
|
||||
}
|
||||
264
providers/hetznerv2/hetznerv2Provider.go
Normal file
264
providers/hetznerv2/hetznerv2Provider.go
Normal file
|
|
@ -0,0 +1,264 @@
|
|||
package hetznerv2
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
|
||||
"github.com/hetznercloud/hcloud-go/v2/hcloud"
|
||||
"golang.org/x/net/idna"
|
||||
|
||||
"github.com/StackExchange/dnscontrol/v4/models"
|
||||
"github.com/StackExchange/dnscontrol/v4/pkg/diff2"
|
||||
"github.com/StackExchange/dnscontrol/v4/pkg/txtutil"
|
||||
"github.com/StackExchange/dnscontrol/v4/pkg/version"
|
||||
"github.com/StackExchange/dnscontrol/v4/pkg/zonecache"
|
||||
"github.com/StackExchange/dnscontrol/v4/providers"
|
||||
)
|
||||
|
||||
var features = providers.DocumentationNotes{
|
||||
// The default for unlisted capabilities is 'Cannot'.
|
||||
// See providers/capabilities.go for the entire list of capabilities.
|
||||
providers.CanAutoDNSSEC: providers.Cannot(),
|
||||
providers.CanConcur: providers.Can(),
|
||||
providers.CanGetZones: providers.Can(),
|
||||
providers.CanOnlyDiff1Features: providers.Can(),
|
||||
providers.CanUseAlias: providers.Cannot(),
|
||||
providers.CanUseCAA: providers.Can(),
|
||||
providers.CanUseDS: providers.Can(),
|
||||
providers.CanUseDSForChildren: providers.Cannot(),
|
||||
providers.CanUseLOC: providers.Cannot(),
|
||||
providers.CanUseNAPTR: providers.Cannot(),
|
||||
providers.CanUsePTR: providers.Can(),
|
||||
providers.CanUseSOA: providers.Cannot(),
|
||||
providers.CanUseSRV: providers.Can(),
|
||||
providers.CanUseSVCB: providers.Can(),
|
||||
providers.CanUseHTTPS: providers.Can(),
|
||||
providers.CanUseSSHFP: providers.Cannot(),
|
||||
providers.CanUseTLSA: providers.Can(),
|
||||
providers.DocCreateDomains: providers.Can(),
|
||||
providers.DocOfficiallySupported: providers.Cannot(),
|
||||
providers.DocDualHost: providers.Can(),
|
||||
}
|
||||
|
||||
func init() {
|
||||
const providerName = "HETZNER_V2"
|
||||
const providerMaintainer = "@das7pad"
|
||||
fns := providers.DspFuncs{
|
||||
Initializer: New,
|
||||
RecordAuditor: AuditRecords,
|
||||
}
|
||||
providers.RegisterDomainServiceProviderType(providerName, fns, features)
|
||||
providers.RegisterMaintainer(providerName, providerMaintainer)
|
||||
}
|
||||
|
||||
// New creates a new API handle.
|
||||
func New(settings map[string]string, _ json.RawMessage) (providers.DNSServiceProvider, error) {
|
||||
apiToken := settings["api_token"]
|
||||
if apiToken == "" {
|
||||
return nil, errors.New("missing HETZNER_V2 api_token")
|
||||
}
|
||||
|
||||
h := &hetznerv2Provider{
|
||||
client: hcloud.NewClient(
|
||||
hcloud.WithToken(apiToken),
|
||||
hcloud.WithApplication("dnscontrol", version.Version()),
|
||||
),
|
||||
}
|
||||
h.zoneCache = zonecache.New(h.fetchAllZones)
|
||||
return h, nil
|
||||
}
|
||||
|
||||
type hetznerv2Provider struct {
|
||||
zoneCache zonecache.ZoneCache[*hcloud.Zone]
|
||||
client *hcloud.Client
|
||||
}
|
||||
|
||||
// fetchAllZones is used by the zonecache.ZoneCache.
|
||||
func (h *hetznerv2Provider) fetchAllZones() (map[string]*hcloud.Zone, error) {
|
||||
flat, err := h.client.Zone.All(context.Background())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
zones := make(map[string]*hcloud.Zone, len(flat))
|
||||
for _, z := range flat {
|
||||
zones[z.Name] = z
|
||||
}
|
||||
return zones, nil
|
||||
}
|
||||
|
||||
// EnsureZoneExists creates a zone if it does not exist
|
||||
func (h *hetznerv2Provider) EnsureZoneExists(domain string, _ map[string]string) error {
|
||||
encoded, err := idna.ToASCII(domain)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if ok, err2 := h.zoneCache.HasZone(encoded); err2 != nil || ok {
|
||||
return err2
|
||||
}
|
||||
result, _, err := h.client.Zone.Create(context.Background(), hcloud.ZoneCreateOpts{
|
||||
Name: encoded,
|
||||
Mode: hcloud.ZoneModePrimary,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = h.client.Action.WaitFor(context.Background(), result.Action)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
z, _, err := h.client.Zone.GetByID(context.Background(), result.Zone.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
h.zoneCache.SetZone(encoded, z)
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetZoneRecordsCorrections returns a list of corrections that will turn existing records into dc.Records.
|
||||
func (h *hetznerv2Provider) GetZoneRecordsCorrections(dc *models.DomainConfig, existingRecords models.Records) ([]*models.Correction, int, error) {
|
||||
encoded, err := idna.ToASCII(dc.Name)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
z, err := h.zoneCache.GetZone(encoded)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
// Hetzner Cloud has a "ByRecordSet" API for DNS.
|
||||
// At each label:rtype pair, we either delete all records or UPSERT the desired records.
|
||||
instructions, actualChangeCount, err := diff2.ByRecordSet(existingRecords, dc, nil)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
var reports []*models.Correction
|
||||
for _, instruction := range instructions {
|
||||
switch instruction.Type {
|
||||
case diff2.REPORT:
|
||||
reports = append(reports, &models.Correction{
|
||||
Msg: instruction.MsgsJoined,
|
||||
})
|
||||
continue
|
||||
case diff2.CREATE:
|
||||
first := instruction.New[0]
|
||||
ttl := int(first.TTL)
|
||||
opts := hcloud.ZoneRRSetCreateOpts{
|
||||
Name: first.Name,
|
||||
Type: hcloud.ZoneRRSetType(first.Type),
|
||||
TTL: &ttl,
|
||||
}
|
||||
for _, r := range instruction.New {
|
||||
opts.Records = append(opts.Records, hcloud.ZoneRRSetRecord{
|
||||
Value: r.GetTargetCombinedFunc(txtutil.EncodeQuoted),
|
||||
})
|
||||
}
|
||||
reports = append(reports, &models.Correction{
|
||||
F: func() error {
|
||||
_, _, err2 := h.client.Zone.CreateRRSet(context.Background(), z, opts)
|
||||
return err2
|
||||
},
|
||||
Msg: instruction.MsgsJoined,
|
||||
})
|
||||
case diff2.CHANGE:
|
||||
rrSet := instruction.Old[0].Original.(*hcloud.ZoneRRSet)
|
||||
reports = append(reports, &models.Correction{
|
||||
F: func() error {
|
||||
if instruction.New[0].TTL != instruction.Old[0].TTL {
|
||||
ttl := int(instruction.New[0].TTL)
|
||||
opts := hcloud.ZoneRRSetChangeTTLOpts{TTL: &ttl}
|
||||
_, _, err2 := h.client.Zone.ChangeRRSetTTL(context.Background(), rrSet, opts)
|
||||
if err2 != nil {
|
||||
return err2
|
||||
}
|
||||
}
|
||||
|
||||
opts := hcloud.ZoneRRSetSetRecordsOpts{}
|
||||
for _, r := range instruction.New {
|
||||
opts.Records = append(opts.Records, hcloud.ZoneRRSetRecord{
|
||||
Value: r.GetTargetCombinedFunc(txtutil.EncodeQuoted),
|
||||
})
|
||||
}
|
||||
_, _, err2 := h.client.Zone.SetRRSetRecords(context.Background(), rrSet, opts)
|
||||
return err2
|
||||
},
|
||||
Msg: instruction.MsgsJoined,
|
||||
})
|
||||
case diff2.DELETE:
|
||||
reports = append(reports, &models.Correction{
|
||||
F: func() error {
|
||||
rc := instruction.Old[0].Original.(*hcloud.ZoneRRSet)
|
||||
_, _, err2 := h.client.Zone.DeleteRRSet(context.Background(), rc)
|
||||
return err2
|
||||
},
|
||||
Msg: instruction.MsgsJoined,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return reports, actualChangeCount, nil
|
||||
}
|
||||
|
||||
// GetNameservers returns the nameservers for a domain.
|
||||
func (h *hetznerv2Provider) GetNameservers(domain string) ([]*models.Nameserver, error) {
|
||||
encoded, err := idna.ToASCII(domain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
z, err := h.zoneCache.GetZone(encoded)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return models.ToNameserversStripTD(z.AuthoritativeNameservers.Assigned)
|
||||
}
|
||||
|
||||
// GetZoneRecords gets the records of a zone and returns them in RecordConfig format.
|
||||
func (h *hetznerv2Provider) GetZoneRecords(domain string, _ map[string]string) (models.Records, error) {
|
||||
encoded, err := idna.ToASCII(domain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
z, err := h.zoneCache.GetZone(encoded)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
opts := hcloud.ZoneRRSetListOpts{}
|
||||
opts.PerPage = 100
|
||||
records, err := h.client.Zone.AllRRSetsWithOpts(context.Background(), z, opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
existingRecords := make([]*models.RecordConfig, 0, len(records))
|
||||
for _, rrSet := range records {
|
||||
if rrSet.Type == hcloud.ZoneRRSetTypeSOA {
|
||||
// SOA records are not available for editing, hide them.
|
||||
continue
|
||||
}
|
||||
base := models.RecordConfig{
|
||||
Type: string(rrSet.Type),
|
||||
Original: rrSet,
|
||||
}
|
||||
base.SetLabel(rrSet.Name, z.Name)
|
||||
if rrSet.TTL != nil {
|
||||
base.TTL = uint32(*rrSet.TTL)
|
||||
} else {
|
||||
base.TTL = uint32(z.TTL)
|
||||
}
|
||||
|
||||
for _, r := range rrSet.Records {
|
||||
rc := base
|
||||
if err = rc.PopulateFromStringFunc(rc.Type, r.Value, z.Name, txtutil.ParseQuoted); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
existingRecords = append(existingRecords, &rc)
|
||||
}
|
||||
}
|
||||
return existingRecords, nil
|
||||
}
|
||||
|
||||
// ListZones lists the zones on this account.
|
||||
func (h *hetznerv2Provider) ListZones() ([]string, error) {
|
||||
return h.zoneCache.GetZoneNames()
|
||||
}
|
||||
|
|
@ -10,12 +10,8 @@ import (
|
|||
// supported, an empty list is returned.
|
||||
func AuditRecords(records []*models.RecordConfig) []error {
|
||||
a := rejectif.Auditor{}
|
||||
|
||||
a.Add("TXT", rejectif.TxtHasBackticks) // Last verified 2021-03-01
|
||||
|
||||
a.Add("TXT", rejectif.TxtHasTrailingSpace) // Last verified 2021-03-01
|
||||
|
||||
a.Add("TXT", rejectif.TxtIsEmpty) // Last verified 2021-03-01
|
||||
|
||||
return a.Audit(records)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,25 +10,22 @@ const (
|
|||
// testing shows 'AUTO' is what to expect if the domain has automatic
|
||||
// DNSSEC enabled.
|
||||
|
||||
// AutoDNSSEC is the status for DNSSEC enabled with automatic management
|
||||
// AutoDNSSECStatus is the status for DNSSEC enabled with automatic management
|
||||
AutoDNSSECStatus = "AUTO"
|
||||
// ManualDNSSEC is the status for DNSSEC enabled with manual management
|
||||
// ManualDNSSECStatus is the status for DNSSEC enabled with manual management
|
||||
ManualDNSSECStatus = "MANUAL"
|
||||
)
|
||||
|
||||
// DNSSecStatus returns domain dnssec status
|
||||
func (api *inwxAPI) DNSSecStatus(domain string) (string, error) {
|
||||
|
||||
resp, err := api.client.Dnssec.Info([]string{domain})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// domain has no DNSSEC configuration
|
||||
if len(resp.Data) == 0 {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
return resp.Data[0].DNSSecStatus, nil
|
||||
}
|
||||
|
||||
|
|
@ -40,16 +37,12 @@ func (api *inwxAPI) enableAutoDNSSEC(domain string) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = api.client.Dnssec.Enable(domain)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// disableAutoDNSSEC disables automatic management of DNSSEC
|
||||
func (api *inwxAPI) disableAutoDNSSEC(domain string) error {
|
||||
|
||||
err := api.client.Dnssec.Disable(domain)
|
||||
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,9 @@ import (
|
|||
/*
|
||||
INWX Registrar and DNS provider
|
||||
|
||||
Based on this great INWX API implementation:
|
||||
https://github.com/nrdcg/goinwx
|
||||
|
||||
Info required in `creds.json`:
|
||||
- username
|
||||
- password
|
||||
|
|
@ -34,7 +37,6 @@ Either of the following settings is required when two factor authentication is e
|
|||
|
||||
Additional settings available in `creds.json`:
|
||||
- sandbox (set to 1 to use the sandbox API from INWX)
|
||||
|
||||
*/
|
||||
|
||||
// InwxProductionDefaultNs contains the default INWX nameservers.
|
||||
|
|
@ -182,10 +184,10 @@ func makeNameserverRecordRequest(domain string, rec *models.RecordConfig) *goinw
|
|||
|
||||
switch rType := rec.Type; rType {
|
||||
/*
|
||||
INWX is a little bit special for CNAME,NS,MX and SRV records:
|
||||
INWX is a little bit special for CNAME, NS, MX and SRV records:
|
||||
The API will not accept any target with a final dot but will
|
||||
instead always add this final dot internally.
|
||||
Records with empty targets (i.e. records with target ".")
|
||||
Records with empty targets (i.e., records with target ".")
|
||||
are allowed.
|
||||
*/
|
||||
case "CNAME", "NS", "ALIAS":
|
||||
|
|
@ -219,14 +221,14 @@ func (api *inwxAPI) createRecord(domain string, rec *models.RecordConfig) error
|
|||
}
|
||||
|
||||
// updateRecord is used by GetDomainCorrections to update an existing record.
|
||||
func (api *inwxAPI) updateRecord(RecordID int, rec *models.RecordConfig) error {
|
||||
func (api *inwxAPI) updateRecord(RecordID string, rec *models.RecordConfig) error {
|
||||
req := makeNameserverRecordRequest("", rec)
|
||||
err := api.client.Nameservers.UpdateRecord(RecordID, req)
|
||||
return err
|
||||
}
|
||||
|
||||
// deleteRecord is used by GetDomainCorrections to delete a record.
|
||||
func (api *inwxAPI) deleteRecord(RecordID int) error {
|
||||
func (api *inwxAPI) deleteRecord(RecordID string) error {
|
||||
return api.client.Nameservers.DeleteRecord(RecordID)
|
||||
}
|
||||
|
||||
|
|
@ -244,7 +246,8 @@ func (api *inwxAPI) AutoDnssecToggle(dc *models.DomainConfig, corrections []*mod
|
|||
}
|
||||
|
||||
if dnssecStatus == ManualDNSSECStatus && dc.AutoDNSSEC != "" {
|
||||
return corrections, fmt.Errorf("INWX: Domain %s has manual DNSSEC enabled. Disable it before using AUTODNSSEC_ON/AUTODNSSEC_OFF", dc.Name)
|
||||
return corrections, fmt.Errorf("INWX: Domain %s has manual DNSSEC enabled. Disable it before using "+
|
||||
"AUTODNSSEC_ON/AUTODNSSEC_OFF", dc.Name)
|
||||
}
|
||||
|
||||
if dnssecStatus != AutoDNSSECStatus && dc.AutoDNSSEC == "on" {
|
||||
|
|
@ -289,23 +292,25 @@ func (api *inwxAPI) GetZoneRecordsCorrections(dc *models.DomainConfig, foundReco
|
|||
return nil, 0, err
|
||||
}
|
||||
for _, change := range changes {
|
||||
changeMsgs := change.MsgsJoined
|
||||
changeMessage := change.MsgsJoined
|
||||
switch change.Type {
|
||||
case diff2.REPORT:
|
||||
corrections = append(corrections, &models.Correction{Msg: changeMsgs})
|
||||
corrections = append(corrections, &models.Correction{Msg: changeMessage})
|
||||
case diff2.CHANGE:
|
||||
oldRec := change.Old[0]
|
||||
newRec := change.New[0]
|
||||
if isNullMX(newRec) || isNullMX(oldRec) {
|
||||
// changing to or from a Null MX has to be delete then create
|
||||
// changing to or from a Null MX has to be deleted then create
|
||||
deletes = append(deletes, &models.Correction{
|
||||
Msg: color.RedString("- DELETE %s %s %s ttl=%d", oldRec.GetLabelFQDN(), oldRec.Type, oldRec.ToComparableNoTTL(), oldRec.TTL),
|
||||
Msg: color.RedString("- DELETE %s %s %s ttl=%d", oldRec.GetLabelFQDN(), oldRec.Type,
|
||||
oldRec.ToComparableNoTTL(), oldRec.TTL),
|
||||
F: func() error {
|
||||
return api.deleteRecord(oldRec.Original.(goinwx.NameserverRecord).ID)
|
||||
},
|
||||
})
|
||||
deferred = append(deferred, &models.Correction{
|
||||
Msg: color.GreenString("+ CREATE %s %s %s ttl=%d", newRec.GetLabelFQDN(), newRec.Type, newRec.ToComparableNoTTL(), newRec.TTL),
|
||||
Msg: color.GreenString("+ CREATE %s %s %s ttl=%d", newRec.GetLabelFQDN(), newRec.Type,
|
||||
newRec.ToComparableNoTTL(), newRec.TTL),
|
||||
F: func() error {
|
||||
return api.createRecord(dc.Name, newRec)
|
||||
},
|
||||
|
|
@ -313,7 +318,7 @@ func (api *inwxAPI) GetZoneRecordsCorrections(dc *models.DomainConfig, foundReco
|
|||
} else {
|
||||
recID := oldRec.Original.(goinwx.NameserverRecord).ID
|
||||
corrections = append(corrections, &models.Correction{
|
||||
Msg: changeMsgs,
|
||||
Msg: changeMessage,
|
||||
F: func() error {
|
||||
return api.updateRecord(recID, newRec)
|
||||
},
|
||||
|
|
@ -322,7 +327,7 @@ func (api *inwxAPI) GetZoneRecordsCorrections(dc *models.DomainConfig, foundReco
|
|||
}
|
||||
case diff2.CREATE:
|
||||
creates = append(creates, &models.Correction{
|
||||
Msg: changeMsgs,
|
||||
Msg: changeMessage,
|
||||
F: func() error {
|
||||
return api.createRecord(dc.Name, change.New[0])
|
||||
},
|
||||
|
|
@ -330,7 +335,7 @@ func (api *inwxAPI) GetZoneRecordsCorrections(dc *models.DomainConfig, foundReco
|
|||
case diff2.DELETE:
|
||||
recID := change.Old[0].Original.(goinwx.NameserverRecord).ID
|
||||
deletes = append(deletes, &models.Correction{
|
||||
Msg: changeMsgs,
|
||||
Msg: changeMessage,
|
||||
F: func() error { return api.deleteRecord(recID) },
|
||||
})
|
||||
default:
|
||||
|
|
@ -343,7 +348,7 @@ func (api *inwxAPI) GetZoneRecordsCorrections(dc *models.DomainConfig, foundReco
|
|||
return corrections, actualChangeCount, nil
|
||||
}
|
||||
|
||||
// getDefaultNameservers returns string map with default nameservers based on e.g. sandbox mode.
|
||||
// getDefaultNameservers returns a string map with default nameservers based on e.g. sandbox mode.
|
||||
func (api *inwxAPI) getDefaultNameservers() []string {
|
||||
if api.sandbox {
|
||||
return InwxSandboxDefaultNs
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue