calagoapi 1.0.dev1__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.
Files changed (71) hide show
  1. calagoapi/__init__.py +190 -0
  2. calagoapi/account/__init__.py +14 -0
  3. calagoapi/account/account.py +292 -0
  4. calagoapi/account/auth.py +72 -0
  5. calagoapi/account/models.py +221 -0
  6. calagoapi/admin/__init__.py +48 -0
  7. calagoapi/admin/admin.py +341 -0
  8. calagoapi/admin/managers.py +490 -0
  9. calagoapi/admin/resources.py +970 -0
  10. calagoapi/aio/__init__.py +9 -0
  11. calagoapi/aio/console.py +289 -0
  12. calagoapi/aio/panel.py +176 -0
  13. calagoapi/api/__init__.py +63 -0
  14. calagoapi/api/account.py +195 -0
  15. calagoapi/api/admin.py +402 -0
  16. calagoapi/api/attachments.py +27 -0
  17. calagoapi/api/auth.py +52 -0
  18. calagoapi/api/backups.py +99 -0
  19. calagoapi/api/client.py +198 -0
  20. calagoapi/api/databases.py +217 -0
  21. calagoapi/api/files.py +210 -0
  22. calagoapi/api/network.py +84 -0
  23. calagoapi/api/public.py +13 -0
  24. calagoapi/api/schedules.py +79 -0
  25. calagoapi/api/servers.py +114 -0
  26. calagoapi/api/users.py +27 -0
  27. calagoapi/api/versions.py +29 -0
  28. calagoapi/backups/__init__.py +8 -0
  29. calagoapi/backups/backup.py +292 -0
  30. calagoapi/backups/manager.py +177 -0
  31. calagoapi/console/__init__.py +6 -0
  32. calagoapi/console/console.py +392 -0
  33. calagoapi/databases/__init__.py +12 -0
  34. calagoapi/databases/database.py +445 -0
  35. calagoapi/databases/explorer.py +159 -0
  36. calagoapi/databases/manager.py +122 -0
  37. calagoapi/files/__init__.py +9 -0
  38. calagoapi/files/file.py +196 -0
  39. calagoapi/files/manager.py +437 -0
  40. calagoapi/network/__init__.py +8 -0
  41. calagoapi/network/allocation.py +99 -0
  42. calagoapi/network/manager.py +132 -0
  43. calagoapi/nodes/__init__.py +6 -0
  44. calagoapi/nodes/node.py +477 -0
  45. calagoapi/panel.py +162 -0
  46. calagoapi/schedules/__init__.py +14 -0
  47. calagoapi/schedules/builders.py +461 -0
  48. calagoapi/schedules/manager.py +107 -0
  49. calagoapi/schedules/schedule.py +214 -0
  50. calagoapi/servers/__init__.py +13 -0
  51. calagoapi/servers/admin.py +430 -0
  52. calagoapi/servers/generic.py +785 -0
  53. calagoapi/servers/manager.py +167 -0
  54. calagoapi/servers/minecraft.py +207 -0
  55. calagoapi/tunnels/__init__.py +5 -0
  56. calagoapi/tunnels/tunnel.py +112 -0
  57. calagoapi/users/__init__.py +11 -0
  58. calagoapi/users/activity.py +45 -0
  59. calagoapi/users/subuser.py +127 -0
  60. calagoapi/users/user.py +267 -0
  61. calagoapi/utils/__init__.py +43 -0
  62. calagoapi/utils/convert.py +113 -0
  63. calagoapi/utils/exceptions.py +72 -0
  64. calagoapi/utils/model.py +142 -0
  65. calagoapi/utils/resource.py +100 -0
  66. calagoapi/utils/time.py +68 -0
  67. calagoapi-1.0.dev1.dist-info/METADATA +266 -0
  68. calagoapi-1.0.dev1.dist-info/RECORD +71 -0
  69. calagoapi-1.0.dev1.dist-info/WHEEL +5 -0
  70. calagoapi-1.0.dev1.dist-info/licenses/LICENSE +674 -0
  71. calagoapi-1.0.dev1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,195 @@
