cacholong-cloud-cli 0.3.0__py3-none-any.whl
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.
- cacholong_cli/AsyncTyper.py +17 -0
- cacholong_cli/__init__.py +0 -0
- cacholong_cli/cli.py +110 -0
- cacholong_cli/commands/accounts.py +105 -0
- cacholong_cli/commands/addresses.py +280 -0
- cacholong_cli/commands/companies.py +100 -0
- cacholong_cli/commands/dns_records.py +275 -0
- cacholong_cli/commands/dns_templates.py +141 -0
- cacholong_cli/commands/dns_zones.py +277 -0
- cacholong_cli/commands/products.py +121 -0
- cacholong_cli/commands/purchases.py +127 -0
- cacholong_cli/common.py +179 -0
- cacholong_cli/connection.py +18 -0
- cacholong_cloud_cli-0.3.0.dist-info/METADATA +115 -0
- cacholong_cloud_cli-0.3.0.dist-info/RECORD +39 -0
- cacholong_cloud_cli-0.3.0.dist-info/WHEEL +4 -0
- cacholong_cloud_cli-0.3.0.dist-info/entry_points.txt +3 -0
- cacholong_sdk/__init__.py +18 -0
- cacholong_sdk/account.py +14 -0
- cacholong_sdk/address.py +14 -0
- cacholong_sdk/api_schema.py +124 -0
- cacholong_sdk/common.py +119 -0
- cacholong_sdk/company.py +14 -0
- cacholong_sdk/connection.py +22 -0
- cacholong_sdk/dns_record.py +14 -0
- cacholong_sdk/dns_template.py +14 -0
- cacholong_sdk/dns_zone.py +14 -0
- cacholong_sdk/exception.py +7 -0
- cacholong_sdk/product.py +14 -0
- cacholong_sdk/purchase.py +14 -0
- jsonapi_client/__init__.py +42 -0
- jsonapi_client/common.py +186 -0
- jsonapi_client/document.py +161 -0
- jsonapi_client/exceptions.py +62 -0
- jsonapi_client/filter.py +155 -0
- jsonapi_client/objects.py +187 -0
- jsonapi_client/relationships.py +447 -0
- jsonapi_client/resourceobject.py +656 -0
- jsonapi_client/session.py +755 -0
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import typer
|
|
3
|
+
from typing import List, Optional
|
|
4
|
+
from typing_extensions import Annotated
|
|
5
|
+
from rich.table import Column
|
|
6
|
+
from uuid import UUID
|
|
7
|
+
from cacholong_cli.AsyncTyper import AsyncTyper
|
|
8
|
+
from cacholong_cli.common import (
|
|
9
|
+
list_resources,
|
|
10
|
+
list_relation_resources,
|
|
11
|
+
show_resource,
|
|
12
|
+
print_document_error,
|
|
13
|
+
)
|
|
14
|
+
from cacholong_cli.connection import Connection
|
|
15
|
+
from cacholong_sdk import Filter, Inclusion, DocumentError, ResourceTuple
|
|
16
|
+
from cacholong_sdk import DnsRecord, DnsRecordModel
|
|
17
|
+
|
|
18
|
+
# Create typer object
|
|
19
|
+
app = AsyncTyper()
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@app.async_command()
|
|
23
|
+
async def list(
|
|
24
|
+
ctx: typer.Context,
|
|
25
|
+
external_service_provider_status: Annotated[
|
|
26
|
+
Optional[str], typer.Option(help="Status for external service provider.")
|
|
27
|
+
] = None,
|
|
28
|
+
dns_record_type: Annotated[
|
|
29
|
+
Optional[str],
|
|
30
|
+
typer.Option(
|
|
31
|
+
help="Depending on DNS record type name, content, ttl and priority will be validated. Only record types mentioned are allowed and NS record type is only available for certain users."
|
|
32
|
+
),
|
|
33
|
+
] = None,
|
|
34
|
+
name: Annotated[
|
|
35
|
+
Optional[str],
|
|
36
|
+
typer.Option(
|
|
37
|
+
help="For most records this must be a valid domain (SRV, TLSA and NS records follow different rules). When dns template is given, placeholder $domain$ must be used. When dns zone is given, name must be identical to dns zone domain fqdn. It is not allowed to end the name with a point."
|
|
38
|
+
),
|
|
39
|
+
] = None,
|
|
40
|
+
content: Annotated[
|
|
41
|
+
Optional[str],
|
|
42
|
+
typer.Option(
|
|
43
|
+
help="Content differs for each DNS record type. When dns template is given, placeholder $domain$ is allowed for some records (for example CAA or CNAME records). Only TXT records can be longer then 255 chars."
|
|
44
|
+
),
|
|
45
|
+
] = None,
|
|
46
|
+
ttl: Annotated[
|
|
47
|
+
Optional[str],
|
|
48
|
+
typer.Option(
|
|
49
|
+
help='Time to live in seconds, limited to allowed values. Please note that a TTL of 1 (one) can have a special meaning (Cloudflare considers this value "automatic").'
|
|
50
|
+
),
|
|
51
|
+
] = None,
|
|
52
|
+
priority: Annotated[
|
|
53
|
+
Optional[str], typer.Option(help="Prohibited, except for MX and SRV record.")
|
|
54
|
+
] = None,
|
|
55
|
+
created_at: Annotated[Optional[str], typer.Option(help="")] = None,
|
|
56
|
+
updated_at: Annotated[Optional[str], typer.Option(help="")] = None,
|
|
57
|
+
dns_zone: Annotated[
|
|
58
|
+
Optional[UUID],
|
|
59
|
+
typer.Option(
|
|
60
|
+
help="Existing dns zone. Required unless dns template is given. Only available for certain users, dnz zone should not be administratively disabled. Must be unique with type, name, content and priority."
|
|
61
|
+
),
|
|
62
|
+
] = None,
|
|
63
|
+
dns_template: Annotated[
|
|
64
|
+
Optional[UUID],
|
|
65
|
+
typer.Option(
|
|
66
|
+
help="Existing dns template. Required unless dns zone is given. Must be unique with type, name, content and priority."
|
|
67
|
+
),
|
|
68
|
+
] = None,
|
|
69
|
+
):
|
|
70
|
+
# Build modifier
|
|
71
|
+
modifier = []
|
|
72
|
+
if external_service_provider_status is not None:
|
|
73
|
+
modifier.append(
|
|
74
|
+
Filter(
|
|
75
|
+
query_str="filter[external_service_provider_status]="
|
|
76
|
+
+ str(external_service_provider_status)
|
|
77
|
+
)
|
|
78
|
+
)
|
|
79
|
+
if dns_record_type is not None:
|
|
80
|
+
modifier.append(
|
|
81
|
+
Filter(query_str="filter[dns_record_type]=" + str(dns_record_type))
|
|
82
|
+
)
|
|
83
|
+
if name is not None:
|
|
84
|
+
modifier.append(Filter(name=name))
|
|
85
|
+
if content is not None:
|
|
86
|
+
modifier.append(Filter(content=content))
|
|
87
|
+
if ttl is not None:
|
|
88
|
+
modifier.append(Filter(ttl=ttl))
|
|
89
|
+
if priority is not None:
|
|
90
|
+
modifier.append(Filter(priority=priority))
|
|
91
|
+
if created_at is not None:
|
|
92
|
+
modifier.append(Filter(query_str="filter[created_at]=" + str(created_at)))
|
|
93
|
+
if updated_at is not None:
|
|
94
|
+
modifier.append(Filter(query_str="filter[updated_at]=" + str(updated_at)))
|
|
95
|
+
if dns_zone is not None:
|
|
96
|
+
modifier.append(Filter(query_str="filter[dns-zone]=" + str(dns_zone)))
|
|
97
|
+
if dns_template is not None:
|
|
98
|
+
modifier.append(Filter(query_str="filter[dns-template]=" + str(dns_template)))
|
|
99
|
+
|
|
100
|
+
# Table definition
|
|
101
|
+
tabledef = [
|
|
102
|
+
{"header": Column("Id", no_wrap=True), "column": "id"},
|
|
103
|
+
{"header": "Name", "column": "name"},
|
|
104
|
+
{"header": "Dns record type", "column": "dns_record_type"},
|
|
105
|
+
{"header": "Content", "column": "content"},
|
|
106
|
+
{
|
|
107
|
+
"header": "External service provider status",
|
|
108
|
+
"column": "external_service_provider_status",
|
|
109
|
+
},
|
|
110
|
+
{"header": "Created", "column": "created_at"},
|
|
111
|
+
{"header": "Updated", "column": "updated_at"},
|
|
112
|
+
]
|
|
113
|
+
async with Connection() as conn:
|
|
114
|
+
await list_resources(ctx, DnsRecord(conn), tabledef, modifier)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
@app.async_command()
|
|
118
|
+
async def show(
|
|
119
|
+
ctx: typer.Context,
|
|
120
|
+
dns_record_id: Annotated[UUID, typer.Argument()],
|
|
121
|
+
):
|
|
122
|
+
# Show resource
|
|
123
|
+
try:
|
|
124
|
+
async with Connection() as conn:
|
|
125
|
+
ctrl = DnsRecord(conn)
|
|
126
|
+
model = await ctrl.fetch(dns_record_id)
|
|
127
|
+
|
|
128
|
+
show_resource(ctx, model)
|
|
129
|
+
except DocumentError as e:
|
|
130
|
+
await print_document_error(e)
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
@app.async_command()
|
|
134
|
+
async def create(
|
|
135
|
+
ctx: typer.Context,
|
|
136
|
+
dns_record_type: Annotated[
|
|
137
|
+
str,
|
|
138
|
+
typer.Option(
|
|
139
|
+
help="Depending on DNS record type name, content, ttl and priority will be validated. Only record types mentioned are allowed and NS record type is only available for certain users."
|
|
140
|
+
),
|
|
141
|
+
],
|
|
142
|
+
name: Annotated[
|
|
143
|
+
str,
|
|
144
|
+
typer.Option(
|
|
145
|
+
help="For most records this must be a valid domain (SRV, TLSA and NS records follow different rules). When dns template is given, placeholder $domain$ must be used. When dns zone is given, name must be identical to dns zone domain fqdn. It is not allowed to end the name with a point."
|
|
146
|
+
),
|
|
147
|
+
],
|
|
148
|
+
content: Annotated[
|
|
149
|
+
str,
|
|
150
|
+
typer.Option(
|
|
151
|
+
help="Content differs for each DNS record type. When dns template is given, placeholder $domain$ is allowed for some records (for example CAA or CNAME records). Only TXT records can be longer then 255 chars."
|
|
152
|
+
),
|
|
153
|
+
],
|
|
154
|
+
ttl: Annotated[
|
|
155
|
+
Optional[int],
|
|
156
|
+
typer.Option(
|
|
157
|
+
help='Time to live in seconds, limited to allowed values. Please note that a TTL of 1 (one) can have a special meaning (Cloudflare considers this value "automatic").'
|
|
158
|
+
),
|
|
159
|
+
] = None,
|
|
160
|
+
priority: Annotated[
|
|
161
|
+
Optional[int], typer.Option(help="Prohibited, except for MX and SRV record.")
|
|
162
|
+
] = None,
|
|
163
|
+
dns_zone: Annotated[
|
|
164
|
+
Optional[UUID],
|
|
165
|
+
typer.Option(
|
|
166
|
+
help="Existing dns zone. Required unless dns template is given. Only available for certain users, dnz zone should not be administratively disabled. Must be unique with type, name, content and priority."
|
|
167
|
+
),
|
|
168
|
+
] = None,
|
|
169
|
+
dns_template: Annotated[
|
|
170
|
+
Optional[UUID],
|
|
171
|
+
typer.Option(
|
|
172
|
+
help="Existing dns template. Required unless dns zone is given. Must be unique with type, name, content and priority."
|
|
173
|
+
),
|
|
174
|
+
] = None,
|
|
175
|
+
):
|
|
176
|
+
try:
|
|
177
|
+
async with Connection() as conn:
|
|
178
|
+
ctrl = DnsRecord(conn)
|
|
179
|
+
model = ctrl.create()
|
|
180
|
+
model["dns_record_type"] = dns_record_type
|
|
181
|
+
model["name"] = name
|
|
182
|
+
model["content"] = content
|
|
183
|
+
if ttl is not None:
|
|
184
|
+
model["ttl"] = ttl
|
|
185
|
+
if priority is not None:
|
|
186
|
+
model["priority"] = priority
|
|
187
|
+
if dns_zone is not None:
|
|
188
|
+
model["dns-zone"] = ResourceTuple(dns_zone, "dns-zones")
|
|
189
|
+
if dns_template is not None:
|
|
190
|
+
model["dns-template"] = ResourceTuple(dns_template, "dns-templates")
|
|
191
|
+
await ctrl.store(model, ctx.obj["create_issue"])
|
|
192
|
+
|
|
193
|
+
show_resource(ctx, model)
|
|
194
|
+
except DocumentError as e:
|
|
195
|
+
await print_document_error(e)
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
@app.async_command()
|
|
199
|
+
async def update(
|
|
200
|
+
ctx: typer.Context,
|
|
201
|
+
dns_record_id: Annotated[UUID, typer.Argument()],
|
|
202
|
+
dns_record_type: Annotated[
|
|
203
|
+
Optional[str],
|
|
204
|
+
typer.Option(
|
|
205
|
+
help="Depending on DNS record type name, content, ttl and priority will be validated. Only record types mentioned are allowed and NS record type is only available for certain users."
|
|
206
|
+
),
|
|
207
|
+
] = None,
|
|
208
|
+
name: Annotated[
|
|
209
|
+
Optional[str],
|
|
210
|
+
typer.Option(
|
|
211
|
+
help="For most records this must be a valid domain (SRV, TLSA and NS records follow different rules). When dns template is given, placeholder $domain$ must be used. When dns zone is given, name must be identical to dns zone domain fqdn. It is not allowed to end the name with a point."
|
|
212
|
+
),
|
|
213
|
+
] = None,
|
|
214
|
+
content: Annotated[
|
|
215
|
+
Optional[str],
|
|
216
|
+
typer.Option(
|
|
217
|
+
help="Content differs for each DNS record type. When dns template is given, placeholder $domain$ is allowed for some records (for example CAA or CNAME records). Only TXT records can be longer then 255 chars."
|
|
218
|
+
),
|
|
219
|
+
] = None,
|
|
220
|
+
ttl: Annotated[
|
|
221
|
+
Optional[int],
|
|
222
|
+
typer.Option(
|
|
223
|
+
help='Time to live in seconds, limited to allowed values. Please note that a TTL of 1 (one) can have a special meaning (Cloudflare considers this value "automatic").'
|
|
224
|
+
),
|
|
225
|
+
] = None,
|
|
226
|
+
priority: Annotated[
|
|
227
|
+
Optional[int], typer.Option(help="Prohibited, except for MX and SRV record.")
|
|
228
|
+
] = None,
|
|
229
|
+
dns_zone: Annotated[
|
|
230
|
+
Optional[UUID],
|
|
231
|
+
typer.Option(
|
|
232
|
+
help="Existing dns zone. Required unless dns template is given. Only available for certain users, dnz zone should not be administratively disabled. Must be unique with type, name, content and priority."
|
|
233
|
+
),
|
|
234
|
+
] = None,
|
|
235
|
+
dns_template: Annotated[
|
|
236
|
+
Optional[UUID],
|
|
237
|
+
typer.Option(
|
|
238
|
+
help="Existing dns template. Required unless dns zone is given. Must be unique with type, name, content and priority."
|
|
239
|
+
),
|
|
240
|
+
] = None,
|
|
241
|
+
):
|
|
242
|
+
try:
|
|
243
|
+
async with Connection() as conn:
|
|
244
|
+
ctrl = DnsRecord(conn)
|
|
245
|
+
model = await ctrl.fetch(dns_record_id)
|
|
246
|
+
if dns_record_type is not None:
|
|
247
|
+
model["dns_record_type"] = dns_record_type
|
|
248
|
+
if name is not None:
|
|
249
|
+
model["name"] = name
|
|
250
|
+
if content is not None:
|
|
251
|
+
model["content"] = content
|
|
252
|
+
if ttl is not None:
|
|
253
|
+
model["ttl"] = ttl
|
|
254
|
+
if priority is not None:
|
|
255
|
+
model["priority"] = priority
|
|
256
|
+
if dns_zone is not None:
|
|
257
|
+
model["dns-zone"].set(dns_zone, "dns-zones")
|
|
258
|
+
if dns_template is not None:
|
|
259
|
+
model["dns-template"].set(dns_template, "dns-templates")
|
|
260
|
+
except DocumentError as e:
|
|
261
|
+
await print_document_error(e)
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
@app.async_command()
|
|
265
|
+
async def delete(
|
|
266
|
+
ctx: typer.Context,
|
|
267
|
+
dns_record_id: Annotated[List[UUID], typer.Argument()],
|
|
268
|
+
):
|
|
269
|
+
try:
|
|
270
|
+
async with Connection() as conn, asyncio.TaskGroup() as tg:
|
|
271
|
+
ctrl = DnsRecord(conn)
|
|
272
|
+
for resource_id in dns_record_id:
|
|
273
|
+
tg.create_task(ctrl.destroy(resource_id))
|
|
274
|
+
except DocumentError as e:
|
|
275
|
+
await print_document_error(e)
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import typer
|
|
3
|
+
from typing import List, Optional
|
|
4
|
+
from typing_extensions import Annotated
|
|
5
|
+
from rich.table import Column
|
|
6
|
+
from uuid import UUID
|
|
7
|
+
from cacholong_cli.AsyncTyper import AsyncTyper
|
|
8
|
+
from cacholong_cli.common import (
|
|
9
|
+
list_resources,
|
|
10
|
+
list_relation_resources,
|
|
11
|
+
show_resource,
|
|
12
|
+
print_document_error,
|
|
13
|
+
)
|
|
14
|
+
from cacholong_cli.connection import Connection
|
|
15
|
+
from cacholong_sdk import Filter, Inclusion, DocumentError, ResourceTuple
|
|
16
|
+
from cacholong_sdk import DnsTemplate, DnsTemplateModel
|
|
17
|
+
|
|
18
|
+
# Create typer object
|
|
19
|
+
app = AsyncTyper()
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@app.async_command()
|
|
23
|
+
async def list(
|
|
24
|
+
ctx: typer.Context,
|
|
25
|
+
name: Annotated[
|
|
26
|
+
Optional[str], typer.Option(help="Must be unique or unique with given account.")
|
|
27
|
+
] = None,
|
|
28
|
+
created_at: Annotated[Optional[str], typer.Option(help="")] = None,
|
|
29
|
+
updated_at: Annotated[Optional[str], typer.Option(help="")] = None,
|
|
30
|
+
account: Annotated[
|
|
31
|
+
Optional[UUID],
|
|
32
|
+
typer.Option(
|
|
33
|
+
help="Existing account. Some users can set this to null, meaning template is not limited to an account."
|
|
34
|
+
),
|
|
35
|
+
] = None,
|
|
36
|
+
):
|
|
37
|
+
# Build modifier
|
|
38
|
+
modifier = []
|
|
39
|
+
if name is not None:
|
|
40
|
+
modifier.append(Filter(name=name))
|
|
41
|
+
if created_at is not None:
|
|
42
|
+
modifier.append(Filter(query_str="filter[created_at]=" + str(created_at)))
|
|
43
|
+
if updated_at is not None:
|
|
44
|
+
modifier.append(Filter(query_str="filter[updated_at]=" + str(updated_at)))
|
|
45
|
+
if account is not None:
|
|
46
|
+
modifier.append(Filter(account=str(account)))
|
|
47
|
+
modifier.append(Inclusion("account"))
|
|
48
|
+
|
|
49
|
+
# Table definition
|
|
50
|
+
tabledef = [
|
|
51
|
+
{"header": Column("Id", no_wrap=True), "column": "id"},
|
|
52
|
+
{"header": "Account", "column": "account", "nested_column": "name"},
|
|
53
|
+
{"header": "Name", "column": "name"},
|
|
54
|
+
{"header": "Created", "column": "created_at"},
|
|
55
|
+
{"header": "Updated", "column": "updated_at"},
|
|
56
|
+
]
|
|
57
|
+
async with Connection() as conn:
|
|
58
|
+
await list_resources(ctx, DnsTemplate(conn), tabledef, modifier)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
@app.async_command()
|
|
62
|
+
async def show(
|
|
63
|
+
ctx: typer.Context,
|
|
64
|
+
dns_template_id: Annotated[UUID, typer.Argument()],
|
|
65
|
+
):
|
|
66
|
+
# Show resource
|
|
67
|
+
try:
|
|
68
|
+
async with Connection() as conn:
|
|
69
|
+
ctrl = DnsTemplate(conn)
|
|
70
|
+
model = await ctrl.fetch(dns_template_id)
|
|
71
|
+
|
|
72
|
+
show_resource(ctx, model)
|
|
73
|
+
except DocumentError as e:
|
|
74
|
+
await print_document_error(e)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
@app.async_command()
|
|
78
|
+
async def create(
|
|
79
|
+
ctx: typer.Context,
|
|
80
|
+
name: Annotated[
|
|
81
|
+
str, typer.Option(help="Must be unique or unique with given account.")
|
|
82
|
+
],
|
|
83
|
+
account: Annotated[
|
|
84
|
+
Optional[UUID],
|
|
85
|
+
typer.Option(
|
|
86
|
+
help="Existing account. Some users can set this to null, meaning template is not limited to an account."
|
|
87
|
+
),
|
|
88
|
+
] = None,
|
|
89
|
+
):
|
|
90
|
+
try:
|
|
91
|
+
async with Connection() as conn:
|
|
92
|
+
ctrl = DnsTemplate(conn)
|
|
93
|
+
model = ctrl.create()
|
|
94
|
+
model["name"] = name
|
|
95
|
+
if account is not None:
|
|
96
|
+
model["account"] = ResourceTuple(account, "accounts")
|
|
97
|
+
await ctrl.store(model, ctx.obj["create_issue"])
|
|
98
|
+
|
|
99
|
+
show_resource(ctx, model)
|
|
100
|
+
except DocumentError as e:
|
|
101
|
+
await print_document_error(e)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
@app.async_command()
|
|
105
|
+
async def update(
|
|
106
|
+
ctx: typer.Context,
|
|
107
|
+
dns_template_id: Annotated[UUID, typer.Argument()],
|
|
108
|
+
name: Annotated[
|
|
109
|
+
Optional[str], typer.Option(help="Must be unique or unique with given account.")
|
|
110
|
+
] = None,
|
|
111
|
+
account: Annotated[
|
|
112
|
+
Optional[UUID],
|
|
113
|
+
typer.Option(
|
|
114
|
+
help="Existing account. Some users can set this to null, meaning template is not limited to an account."
|
|
115
|
+
),
|
|
116
|
+
] = None,
|
|
117
|
+
):
|
|
118
|
+
try:
|
|
119
|
+
async with Connection() as conn:
|
|
120
|
+
ctrl = DnsTemplate(conn)
|
|
121
|
+
model = await ctrl.fetch(dns_template_id)
|
|
122
|
+
if name is not None:
|
|
123
|
+
model["name"] = name
|
|
124
|
+
if account is not None:
|
|
125
|
+
model["account"].set(account, "accounts")
|
|
126
|
+
except DocumentError as e:
|
|
127
|
+
await print_document_error(e)
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
@app.async_command()
|
|
131
|
+
async def delete(
|
|
132
|
+
ctx: typer.Context,
|
|
133
|
+
dns_template_id: Annotated[List[UUID], typer.Argument()],
|
|
134
|
+
):
|
|
135
|
+
try:
|
|
136
|
+
async with Connection() as conn, asyncio.TaskGroup() as tg:
|
|
137
|
+
ctrl = DnsTemplate(conn)
|
|
138
|
+
for resource_id in dns_template_id:
|
|
139
|
+
tg.create_task(ctrl.destroy(resource_id))
|
|
140
|
+
except DocumentError as e:
|
|
141
|
+
await print_document_error(e)
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import typer
|
|
3
|
+
from typing import List, Optional
|
|
4
|
+
from typing_extensions import Annotated
|
|
5
|
+
from rich.table import Column
|
|
6
|
+
from uuid import UUID
|
|
7
|
+
from cacholong_cli.AsyncTyper import AsyncTyper
|
|
8
|
+
from cacholong_cli.common import (
|
|
9
|
+
list_resources,
|
|
10
|
+
list_relation_resources,
|
|
11
|
+
show_resource,
|
|
12
|
+
print_document_error,
|
|
13
|
+
)
|
|
14
|
+
from cacholong_cli.connection import Connection
|
|
15
|
+
from cacholong_sdk import Filter, Inclusion, DocumentError, ResourceTuple
|
|
16
|
+
from cacholong_sdk import DnsZone, DnsZoneModel
|
|
17
|
+
|
|
18
|
+
# Create typer object
|
|
19
|
+
app = AsyncTyper()
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@app.async_command()
|
|
23
|
+
async def list(
|
|
24
|
+
ctx: typer.Context,
|
|
25
|
+
external_service_provider_status: Annotated[
|
|
26
|
+
Optional[str], typer.Option(help="Status for external service provider.")
|
|
27
|
+
] = None,
|
|
28
|
+
domain: Annotated[
|
|
29
|
+
Optional[str],
|
|
30
|
+
typer.Option(
|
|
31
|
+
help="Valid when provided with a domain and TLD (without a protocol)."
|
|
32
|
+
),
|
|
33
|
+
] = None,
|
|
34
|
+
active: Annotated[
|
|
35
|
+
Optional[str], typer.Option(help="Is dns zone active or not?")
|
|
36
|
+
] = None,
|
|
37
|
+
administratively_disabled: Annotated[
|
|
38
|
+
Optional[str],
|
|
39
|
+
typer.Option(
|
|
40
|
+
help="Is dns zone administratively disabled or not? Only visible for certain users."
|
|
41
|
+
),
|
|
42
|
+
] = None,
|
|
43
|
+
dnssec: Annotated[
|
|
44
|
+
Optional[str], typer.Option(help="Is dnssec enabled or not?")
|
|
45
|
+
] = None,
|
|
46
|
+
dnssec_status: Annotated[
|
|
47
|
+
Optional[str], typer.Option(help="Status of DNSSEC.")
|
|
48
|
+
] = None,
|
|
49
|
+
dnssec_flags: Annotated[
|
|
50
|
+
Optional[str], typer.Option(help="Flag for DNSSEC record.")
|
|
51
|
+
] = None,
|
|
52
|
+
dnssec_algorithm: Annotated[
|
|
53
|
+
Optional[str], typer.Option(help="Algorithm key code.")
|
|
54
|
+
] = None,
|
|
55
|
+
dnssec_public_key: Annotated[
|
|
56
|
+
Optional[str], typer.Option(help="Public key for DS record.")
|
|
57
|
+
] = None,
|
|
58
|
+
created_at: Annotated[Optional[str], typer.Option(help="")] = None,
|
|
59
|
+
updated_at: Annotated[Optional[str], typer.Option(help="")] = None,
|
|
60
|
+
account: Annotated[
|
|
61
|
+
Optional[UUID], typer.Option(help="Account for this dns zone.")
|
|
62
|
+
] = None,
|
|
63
|
+
name_server_group: Annotated[
|
|
64
|
+
Optional[UUID],
|
|
65
|
+
typer.Option(help="Name server groups for this dns zone. Readonly."),
|
|
66
|
+
] = None,
|
|
67
|
+
purchase: Annotated[
|
|
68
|
+
Optional[UUID],
|
|
69
|
+
typer.Option(
|
|
70
|
+
help="Purchase for this dns zone. Required if no product is provided."
|
|
71
|
+
),
|
|
72
|
+
] = None,
|
|
73
|
+
product: Annotated[
|
|
74
|
+
Optional[UUID],
|
|
75
|
+
typer.Option(
|
|
76
|
+
help="Product for this dns zone. Required if no purchase is provided."
|
|
77
|
+
),
|
|
78
|
+
] = None,
|
|
79
|
+
):
|
|
80
|
+
# Build modifier
|
|
81
|
+
modifier = []
|
|
82
|
+
if external_service_provider_status is not None:
|
|
83
|
+
modifier.append(
|
|
84
|
+
Filter(
|
|
85
|
+
query_str="filter[external_service_provider_status]="
|
|
86
|
+
+ str(external_service_provider_status)
|
|
87
|
+
)
|
|
88
|
+
)
|
|
89
|
+
if domain is not None:
|
|
90
|
+
modifier.append(Filter(domain=domain))
|
|
91
|
+
if active is not None:
|
|
92
|
+
modifier.append(Filter(active=active))
|
|
93
|
+
if administratively_disabled is not None:
|
|
94
|
+
modifier.append(
|
|
95
|
+
Filter(
|
|
96
|
+
query_str="filter[administratively_disabled]="
|
|
97
|
+
+ str(administratively_disabled)
|
|
98
|
+
)
|
|
99
|
+
)
|
|
100
|
+
if dnssec is not None:
|
|
101
|
+
modifier.append(Filter(dnssec=dnssec))
|
|
102
|
+
if dnssec_status is not None:
|
|
103
|
+
modifier.append(Filter(query_str="filter[dnssec_status]=" + str(dnssec_status)))
|
|
104
|
+
if dnssec_flags is not None:
|
|
105
|
+
modifier.append(Filter(query_str="filter[dnssec_flags]=" + str(dnssec_flags)))
|
|
106
|
+
if dnssec_algorithm is not None:
|
|
107
|
+
modifier.append(
|
|
108
|
+
Filter(query_str="filter[dnssec_algorithm]=" + str(dnssec_algorithm))
|
|
109
|
+
)
|
|
110
|
+
if dnssec_public_key is not None:
|
|
111
|
+
modifier.append(
|
|
112
|
+
Filter(query_str="filter[dnssec_public_key]=" + str(dnssec_public_key))
|
|
113
|
+
)
|
|
114
|
+
if created_at is not None:
|
|
115
|
+
modifier.append(Filter(query_str="filter[created_at]=" + str(created_at)))
|
|
116
|
+
if updated_at is not None:
|
|
117
|
+
modifier.append(Filter(query_str="filter[updated_at]=" + str(updated_at)))
|
|
118
|
+
if account is not None:
|
|
119
|
+
modifier.append(Filter(account=str(account)))
|
|
120
|
+
if name_server_group is not None:
|
|
121
|
+
modifier.append(
|
|
122
|
+
Filter(query_str="filter[name-server-group]=" + str(name_server_group))
|
|
123
|
+
)
|
|
124
|
+
if purchase is not None:
|
|
125
|
+
modifier.append(Filter(purchase=str(purchase)))
|
|
126
|
+
if product is not None:
|
|
127
|
+
modifier.append(Filter(product=str(product)))
|
|
128
|
+
modifier.append(Inclusion("account"))
|
|
129
|
+
|
|
130
|
+
# Table definition
|
|
131
|
+
tabledef = [
|
|
132
|
+
{"header": Column("Id", no_wrap=True), "column": "id"},
|
|
133
|
+
{"header": "Account", "column": "account", "nested_column": "name"},
|
|
134
|
+
{"header": "Domain", "column": "domain"},
|
|
135
|
+
{"header": "Active", "column": "active"},
|
|
136
|
+
{"header": "Dnssec", "column": "dnssec"},
|
|
137
|
+
{
|
|
138
|
+
"header": "External service provider status",
|
|
139
|
+
"column": "external_service_provider_status",
|
|
140
|
+
},
|
|
141
|
+
{"header": "Created", "column": "created_at"},
|
|
142
|
+
{"header": "Updated", "column": "updated_at"},
|
|
143
|
+
]
|
|
144
|
+
async with Connection() as conn:
|
|
145
|
+
await list_resources(ctx, DnsZone(conn), tabledef, modifier)
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
@app.async_command()
|
|
149
|
+
async def show(
|
|
150
|
+
ctx: typer.Context,
|
|
151
|
+
dns_zone_id: Annotated[UUID, typer.Argument()],
|
|
152
|
+
):
|
|
153
|
+
# Show resource
|
|
154
|
+
try:
|
|
155
|
+
async with Connection() as conn:
|
|
156
|
+
ctrl = DnsZone(conn)
|
|
157
|
+
model = await ctrl.fetch(dns_zone_id)
|
|
158
|
+
|
|
159
|
+
show_resource(ctx, model)
|
|
160
|
+
except DocumentError as e:
|
|
161
|
+
await print_document_error(e)
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
@app.async_command()
|
|
165
|
+
async def create(
|
|
166
|
+
ctx: typer.Context,
|
|
167
|
+
domain: Annotated[
|
|
168
|
+
str,
|
|
169
|
+
typer.Option(
|
|
170
|
+
help="Valid when provided with a domain and TLD (without a protocol)."
|
|
171
|
+
),
|
|
172
|
+
],
|
|
173
|
+
account: Annotated[UUID, typer.Option(help="Account for this dns zone.")],
|
|
174
|
+
active: Annotated[
|
|
175
|
+
Optional[bool], typer.Option(help="Is dns zone active or not?")
|
|
176
|
+
] = None,
|
|
177
|
+
dnssec: Annotated[
|
|
178
|
+
Optional[bool], typer.Option(help="Is dnssec enabled or not?")
|
|
179
|
+
] = None,
|
|
180
|
+
purchase: Annotated[
|
|
181
|
+
Optional[UUID],
|
|
182
|
+
typer.Option(
|
|
183
|
+
help="Purchase for this dns zone. Required if no product is provided."
|
|
184
|
+
),
|
|
185
|
+
] = None,
|
|
186
|
+
product: Annotated[
|
|
187
|
+
Optional[UUID],
|
|
188
|
+
typer.Option(
|
|
189
|
+
help="Product for this dns zone. Required if no purchase is provided."
|
|
190
|
+
),
|
|
191
|
+
] = None,
|
|
192
|
+
):
|
|
193
|
+
try:
|
|
194
|
+
async with Connection() as conn:
|
|
195
|
+
ctrl = DnsZone(conn)
|
|
196
|
+
model = ctrl.create()
|
|
197
|
+
model["domain"] = domain
|
|
198
|
+
if active is not None:
|
|
199
|
+
model["active"] = active
|
|
200
|
+
if dnssec is not None:
|
|
201
|
+
model["dnssec"] = dnssec
|
|
202
|
+
model["account"] = ResourceTuple(account, "accounts")
|
|
203
|
+
if purchase is not None:
|
|
204
|
+
model["purchase"] = ResourceTuple(purchase, "purchases")
|
|
205
|
+
if product is not None:
|
|
206
|
+
model["product"] = ResourceTuple(product, "products")
|
|
207
|
+
await ctrl.store(model, ctx.obj["create_issue"])
|
|
208
|
+
|
|
209
|
+
show_resource(ctx, model)
|
|
210
|
+
except DocumentError as e:
|
|
211
|
+
await print_document_error(e)
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
@app.async_command()
|
|
215
|
+
async def update(
|
|
216
|
+
ctx: typer.Context,
|
|
217
|
+
dns_zone_id: Annotated[UUID, typer.Argument()],
|
|
218
|
+
domain: Annotated[
|
|
219
|
+
Optional[str],
|
|
220
|
+
typer.Option(
|
|
221
|
+
help="Valid when provided with a domain and TLD (without a protocol)."
|
|
222
|
+
),
|
|
223
|
+
] = None,
|
|
224
|
+
active: Annotated[
|
|
225
|
+
Optional[bool], typer.Option(help="Is dns zone active or not?")
|
|
226
|
+
] = None,
|
|
227
|
+
dnssec: Annotated[
|
|
228
|
+
Optional[bool], typer.Option(help="Is dnssec enabled or not?")
|
|
229
|
+
] = None,
|
|
230
|
+
account: Annotated[
|
|
231
|
+
Optional[UUID], typer.Option(help="Account for this dns zone.")
|
|
232
|
+
] = None,
|
|
233
|
+
purchase: Annotated[
|
|
234
|
+
Optional[UUID],
|
|
235
|
+
typer.Option(
|
|
236
|
+
help="Purchase for this dns zone. Required if no product is provided."
|
|
237
|
+
),
|
|
238
|
+
] = None,
|
|
239
|
+
product: Annotated[
|
|
240
|
+
Optional[UUID],
|
|
241
|
+
typer.Option(
|
|
242
|
+
help="Product for this dns zone. Required if no purchase is provided."
|
|
243
|
+
),
|
|
244
|
+
] = None,
|
|
245
|
+
):
|
|
246
|
+
try:
|
|
247
|
+
async with Connection() as conn:
|
|
248
|
+
ctrl = DnsZone(conn)
|
|
249
|
+
model = await ctrl.fetch(dns_zone_id)
|
|
250
|
+
if domain is not None:
|
|
251
|
+
model["domain"] = domain
|
|
252
|
+
if active is not None:
|
|
253
|
+
model["active"] = active
|
|
254
|
+
if dnssec is not None:
|
|
255
|
+
model["dnssec"] = dnssec
|
|
256
|
+
if account is not None:
|
|
257
|
+
model["account"].set(account, "accounts")
|
|
258
|
+
if purchase is not None:
|
|
259
|
+
model["purchase"].set(purchase, "purchases")
|
|
260
|
+
if product is not None:
|
|
261
|
+
model["product"].set(product, "products")
|
|
262
|
+
except DocumentError as e:
|
|
263
|
+
await print_document_error(e)
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
@app.async_command()
|
|
267
|
+
async def delete(
|
|
268
|
+
ctx: typer.Context,
|
|
269
|
+
dns_zone_id: Annotated[List[UUID], typer.Argument()],
|
|
270
|
+
):
|
|
271
|
+
try:
|
|
272
|
+
async with Connection() as conn, asyncio.TaskGroup() as tg:
|
|
273
|
+
ctrl = DnsZone(conn)
|
|
274
|
+
for resource_id in dns_zone_id:
|
|
275
|
+
tg.create_task(ctrl.destroy(resource_id))
|
|
276
|
+
except DocumentError as e:
|
|
277
|
+
await print_document_error(e)
|