python3-core-api-client 0.1__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.
- cyberfusion/CoreApiClient/__init__.py +0 -0
- cyberfusion/CoreApiClient/_encoders.py +7 -0
- cyberfusion/CoreApiClient/connector.py +382 -0
- cyberfusion/CoreApiClient/exceptions.py +13 -0
- cyberfusion/CoreApiClient/http.py +21 -0
- cyberfusion/CoreApiClient/interfaces.py +9 -0
- cyberfusion/CoreApiClient/models.py +5350 -0
- cyberfusion/CoreApiClient/resources/__init__.py +99 -0
- cyberfusion/CoreApiClient/resources/basic_authentication_realms.py +85 -0
- cyberfusion/CoreApiClient/resources/borg_archives.py +144 -0
- cyberfusion/CoreApiClient/resources/borg_repositories.py +134 -0
- cyberfusion/CoreApiClient/resources/certificate_managers.py +99 -0
- cyberfusion/CoreApiClient/resources/certificates.py +63 -0
- cyberfusion/CoreApiClient/resources/clusters.py +233 -0
- cyberfusion/CoreApiClient/resources/cmses.py +289 -0
- cyberfusion/CoreApiClient/resources/crons.py +76 -0
- cyberfusion/CoreApiClient/resources/custom_config_snippets.py +88 -0
- cyberfusion/CoreApiClient/resources/custom_configs.py +82 -0
- cyberfusion/CoreApiClient/resources/customers.py +97 -0
- cyberfusion/CoreApiClient/resources/daemons.py +76 -0
- cyberfusion/CoreApiClient/resources/database_user_grants.py +66 -0
- cyberfusion/CoreApiClient/resources/database_users.py +82 -0
- cyberfusion/CoreApiClient/resources/databases.py +140 -0
- cyberfusion/CoreApiClient/resources/domain_routers.py +43 -0
- cyberfusion/CoreApiClient/resources/firewall_groups.py +82 -0
- cyberfusion/CoreApiClient/resources/firewall_rules.py +67 -0
- cyberfusion/CoreApiClient/resources/fpm_pools.py +110 -0
- cyberfusion/CoreApiClient/resources/ftp_users.py +89 -0
- cyberfusion/CoreApiClient/resources/haproxy_listens.py +67 -0
- cyberfusion/CoreApiClient/resources/haproxy_listens_to_nodes.py +70 -0
- cyberfusion/CoreApiClient/resources/health.py +14 -0
- cyberfusion/CoreApiClient/resources/hosts_entries.py +63 -0
- cyberfusion/CoreApiClient/resources/htpasswd_files.py +67 -0
- cyberfusion/CoreApiClient/resources/htpasswd_users.py +82 -0
- cyberfusion/CoreApiClient/resources/login.py +28 -0
- cyberfusion/CoreApiClient/resources/logs.py +50 -0
- cyberfusion/CoreApiClient/resources/mail_accounts.py +105 -0
- cyberfusion/CoreApiClient/resources/mail_aliases.py +79 -0
- cyberfusion/CoreApiClient/resources/mail_domains.py +79 -0
- cyberfusion/CoreApiClient/resources/mail_hostnames.py +82 -0
- cyberfusion/CoreApiClient/resources/malwares.py +53 -0
- cyberfusion/CoreApiClient/resources/mariadb_encryption_keys.py +56 -0
- cyberfusion/CoreApiClient/resources/node_add_ons.py +74 -0
- cyberfusion/CoreApiClient/resources/nodes.py +112 -0
- cyberfusion/CoreApiClient/resources/passenger_apps.py +99 -0
- cyberfusion/CoreApiClient/resources/redis_instances.py +85 -0
- cyberfusion/CoreApiClient/resources/root_ssh_keys.py +77 -0
- cyberfusion/CoreApiClient/resources/security_txt_policies.py +85 -0
- cyberfusion/CoreApiClient/resources/sites.py +29 -0
- cyberfusion/CoreApiClient/resources/ssh_keys.py +77 -0
- cyberfusion/CoreApiClient/resources/task_collections.py +38 -0
- cyberfusion/CoreApiClient/resources/tombstones.py +29 -0
- cyberfusion/CoreApiClient/resources/unix_users.py +122 -0
- cyberfusion/CoreApiClient/resources/url_redirects.py +79 -0
- cyberfusion/CoreApiClient/resources/virtual_hosts.py +120 -0
- python3_core_api_client-0.1.dist-info/METADATA +236 -0
- python3_core_api_client-0.1.dist-info/RECORD +59 -0
- python3_core_api_client-0.1.dist-info/WHEEL +5 -0
- python3_core_api_client-0.1.dist-info/top_level.txt +1 -0
File without changes
|
@@ -0,0 +1,382 @@
|
|
1
|
+
import json
|
2
|
+
from typing import Optional, Tuple
|
3
|
+
from urllib.parse import urlparse
|
4
|
+
|
5
|
+
from cyberfusion.CoreApiClient._encoders import DatetimeEncoder
|
6
|
+
from cyberfusion.CoreApiClient.exceptions import CallException, AuthenticationException
|
7
|
+
|
8
|
+
from requests.sessions import Session
|
9
|
+
from typing import Dict, Any, Union
|
10
|
+
from requests.adapters import HTTPAdapter, Retry
|
11
|
+
import requests
|
12
|
+
import certifi
|
13
|
+
from functools import cached_property
|
14
|
+
from cyberfusion.CoreApiClient import resources
|
15
|
+
import datetime
|
16
|
+
import importlib.metadata
|
17
|
+
from cyberfusion.CoreApiClient.http import Response
|
18
|
+
|
19
|
+
|
20
|
+
class CoreApiConnector:
|
21
|
+
def __init__(
|
22
|
+
self,
|
23
|
+
base_url: str = "https://core-api.cyberfusion.io",
|
24
|
+
*,
|
25
|
+
username: Optional[str] = None,
|
26
|
+
password: Optional[str] = None,
|
27
|
+
api_key: Optional[str] = None,
|
28
|
+
requests_session: Optional[Session] = None,
|
29
|
+
) -> None:
|
30
|
+
self.base_url = base_url
|
31
|
+
self.username = username
|
32
|
+
self.password = password
|
33
|
+
self.api_key = api_key
|
34
|
+
|
35
|
+
self._jwt_metadata: Optional[Tuple[str, Any]] = None
|
36
|
+
|
37
|
+
if (self.username and self.password) and self.api_key:
|
38
|
+
raise ValueError(
|
39
|
+
"Specify either username and password, or API key, not both"
|
40
|
+
)
|
41
|
+
|
42
|
+
if self.username and not self.password:
|
43
|
+
raise ValueError("If username is specified, password must be specified")
|
44
|
+
|
45
|
+
if self.password and not self.username:
|
46
|
+
raise ValueError("If password is specified, username must be specified")
|
47
|
+
|
48
|
+
if not self.api_key and not (self.username and self.password):
|
49
|
+
raise ValueError("Specify either username and password, or API key")
|
50
|
+
|
51
|
+
self.requests_session = requests_session or self.get_default_requests_session()
|
52
|
+
|
53
|
+
@property
|
54
|
+
def root_url(self) -> str:
|
55
|
+
return urlparse(self.base_url)._replace(path="").geturl()
|
56
|
+
|
57
|
+
@property
|
58
|
+
def authentication_headers(self) -> Dict[str, str]:
|
59
|
+
headers = {}
|
60
|
+
|
61
|
+
if self.api_key:
|
62
|
+
headers["X-API-Key"] = self.api_key
|
63
|
+
else:
|
64
|
+
login = False
|
65
|
+
|
66
|
+
if not self._jwt_metadata:
|
67
|
+
login = True
|
68
|
+
else:
|
69
|
+
access_token, expires_at = self._jwt_metadata
|
70
|
+
|
71
|
+
if datetime.datetime.utcnow() >= expires_at:
|
72
|
+
login = True
|
73
|
+
|
74
|
+
if login:
|
75
|
+
response = self.requests_session.post(
|
76
|
+
"".join([self.root_url, "/api/v1/login/access-token"]),
|
77
|
+
data={"username": self.username, "password": self.password},
|
78
|
+
verify=certifi.where(),
|
79
|
+
timeout=60,
|
80
|
+
headers={"Content-Type": "application/x-www-form-urlencoded"},
|
81
|
+
)
|
82
|
+
|
83
|
+
try:
|
84
|
+
response.raise_for_status()
|
85
|
+
except requests.exceptions.HTTPError as e:
|
86
|
+
raise AuthenticationException(
|
87
|
+
response.text, response.status_code
|
88
|
+
) from e
|
89
|
+
|
90
|
+
json = response.json()
|
91
|
+
|
92
|
+
access_token = json["access_token"]
|
93
|
+
expires_in = json["expires_in"]
|
94
|
+
expires_at = datetime.datetime.utcnow() + datetime.timedelta(
|
95
|
+
seconds=expires_in
|
96
|
+
)
|
97
|
+
|
98
|
+
self._jwt_metadata = (access_token, expires_at)
|
99
|
+
|
100
|
+
headers["Authorization"] = "Bearer " + access_token
|
101
|
+
|
102
|
+
return headers
|
103
|
+
|
104
|
+
def send(
|
105
|
+
self,
|
106
|
+
method: str,
|
107
|
+
path: str,
|
108
|
+
data: Optional[Union[str, dict]] = None,
|
109
|
+
query_parameters: Optional[dict] = None,
|
110
|
+
*,
|
111
|
+
content_type: str = "application/json",
|
112
|
+
) -> Response:
|
113
|
+
url = "".join([self.base_url, path])
|
114
|
+
|
115
|
+
if data and content_type == "application/json":
|
116
|
+
data = json.dumps(data, cls=DatetimeEncoder)
|
117
|
+
|
118
|
+
if query_parameters:
|
119
|
+
for key, value in query_parameters.items():
|
120
|
+
if isinstance(value, datetime.datetime):
|
121
|
+
query_parameters[key] = json.loads(
|
122
|
+
json.dumps(value, cls=DatetimeEncoder)
|
123
|
+
)
|
124
|
+
|
125
|
+
requests_response = self.requests_session.request(
|
126
|
+
method,
|
127
|
+
url,
|
128
|
+
headers=self.authentication_headers | {"Content-Type": content_type},
|
129
|
+
data=data,
|
130
|
+
params=query_parameters,
|
131
|
+
verify=certifi.where(),
|
132
|
+
timeout=60,
|
133
|
+
)
|
134
|
+
|
135
|
+
local_response = Response(
|
136
|
+
status_code=requests_response.status_code,
|
137
|
+
body=requests_response.text,
|
138
|
+
headers=requests_response.headers,
|
139
|
+
)
|
140
|
+
|
141
|
+
return local_response
|
142
|
+
|
143
|
+
def send_or_fail(
|
144
|
+
self,
|
145
|
+
method: str,
|
146
|
+
path: str,
|
147
|
+
data: Optional[dict] = None,
|
148
|
+
query_parameters: Optional[dict] = None,
|
149
|
+
*,
|
150
|
+
content_type: str = "application/json",
|
151
|
+
) -> Response:
|
152
|
+
local_response = self.send(
|
153
|
+
method, path, data, query_parameters, content_type=content_type
|
154
|
+
)
|
155
|
+
|
156
|
+
if local_response.failed:
|
157
|
+
raise CallException(local_response.body, local_response.status_code)
|
158
|
+
|
159
|
+
return local_response
|
160
|
+
|
161
|
+
def get_default_requests_session(self) -> requests.sessions.Session:
|
162
|
+
session = requests.Session()
|
163
|
+
|
164
|
+
adapter = HTTPAdapter(
|
165
|
+
max_retries=Retry(
|
166
|
+
total=10,
|
167
|
+
backoff_factor=2.5,
|
168
|
+
allowed_methods=None,
|
169
|
+
status_forcelist=[502, 503],
|
170
|
+
)
|
171
|
+
)
|
172
|
+
|
173
|
+
session.mount(self.base_url + "/", adapter)
|
174
|
+
|
175
|
+
session.headers.update(
|
176
|
+
{
|
177
|
+
"User-Agent": "python3-core-api-client/"
|
178
|
+
+ importlib.metadata.version("python3-core-api-client")
|
179
|
+
}
|
180
|
+
)
|
181
|
+
|
182
|
+
return session
|
183
|
+
|
184
|
+
@cached_property
|
185
|
+
def login(self) -> resources.login.Login:
|
186
|
+
return resources.login.Login(self)
|
187
|
+
|
188
|
+
@cached_property
|
189
|
+
def sites(self) -> resources.sites.Sites:
|
190
|
+
return resources.sites.Sites(self)
|
191
|
+
|
192
|
+
@cached_property
|
193
|
+
def customers(self) -> resources.customers.Customers:
|
194
|
+
return resources.customers.Customers(self)
|
195
|
+
|
196
|
+
@cached_property
|
197
|
+
def haproxy_listens(self) -> resources.haproxy_listens.HAProxyListens:
|
198
|
+
return resources.haproxy_listens.HAProxyListens(self)
|
199
|
+
|
200
|
+
@cached_property
|
201
|
+
def haproxy_listens_to_nodes(
|
202
|
+
self,
|
203
|
+
) -> resources.haproxy_listens_to_nodes.HAProxyListensToNodes:
|
204
|
+
return resources.haproxy_listens_to_nodes.HAProxyListensToNodes(self)
|
205
|
+
|
206
|
+
@cached_property
|
207
|
+
def borg_repositories(self) -> resources.borg_repositories.BorgRepositories:
|
208
|
+
return resources.borg_repositories.BorgRepositories(self)
|
209
|
+
|
210
|
+
@cached_property
|
211
|
+
def borg_archives(self) -> resources.borg_archives.BorgArchives:
|
212
|
+
return resources.borg_archives.BorgArchives(self)
|
213
|
+
|
214
|
+
@cached_property
|
215
|
+
def certificates(self) -> resources.certificates.Certificates:
|
216
|
+
return resources.certificates.Certificates(self)
|
217
|
+
|
218
|
+
@cached_property
|
219
|
+
def certificate_managers(
|
220
|
+
self,
|
221
|
+
) -> resources.certificate_managers.CertificateManagers:
|
222
|
+
return resources.certificate_managers.CertificateManagers(self)
|
223
|
+
|
224
|
+
@cached_property
|
225
|
+
def tombstones(self) -> resources.tombstones.Tombstones:
|
226
|
+
return resources.tombstones.Tombstones(self)
|
227
|
+
|
228
|
+
@cached_property
|
229
|
+
def clusters(self) -> resources.clusters.Clusters:
|
230
|
+
return resources.clusters.Clusters(self)
|
231
|
+
|
232
|
+
@cached_property
|
233
|
+
def virtual_hosts(self) -> resources.virtual_hosts.VirtualHosts:
|
234
|
+
return resources.virtual_hosts.VirtualHosts(self)
|
235
|
+
|
236
|
+
@cached_property
|
237
|
+
def mail_hostnames(self) -> resources.mail_hostnames.MailHostnames:
|
238
|
+
return resources.mail_hostnames.MailHostnames(self)
|
239
|
+
|
240
|
+
@cached_property
|
241
|
+
def domain_routers(self) -> resources.domain_routers.DomainRouters:
|
242
|
+
return resources.domain_routers.DomainRouters(self)
|
243
|
+
|
244
|
+
@cached_property
|
245
|
+
def url_redirects(self) -> resources.url_redirects.URLRedirects:
|
246
|
+
return resources.url_redirects.URLRedirects(self)
|
247
|
+
|
248
|
+
@cached_property
|
249
|
+
def htpasswd_files(self) -> resources.htpasswd_files.HtpasswdFiles:
|
250
|
+
return resources.htpasswd_files.HtpasswdFiles(self)
|
251
|
+
|
252
|
+
@cached_property
|
253
|
+
def htpasswd_users(self) -> resources.htpasswd_users.HtpasswdUsers:
|
254
|
+
return resources.htpasswd_users.HtpasswdUsers(self)
|
255
|
+
|
256
|
+
@cached_property
|
257
|
+
def basic_authentication_realms(
|
258
|
+
self,
|
259
|
+
) -> resources.basic_authentication_realms.BasicAuthenticationRealms:
|
260
|
+
return resources.basic_authentication_realms.BasicAuthenticationRealms(self)
|
261
|
+
|
262
|
+
@cached_property
|
263
|
+
def node_add_ons(self) -> resources.node_add_ons.NodeAddOns:
|
264
|
+
return resources.node_add_ons.NodeAddOns(self)
|
265
|
+
|
266
|
+
@cached_property
|
267
|
+
def crons(self) -> resources.crons.Crons:
|
268
|
+
return resources.crons.Crons(self)
|
269
|
+
|
270
|
+
@cached_property
|
271
|
+
def daemons(self) -> resources.daemons.Daemons:
|
272
|
+
return resources.daemons.Daemons(self)
|
273
|
+
|
274
|
+
@cached_property
|
275
|
+
def mariadb_encryption_keys(
|
276
|
+
self,
|
277
|
+
) -> resources.mariadb_encryption_keys.MariaDBEncryptionKeys:
|
278
|
+
return resources.mariadb_encryption_keys.MariaDBEncryptionKeys(self)
|
279
|
+
|
280
|
+
@cached_property
|
281
|
+
def firewall_rules(self) -> resources.firewall_rules.FirewallRules:
|
282
|
+
return resources.firewall_rules.FirewallRules(self)
|
283
|
+
|
284
|
+
@cached_property
|
285
|
+
def hosts_entries(self) -> resources.hosts_entries.HostsEntries:
|
286
|
+
return resources.hosts_entries.HostsEntries(self)
|
287
|
+
|
288
|
+
@cached_property
|
289
|
+
def security_txt_policies(
|
290
|
+
self,
|
291
|
+
) -> resources.security_txt_policies.SecurityTXTPolicies:
|
292
|
+
return resources.security_txt_policies.SecurityTXTPolicies(self)
|
293
|
+
|
294
|
+
@cached_property
|
295
|
+
def firewall_groups(self) -> resources.firewall_groups.FirewallGroups:
|
296
|
+
return resources.firewall_groups.FirewallGroups(self)
|
297
|
+
|
298
|
+
@cached_property
|
299
|
+
def custom_config_snippets(
|
300
|
+
self,
|
301
|
+
) -> resources.custom_config_snippets.CustomConfigSnippets:
|
302
|
+
return resources.custom_config_snippets.CustomConfigSnippets(self)
|
303
|
+
|
304
|
+
@cached_property
|
305
|
+
def custom_configs(self) -> resources.custom_configs.CustomConfigs:
|
306
|
+
return resources.custom_configs.CustomConfigs(self)
|
307
|
+
|
308
|
+
@cached_property
|
309
|
+
def ftp_users(self) -> resources.ftp_users.FTPUsers:
|
310
|
+
return resources.ftp_users.FTPUsers(self)
|
311
|
+
|
312
|
+
@cached_property
|
313
|
+
def cmses(self) -> resources.cmses.CMSes:
|
314
|
+
return resources.cmses.CMSes(self)
|
315
|
+
|
316
|
+
@cached_property
|
317
|
+
def fpm_pools(self) -> resources.fpm_pools.FPMPools:
|
318
|
+
return resources.fpm_pools.FPMPools(self)
|
319
|
+
|
320
|
+
@cached_property
|
321
|
+
def passenger_apps(self) -> resources.passenger_apps.PassengerApps:
|
322
|
+
return resources.passenger_apps.PassengerApps(self)
|
323
|
+
|
324
|
+
@cached_property
|
325
|
+
def redis_instances(self) -> resources.redis_instances.RedisInstances:
|
326
|
+
return resources.redis_instances.RedisInstances(self)
|
327
|
+
|
328
|
+
@cached_property
|
329
|
+
def task_collections(self) -> resources.task_collections.TaskCollections:
|
330
|
+
return resources.task_collections.TaskCollections(self)
|
331
|
+
|
332
|
+
@cached_property
|
333
|
+
def nodes(self) -> resources.nodes.Nodes:
|
334
|
+
return resources.nodes.Nodes(self)
|
335
|
+
|
336
|
+
@cached_property
|
337
|
+
def unix_users(self) -> resources.unix_users.UNIXUsers:
|
338
|
+
return resources.unix_users.UNIXUsers(self)
|
339
|
+
|
340
|
+
@cached_property
|
341
|
+
def logs(self) -> resources.logs.Logs:
|
342
|
+
return resources.logs.Logs(self)
|
343
|
+
|
344
|
+
@cached_property
|
345
|
+
def ssh_keys(self) -> resources.ssh_keys.SSHKeys:
|
346
|
+
return resources.ssh_keys.SSHKeys(self)
|
347
|
+
|
348
|
+
@cached_property
|
349
|
+
def root_ssh_keys(self) -> resources.root_ssh_keys.RootSSHKeys:
|
350
|
+
return resources.root_ssh_keys.RootSSHKeys(self)
|
351
|
+
|
352
|
+
@cached_property
|
353
|
+
def malwares(self) -> resources.malwares.Malwares:
|
354
|
+
return resources.malwares.Malwares(self)
|
355
|
+
|
356
|
+
@cached_property
|
357
|
+
def databases(self) -> resources.databases.Databases:
|
358
|
+
return resources.databases.Databases(self)
|
359
|
+
|
360
|
+
@cached_property
|
361
|
+
def database_users(self) -> resources.database_users.DatabaseUsers:
|
362
|
+
return resources.database_users.DatabaseUsers(self)
|
363
|
+
|
364
|
+
@cached_property
|
365
|
+
def database_user_grants(self) -> resources.database_user_grants.DatabaseUserGrants:
|
366
|
+
return resources.database_user_grants.DatabaseUserGrants(self)
|
367
|
+
|
368
|
+
@cached_property
|
369
|
+
def mail_domains(self) -> resources.mail_domains.MailDomains:
|
370
|
+
return resources.mail_domains.MailDomains(self)
|
371
|
+
|
372
|
+
@cached_property
|
373
|
+
def mail_accounts(self) -> resources.mail_accounts.MailAccounts:
|
374
|
+
return resources.mail_accounts.MailAccounts(self)
|
375
|
+
|
376
|
+
@cached_property
|
377
|
+
def mail_aliases(self) -> resources.mail_aliases.MailAliases:
|
378
|
+
return resources.mail_aliases.MailAliases(self)
|
379
|
+
|
380
|
+
@cached_property
|
381
|
+
def health(self) -> resources.health.Health:
|
382
|
+
return resources.health.Health(self)
|
@@ -0,0 +1,21 @@
|
|
1
|
+
import json
|
2
|
+
from dataclasses import dataclass
|
3
|
+
from http import HTTPStatus
|
4
|
+
from typing import Any
|
5
|
+
|
6
|
+
from requests.structures import CaseInsensitiveDict
|
7
|
+
|
8
|
+
|
9
|
+
@dataclass
|
10
|
+
class Response:
|
11
|
+
status_code: int
|
12
|
+
body: str
|
13
|
+
headers: CaseInsensitiveDict
|
14
|
+
|
15
|
+
@property
|
16
|
+
def failed(self) -> bool:
|
17
|
+
return self.status_code >= HTTPStatus.BAD_REQUEST
|
18
|
+
|
19
|
+
@property
|
20
|
+
def json(self) -> Any:
|
21
|
+
return json.loads(self.body)
|
@@ -0,0 +1,9 @@
|
|
1
|
+
from typing import TYPE_CHECKING
|
2
|
+
|
3
|
+
if TYPE_CHECKING: # pragma: no cover
|
4
|
+
from cyberfusion.CoreApiClient.connector import CoreApiConnector
|
5
|
+
|
6
|
+
|
7
|
+
class Resource:
|
8
|
+
def __init__(self, api_connector: "CoreApiConnector") -> None:
|
9
|
+
self.api_connector = api_connector
|