mtn-cloud 0.2.16__tar.gz → 0.2.19__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.
Files changed (88) hide show
  1. {mtn_cloud-0.2.16 → mtn_cloud-0.2.19}/PKG-INFO +111 -14
  2. {mtn_cloud-0.2.16 → mtn_cloud-0.2.19}/README.md +110 -13
  3. {mtn_cloud-0.2.16 → mtn_cloud-0.2.19}/docs/api-overview.md +20 -1
  4. mtn_cloud-0.2.19/docs/api-reference/backups.md +59 -0
  5. {mtn_cloud-0.2.16 → mtn_cloud-0.2.19}/docs/api-reference/index.md +3 -0
  6. {mtn_cloud-0.2.16 → mtn_cloud-0.2.19}/docs/api-reference/instances.md +67 -2
  7. {mtn_cloud-0.2.16 → mtn_cloud-0.2.19}/docs/api-reference/networks.md +16 -20
  8. mtn_cloud-0.2.19/docs/api-reference/security-groups.md +94 -0
  9. mtn_cloud-0.2.19/docs/api-reference/virtual-images.md +37 -0
  10. mtn_cloud-0.2.19/docs/backups.md +80 -0
  11. {mtn_cloud-0.2.16 → mtn_cloud-0.2.19}/docs/index.md +13 -7
  12. {mtn_cloud-0.2.16 → mtn_cloud-0.2.19}/docs/instances.md +82 -11
  13. {mtn_cloud-0.2.16 → mtn_cloud-0.2.19}/docs/networking.md +24 -28
  14. mtn_cloud-0.2.19/docs/security-groups.md +146 -0
  15. mtn_cloud-0.2.19/docs/virtual-images.md +65 -0
  16. {mtn_cloud-0.2.16 → mtn_cloud-0.2.19}/src/mtn_cloud/_version.py +1 -1
  17. {mtn_cloud-0.2.16 → mtn_cloud-0.2.19}/src/mtn_cloud/client.py +59 -3
  18. {mtn_cloud-0.2.16 → mtn_cloud-0.2.19}/src/mtn_cloud/config.py +1 -7
  19. {mtn_cloud-0.2.16 → mtn_cloud-0.2.19}/src/mtn_cloud/http.py +0 -13
  20. {mtn_cloud-0.2.16 → mtn_cloud-0.2.19}/src/mtn_cloud/models/__init__.py +36 -2
  21. mtn_cloud-0.2.19/src/mtn_cloud/models/backup.py +93 -0
  22. {mtn_cloud-0.2.16 → mtn_cloud-0.2.19}/src/mtn_cloud/models/base.py +3 -6
  23. {mtn_cloud-0.2.16 → mtn_cloud-0.2.19}/src/mtn_cloud/models/cloud.py +0 -10
  24. {mtn_cloud-0.2.16 → mtn_cloud-0.2.19}/src/mtn_cloud/models/group.py +0 -8
  25. {mtn_cloud-0.2.16 → mtn_cloud-0.2.19}/src/mtn_cloud/models/instance.py +3 -55
  26. {mtn_cloud-0.2.16 → mtn_cloud-0.2.19}/src/mtn_cloud/models/instance_type.py +0 -8
  27. {mtn_cloud-0.2.16 → mtn_cloud-0.2.19}/src/mtn_cloud/models/network.py +43 -19
  28. {mtn_cloud-0.2.16 → mtn_cloud-0.2.19}/src/mtn_cloud/models/plan.py +0 -8
  29. mtn_cloud-0.2.19/src/mtn_cloud/models/resource_pool.py +50 -0
  30. mtn_cloud-0.2.19/src/mtn_cloud/models/security_group.py +195 -0
  31. mtn_cloud-0.2.19/src/mtn_cloud/models/snapshot.py +54 -0
  32. {mtn_cloud-0.2.16 → mtn_cloud-0.2.19}/src/mtn_cloud/models/user.py +0 -6
  33. mtn_cloud-0.2.19/src/mtn_cloud/models/virtual_image.py +57 -0
  34. {mtn_cloud-0.2.16 → mtn_cloud-0.2.19}/src/mtn_cloud/models/volume.py +1 -10
  35. {mtn_cloud-0.2.16 → mtn_cloud-0.2.19}/src/mtn_cloud/resources/__init__.py +8 -0
  36. mtn_cloud-0.2.19/src/mtn_cloud/resources/backups.py +173 -0
  37. {mtn_cloud-0.2.16 → mtn_cloud-0.2.19}/src/mtn_cloud/resources/instances.py +278 -14
  38. {mtn_cloud-0.2.16 → mtn_cloud-0.2.19}/src/mtn_cloud/resources/networks.py +63 -45
  39. mtn_cloud-0.2.19/src/mtn_cloud/resources/security_groups.py +350 -0
  40. mtn_cloud-0.2.19/src/mtn_cloud/resources/virtual_images.py +124 -0
  41. {mtn_cloud-0.2.16 → mtn_cloud-0.2.19}/tests/conftest.py +20 -3
  42. {mtn_cloud-0.2.16 → mtn_cloud-0.2.19}/tests/test_archive_buckets.py +62 -76
  43. mtn_cloud-0.2.19/tests/test_backups.py +163 -0
  44. mtn_cloud-0.2.19/tests/test_client.py +230 -0
  45. mtn_cloud-0.2.19/tests/test_clouds.py +102 -0
  46. {mtn_cloud-0.2.16 → mtn_cloud-0.2.19}/tests/test_config.py +65 -58
  47. mtn_cloud-0.2.19/tests/test_groups.py +69 -0
  48. mtn_cloud-0.2.19/tests/test_instance_types.py +370 -0
  49. mtn_cloud-0.2.19/tests/test_instances.py +549 -0
  50. mtn_cloud-0.2.19/tests/test_networks.py +445 -0
  51. mtn_cloud-0.2.19/tests/test_plans.py +107 -0
  52. mtn_cloud-0.2.19/tests/test_security_groups.py +239 -0
  53. mtn_cloud-0.2.19/tests/test_storage_buckets.py +256 -0
  54. mtn_cloud-0.2.19/tests/test_virtual_images.py +117 -0
  55. mtn_cloud-0.2.16/tests/test_client.py +0 -183
  56. mtn_cloud-0.2.16/tests/test_clouds.py +0 -50
  57. mtn_cloud-0.2.16/tests/test_instance_types.py +0 -325
  58. mtn_cloud-0.2.16/tests/test_instances.py +0 -367
  59. mtn_cloud-0.2.16/tests/test_networks.py +0 -256
  60. mtn_cloud-0.2.16/tests/test_storage_buckets.py +0 -152
  61. {mtn_cloud-0.2.16 → mtn_cloud-0.2.19}/.gitignore +0 -0
  62. {mtn_cloud-0.2.16 → mtn_cloud-0.2.19}/LICENSE +0 -0
  63. {mtn_cloud-0.2.16 → mtn_cloud-0.2.19}/docs/advanced-cookbook.md +0 -0
  64. {mtn_cloud-0.2.16 → mtn_cloud-0.2.19}/docs/api-reference/archive-buckets.md +0 -0
  65. {mtn_cloud-0.2.16 → mtn_cloud-0.2.19}/docs/api-reference/client.md +0 -0
  66. {mtn_cloud-0.2.16 → mtn_cloud-0.2.19}/docs/api-reference/clouds.md +0 -0
  67. {mtn_cloud-0.2.16 → mtn_cloud-0.2.19}/docs/api-reference/groups.md +0 -0
  68. {mtn_cloud-0.2.16 → mtn_cloud-0.2.19}/docs/api-reference/instance-types.md +0 -0
  69. {mtn_cloud-0.2.16 → mtn_cloud-0.2.19}/docs/api-reference/plans.md +0 -0
  70. {mtn_cloud-0.2.16 → mtn_cloud-0.2.19}/docs/api-reference/storage-buckets.md +0 -0
  71. {mtn_cloud-0.2.16 → mtn_cloud-0.2.19}/docs/docstring-style.md +0 -0
  72. {mtn_cloud-0.2.16 → mtn_cloud-0.2.19}/docs/quickstart.md +0 -0
  73. {mtn_cloud-0.2.16 → mtn_cloud-0.2.19}/docs/storage.md +0 -0
  74. {mtn_cloud-0.2.16 → mtn_cloud-0.2.19}/docs/stylesheets/extra.css +0 -0
  75. {mtn_cloud-0.2.16 → mtn_cloud-0.2.19}/pyproject.toml +0 -0
  76. {mtn_cloud-0.2.16 → mtn_cloud-0.2.19}/src/mtn_cloud/__init__.py +0 -0
  77. {mtn_cloud-0.2.16 → mtn_cloud-0.2.19}/src/mtn_cloud/exceptions.py +0 -0
  78. {mtn_cloud-0.2.16 → mtn_cloud-0.2.19}/src/mtn_cloud/models/archive.py +0 -0
  79. {mtn_cloud-0.2.16 → mtn_cloud-0.2.19}/src/mtn_cloud/models/storage_bucket.py +0 -0
  80. {mtn_cloud-0.2.16 → mtn_cloud-0.2.19}/src/mtn_cloud/resources/archive_buckets.py +0 -0
  81. {mtn_cloud-0.2.16 → mtn_cloud-0.2.19}/src/mtn_cloud/resources/base.py +0 -0
  82. {mtn_cloud-0.2.16 → mtn_cloud-0.2.19}/src/mtn_cloud/resources/clouds.py +0 -0
  83. {mtn_cloud-0.2.16 → mtn_cloud-0.2.19}/src/mtn_cloud/resources/groups.py +0 -0
  84. {mtn_cloud-0.2.16 → mtn_cloud-0.2.19}/src/mtn_cloud/resources/instance_types.py +0 -0
  85. {mtn_cloud-0.2.16 → mtn_cloud-0.2.19}/src/mtn_cloud/resources/plans.py +0 -0
  86. {mtn_cloud-0.2.16 → mtn_cloud-0.2.19}/src/mtn_cloud/resources/storage_buckets.py +0 -0
  87. {mtn_cloud-0.2.16 → mtn_cloud-0.2.19}/tests/__init__.py +0 -0
  88. {mtn_cloud-0.2.16 → mtn_cloud-0.2.19}/tests/test_exceptions.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mtn-cloud
