npmctl-godaddy 0.3.6__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- npmctl_godaddy-0.3.6/LICENSE +1 -0
- npmctl_godaddy-0.3.6/PKG-INFO +189 -0
- npmctl_godaddy-0.3.6/README.md +161 -0
- npmctl_godaddy-0.3.6/pyproject.toml +39 -0
- npmctl_godaddy-0.3.6/src/npmctl_godaddy/__init__.py +7 -0
- npmctl_godaddy-0.3.6/src/npmctl_godaddy/client.py +78 -0
- npmctl_godaddy-0.3.6/src/npmctl_godaddy/config.py +32 -0
- npmctl_godaddy-0.3.6/src/npmctl_godaddy/errors.py +7 -0
- npmctl_godaddy-0.3.6/src/npmctl_godaddy/models.py +43 -0
- npmctl_godaddy-0.3.6/src/npmctl_godaddy/provider.py +27 -0
- npmctl_godaddy-0.3.6/src/npmctl_godaddy/py.typed +1 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Apache-2.0
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: npmctl-godaddy
|
|
3
|
+
Version: 0.3.6
|
|
4
|
+
Summary: GoDaddy DNS provider extension for npmctl.
|
|
5
|
+
Keywords: godaddy,dns,nginx-proxy-manager,npmctl
|
|
6
|
+
Author: Jacob Stewart
|
|
7
|
+
Author-email: Jacob Stewart <jacob@swarmauri.com>
|
|
8
|
+
License-Expression: Apache-2.0
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Classifier: Development Status :: 1 - Planning
|
|
11
|
+
Classifier: Intended Audience :: System Administrators
|
|
12
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
19
|
+
Classifier: Topic :: Internet :: Name Service (DNS)
|
|
20
|
+
Classifier: Topic :: System :: Systems Administration
|
|
21
|
+
Requires-Dist: requests>=2.32.0
|
|
22
|
+
Requires-Python: >=3.10, <3.15
|
|
23
|
+
Project-URL: Homepage, https://github.com/groupsum/npmctl
|
|
24
|
+
Project-URL: Repository, https://github.com/groupsum/npmctl
|
|
25
|
+
Project-URL: Documentation, https://github.com/groupsum/npmctl/tree/master/packages/npmctl-godaddy
|
|
26
|
+
Project-URL: Issues, https://github.com/groupsum/npmctl/issues
|
|
27
|
+
Description-Content-Type: text/markdown
|
|
28
|
+
|
|
29
|
+
<h1 align="center">npmctl-godaddy</h1>
|
|
30
|
+
|
|
31
|
+
<p align="center"><strong>GoDaddy DNS provider plugin for npmctl</strong></p>
|
|
32
|
+
|
|
33
|
+
<p align="center">
|
|
34
|
+
Extend <code>npmctl</code> with GoDaddy-backed DNS record management for declarative workflows, provider discovery, and DNS-aware automation.
|
|
35
|
+
</p>
|
|
36
|
+
|
|
37
|
+
<p align="center">
|
|
38
|
+
<a href="https://pypi.org/project/npmctl-godaddy/"><img src="https://img.shields.io/pypi/v/npmctl-godaddy.svg" alt="PyPI version"></a>
|
|
39
|
+
<a href="https://pypi.org/project/npmctl-godaddy/"><img src="https://img.shields.io/pypi/pyversions/npmctl-godaddy.svg" alt="Python versions"></a>
|
|
40
|
+
<a href="https://github.com/groupsum/npmctl/actions/workflows/ci.yml"><img src="https://github.com/groupsum/npmctl/actions/workflows/ci.yml/badge.svg?branch=master" alt="CI"></a>
|
|
41
|
+
<a href="https://github.com/groupsum/npmctl/blob/master/LICENSE"><img src="https://img.shields.io/badge/License-Apache%202.0-blue.svg" alt="Apache 2.0 License"></a>
|
|
42
|
+
</p>
|
|
43
|
+
|
|
44
|
+
<p align="center">
|
|
45
|
+
<a href="https://hits.sh/github.com/groupsum/npmctl/blob/master/packages/npmctl-godaddy/README.md/"><img src="https://hits.sh/github.com/groupsum/npmctl/blob/master/packages/npmctl-godaddy/README.md.svg?label=npmctl-godaddy%20package%20hits" alt="npmctl-godaddy package hits"></a>
|
|
46
|
+
<a href="https://pepy.tech/projects/npmctl-godaddy"><img src="https://static.pepy.tech/badge/npmctl-godaddy" alt="npmctl-godaddy downloads"></a>
|
|
47
|
+
</p>
|
|
48
|
+
|
|
49
|
+
<p align="center">
|
|
50
|
+
<img src="https://raw.githubusercontent.com/groupsum/npmctl/master/docs/images/marketing/npmctl-architecture-infographic.png" alt="npmctl architecture infographic">
|
|
51
|
+
</p>
|
|
52
|
+
|
|
53
|
+
`npmctl-godaddy` is the GoDaddy DNS provider package for `npmctl`. Install it when you want desired-state DNS records or DNS diagnostics to resolve through GoDaddy instead of using only the base `npmctl` package.
|
|
54
|
+
|
|
55
|
+
## Supported Python Versions
|
|
56
|
+
|
|
57
|
+
`npmctl-godaddy` supports Python `3.10`, `3.11`, `3.12`, `3.13`, and `3.14`.
|
|
58
|
+
|
|
59
|
+
## Why npmctl-godaddy
|
|
60
|
+
|
|
61
|
+
- Adds GoDaddy DNS provider discovery to `npmctl`
|
|
62
|
+
- Lets DNS workflows live beside proxy and certificate desired state
|
|
63
|
+
- Keeps GoDaddy API keys out of the core CLI package
|
|
64
|
+
- Supports operator diagnostics through `npmctl dns doctor`
|
|
65
|
+
- Documents GoDaddy's record-set replacement behavior for safer automation
|
|
66
|
+
|
|
67
|
+
## FAQ
|
|
68
|
+
|
|
69
|
+
### What is npmctl-godaddy?
|
|
70
|
+
|
|
71
|
+
**Answer:** `npmctl-godaddy` is a plugin package that teaches `npmctl` how to talk to the GoDaddy Domains API for DNS record operations and DNS provider diagnostics.
|
|
72
|
+
|
|
73
|
+
### When do I need npmctl-godaddy?
|
|
74
|
+
|
|
75
|
+
**Answer:** You need `npmctl-godaddy` when your `npmctl` workflow includes GoDaddy-managed DNS records or when you want `npmctl` to validate GoDaddy DNS connectivity and credentials.
|
|
76
|
+
|
|
77
|
+
### Does npmctl-godaddy work without npmctl?
|
|
78
|
+
|
|
79
|
+
**Answer:** No. `npmctl-godaddy` is an extension package for `npmctl`, not a standalone CLI.
|
|
80
|
+
|
|
81
|
+
### Can npmctl-godaddy set A and CNAME records?
|
|
82
|
+
|
|
83
|
+
**Answer:** Yes. GoDaddy's Domains API supports A and CNAME records. Its DNS mutation endpoint replaces all records for one `{type, name}` pair, so preserve existing values when managing multi-value records.
|
|
84
|
+
|
|
85
|
+
### What credentials are required?
|
|
86
|
+
|
|
87
|
+
**Answer:** GoDaddy API access requires `GODADDY_API_KEY` and `GODADDY_API_SECRET`. Account protection, domain locks, or product eligibility can still block DNS mutations even when credentials are valid.
|
|
88
|
+
|
|
89
|
+
## Install
|
|
90
|
+
|
|
91
|
+
Install the base CLI and the GoDaddy provider package together:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
pipx install npmctl
|
|
95
|
+
pipx inject npmctl npmctl-godaddy
|
|
96
|
+
npmctl plugins list
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
With `uv`:
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
uv tool install npmctl
|
|
103
|
+
uv tool install npmctl-godaddy
|
|
104
|
+
npmctl plugins list
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Inside a virtual environment:
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
python -m venv .venv
|
|
111
|
+
. .venv/bin/activate
|
|
112
|
+
python -m pip install npmctl npmctl-godaddy
|
|
113
|
+
npmctl plugins list
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Configure GoDaddy
|
|
117
|
+
|
|
118
|
+
Set the required environment variables:
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
export GODADDY_API_KEY=your-api-key
|
|
122
|
+
export GODADDY_API_SECRET=your-api-secret
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Optional for tests or alternate endpoints:
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
export GODADDY_API_BASE_URL=https://api.godaddy.com
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## Verify Plugin Discovery
|
|
132
|
+
|
|
133
|
+
Check that `npmctl` can discover the provider:
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
npmctl plugins list
|
|
137
|
+
npmctl dns doctor --provider godaddy
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Minimal DNS Workflow
|
|
141
|
+
|
|
142
|
+
Once the provider is installed and configured, `npmctl` can validate or diagnose GoDaddy-backed DNS behavior through the base CLI:
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
npmctl dns providers
|
|
146
|
+
npmctl dns zones --provider godaddy
|
|
147
|
+
npmctl dns records --provider godaddy --zone example.com
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## GoDaddy API Surface
|
|
151
|
+
|
|
152
|
+
The provider follows the GoDaddy Domains API DNS record surface:
|
|
153
|
+
|
|
154
|
+
- `GET /v1/domains`: discover domains in the account.
|
|
155
|
+
- `GET /v1/domains/{domain}/records`: list all DNS records for one domain.
|
|
156
|
+
- `GET /v1/domains/{domain}/records/{type}/{name}`: list records for one type and name.
|
|
157
|
+
- `PUT /v1/domains/{domain}/records/{type}/{name}`: replace the full record set for one type and name.
|
|
158
|
+
- `DELETE /v1/domains/{domain}/records/{type}/{name}`: delete records for one type and name.
|
|
159
|
+
|
|
160
|
+
## Programmatic Record Operations
|
|
161
|
+
|
|
162
|
+
`create_record()` is a convenience wrapper that replaces a `{type, name}` pair with one record. Use `replace_records()` when preserving multiple values for the same record name and type:
|
|
163
|
+
|
|
164
|
+
```python
|
|
165
|
+
from npmctl_godaddy import GoDaddyClient, GoDaddyConfig
|
|
166
|
+
|
|
167
|
+
client = GoDaddyClient(GoDaddyConfig.from_env())
|
|
168
|
+
client.create_record("example.com", type="A", name="www", value="192.0.2.10", ttl=600)
|
|
169
|
+
client.replace_records(
|
|
170
|
+
"example.com",
|
|
171
|
+
type="CNAME",
|
|
172
|
+
name="app",
|
|
173
|
+
records=[{"data": "target.example.net", "ttl": 600}],
|
|
174
|
+
)
|
|
175
|
+
client.delete_records("example.com", type="A", name="www")
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## Safety Notes
|
|
179
|
+
|
|
180
|
+
- GoDaddy `PUT` replaces all records for the selected `{type, name}` pair.
|
|
181
|
+
- Account-level domain locks, premium DNS status, protection settings, or product eligibility may block API changes even when credentials are valid.
|
|
182
|
+
- Use least-privilege keys where available and avoid broad automation over unrelated domains.
|
|
183
|
+
- Use npmctl owner metadata for desired DNS records so future apply support can remain owner-scoped.
|
|
184
|
+
|
|
185
|
+
## More Documentation
|
|
186
|
+
|
|
187
|
+
- Related PyPI package: https://pypi.org/project/npmctl/
|
|
188
|
+
- Repository: https://github.com/groupsum/npmctl
|
|
189
|
+
- DNS provider docs: https://github.com/groupsum/npmctl/tree/master/docs/dns-providers.md
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
<h1 align="center">npmctl-godaddy</h1>
|
|
2
|
+
|
|
3
|
+
<p align="center"><strong>GoDaddy DNS provider plugin for npmctl</strong></p>
|
|
4
|
+
|
|
5
|
+
<p align="center">
|
|
6
|
+
Extend <code>npmctl</code> with GoDaddy-backed DNS record management for declarative workflows, provider discovery, and DNS-aware automation.
|
|
7
|
+
</p>
|
|
8
|
+
|
|
9
|
+
<p align="center">
|
|
10
|
+
<a href="https://pypi.org/project/npmctl-godaddy/"><img src="https://img.shields.io/pypi/v/npmctl-godaddy.svg" alt="PyPI version"></a>
|
|
11
|
+
<a href="https://pypi.org/project/npmctl-godaddy/"><img src="https://img.shields.io/pypi/pyversions/npmctl-godaddy.svg" alt="Python versions"></a>
|
|
12
|
+
<a href="https://github.com/groupsum/npmctl/actions/workflows/ci.yml"><img src="https://github.com/groupsum/npmctl/actions/workflows/ci.yml/badge.svg?branch=master" alt="CI"></a>
|
|
13
|
+
<a href="https://github.com/groupsum/npmctl/blob/master/LICENSE"><img src="https://img.shields.io/badge/License-Apache%202.0-blue.svg" alt="Apache 2.0 License"></a>
|
|
14
|
+
</p>
|
|
15
|
+
|
|
16
|
+
<p align="center">
|
|
17
|
+
<a href="https://hits.sh/github.com/groupsum/npmctl/blob/master/packages/npmctl-godaddy/README.md/"><img src="https://hits.sh/github.com/groupsum/npmctl/blob/master/packages/npmctl-godaddy/README.md.svg?label=npmctl-godaddy%20package%20hits" alt="npmctl-godaddy package hits"></a>
|
|
18
|
+
<a href="https://pepy.tech/projects/npmctl-godaddy"><img src="https://static.pepy.tech/badge/npmctl-godaddy" alt="npmctl-godaddy downloads"></a>
|
|
19
|
+
</p>
|
|
20
|
+
|
|
21
|
+
<p align="center">
|
|
22
|
+
<img src="https://raw.githubusercontent.com/groupsum/npmctl/master/docs/images/marketing/npmctl-architecture-infographic.png" alt="npmctl architecture infographic">
|
|
23
|
+
</p>
|
|
24
|
+
|
|
25
|
+
`npmctl-godaddy` is the GoDaddy DNS provider package for `npmctl`. Install it when you want desired-state DNS records or DNS diagnostics to resolve through GoDaddy instead of using only the base `npmctl` package.
|
|
26
|
+
|
|
27
|
+
## Supported Python Versions
|
|
28
|
+
|
|
29
|
+
`npmctl-godaddy` supports Python `3.10`, `3.11`, `3.12`, `3.13`, and `3.14`.
|
|
30
|
+
|
|
31
|
+
## Why npmctl-godaddy
|
|
32
|
+
|
|
33
|
+
- Adds GoDaddy DNS provider discovery to `npmctl`
|
|
34
|
+
- Lets DNS workflows live beside proxy and certificate desired state
|
|
35
|
+
- Keeps GoDaddy API keys out of the core CLI package
|
|
36
|
+
- Supports operator diagnostics through `npmctl dns doctor`
|
|
37
|
+
- Documents GoDaddy's record-set replacement behavior for safer automation
|
|
38
|
+
|
|
39
|
+
## FAQ
|
|
40
|
+
|
|
41
|
+
### What is npmctl-godaddy?
|
|
42
|
+
|
|
43
|
+
**Answer:** `npmctl-godaddy` is a plugin package that teaches `npmctl` how to talk to the GoDaddy Domains API for DNS record operations and DNS provider diagnostics.
|
|
44
|
+
|
|
45
|
+
### When do I need npmctl-godaddy?
|
|
46
|
+
|
|
47
|
+
**Answer:** You need `npmctl-godaddy` when your `npmctl` workflow includes GoDaddy-managed DNS records or when you want `npmctl` to validate GoDaddy DNS connectivity and credentials.
|
|
48
|
+
|
|
49
|
+
### Does npmctl-godaddy work without npmctl?
|
|
50
|
+
|
|
51
|
+
**Answer:** No. `npmctl-godaddy` is an extension package for `npmctl`, not a standalone CLI.
|
|
52
|
+
|
|
53
|
+
### Can npmctl-godaddy set A and CNAME records?
|
|
54
|
+
|
|
55
|
+
**Answer:** Yes. GoDaddy's Domains API supports A and CNAME records. Its DNS mutation endpoint replaces all records for one `{type, name}` pair, so preserve existing values when managing multi-value records.
|
|
56
|
+
|
|
57
|
+
### What credentials are required?
|
|
58
|
+
|
|
59
|
+
**Answer:** GoDaddy API access requires `GODADDY_API_KEY` and `GODADDY_API_SECRET`. Account protection, domain locks, or product eligibility can still block DNS mutations even when credentials are valid.
|
|
60
|
+
|
|
61
|
+
## Install
|
|
62
|
+
|
|
63
|
+
Install the base CLI and the GoDaddy provider package together:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
pipx install npmctl
|
|
67
|
+
pipx inject npmctl npmctl-godaddy
|
|
68
|
+
npmctl plugins list
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
With `uv`:
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
uv tool install npmctl
|
|
75
|
+
uv tool install npmctl-godaddy
|
|
76
|
+
npmctl plugins list
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Inside a virtual environment:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
python -m venv .venv
|
|
83
|
+
. .venv/bin/activate
|
|
84
|
+
python -m pip install npmctl npmctl-godaddy
|
|
85
|
+
npmctl plugins list
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Configure GoDaddy
|
|
89
|
+
|
|
90
|
+
Set the required environment variables:
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
export GODADDY_API_KEY=your-api-key
|
|
94
|
+
export GODADDY_API_SECRET=your-api-secret
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Optional for tests or alternate endpoints:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
export GODADDY_API_BASE_URL=https://api.godaddy.com
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Verify Plugin Discovery
|
|
104
|
+
|
|
105
|
+
Check that `npmctl` can discover the provider:
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
npmctl plugins list
|
|
109
|
+
npmctl dns doctor --provider godaddy
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## Minimal DNS Workflow
|
|
113
|
+
|
|
114
|
+
Once the provider is installed and configured, `npmctl` can validate or diagnose GoDaddy-backed DNS behavior through the base CLI:
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
npmctl dns providers
|
|
118
|
+
npmctl dns zones --provider godaddy
|
|
119
|
+
npmctl dns records --provider godaddy --zone example.com
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## GoDaddy API Surface
|
|
123
|
+
|
|
124
|
+
The provider follows the GoDaddy Domains API DNS record surface:
|
|
125
|
+
|
|
126
|
+
- `GET /v1/domains`: discover domains in the account.
|
|
127
|
+
- `GET /v1/domains/{domain}/records`: list all DNS records for one domain.
|
|
128
|
+
- `GET /v1/domains/{domain}/records/{type}/{name}`: list records for one type and name.
|
|
129
|
+
- `PUT /v1/domains/{domain}/records/{type}/{name}`: replace the full record set for one type and name.
|
|
130
|
+
- `DELETE /v1/domains/{domain}/records/{type}/{name}`: delete records for one type and name.
|
|
131
|
+
|
|
132
|
+
## Programmatic Record Operations
|
|
133
|
+
|
|
134
|
+
`create_record()` is a convenience wrapper that replaces a `{type, name}` pair with one record. Use `replace_records()` when preserving multiple values for the same record name and type:
|
|
135
|
+
|
|
136
|
+
```python
|
|
137
|
+
from npmctl_godaddy import GoDaddyClient, GoDaddyConfig
|
|
138
|
+
|
|
139
|
+
client = GoDaddyClient(GoDaddyConfig.from_env())
|
|
140
|
+
client.create_record("example.com", type="A", name="www", value="192.0.2.10", ttl=600)
|
|
141
|
+
client.replace_records(
|
|
142
|
+
"example.com",
|
|
143
|
+
type="CNAME",
|
|
144
|
+
name="app",
|
|
145
|
+
records=[{"data": "target.example.net", "ttl": 600}],
|
|
146
|
+
)
|
|
147
|
+
client.delete_records("example.com", type="A", name="www")
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Safety Notes
|
|
151
|
+
|
|
152
|
+
- GoDaddy `PUT` replaces all records for the selected `{type, name}` pair.
|
|
153
|
+
- Account-level domain locks, premium DNS status, protection settings, or product eligibility may block API changes even when credentials are valid.
|
|
154
|
+
- Use least-privilege keys where available and avoid broad automation over unrelated domains.
|
|
155
|
+
- Use npmctl owner metadata for desired DNS records so future apply support can remain owner-scoped.
|
|
156
|
+
|
|
157
|
+
## More Documentation
|
|
158
|
+
|
|
159
|
+
- Related PyPI package: https://pypi.org/project/npmctl/
|
|
160
|
+
- Repository: https://github.com/groupsum/npmctl
|
|
161
|
+
- DNS provider docs: https://github.com/groupsum/npmctl/tree/master/docs/dns-providers.md
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "npmctl-godaddy"
|
|
3
|
+
version = "0.3.6"
|
|
4
|
+
description = "GoDaddy DNS provider extension for npmctl."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.10,<3.15"
|
|
7
|
+
license = "Apache-2.0"
|
|
8
|
+
license-files = ["LICENSE"]
|
|
9
|
+
authors = [{ name = "Jacob Stewart", email = "jacob@swarmauri.com" }]
|
|
10
|
+
classifiers = [
|
|
11
|
+
"Development Status :: 1 - Planning",
|
|
12
|
+
"Intended Audience :: System Administrators",
|
|
13
|
+
"License :: OSI Approved :: Apache Software License",
|
|
14
|
+
"Programming Language :: Python :: 3",
|
|
15
|
+
"Programming Language :: Python :: 3.10",
|
|
16
|
+
"Programming Language :: Python :: 3.11",
|
|
17
|
+
"Programming Language :: Python :: 3.12",
|
|
18
|
+
"Programming Language :: Python :: 3.13",
|
|
19
|
+
"Programming Language :: Python :: 3.14",
|
|
20
|
+
"Topic :: Internet :: Name Service (DNS)",
|
|
21
|
+
"Topic :: System :: Systems Administration",
|
|
22
|
+
]
|
|
23
|
+
keywords = ["godaddy", "dns", "nginx-proxy-manager", "npmctl"]
|
|
24
|
+
dependencies = [
|
|
25
|
+
"requests>=2.32.0",
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
[project.entry-points."npmctl.dns_providers"]
|
|
29
|
+
godaddy = "npmctl_godaddy.provider:GoDaddyDnsProvider"
|
|
30
|
+
|
|
31
|
+
[project.urls]
|
|
32
|
+
Homepage = "https://github.com/groupsum/npmctl"
|
|
33
|
+
Repository = "https://github.com/groupsum/npmctl"
|
|
34
|
+
Documentation = "https://github.com/groupsum/npmctl/tree/master/packages/npmctl-godaddy"
|
|
35
|
+
Issues = "https://github.com/groupsum/npmctl/issues"
|
|
36
|
+
|
|
37
|
+
[build-system]
|
|
38
|
+
requires = ["uv-build>=0.11.8,<0.12"]
|
|
39
|
+
build-backend = "uv_build"
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"""GoDaddy DNS extension for npmctl."""
|
|
2
|
+
|
|
3
|
+
from npmctl_godaddy.client import GoDaddyClient
|
|
4
|
+
from npmctl_godaddy.config import GoDaddyConfig
|
|
5
|
+
from npmctl_godaddy.provider import GoDaddyDnsProvider
|
|
6
|
+
|
|
7
|
+
__all__ = ["GoDaddyClient", "GoDaddyConfig", "GoDaddyDnsProvider"]
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"""Small GoDaddy Domains API client."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any, Mapping
|
|
6
|
+
|
|
7
|
+
import requests
|
|
8
|
+
|
|
9
|
+
from npmctl_godaddy.config import GoDaddyConfig
|
|
10
|
+
from npmctl_godaddy.errors import GoDaddyError
|
|
11
|
+
from npmctl_godaddy.models import GoDaddyRecord
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class GoDaddyClient:
|
|
15
|
+
"""HTTP client for GoDaddy domain DNS records."""
|
|
16
|
+
|
|
17
|
+
def __init__(self, config: GoDaddyConfig, *, timeout_s: float = 15.0) -> None:
|
|
18
|
+
self.config = config
|
|
19
|
+
self.timeout_s = timeout_s
|
|
20
|
+
self.session = requests.Session()
|
|
21
|
+
|
|
22
|
+
def zones(self) -> tuple[str, ...]:
|
|
23
|
+
data = self._request("GET", "/v1/domains")
|
|
24
|
+
return tuple(sorted(str(item.get("domain", "")).lower().rstrip(".") for item in data if item.get("domain")))
|
|
25
|
+
|
|
26
|
+
def records(self, zone: str) -> tuple[GoDaddyRecord, ...]:
|
|
27
|
+
data = self._request("GET", f"/v1/domains/{_zone(zone)}/records")
|
|
28
|
+
return tuple(GoDaddyRecord.from_mapping(item) for item in data)
|
|
29
|
+
|
|
30
|
+
def records_by_name(self, zone: str, *, type: str, name: str) -> tuple[GoDaddyRecord, ...]:
|
|
31
|
+
data = self._request("GET", f"/v1/domains/{_zone(zone)}/records/{type.upper()}/{_name(name)}")
|
|
32
|
+
return tuple(GoDaddyRecord.from_mapping({**item, "type": type.upper(), "name": name}) for item in data)
|
|
33
|
+
|
|
34
|
+
def create_record(self, zone: str, *, type: str, name: str, value: str, ttl: int | None = None) -> None:
|
|
35
|
+
record: dict[str, object] = {"data": value}
|
|
36
|
+
if ttl is not None:
|
|
37
|
+
record["ttl"] = ttl
|
|
38
|
+
self.replace_records(zone, type=type, name=name, records=[record])
|
|
39
|
+
|
|
40
|
+
def replace_records(self, zone: str, *, type: str, name: str, records: list[Mapping[str, object]]) -> None:
|
|
41
|
+
payload = [_record_payload(item) for item in records]
|
|
42
|
+
self._request("PUT", f"/v1/domains/{_zone(zone)}/records/{type.upper()}/{_name(name)}", json=payload)
|
|
43
|
+
|
|
44
|
+
def delete_records(self, zone: str, *, type: str, name: str) -> None:
|
|
45
|
+
self._request("DELETE", f"/v1/domains/{_zone(zone)}/records/{type.upper()}/{_name(name)}")
|
|
46
|
+
|
|
47
|
+
def _request(self, method: str, path: str, **kwargs: Any) -> Any:
|
|
48
|
+
response = self.session.request(
|
|
49
|
+
method,
|
|
50
|
+
f"{self.config.api_base_url}{path}",
|
|
51
|
+
headers={"Authorization": f"sso-key {self.config.api_key}:{self.config.api_secret}"},
|
|
52
|
+
timeout=self.timeout_s,
|
|
53
|
+
**kwargs,
|
|
54
|
+
)
|
|
55
|
+
if response.status_code < 200 or response.status_code >= 300:
|
|
56
|
+
raise GoDaddyError(f"GoDaddy API failed: HTTP {response.status_code}")
|
|
57
|
+
if response.status_code == 204:
|
|
58
|
+
return []
|
|
59
|
+
try:
|
|
60
|
+
return response.json()
|
|
61
|
+
except ValueError as exc:
|
|
62
|
+
raise GoDaddyError("GoDaddy API returned invalid JSON") from exc
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def _record_payload(item: Mapping[str, object]) -> dict[str, object]:
|
|
66
|
+
payload = {"data": item["data"]}
|
|
67
|
+
for key in ("ttl", "priority", "port", "protocol", "service", "weight"):
|
|
68
|
+
if key in item and item[key] is not None:
|
|
69
|
+
payload[key] = item[key]
|
|
70
|
+
return payload
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def _name(name: str) -> str:
|
|
74
|
+
return name.strip().lower().rstrip(".")
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def _zone(zone: str) -> str:
|
|
78
|
+
return zone.strip().lower().rstrip(".")
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"""Configuration loading for the GoDaddy DNS provider."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
from dataclasses import dataclass
|
|
7
|
+
from typing import Mapping
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@dataclass(frozen=True, slots=True)
|
|
11
|
+
class GoDaddyConfig:
|
|
12
|
+
"""GoDaddy API configuration."""
|
|
13
|
+
|
|
14
|
+
api_key: str
|
|
15
|
+
api_secret: str
|
|
16
|
+
api_base_url: str = "https://api.godaddy.com"
|
|
17
|
+
|
|
18
|
+
@classmethod
|
|
19
|
+
def from_env(cls, env: Mapping[str, str] | None = None) -> GoDaddyConfig:
|
|
20
|
+
values = os.environ if env is None else env
|
|
21
|
+
required = {"api_key": values.get("GODADDY_API_KEY"), "api_secret": values.get("GODADDY_API_SECRET")}
|
|
22
|
+
missing = [name for name, value in required.items() if not value]
|
|
23
|
+
if missing:
|
|
24
|
+
raise ValueError(f"missing GoDaddy config: {', '.join(missing)}")
|
|
25
|
+
return cls(
|
|
26
|
+
api_key=str(required["api_key"]),
|
|
27
|
+
api_secret=str(required["api_secret"]),
|
|
28
|
+
api_base_url=values.get("GODADDY_API_BASE_URL", "https://api.godaddy.com"),
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
def redacted(self) -> dict[str, str | bool]:
|
|
32
|
+
return {"api_key": bool(self.api_key), "api_secret": bool(self.api_secret), "api_base_url": self.api_base_url}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"""GoDaddy DNS response models."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
from typing import Any, Mapping
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@dataclass(frozen=True, slots=True)
|
|
10
|
+
class GoDaddyRecord:
|
|
11
|
+
"""One GoDaddy DNS record."""
|
|
12
|
+
|
|
13
|
+
name: str
|
|
14
|
+
type: str
|
|
15
|
+
value: str
|
|
16
|
+
ttl: int | None = None
|
|
17
|
+
priority: int | None = None
|
|
18
|
+
|
|
19
|
+
@classmethod
|
|
20
|
+
def from_mapping(cls, raw: Mapping[str, Any]) -> GoDaddyRecord:
|
|
21
|
+
return cls(
|
|
22
|
+
name=str(raw.get("name", "")).lower().rstrip("."),
|
|
23
|
+
type=str(raw.get("type", "")).upper(),
|
|
24
|
+
value=str(raw.get("data", "")),
|
|
25
|
+
ttl=_optional_int(raw.get("ttl")),
|
|
26
|
+
priority=_optional_int(raw.get("priority")),
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
def to_dict(self) -> dict[str, str | int | None]:
|
|
30
|
+
return {
|
|
31
|
+
"id": None,
|
|
32
|
+
"name": self.name,
|
|
33
|
+
"type": self.type,
|
|
34
|
+
"value": self.value,
|
|
35
|
+
"ttl": self.ttl,
|
|
36
|
+
"priority": self.priority,
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _optional_int(value: Any) -> int | None:
|
|
41
|
+
if value in (None, ""):
|
|
42
|
+
return None
|
|
43
|
+
return int(value)
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"""npmctl DNS provider implementation for GoDaddy."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from npmctl_godaddy.client import GoDaddyClient
|
|
6
|
+
from npmctl_godaddy.config import GoDaddyConfig
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class GoDaddyDnsProvider:
|
|
10
|
+
"""DNS provider backed by the GoDaddy Domains API."""
|
|
11
|
+
|
|
12
|
+
name = "godaddy"
|
|
13
|
+
|
|
14
|
+
def __init__(self, client: GoDaddyClient | None = None) -> None:
|
|
15
|
+
self._client = client
|
|
16
|
+
|
|
17
|
+
@property
|
|
18
|
+
def client(self) -> GoDaddyClient:
|
|
19
|
+
if self._client is None:
|
|
20
|
+
self._client = GoDaddyClient(GoDaddyConfig.from_env())
|
|
21
|
+
return self._client
|
|
22
|
+
|
|
23
|
+
def zones(self) -> tuple[str, ...]:
|
|
24
|
+
return self.client.zones()
|
|
25
|
+
|
|
26
|
+
def records(self, zone: str) -> tuple[dict[str, object], ...]:
|
|
27
|
+
return tuple(record.to_dict() for record in self.client.records(zone))
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|