1
+ from calagoapi.api.client import segment
2
+
3
+
4
+ # Internal Calagopus AccountAPI
5
+ class AccountAPI:
6
+ def __init__(self, client):
7
+ self.client = client
8
+
9
+ def _path(self, suffix=''):
10
+ return f'/api/client/account{suffix}'
11
+
12
+ # profile
13
+ def get(self):
14
+ return self.client.get(self._path())['user']
15
+
16
+ def update(self, username=None, name_first=None, name_last=None, language=None):
17
+ return self.client.patch(self._path(), json={
18
+ 'username': username,
19
+ 'name_first': name_first,
20
+ 'name_last': name_last,
21
+ 'language': language,
22
+ })
23
+
24
+ def permissions(self):
25
+ return self.client.get('/api/client/permissions')
26
+
27
+ def activity(self, search=None, page=None, per_page=None):
28
+ return self.client.list(self._path('/activity'), 'activities', {'search': search}, page, per_page)
29
+
30
+ def settings(self):
31
+ return self.client.get(self._path('/settings'))['settings']
32
+
33
+ def updateSettings(self, settings):
34
+ return self.client.patch(self._path('/settings'), json={'settings': settings})
35
+
36
+ def setAvatar(self, content, content_type='image/png'):
37
+ return self.client.request(
38
+ 'PUT', self._path('/avatar'), data=content, headers={'Content-Type': content_type}
39
+ )['avatar']
40
+
41
+ def deleteAvatar(self):
42
+ return self.client.delete(self._path('/avatar'))
43
+
44
+ def logout(self):
45
+ return self.client.post(self._path('/logout'))
46
+
47
+ # email and password
48
+ def changeEmail(self, email, password):
49
+ return self.client.put(self._path('/email'), json={'email': email, 'password': password})
50
+
51
+ def resendVerification(self):
52
+ return self.client.post(self._path('/email/resend-verification'))
53
+
54
+ def changePassword(self, password, new_password):
55
+ return self.client.put(self._path('/password'), json={'password': password, 'new_password': new_password})
56
+
57
+ def setPasswordLogin(self, disabled, password):
58
+ return self.client.put(self._path('/password-login'), json={'disabled': disabled, 'password': password})
59
+
60
+ # two factor
61
+ def twoFactorSetup(self):
62
+ return self.client.get(self._path('/two-factor'))
63
+
64
+ def enableTwoFactor(self, code, password):
65
+ return self.client.post(self._path('/two-factor'), json={'code': code, 'password': password})['recovery_codes']
66
+
67
+ def disableTwoFactor(self, code, password):
68
+ return self.client.delete(self._path('/two-factor'), json={'code': code, 'password': password})
69
+
70
+ def enableEmailTwoFactor(self, password):
71
+ return self.client.post(self._path('/two-factor/email'), json={'password': password})['recovery_codes']
72
+
73
+ def disableEmailTwoFactor(self, password):
74
+ return self.client.delete(self._path('/two-factor/email'), json={'password': password})
75
+
76
+ # api keys
77
+ def apiKeys(self, search=None, page=None, per_page=None):
78
+ return self.client.list(self._path('/api-keys'), 'api_keys', {'search': search}, page, per_page)
79
+
80
+ def apiKeyByIdentifier(self, identifier):
81
+ return self.client.get(self._path(f'/api-keys/identifier/{segment(identifier)}'))['api_key']
82
+
83
+ def createApiKey(self, name, allowed_ips=None, user_permissions=None, admin_permissions=None, server_permissions=None, enabled=None, expires=None):
84
+ return self.client.post(self._path('/api-keys'), json={
85
+ 'name': name,
86
+ 'allowed_ips': allowed_ips or [],
87
+ 'user_permissions': user_permissions or [],
88
+ 'admin_permissions': admin_permissions or [],
89
+ 'server_permissions': server_permissions or [],
90
+ 'enabled': enabled,
91
+ 'expires': expires,
92
+ })
93
+
94
+ def updateApiKey(self, api_key_id, allowed_ips, name=None, enabled=None, user_permissions=None, admin_permissions=None, server_permissions=None, expires=None):
95
+ return self.client.patch(self._path(f'/api-keys/{api_key_id}'), json={
96
+ 'allowed_ips': allowed_ips,
97
+ 'name': name,
98
+ 'enabled': enabled,
99
+ 'user_permissions': user_permissions,
100
+ 'admin_permissions': admin_permissions,
101
+ 'server_permissions': server_permissions,
102
+ 'expires': expires,
103
+ })
104
+
105
+ def deleteApiKey(self, api_key_id):
106
+ return self.client.delete(self._path(f'/api-keys/{api_key_id}'))
107
+
108
+ def duplicateApiKey(self, api_key_id, name):
109
+ return self.client.post(self._path(f'/api-keys/{api_key_id}/duplicate'), json={'name': name})
110
+
111
+ def recreateApiKey(self, api_key_id):
112
+ return self.client.post(self._path(f'/api-keys/{api_key_id}/recreate'))['key']
113
+
114
+ # ssh keys
115
+ def sshKeys(self, search=None, page=None, per_page=None):
116
+ return self.client.list(self._path('/ssh-keys'), 'ssh_keys', {'search': search}, page, per_page)
117
+
118
+ def createSshKey(self, name, public_key):
119
+ return self.client.post(self._path('/ssh-keys'), json={'name': name, 'public_key': public_key})['ssh_key']
120
+
121
+ def importSshKeys(self, provider, username):
122
+ return self.client.post(self._path('/ssh-keys/import'), json={'provider': provider, 'username': username})['ssh_keys']
123
+
124
+ def updateSshKey(self, ssh_key_id, name):
125
+ return self.client.patch(self._path(f'/ssh-keys/{ssh_key_id}'), json={'name': name})
126
+
127
+ def deleteSshKey(self, ssh_key_id):
128
+ return self.client.delete(self._path(f'/ssh-keys/{ssh_key_id}'))
129
+
130
+ # security keys
131
+ def securityKeys(self, search=None, page=None, per_page=None):
132
+ return self.client.list(self._path('/security-keys'), 'security_keys', {'search': search}, page, per_page)
133
+
134
+ def createSecurityKey(self, name, password, allow_usernameless_login=None):
135
+ return self.client.post(self._path('/security-keys'), json={
136
+ 'name': name,
137
+ 'password': password,
138
+ 'allow_usernameless_login': allow_usernameless_login,
139
+ })
140
+
141
+ def challengeSecurityKey(self, security_key_id, public_key_credential):
142
+ return self.client.post(
143
+ self._path(f'/security-keys/{security_key_id}/challenge'),
144
+ json={'public_key_credential': public_key_credential}
145
+ )['credential_id']
146
+
147
+ def updateSecurityKey(self, security_key_id, name):
148
+ return self.client.patch(self._path(f'/security-keys/{security_key_id}'), json={'name': name})
149
+
150
+ def deleteSecurityKey(self, security_key_id, password=None):
151
+ return self.client.delete(self._path(f'/security-keys/{security_key_id}'), json={'password': password})
152
+
153
+ # sessions
154
+ def sessions(self, search=None, page=None, per_page=None):
155
+ return self.client.list(self._path('/sessions'), 'sessions', {'search': search}, page, per_page)
156
+
157
+ def deleteSession(self, session_id):
158
+ return self.client.delete(self._path(f'/sessions/{session_id}'))
159
+
160
+ def deleteOtherSessions(self):
161
+ return self.client.delete(self._path('/sessions'))['deleted']
162
+
163
+ # oauth links
164
+ def oauthLinks(self, page=None, per_page=None):
165
+ return self.client.list(self._path('/oauth-links'), 'oauth_links', None, page, per_page)
166
+
167
+ def oauthLink(self, oauth_link_id):
168
+ return self.client.get(self._path(f'/oauth-links/{oauth_link_id}'))['oauth_link']
169
+
170
+ def deleteOauthLink(self, oauth_link_id):
171
+ return self.client.delete(self._path(f'/oauth-links/{oauth_link_id}'))
172
+
173
+ # command snippets
174
+ def commandSnippets(self, search=None, page=None, per_page=None):
175
+ return self.client.list(self._path('/command-snippets'), 'command_snippets', {'search': search}, page, per_page)
176
+
177
+ def createCommandSnippet(self, name, command, eggs=None):
178
+ return self.client.post(self._path('/command-snippets'), json={
179
+ 'name': name,
180
+ 'command': command,
181
+ 'eggs': eggs or [],
182
+ })['command_snippet']
183
+
184
+ def updateCommandSnippet(self, snippet_id, name, command=None, eggs=None):
185
+ return self.client.patch(self._path(f'/command-snippets/{snippet_id}'), json={
186
+ 'name': name,
187
+ 'command': command,
188
+ 'eggs': eggs,
189
+ })
190
+
191
+ def deleteCommandSnippet(self, snippet_id):
192
+ return self.client.delete(self._path(f'/command-snippets/{snippet_id}'))
193
+
194
+ def duplicateCommandSnippet(self, snippet_id, name):
195
+ return self.client.post(self._path(f'/command-snippets/{snippet_id}/duplicate'), json={'name': name})['command_snippet']
calagoapi/api/admin.py ADDED
@@ -0,0 +1,402 @@
1
+ from calagoapi.api.client import segment
2
+
3
+
4
+ # Internal Calagopus AdminAPI
5
+ class ResourceAPI:
6
+ '''Standard CRUD calls for one admin collection, e.g. /api/admin/locations'''
7
+ def __init__(self, client, path, key, plural, parent=None):
8
+ self.client = client
9
+ self.path = f'/api/admin{path}'
10
+ self.key = key
11
+ self.plural = plural
12
+ # id(s) of the owning object for nested collections, e.g. the nest of an egg
13
+ self.parent = parent
14
+
15
+ def list(self, search=None, page=None, per_page=None, **params):
16
+ if search is not None:
17
+ params['search'] = search
18
+ return self.client.list(self.path, self.plural, params, page, per_page)
19
+
20
+ def listAll(self):
21
+ '''For collections that are not paginated'''
22
+ return self.client.get(self.path)[self.plural]
23
+
24
+ def get(self, resource_id):
25
+ return self.client.get(f'{self.path}/{resource_id}')[self.key]
26
+
27
+ def create(self, **fields):
28
+ return self.client.post(self.path, json=fields)[self.key]
29
+
30
+ def update(self, resource_id, **fields):
31
+ return self.client.patch(f'{self.path}/{resource_id}', json=fields)
32
+
33
+ def delete(self, resource_id, **body):
34
+ return self.client.delete(f'{self.path}/{resource_id}', json=body or None)
35
+
36
+ def duplicate(self, resource_id, **fields):
37
+ return self.client.post(f'{self.path}/{resource_id}/duplicate', json=fields or None)[self.key]
38
+
39
+ # sub-collections like /locations/{id}/nodes
40
+ def related(self, resource_id, suffix, key, search=None, page=None, per_page=None, **params):
41
+ if search is not None:
42
+ params['search'] = search
43
+ return self.client.list(f'{self.path}/{resource_id}/{suffix}', key, params, page, per_page)
44
+
45
+ def attach(self, resource_id, suffix, field, value):
46
+ return self.client.post(f'{self.path}/{resource_id}/{suffix}', json={field: value})
47
+
48
+ def detach(self, resource_id, suffix, child_id):
49
+ return self.client.delete(f'{self.path}/{resource_id}/{suffix}/{child_id}')
50
+
51
+ def action(self, resource_id, suffix, method='POST', json=None, params=None):
52
+ return self.client.request(method, f'{self.path}/{resource_id}/{suffix}', json=json, params=params)
53
+
54
+
55
+ class AdminAPI:
56
+ def __init__(self, client):
57
+ self.client = client
58
+
59
+ self.users = ResourceAPI(client, '/users', 'user', 'users')
60
+ self.servers = ResourceAPI(client, '/servers', 'server', 'servers')
61
+ self.nodes = ResourceAPI(client, '/nodes', 'node', 'nodes')
62
+ self.locations = ResourceAPI(client, '/locations', 'location', 'locations')
63
+ self.nests = ResourceAPI(client, '/nests', 'nest', 'nests')
64
+ self.mounts = ResourceAPI(client, '/mounts', 'mount', 'mounts')
65
+ self.devices = ResourceAPI(client, '/devices', 'device', 'devices')
66
+ self.roles = ResourceAPI(client, '/roles', 'role', 'roles')
67
+ self.announcements = ResourceAPI(client, '/announcements', 'announcement', 'announcements')
68
+ self.oauth_providers = ResourceAPI(client, '/oauth-providers', 'oauth_provider', 'oauth_providers')
69
+ self.database_hosts = ResourceAPI(client, '/database-hosts', 'database_host', 'database_hosts')
70
+ self.database_agent_hosts = ResourceAPI(client, '/database-agent-hosts', 'database_agent_host', 'database_agent_hosts')
71
+ self.database_agent_templates = ResourceAPI(client, '/database-agent-templates', 'database_agent_template', 'database_agent_templates')
72
+ self.backup_configurations = ResourceAPI(client, '/backup-configurations', 'backup_configuration', 'backup_configurations')
73
+ self.system_backup_policies = ResourceAPI(client, '/system-backup-policies', 'system_backup_policy', 'system_backup_policies')
74
+ self.egg_repositories = ResourceAPI(client, '/egg-repositories', 'egg_repository', 'egg_repositories')
75
+ self.egg_configurations = ResourceAPI(client, '/egg-configurations', 'egg_configuration', 'egg_configurations')
76
+ self.subdomain_domains = ResourceAPI(client, '/extensions/dev.0x7d8.subdomainmanager/domains', 'domain', 'domains')
77
+
78
+ # nested collections
79
+ def eggs(self, nest_id):
80
+ return ResourceAPI(self.client, f'/nests/{nest_id}/eggs', 'egg', 'eggs', nest_id)
81
+
82
+ def eggVariables(self, nest_id, egg_id):
83
+ return ResourceAPI(self.client, f'/nests/{nest_id}/eggs/{egg_id}/variables', 'variable', 'variables', (nest_id, egg_id))
84
+
85
+ def orderEggVariables(self, nest_id, egg_id, variable_order):
86
+ return self.client.put(f'/api/admin/nests/{nest_id}/eggs/{egg_id}/variables/order', json={'variable_order': variable_order})
87
+
88
+ def oauthMappings(self, oauth_provider_id):
89
+ return ResourceAPI(self.client, f'/oauth-providers/{oauth_provider_id}/mappings', 'oauth_mapping', 'oauth_mappings', oauth_provider_id)
90
+
91
+ def userOauthLinks(self, user_id):
92
+ return ResourceAPI(self.client, f'/users/{user_id}/oauth-links', 'oauth_link', 'oauth_links', user_id)
93
+
94
+ # users
95
+ def userByExternalId(self, external_id):
96
+ return self.client.get(f'/api/admin/users/external/{segment(external_id)}')['user']
97
+
98
+ def userServers(self, user_id, owned=None, search=None, page=None, per_page=None):
99
+ return self.users.related(user_id, 'servers', 'servers', search, page, per_page, owned=owned)
100
+
101
+ def userActivity(self, user_id, search=None, page=None, per_page=None):
102
+ return self.users.related(user_id, 'activity', 'activities', search, page, per_page)
103
+
104
+ def userDisableTwoFactor(self, user_id):
105
+ return self.client.delete(f'/api/admin/users/{user_id}/two-factor')
106
+
107
+ def userSendPasswordReset(self, user_id):
108
+ return self.client.post(f'/api/admin/users/{user_id}/email/reset-password')
109
+
110
+ def userVerifyEmail(self, user_id):
111
+ return self.client.post(f'/api/admin/users/{user_id}/email/verify')
112
+
113
+ # servers
114
+ def serverByExternalId(self, external_id):
115
+ return self.client.get(f'/api/admin/servers/external/{segment(external_id)}')['server']
116
+
117
+ def deployServer(self, **fields):
118
+ return self.client.post('/api/admin/servers/deploy', json=fields)['server']
119
+
120
+ def serverLogs(self, server_id, lines=None, install=False):
121
+ suffix = 'logs/install' if install else 'logs'
122
+ return self.client.get(f'/api/admin/servers/{server_id}/{suffix}', params={'lines': lines})
123
+
124
+ def serverVariables(self, server_id):
125
+ return self.client.get(f'/api/admin/servers/{server_id}/variables')['variables']
126
+
127
+ def setServerVariables(self, server_id, variables):
128
+ return self.client.put(f'/api/admin/servers/{server_id}/variables', json={'variables': variables})
129
+
130
+ def serverAllocations(self, server_id, search=None, page=None, per_page=None):
131
+ return self.servers.related(server_id, 'allocations', 'allocations', search, page, per_page)
132
+
133
+ def addServerAllocation(self, server_id, allocation_uuid):
134
+ return self.client.post(f'/api/admin/servers/{server_id}/allocations', json={'allocation_uuid': allocation_uuid})['allocation']
135
+
136
+ def updateServerAllocation(self, server_id, allocation_id, notes=None, primary=None):
137
+ return self.client.patch(f'/api/admin/servers/{server_id}/allocations/{allocation_id}', json={'notes': notes, 'primary': primary})
138
+
139
+ def removeServerAllocation(self, server_id, allocation_id):
140
+ return self.client.delete(f'/api/admin/servers/{server_id}/allocations/{allocation_id}')
141
+
142
+ def serverBackups(self, server_id, partially_detached=None, search=None, page=None, per_page=None):
143
+ return self.servers.related(server_id, 'backups', 'backups', search, page, per_page, partially_detached=partially_detached)
144
+
145
+ def serverDeleteFailedBackups(self, server_id, force=False, partially_detached=None):
146
+ return self.client.post(
147
+ f'/api/admin/servers/{server_id}/backups/delete-failed',
148
+ json={'force': force, 'partially_detached': partially_detached}
149
+ )['queued']
150
+
151
+ def serverDatabases(self, server_id, search=None, page=None, per_page=None):
152
+ return self.servers.related(server_id, 'databases', 'databases', search, page, per_page)
153
+
154
+ def serverDatabaseInstances(self, server_id, search=None, page=None, per_page=None):
155
+ return self.servers.related(server_id, 'databases/instances', 'instances', search, page, per_page)
156
+
157
+ def serverMounts(self, server_id, available=False, search=None, page=None, per_page=None):
158
+ suffix = 'mounts/available' if available else 'mounts'
159
+ return self.servers.related(server_id, suffix, 'mounts', search, page, per_page)
160
+
161
+ def serverDevices(self, server_id, available=False, search=None, page=None, per_page=None):
162
+ suffix = 'devices/available' if available else 'devices'
163
+ return self.servers.related(server_id, suffix, 'devices', search, page, per_page)
164
+
165
+ def clearServerState(self, server_id):
166
+ return self.client.post(f'/api/admin/servers/{server_id}/clear-state')
167
+
168
+ def transferServer(self, server_id, **fields):
169
+ return self.client.post(f'/api/admin/servers/{server_id}/transfer', json=fields)
170
+
171
+ def cancelServerTransfer(self, server_id):
172
+ return self.client.post(f'/api/admin/servers/{server_id}/transfer/cancel')
173
+
174
+ # nodes
175
+ def nodeAllocations(self, node_id, search=None, ip=None, port_from=None, port_to=None, assigned=None, page=None, per_page=None):
176
+ return self.nodes.related(
177
+ node_id, 'allocations', 'allocations', search, page, per_page,
178
+ ip=ip, port_from=port_from, port_to=port_to, assigned=assigned
179
+ )
180
+
181
+ def nodeAvailableAllocations(self, node_id, search=None, page=None, per_page=None):
182
+ return self.nodes.related(node_id, 'allocations/available', 'allocations', search, page, per_page)
183
+
184
+ def nodeAllocationIps(self, node_id):
185
+ return self.client.get(f'/api/admin/nodes/{node_id}/allocations/ips')['ips']
186
+
187
+ def createNodeAllocations(self, node_id, ip, ports, ip_alias=None):
188
+ return self.client.post(f'/api/admin/nodes/{node_id}/allocations', json={'ip': ip, 'ports': ports, 'ip_alias': ip_alias})['created']
189
+
190
+ def updateNodeAllocations(self, node_id, selector, ip, ip_alias=None):
191
+ return self.client.patch(f'/api/admin/nodes/{node_id}/allocations', json={'selector': selector, 'ip': ip, 'ip_alias': ip_alias})
192
+
193
+ def deleteNodeAllocations(self, node_id, selector, force=None):
194
+ return self.client.delete(f'/api/admin/nodes/{node_id}/allocations', json={'selector': selector, 'force': force})
195
+
196
+ def nodeBackups(self, node_id, detached=None, search=None, page=None, per_page=None):
197
+ return self.nodes.related(node_id, 'backups', 'backups', search, page, per_page, detached=detached)
198
+
199
+ def nodeBackup(self, node_id, backup_id):
200
+ return self.client.get(f'/api/admin/nodes/{node_id}/backups/{backup_id}')['backup']
201
+
202
+ def nodeBackupAction(self, node_id, backup_id, action, method='POST', json=None):
203
+ suffix = f'/{action}' if action else ''
204
+ return self.client.request(method, f'/api/admin/nodes/{node_id}/backups/{backup_id}{suffix}', json=json)
205
+
206
+ def nodeDeleteFailedBackups(self, node_id, force=False, detached=None):
207
+ return self.client.post(f'/api/admin/nodes/{node_id}/backups/delete-failed', json={'force': force, 'detached': detached})['queued']
208
+
209
+ def nodeConfig(self, node_id):
210
+ return self.client.get(f'/api/admin/nodes/{node_id}/config')
211
+
212
+ def updateNodeConfig(self, node_id, config):
213
+ return self.client.patch(f'/api/admin/nodes/{node_id}/config', json=config)['applied']
214
+
215
+ def updateNodesConfig(self, node_ids, config):
216
+ return self.client.patch('/api/admin/nodes/config', json={'node_uuids': node_ids, 'config': config})
217
+
218
+ def nodeCapacities(self):
219
+ return self.client.get('/api/admin/nodes/capacities')['allocated']
220
+
221
+ def probeNode(self, url, pairing_code):
222
+ return self.client.post('/api/admin/nodes/probe', json={'url': url, 'pairing_code': pairing_code})['probe']
223
+
224
+ def nodeGet(self, node_id, suffix, params=None):
225
+ return self.client.get(f'/api/admin/nodes/{node_id}/{suffix}', params=params)
226
+
227
+ def nodePost(self, node_id, suffix, json=None):
228
+ return self.client.post(f'/api/admin/nodes/{node_id}/{suffix}', json=json)
229
+
230
+ def nodeSystemLog(self, node_id, file, lines=None):
231
+ return self.client.get(f'/api/admin/nodes/{node_id}/system/logs/{segment(file)}', params={'lines': lines})
232
+
233
+ def nodeServerPower(self, node_id, action, server_ids=None):
234
+ selector = {'type': 'uuids', 'uuids': server_ids} if server_ids else {'type': 'all'}
235
+ return self.client.post(f'/api/admin/nodes/{node_id}/servers/power', json={'servers': selector, 'action': action})['affected']
236
+
237
+ def nodeServerTransfer(self, node_id, **fields):
238
+ return self.client.post(f'/api/admin/nodes/{node_id}/servers/transfer', json=fields)
239
+
240
+ def nodeTunnel(self, node_id, method='GET', json=None, suffix=''):
241
+ return self.client.request(method, f'/api/admin/nodes/{node_id}/tunnel{suffix}', json=json)
242
+
243
+ # nests and eggs
244
+ def allEggs(self):
245
+ return self.client.get('/api/admin/nests/eggs')['nests']
246
+
247
+ # egg repositories
248
+ def syncEggRepository(self, repository_id):
249
+ return self.client.post(f'/api/admin/egg-repositories/{repository_id}/sync')['found']
250
+
251
+ def installRepositoryEggs(self, repository_id, egg_ids, nest_uuid):
252
+ return self.client.post(
253
+ f'/api/admin/egg-repositories/{repository_id}/eggs/install',
254
+ json={'egg_uuids': egg_ids, 'nest_uuid': nest_uuid}
255
+ )['installed']
256
+
257
+ def installRepositoryEgg(self, repository_id, egg_id, nest_uuid):
258
+ return self.client.post(
259
+ f'/api/admin/egg-repositories/{repository_id}/eggs/{egg_id}/install',
260
+ json={'nest_uuid': nest_uuid}
261
+ )['egg']
262
+
263
+ # oauth
264
+ def discoverOauthProvider(self, url):
265
+ return self.client.post('/api/admin/oauth-providers/discover', json={'url': url})['oauth_provider']
266
+
267
+ def oauthProviderUserLink(self, oauth_provider_id, identifier):
268
+ return self.client.get(f'/api/admin/oauth-providers/{oauth_provider_id}/users/identifier/{segment(identifier)}')['user_oauth_link']
269
+
270
+ # database agent hosts
271
+ def databaseAgentHostGet(self, host_id, suffix, params=None):
272
+ return self.client.get(f'/api/admin/database-agent-hosts/{host_id}/{suffix}', params=params)
273
+
274
+ def databaseAgentHostPost(self, host_id, suffix, json=None):
275
+ return self.client.post(f'/api/admin/database-agent-hosts/{host_id}/{suffix}', json=json)
276
+
277
+ def databaseAgentInstance(self, host_id, instance_id, method='GET', json=None):
278
+ return self.client.request(method, f'/api/admin/database-agent-hosts/{host_id}/instances/{instance_id}', json=json)
279
+
280
+ def updateDatabaseAgentHostConfig(self, host_id, config):
281
+ return self.client.patch(f'/api/admin/database-agent-hosts/{host_id}/config', json=config)['applied']
282
+
283
+ def updateDatabaseAgentHostsConfig(self, host_ids, config):
284
+ return self.client.patch('/api/admin/database-agent-hosts/config', json={'database_agent_host_uuids': host_ids, 'config': config})
285
+
286
+ def databaseAgentCapacities(self):
287
+ return self.client.get('/api/admin/database-agent-hosts/capacities')['allocated']
288
+
289
+ def updateTemplateInstances(self, template_id, instances):
290
+ return self.client.post(
291
+ f'/api/admin/database-agent-templates/{template_id}/instances/update',
292
+ json={'instances': instances}
293
+ )['updated']
294
+
295
+ # database hosts
296
+ def testDatabaseHost(self, host_id):
297
+ return self.client.post(f'/api/admin/database-hosts/{host_id}/test')
298
+
299
+ def deleteHostDatabase(self, host_id, database_id, force=False):
300
+ return self.client.delete(f'/api/admin/database-hosts/{host_id}/databases/{database_id}', json={'force': force})
301
+
302
+ # backup configurations
303
+ def testBackupConfiguration(self, node_uuid, backup_disk, backup_configs):
304
+ return self.client.post('/api/admin/backup-configurations/test', json={
305
+ 'node_uuid': node_uuid,
306
+ 'backup_disk': backup_disk,
307
+ 'backup_configs': backup_configs,
308
+ })
309
+
310
+ def deleteFailedBackups(self, collection, resource_id, force=False):
311
+ return self.client.post(f'/api/admin/{collection}/{resource_id}/backups/delete-failed', json={'force': force})['queued']
312
+
313
+ def backupConfigurationStats(self, configuration_id):
314
+ return self.client.get(f'/api/admin/backup-configurations/{configuration_id}/stats')
315
+
316
+ def triggerSystemBackupPolicy(self, policy_id):
317
+ return self.client.post(f'/api/admin/system-backup-policies/{policy_id}/trigger')
318
+
319
+ # subdomain manager
320
+ def testSubdomainDomain(self, domain_id):
321
+ return self.client.post(f'/api/admin/extensions/dev.0x7d8.subdomainmanager/domains/{domain_id}/test')
322
+
323
+ # settings and stats
324
+ def settings(self):
325
+ return self.client.get('/api/admin/settings')['settings']
326
+
327
+ def updateSettings(self, **fields):
328
+ return self.client.put('/api/admin/settings', json=fields)
329
+
330
+ def activity(self, user=None, search=None, page=None, per_page=None):
331
+ return self.client.list('/api/admin/activity', 'activities', {'user': user, 'search': search}, page, per_page)
332
+
333
+ def generalStats(self):
334
+ return self.client.get('/api/admin/stats/general')['stats']
335
+
336
+ def backupStats(self):
337
+ return self.client.get('/api/admin/stats/backups')
338
+
339
+ # system
340
+ def system(self, suffix, method='GET', json=None, params=None):
341
+ return self.client.request(method, f'/api/admin/system/{suffix}', json=json, params=params)
342
+
343
+ # email
344
+ def emailTemplates(self):
345
+ return self.client.get('/api/admin/system/email/templates')['email_templates']
346
+
347
+ def emailTemplate(self, identifier):
348
+ return self.client.get(f'/api/admin/system/email/templates/{segment(identifier)}')['email_template']
349
+
350
+ def updateEmailTemplate(self, identifier, subject=None, content=None, enabled=None):
351
+ return self.client.put(f'/api/admin/system/email/templates/{segment(identifier)}', json={'subject': subject, 'content': content, 'enabled': enabled})
352
+
353
+ def emailVariables(self, identifier=None):
354
+ path = f'templates/{segment(identifier)}/variables' if identifier else 'variables'
355
+ return self.client.get(f'/api/admin/system/email/{path}')['email_variables']
356
+
357
+ def createEmailVariable(self, name, value, value_translations=None, identifier=None):
358
+ path = f'templates/{segment(identifier)}/variables' if identifier else 'variables'
359
+ return self.client.post(f'/api/admin/system/email/{path}', json={'name': name, 'value': value, 'value_translations': value_translations})
360
+
361
+ def updateEmailVariable(self, name, value=None, value_translations=None, identifier=None):
362
+ path = f'templates/{segment(identifier)}/variables' if identifier else 'variables'
363
+ return self.client.put(f'/api/admin/system/email/{path}/{segment(name)}', json={'value': value, 'value_translations': value_translations})
364
+
365
+ def deleteEmailVariable(self, name, identifier=None):
366
+ path = f'templates/{segment(identifier)}/variables' if identifier else 'variables'
367
+ return self.client.delete(f'/api/admin/system/email/{path}/{segment(name)}')
368
+
369
+ def sendTestEmail(self, email):
370
+ return self.client.post('/api/admin/system/email/test', json={'email': email})
371
+
372
+ # assets
373
+ def assets(self, directory=None, page=None, per_page=None):
374
+ return self.client.list('/api/admin/assets', 'assets', {'directory': directory}, page, per_page)
375
+
376
+ def uploadAsset(self, content, directory=None, content_type='application/octet-stream'):
377
+ return self.client.request(
378
+ 'PUT', '/api/admin/assets', params={'directory': directory},
379
+ data=content, headers={'Content-Type': content_type}
380
+ )['assets']
381
+
382
+ def searchAssets(self, search, directory=None, per_page=None):
383
+ return self.client.post('/api/admin/assets/search', json={'search': search, 'directory': directory, 'per_page': per_page})['assets']
384
+
385
+ def deleteAssets(self, names):
386
+ return self.client.post('/api/admin/assets/delete', json={'names': names})['deleted']
387
+
388
+ # extensions
389
+ def extensions(self):
390
+ return self.client.get('/api/admin/extensions')
391
+
392
+ def setExtensionEnabled(self, extension_id, enabled):
393
+ return self.client.patch(f'/api/admin/extensions/{segment(extension_id)}', json={'enabled': enabled})['pending_restart']
394
+
395
+ def manageExtensions(self, suffix, method='GET', json=None, params=None, data=None, headers=None):
396
+ return self.client.request(method, f'/api/admin/extensions/manage/{suffix}', json=json, params=params, data=data, headers=headers)
397
+
398
+ def removeExtension(self, extension_id, remove_migrations=False):
399
+ return self.client.delete(f'/api/admin/extensions/manage/{segment(extension_id)}', json={'remove_migrations': remove_migrations})
400
+
401
+ def extension(self, extension_id, suffix, method='GET', json=None):
402
+ return self.client.request(method, f'/api/admin/extensions/{extension_id}/{suffix}', json=json)
@@ -0,0 +1,27 @@
1
+ # Internal Calagopus AttachmentsAPI (server mounts and devices)
2
+ class AttachmentsAPI:
3
+ def __init__(self, client):
4
+ self.client = client
5
+
6
+ def _path(self, server_id, suffix=''):
7
+ return f'/api/client/servers/{server_id}{suffix}'
8
+
9
+ # mounts
10
+ def mounts(self, server_id, search=None, page=None, per_page=None):
11
+ return self.client.list(self._path(server_id, '/mounts'), 'mounts', {'search': search}, page, per_page)
12
+
13
+ def attachMount(self, server_id, mount_uuid):
14
+ return self.client.post(self._path(server_id, '/mounts'), json={'mount_uuid': mount_uuid})
15
+
16
+ def detachMount(self, server_id, mount_uuid):
17
+ return self.client.delete(self._path(server_id, f'/mounts/{mount_uuid}'))
18
+
19
+ # devices
20
+ def devices(self, server_id, search=None, page=None, per_page=None):
21
+ return self.client.list(self._path(server_id, '/devices'), 'devices', {'search': search}, page, per_page)
22
+
23
+ def attachDevice(self, server_id, device_uuid):
24
+ return self.client.post(self._path(server_id, '/devices'), json={'device_uuid': device_uuid})
25
+
26
+ def detachDevice(self, server_id, device_uuid):
27
+ return self.client.delete(self._path(server_id, f'/devices/{device_uuid}'))