3
- Version: 0.2.16
3
+ Version: 0.2.19
4
4
  Summary: Community Python SDK for MTN Cloud - Deploy and manage cloud resources with ease
5
5
  Project-URL: Homepage, https://github.com/mahveotm/mtn-cloud-python
6
6
  Project-URL: Documentation, https://github.com/mahveotm/mtn-cloud-python#readme
@@ -50,7 +50,7 @@ Description-Content-Type: text/markdown
50
50
  [![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
51
51
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
52
52
 
53
- A Modern Python SDK for [MTN Cloud](https://console.cloud.mtn.ng) with typed models, clear resource managers, and practical workflows for compute, networking, storage, and archives.
53
+ A Modern Python SDK for [MTN Cloud](https://console.cloud.mtn.ng) with typed models, clear resource managers, and practical workflows for compute, networking, storage, archives, security groups, backups, and more.
54
54
 
55
55
  Docs: [mtn-cloud-python](https://mahveotm.github.io/mtn-cloud-python/)
56
56
 
@@ -78,6 +78,9 @@ pip install mtn-cloud
78
78
  - [Instances](https://mahveotm.github.io/mtn-cloud-python/instances/)
79
79
  - [Networking](https://mahveotm.github.io/mtn-cloud-python/networking/)
80
80
  - [Storage](https://mahveotm.github.io/mtn-cloud-python/storage/)
81
+ - [Security Groups](https://mahveotm.github.io/mtn-cloud-python/security-groups/)
82
+ - [Backups](https://mahveotm.github.io/mtn-cloud-python/backups/)
83
+ - [Virtual Images](https://mahveotm.github.io/mtn-cloud-python/virtual-images/)
81
84
  - [Advanced Cookbook](https://mahveotm.github.io/mtn-cloud-python/advanced-cookbook/)
82
85
  - [API Overview](https://mahveotm.github.io/mtn-cloud-python/api-overview/)
83
86
  - [API Reference](https://mahveotm.github.io/mtn-cloud-python/api-reference/)
@@ -124,23 +127,45 @@ User Icon (top-right) -> User Settings -> API Access.
124
127
 
125
128
  ### 1. Discover Reference Data
126
129
 
127
- Use these lookups before provisioning so your scripts stay deterministic.
130
+ Use these lookups before provisioning so your scripts stay deterministic. They all use permission-safe endpoints (the admin-level `clouds`/`plans` endpoints are restricted on most tenant accounts — you don't need them).
128
131
 
129
132
  ```python
130
- # Groups (sites)
131
- groups = cloud.groups.list()
132
- for group in groups[:5]:
133
- print(group.id, group.name)
134
-
135
- # Instance types
136
- types = cloud.instance_types.list_os()
137
- for t in types[:5]:
138
- print(t.code, t.name, t.default_layout_id)
133
+ # Groups (sites) — also carry the cloud/zone IDs you need
134
+ group = cloud.groups.get_by_name("MTNNG_CLOUD_AZ_1")
135
+ print(group.id, group.name, group.cloud_ids)
136
+
137
+ # Instance types — each carries its own default_layout_id
138
+ itype = cloud.instance_types.get_by_code("MTN-CS10")
139
+ print(itype.code, itype.default_layout_id)
140
+
141
+ # Resource pools — where the instance is hosted (the resource_pool_id)
142
+ for pool in cloud.instances.list_resource_pools(group="MTNNG_CLOUD_AZ_1"):
143
+ print(pool.code, pool.name)
144
+
145
+ # Service plans — CPU/memory/storage tiers for this zone + layout
146
+ for plan in cloud.instances.list_service_plans(
147
+ zone_id=group.cloud_ids[0],
148
+ layout_id=itype.default_layout_id,
149
+ group_id=group.id,
150
+ ):
151
+ print(plan["id"], plan["name"])
152
+ ```
153
+
154
+ A **resource pool is required** to create an instance — it's where the VM is hosted. Discover it by group name (the cloud/zone is resolved for you), or fetch one directly by name:
155
+
156
+ ```python
157
+ pool = cloud.instances.get_resource_pool(
158
+ "my-project-name",
159
+ group="MTNNG_CLOUD_AZ_1",
160
+ )
161
+ print(pool.code) # e.g. "pool-214" — pass this as resource_pool_id
139
162
  ```
140
163
 
141
164
  ### 2. Create an Instance
142
165
 
143
166
  ```python
167
+ pool = cloud.instances.get_resource_pool("my-project-name", group="MTNNG_CLOUD_AZ_1")
168
+
144
169
  instance = cloud.instances.create(
145
170
  name="my-server",
146
171
  cloud="MTNNG_CLOUD_AZ_1",
@@ -148,7 +173,7 @@ instance = cloud.instances.create(
148
173
  group="MTNNG_CLOUD_AZ_1",
149
174
  layout=327,
150
175
  plan=6776,
151
- resource_pool_id="pool-214",
176
+ resource_pool_id=pool.code, # "pool-214" — or pass the numeric ID 214
152
177
  labels=["production", "web"],
153
178
  )
154
179
 
@@ -200,7 +225,79 @@ subnets = cloud.networks.list_subnets(new_network.id)
200
225
  print(f"Subnets: {len(subnets)}")
201
226
  ```
202
227
 
203
- ### 5. Work with Storage and Archives
228
+ ### 5. Manage Security Groups
229
+
230
+ ```python
231
+ # Create a security group and add rules
232
+ sg = cloud.security_groups.create(
233
+ name="web-servers",
234
+ description="HTTP, HTTPS, and SSH access",
235
+ )
236
+
237
+ cloud.security_groups.create_rule(
238
+ sg.id,
239
+ name="allow-ssh",
240
+ direction="ingress",
241
+ protocol="tcp",
242
+ port_range="22",
243
+ )
244
+
245
+ cloud.security_groups.create_rule(
246
+ sg.id,
247
+ name="allow-https",
248
+ direction="ingress",
249
+ protocol="tcp",
250
+ port_range="443",
251
+ )
252
+
253
+ # Use the security group when provisioning
254
+ instance = cloud.instances.create(
255
+ name="app-server-01",
256
+ cloud="MTNNG_CLOUD_AZ_1",
257
+ type="MTN-CS10",
258
+ group="MTNNG_CLOUD_AZ_1",
259
+ layout=327,
260
+ plan=6776,
261
+ resource_pool_id="pool-214",
262
+ security_group="web-servers",
263
+ )
264
+ ```
265
+
266
+ ### 6. Snapshot Instances
267
+
268
+ ```python
269
+ # Create a snapshot before a risky operation
270
+ snap = cloud.instances.create_snapshot(
271
+ instance_id=instance.id,
272
+ name="pre-upgrade",
273
+ )
274
+
275
+ # Revert if something goes wrong (stop the instance first)
276
+ cloud.instances.stop(instance.id)
277
+ cloud.instances.wait_until_stopped(instance.id)
278
+ cloud.instances.revert_snapshot(instance.id, snapshot_id=snap.id)
279
+ ```
280
+
281
+ ### 7. Work with Backups
282
+
283
+ ```python
284
+ # List configured backups and their status
285
+ for backup in cloud.backups.list():
286
+ print(f"{backup.name}: last_run={backup.last_run} status={backup.last_status}")
287
+
288
+ # Trigger an immediate backup run
289
+ cloud.backups.execute(backup_id=42)
290
+
291
+ # Check execution history
292
+ for result in cloud.backups.list_results(backup_id=42):
293
+ print(f"{result.start_date}: {result.status} ({result.size_in_mb} MB)")
294
+
295
+ # List and execute backup jobs (schedules)
296
+ for job in cloud.backups.list_jobs():
297
+ print(f"{job.name}: cron={job.cron_expression}")
298
+ ```
299
+
300
+ ### 8. Work with Storage and Archives
204
301
 
205
302
  ```python
206
303
  # Create S3-compatible storage provider
@@ -6,7 +6,7 @@
6
6
  [![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
7
7
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
8
8
 
9
- A Modern Python SDK for [MTN Cloud](https://console.cloud.mtn.ng) with typed models, clear resource managers, and practical workflows for compute, networking, storage, and archives.
9
+ A Modern Python SDK for [MTN Cloud](https://console.cloud.mtn.ng) with typed models, clear resource managers, and practical workflows for compute, networking, storage, archives, security groups, backups, and more.
10
10
 
11
11
  Docs: [mtn-cloud-python](https://mahveotm.github.io/mtn-cloud-python/)
12
12
 
@@ -34,6 +34,9 @@ pip install mtn-cloud
34
34
  - [Instances](https://mahveotm.github.io/mtn-cloud-python/instances/)
35
35
  - [Networking](https://mahveotm.github.io/mtn-cloud-python/networking/)
36
36
  - [Storage](https://mahveotm.github.io/mtn-cloud-python/storage/)
37
+ - [Security Groups](https://mahveotm.github.io/mtn-cloud-python/security-groups/)
38
+ - [Backups](https://mahveotm.github.io/mtn-cloud-python/backups/)
39
+ - [Virtual Images](https://mahveotm.github.io/mtn-cloud-python/virtual-images/)
37
40
  - [Advanced Cookbook](https://mahveotm.github.io/mtn-cloud-python/advanced-cookbook/)
38
41
  - [API Overview](https://mahveotm.github.io/mtn-cloud-python/api-overview/)
39
42
  - [API Reference](https://mahveotm.github.io/mtn-cloud-python/api-reference/)
@@ -80,23 +83,45 @@ User Icon (top-right) -> User Settings -> API Access.
80
83
 
81
84
  ### 1. Discover Reference Data
82
85
 
83
- Use these lookups before provisioning so your scripts stay deterministic.
86
+ Use these lookups before provisioning so your scripts stay deterministic. They all use permission-safe endpoints (the admin-level `clouds`/`plans` endpoints are restricted on most tenant accounts — you don't need them).
84
87
 
85
88
  ```python
86
- # Groups (sites)
87
- groups = cloud.groups.list()
88
- for group in groups[:5]:
89
- print(group.id, group.name)
90
-
91
- # Instance types
92
- types = cloud.instance_types.list_os()
93
- for t in types[:5]:
94
- print(t.code, t.name, t.default_layout_id)
89
+ # Groups (sites) — also carry the cloud/zone IDs you need
90
+ group = cloud.groups.get_by_name("MTNNG_CLOUD_AZ_1")
91
+ print(group.id, group.name, group.cloud_ids)
92
+
93
+ # Instance types — each carries its own default_layout_id
94
+ itype = cloud.instance_types.get_by_code("MTN-CS10")
95
+ print(itype.code, itype.default_layout_id)
96
+
97
+ # Resource pools — where the instance is hosted (the resource_pool_id)
98
+ for pool in cloud.instances.list_resource_pools(group="MTNNG_CLOUD_AZ_1"):
99
+ print(pool.code, pool.name)
100
+
101
+ # Service plans — CPU/memory/storage tiers for this zone + layout
102
+ for plan in cloud.instances.list_service_plans(
103
+ zone_id=group.cloud_ids[0],
104
+ layout_id=itype.default_layout_id,
105
+ group_id=group.id,
106
+ ):
107
+ print(plan["id"], plan["name"])
108
+ ```
109
+
110
+ A **resource pool is required** to create an instance — it's where the VM is hosted. Discover it by group name (the cloud/zone is resolved for you), or fetch one directly by name:
111
+
112
+ ```python
113
+ pool = cloud.instances.get_resource_pool(
114
+ "my-project-name",
115
+ group="MTNNG_CLOUD_AZ_1",
116
+ )
117
+ print(pool.code) # e.g. "pool-214" — pass this as resource_pool_id
95
118
  ```
96
119
 
97
120
  ### 2. Create an Instance
98
121
 
99
122
  ```python
123
+ pool = cloud.instances.get_resource_pool("my-project-name", group="MTNNG_CLOUD_AZ_1")
124
+
100
125
  instance = cloud.instances.create(
101
126
  name="my-server",
102
127
  cloud="MTNNG_CLOUD_AZ_1",
@@ -104,7 +129,7 @@ instance = cloud.instances.create(
104
129
  group="MTNNG_CLOUD_AZ_1",
105
130
  layout=327,
106
131
  plan=6776,
107
- resource_pool_id="pool-214",
132
+ resource_pool_id=pool.code, # "pool-214" — or pass the numeric ID 214
108
133
  labels=["production", "web"],
109
134
  )
110
135
 
@@ -156,7 +181,79 @@ subnets = cloud.networks.list_subnets(new_network.id)
156
181
  print(f"Subnets: {len(subnets)}")
157
182
  ```
158
183
 
159
- ### 5. Work with Storage and Archives
184
+ ### 5. Manage Security Groups
185
+
186
+ ```python
187
+ # Create a security group and add rules
188
+ sg = cloud.security_groups.create(
189
+ name="web-servers",
190
+ description="HTTP, HTTPS, and SSH access",
191
+ )
192
+
193
+ cloud.security_groups.create_rule(
194
+ sg.id,
195
+ name="allow-ssh",
196
+ direction="ingress",
197
+ protocol="tcp",
198
+ port_range="22",
199
+ )
200
+
201
+ cloud.security_groups.create_rule(
202
+ sg.id,
203
+ name="allow-https",
204
+ direction="ingress",
205
+ protocol="tcp",
206
+ port_range="443",
207
+ )
208
+
209
+ # Use the security group when provisioning
210
+ instance = cloud.instances.create(
211
+ name="app-server-01",
212
+ cloud="MTNNG_CLOUD_AZ_1",
213
+ type="MTN-CS10",
214
+ group="MTNNG_CLOUD_AZ_1",
215
+ layout=327,
216
+ plan=6776,
217
+ resource_pool_id="pool-214",
218
+ security_group="web-servers",
219
+ )
220
+ ```
221
+
222
+ ### 6. Snapshot Instances
223
+
224
+ ```python
225
+ # Create a snapshot before a risky operation
226
+ snap = cloud.instances.create_snapshot(
227
+ instance_id=instance.id,
228
+ name="pre-upgrade",
229
+ )
230
+
231
+ # Revert if something goes wrong (stop the instance first)
232
+ cloud.instances.stop(instance.id)
233
+ cloud.instances.wait_until_stopped(instance.id)
234
+ cloud.instances.revert_snapshot(instance.id, snapshot_id=snap.id)
235
+ ```
236
+
237
+ ### 7. Work with Backups
238
+
239
+ ```python
240
+ # List configured backups and their status
241
+ for backup in cloud.backups.list():
242
+ print(f"{backup.name}: last_run={backup.last_run} status={backup.last_status}")
243
+
244
+ # Trigger an immediate backup run
245
+ cloud.backups.execute(backup_id=42)
246
+
247
+ # Check execution history
248
+ for result in cloud.backups.list_results(backup_id=42):
249
+ print(f"{result.start_date}: {result.status} ({result.size_in_mb} MB)")
250
+
251
+ # List and execute backup jobs (schedules)
252
+ for job in cloud.backups.list_jobs():
253
+ print(f"{job.name}: cron={job.cron_expression}")
254
+ ```
255
+
256
+ ### 8. Work with Storage and Archives
160
257
 
161
258
  ```python
162
259
  # Create S3-compatible storage provider
@@ -19,6 +19,9 @@ from mtn_cloud import MTNCloud
19
19
  - `plans`
20
20
  - `storage_buckets`
21
21
  - `archive_buckets`
22
+ - `security_groups`
23
+ - `backups`
24
+ - `virtual_images`
22
25
 
23
26
  ## Authentication Options
24
27
 
@@ -39,10 +42,16 @@ cloud.instance_types.get_by_code("MTN-CS10")
39
42
  ## Common Write Operations
40
43
 
41
44
  ```python
42
- cloud.instances.create(...)
45
+ # Discover the resource pool an instance will be hosted in
46
+ pool = cloud.instances.get_resource_pool("my-project", group="MTNNG_CLOUD_AZ_1")
47
+
48
+ cloud.instances.create(..., resource_pool_id=pool.code)
43
49
  cloud.instances.update(instance_id=123, name="new-name")
44
50
  cloud.instances.delete(123)
45
51
 
52
+ cloud.instances.create_snapshot(123, "pre-upgrade")
53
+ cloud.instances.revert_snapshot(123, snapshot_id=456)
54
+
46
55
  cloud.networks.create(...)
47
56
  cloud.networks.update(298, description="updated")
48
57
  cloud.networks.delete(298)
@@ -50,6 +59,11 @@ cloud.networks.delete(298)
50
59
  cloud.storage_buckets.create_s3(...)
51
60
  cloud.archive_buckets.create(...)
52
61
  cloud.archive_buckets.upload_file(...)
62
+
63
+ cloud.security_groups.create(name="web-servers")
64
+ cloud.security_groups.create_rule(sg_id, direction="ingress", protocol="tcp", port_range="22")
65
+
66
+ cloud.backups.execute(backup_id=42)
53
67
  ```
54
68
 
55
69
  ## Exception Hierarchy
@@ -80,6 +94,11 @@ Resource methods return typed Pydantic models, for example:
80
94
  - `StorageBucket`
81
95
  - `ArchiveBucket`
82
96
  - `ArchiveFile`
97
+ - `SecurityGroup`, `SecurityGroupRule`
98
+ - `Snapshot`
99
+ - `ResourcePool`
100
+ - `Backup`, `BackupJob`, `BackupResult`
101
+ - `VirtualImage`
83
102
 
84
103
  ## Naming Conventions
85
104
 
@@ -0,0 +1,59 @@
1
+ # Resource: `cloud.backups` (`BackupsResource`)
2
+
3
+ ### `list(max_results=None, offset=0, phrase=None, **filters) -> list[Backup]`
4
+
5
+ - Endpoint: `GET /api/backups`
6
+ - Parameters:
7
+ - Shared list args (see [API Reference](./index.md#shared-list-query-arguments))
8
+ - Returns: `list[Backup]`
9
+ - Raises: common API exceptions
10
+
11
+ ### `get(backup_id: int) -> Backup`
12
+
13
+ - Endpoint: `GET /api/backups/{backup_id}`
14
+ - Returns: `Backup`
15
+ - Raises: common API exceptions
16
+
17
+ ### `execute(backup_id: int) -> dict[str, Any]`
18
+
19
+ - Endpoint: `POST /api/backups/{backup_id}/execute`
20
+ - Triggers an immediate out-of-schedule backup run
21
+ - Returns: raw execution status response
22
+ - Raises: common API exceptions
23
+
24
+ ### `list_results(backup_id: int, max_results=None) -> list[BackupResult]`
25
+
26
+ - Endpoint: `GET /api/backups/{backup_id}/results`
27
+ - Parameters:
28
+ - `max_results`: maps to query `max`
29
+ - Returns: `list[BackupResult]` — each result carries `status`, `size_in_mb`, `duration_millis`, `start_date`, `end_date`
30
+ - Raises: common API exceptions
31
+
32
+ ### `delete(backup_id: int) -> bool`
33
+
34
+ - Endpoint: `DELETE /api/backups/{backup_id}`
35
+ - Returns: `True` on success
36
+ - Raises: common API exceptions
37
+
38
+ ---
39
+
40
+ ## Job management
41
+
42
+ ### `list_jobs(max_results=None, offset=0) -> list[BackupJob]`
43
+
44
+ - Endpoint: `GET /api/backups/jobs`
45
+ - Returns: `list[BackupJob]`
46
+ - Raises: common API exceptions
47
+
48
+ ### `get_job(job_id: int) -> BackupJob`
49
+
50
+ - Endpoint: `GET /api/backups/jobs/{job_id}`
51
+ - Returns: `BackupJob`
52
+ - Raises: common API exceptions
53
+
54
+ ### `execute_job(job_id: int) -> dict[str, Any]`
55
+
56
+ - Endpoint: `POST /api/backups/jobs/{job_id}/execute`
57
+ - Triggers an immediate run of all backups under the job
58
+ - Returns: raw execution status response
59
+ - Raises: common API exceptions
@@ -13,6 +13,9 @@ This section documents the public SDK surface in endpoint-first format.
13
13
  - [Plans (`cloud.plans`)](./plans.md)
14
14
  - [Storage Buckets (`cloud.storage_buckets`)](./storage-buckets.md)
15
15
  - [Archive Buckets (`cloud.archive_buckets`)](./archive-buckets.md)
16
+ - [Security Groups (`cloud.security_groups`)](./security-groups.md)
17
+ - [Backups (`cloud.backups`)](./backups.md)
18
+ - [Virtual Images (`cloud.virtual_images`)](./virtual-images.md)
16
19
 
17
20
  ## Conventions
18
21
 
@@ -32,7 +32,7 @@
32
32
  - common API exceptions
33
33
  - `NotFoundError` when no instance matches
34
34
 
35
- ### `create(name: str, *, cloud: str, type: str, group: str, layout: int, plan: int, resource_pool_id: str, description=None, environment=None, labels=None, tags=None, copies=1, layout_size=1, availability_zone=None, security_group="default", os_external_network_id=None, create_user=True, workflow_id=None, shutdown_days=None, expire_days=None, create_backup=None, security_groups=None, ports=None, volumes=None, network_interfaces=None, options=None) -> Instance`
35
+ ### `create(name: str, *, cloud: str, type: str, group: str, layout: int, plan: int, resource_pool_id: str | int, description=None, environment=None, labels=None, tags=None, copies=1, layout_size=1, availability_zone=None, security_group="default", os_external_network_id=None, create_user=True, workflow_id=None, shutdown_days=None, expire_days=None, create_backup=None, security_groups=None, ports=None, volumes=None, network_interfaces=None, options=None) -> Instance`
36
36
 
37
37
  - Endpoint sequence:
38
38
  - `GET /api/groups?name=<group>&max=1` (resolve group name to `group_id`)
@@ -45,7 +45,7 @@
45
45
  - `group`: group/site name (resolved to ID)
46
46
  - `layout`: layout ID
47
47
  - `plan`: service plan ID
48
- - `resource_pool_id`: project resource pool ID
48
+ - `resource_pool_id`: resource pool code (`"pool-214"`) or numeric ID (`214`); both normalize to the code. Discover with `list_resource_pools()` / `get_resource_pool()`
49
49
  - Optional metadata:
50
50
  - `description`, `environment`, `labels`, `tags`
51
51
  - Optional sizing/provisioning:
@@ -165,3 +165,68 @@ Client-side polling helper.
165
165
  - `max_results`: maps to query `max`
166
166
  - Returns: list from response key `processes`
167
167
  - Raises: common API exceptions
168
+
169
+ ---
170
+
171
+ ## Snapshot management
172
+
173
+ ### `list_snapshots(instance_id: int) -> list[Snapshot]`
174
+
175
+ - Endpoint: `GET /api/instances/{instance_id}/snapshots`
176
+ - Returns: `list[Snapshot]`
177
+ - Raises: common API exceptions
178
+
179
+ ### `create_snapshot(instance_id: int, name: str, *, description=None) -> Snapshot`
180
+
181
+ - Endpoint: `POST /api/instances/{instance_id}/snapshots`
182
+ - Parameters:
183
+ - `name`: snapshot name
184
+ - `description`: optional description
185
+ - Returns: `Snapshot`
186
+ - Raises: common API exceptions
187
+
188
+ ### `revert_snapshot(instance_id: int, snapshot_id: int) -> bool`
189
+
190
+ - Endpoint: `PUT /api/instances/{instance_id}/revert-snapshot/{snapshot_id}`
191
+ - The instance should be stopped before reverting
192
+ - Returns: `True` when revert is initiated
193
+ - Raises: common API exceptions
194
+
195
+ ### `delete_snapshot(instance_id: int, snapshot_id: int) -> bool`
196
+
197
+ - Endpoint: `DELETE /api/instances/{instance_id}/snapshots/{snapshot_id}`
198
+ - Returns: `True` on success
199
+ - Raises: common API exceptions
200
+
201
+ ---
202
+
203
+ ## Provisioning discovery
204
+
205
+ These helpers resolve the IDs and codes required by `create()` using permission-safe endpoints (the admin-level `clouds`/`plans` endpoints are restricted on most accounts).
206
+
207
+ ### `list_resource_pools(group=None, *, cloud_id=None, group_id=None, provision_type_code="openstack") -> list[ResourcePool]`
208
+
209
+ - Endpoint: `GET /api/options/zonePools?cloudId={cloud_id}&groupId={group_id}`
210
+ - A resource pool is where an instance is hosted; its `code` is the `resource_pool_id` for `create()`
211
+ - Parameters:
212
+ - `group`: group name or ID — when given, `cloud_id` and `group_id` are resolved from it automatically (the group embeds its cloud/zone IDs)
213
+ - `cloud_id` / `group_id`: explicit IDs, required if `group` is not given
214
+ - `provision_type_code`: provisioning type, defaults to `"openstack"`
215
+ - Returns: `list[ResourcePool]` (group-header rows are filtered out)
216
+ - Raises: `ValueError` if neither `group` nor both `cloud_id`/`group_id` are provided, or the group has no associated cloud
217
+
218
+ ### `get_resource_pool(name: str, *, group=None, cloud_id=None, group_id=None, provision_type_code="openstack") -> ResourcePool`
219
+
220
+ - Fetches a single pool by display name **or** code (e.g. `"pool-214"`)
221
+ - Same resolution rules as `list_resource_pools`
222
+ - Returns: `ResourcePool`
223
+ - Raises: `NotFoundError` if no pool matches `name`
224
+
225
+ ### `list_service_plans(zone_id=None, layout_id=None, group_id=None) -> list[dict[str, Any]]`
226
+
227
+ - Endpoint: `GET /api/instances/service-plans?zoneId={zone_id}&layoutId={layout_id}&siteId={group_id}`
228
+ - Returns available service plans (CPU/memory/storage tiers) scoped to the provisioning context
229
+ - `layout_id` is required by the API; use `instance_type.default_layout_id`
230
+ - Returns: list of plan dicts from response key `plans`
231
+
232
+ **`ResourcePool` model fields:** `id` (numeric), `code` (alias of API `value`, e.g. `"pool-214"`), `name`, `external_id` (OpenStack pool ID), `is_default`.
@@ -88,36 +88,32 @@
88
88
  - Returns: `NetworkTypeInfo`
89
89
  - Raises: common API exceptions
90
90
 
91
- ### `list_floating_ips(*, phrase=None, ip_address=None, ip_status=None, cloud_id=None, server_id=None) -> list[NetworkFloatingIP]`
91
+ ### `list_pools(max_results=None, offset=0, phrase=None) -> list[NetworkPool]`
92
92
 
93
- - Endpoint: `GET /api/networks/floating-ips`
93
+ - Endpoint: `GET /api/networks/pools`
94
94
  - Parameters:
95
+ - `max_results`: maps to query `max`
96
+ - `offset`: pagination offset
95
97
  - `phrase`: search phrase
96
- - `ip_address`: exact IP match
97
- - `ip_status`: provider status value
98
- - `cloud_id`: mapped to `zoneId`
99
- - `server_id`: mapped to `serverId`
100
- - Returns: `list[NetworkFloatingIP]`
98
+ - Returns: `list[NetworkPool]` (each includes its `ip_ranges`, `ip_count`, `free_count`)
101
99
  - Raises: common API exceptions
102
100
 
103
- ### `get_floating_ip(floating_ip_id: int) -> NetworkFloatingIP`
101
+ ### `get_pool(pool_id: int) -> NetworkPool`
104
102
 
105
- - Endpoint: `GET /api/networks/floating-ips/{floating_ip_id}`
106
- - Returns: `NetworkFloatingIP`
103
+ - Endpoint: `GET /api/networks/pools/{pool_id}`
104
+ - Returns: `NetworkPool`
107
105
  - Raises: common API exceptions
108
106
 
109
- ### `allocate_floating_ip(*, network_server_id: int, floating_ip_pool_id: int) -> NetworkFloatingIP`
107
+ ### `list_pool_ips(pool_id: int, *, max_results=None, phrase=None, ip_address=None, hostname=None) -> list[NetworkPoolIp]`
110
108
 
111
- - Endpoint: `POST /api/networks/floating-ips`
109
+ - Endpoint: `GET /api/networks/pools/{pool_id}/ips`
112
110
  - Parameters:
113
- - `network_server_id`: backend network server ID
114
- - `floating_ip_pool_id`: floating IP pool ID
115
- - Returns: `NetworkFloatingIP`
111
+ - `max_results`: maps to query `max`
112
+ - `phrase`: partial match on `ipAddress` or `hostname`
113
+ - `ip_address`: exact IP match
114
+ - `hostname`: exact hostname match
115
+ - Returns: `list[NetworkPoolIp]`
116
116
  - Raises: common API exceptions
117
117
 
118
- ### `release_floating_ip(floating_ip_id: int) -> bool`
119
-
120
- - Endpoint: `PUT /api/networks/floating-ips/{floating_ip_id}/release`
121
- - Returns: `True`
122
- - Raises: common API exceptions
118
+ > **Note:** Standalone floating-IP endpoints (`/api/networks/floating-ips`) are restricted (HTTP 403) on MTN Cloud tenant accounts and are not exposed by the SDK. Assign external/public connectivity at provisioning time via the instance's `os_external_network_id` instead.
123
119