mtn-cloud 0.1.13__tar.gz → 0.2.2__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 (55) hide show
  1. mtn_cloud-0.2.2/PKG-INFO +353 -0
  2. mtn_cloud-0.2.2/README.md +309 -0
  3. mtn_cloud-0.2.2/docs/advanced-cookbook.md +178 -0
  4. mtn_cloud-0.2.2/docs/api-overview.md +86 -0
  5. mtn_cloud-0.2.2/docs/docstring-style.md +50 -0
  6. mtn_cloud-0.2.2/docs/index.md +39 -0
  7. mtn_cloud-0.2.2/docs/instances.md +81 -0
  8. mtn_cloud-0.2.2/docs/networking.md +78 -0
  9. mtn_cloud-0.2.2/docs/quickstart.md +133 -0
  10. mtn_cloud-0.2.2/docs/storage.md +100 -0
  11. {mtn_cloud-0.1.13 → mtn_cloud-0.2.2}/pyproject.toml +6 -2
  12. mtn_cloud-0.2.2/src/mtn_cloud/__init__.py +34 -0
  13. mtn_cloud-0.2.2/src/mtn_cloud/_version.py +3 -0
  14. {mtn_cloud-0.1.13 → mtn_cloud-0.2.2}/src/mtn_cloud/client.py +42 -24
  15. {mtn_cloud-0.1.13 → mtn_cloud-0.2.2}/src/mtn_cloud/config.py +6 -10
  16. {mtn_cloud-0.1.13 → mtn_cloud-0.2.2}/src/mtn_cloud/exceptions.py +3 -7
  17. {mtn_cloud-0.1.13 → mtn_cloud-0.2.2}/src/mtn_cloud/http.py +64 -7
  18. {mtn_cloud-0.1.13 → mtn_cloud-0.2.2}/src/mtn_cloud/models/__init__.py +29 -6
  19. mtn_cloud-0.2.2/src/mtn_cloud/models/archive.py +190 -0
  20. {mtn_cloud-0.1.13 → mtn_cloud-0.2.2}/src/mtn_cloud/models/base.py +1 -6
  21. {mtn_cloud-0.1.13 → mtn_cloud-0.2.2}/src/mtn_cloud/models/cloud.py +2 -10
  22. {mtn_cloud-0.1.13 → mtn_cloud-0.2.2}/src/mtn_cloud/models/group.py +1 -8
  23. {mtn_cloud-0.1.13 → mtn_cloud-0.2.2}/src/mtn_cloud/models/instance.py +1 -10
  24. {mtn_cloud-0.1.13 → mtn_cloud-0.2.2}/src/mtn_cloud/models/instance_type.py +1 -8
  25. {mtn_cloud-0.1.13 → mtn_cloud-0.2.2}/src/mtn_cloud/models/network.py +1 -8
  26. {mtn_cloud-0.1.13 → mtn_cloud-0.2.2}/src/mtn_cloud/models/plan.py +1 -8
  27. mtn_cloud-0.2.2/src/mtn_cloud/models/storage_bucket.py +104 -0
  28. {mtn_cloud-0.1.13 → mtn_cloud-0.2.2}/src/mtn_cloud/models/user.py +1 -8
  29. {mtn_cloud-0.1.13 → mtn_cloud-0.2.2}/src/mtn_cloud/models/volume.py +1 -6
  30. {mtn_cloud-0.1.13 → mtn_cloud-0.2.2}/src/mtn_cloud/resources/__init__.py +5 -6
  31. mtn_cloud-0.2.2/src/mtn_cloud/resources/archive_buckets.py +588 -0
  32. {mtn_cloud-0.1.13 → mtn_cloud-0.2.2}/src/mtn_cloud/resources/base.py +1 -6
  33. {mtn_cloud-0.1.13 → mtn_cloud-0.2.2}/src/mtn_cloud/resources/clouds.py +1 -8
  34. {mtn_cloud-0.1.13 → mtn_cloud-0.2.2}/src/mtn_cloud/resources/groups.py +1 -8
  35. {mtn_cloud-0.1.13 → mtn_cloud-0.2.2}/src/mtn_cloud/resources/instance_types.py +1 -10
  36. {mtn_cloud-0.1.13 → mtn_cloud-0.2.2}/src/mtn_cloud/resources/instances.py +1 -10
  37. {mtn_cloud-0.1.13 → mtn_cloud-0.2.2}/src/mtn_cloud/resources/networks.py +1 -8
  38. {mtn_cloud-0.1.13 → mtn_cloud-0.2.2}/src/mtn_cloud/resources/plans.py +1 -8
  39. mtn_cloud-0.2.2/src/mtn_cloud/resources/storage_buckets.py +268 -0
  40. mtn_cloud-0.2.2/tests/test_archive_buckets.py +569 -0
  41. {mtn_cloud-0.1.13 → mtn_cloud-0.2.2}/tests/test_client.py +16 -0
  42. mtn_cloud-0.2.2/tests/test_storage_buckets.py +152 -0
  43. mtn_cloud-0.1.13/PKG-INFO +0 -521
  44. mtn_cloud-0.1.13/README.md +0 -480
  45. mtn_cloud-0.1.13/src/mtn_cloud/__init__.py +0 -72
  46. {mtn_cloud-0.1.13 → mtn_cloud-0.2.2}/.gitignore +0 -0
  47. {mtn_cloud-0.1.13 → mtn_cloud-0.2.2}/LICENSE +0 -0
  48. {mtn_cloud-0.1.13 → mtn_cloud-0.2.2}/tests/__init__.py +0 -0
  49. {mtn_cloud-0.1.13 → mtn_cloud-0.2.2}/tests/conftest.py +0 -0
  50. {mtn_cloud-0.1.13 → mtn_cloud-0.2.2}/tests/test_clouds.py +0 -0
  51. {mtn_cloud-0.1.13 → mtn_cloud-0.2.2}/tests/test_config.py +0 -0
  52. {mtn_cloud-0.1.13 → mtn_cloud-0.2.2}/tests/test_exceptions.py +0 -0
  53. {mtn_cloud-0.1.13 → mtn_cloud-0.2.2}/tests/test_instance_types.py +0 -0
  54. {mtn_cloud-0.1.13 → mtn_cloud-0.2.2}/tests/test_instances.py +0 -0
  55. {mtn_cloud-0.1.13 → mtn_cloud-0.2.2}/tests/test_networks.py +0 -0
@@ -0,0 +1,353 @@
1
+ Metadata-Version: 2.4
2
+ Name: mtn-cloud
3
+ Version: 0.2.2
4
+ Summary: Community Python SDK for MTN Cloud (Morpheus) - Deploy and manage cloud resources with ease
5
+ Project-URL: Homepage, https://github.com/mahveotm/mtn-cloud-python
6
+ Project-URL: Documentation, https://github.com/mahveotm/mtn-cloud-python#readme
7
+ Project-URL: Repository, https://github.com/mahveotm/mtn-cloud-python
8
+ Project-URL: Issues, https://github.com/mahveotm/mtn-cloud-python/issues
9
+ Author-email: Marvellous Osuolale <m@rvellous.com>
10
+ Maintainer-email: Marvellous Osuolale <m@rvellous.com>
11
+ License: MIT
12
+ License-File: LICENSE
13
+ Keywords: api,cloud,devops,infrastructure,morpheus,mtn,sdk
14
+ Classifier: Development Status :: 4 - Beta
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: License :: OSI Approved :: MIT License
17
+ Classifier: Operating System :: OS Independent
18
+ Classifier: Programming Language :: Python :: 3
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Programming Language :: Python :: 3.13
23
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
24
+ Classifier: Topic :: System :: Systems Administration
25
+ Classifier: Typing :: Typed
26
+ Requires-Python: >=3.10
27
+ Requires-Dist: pydantic-settings>=2.0.0
28
+ Requires-Dist: pydantic>=2.0.0
29
+ Requires-Dist: requests>=2.28.0
30
+ Requires-Dist: typing-extensions>=4.5.0
31
+ Requires-Dist: urllib3>=2.0.0
32
+ Provides-Extra: dev
33
+ Requires-Dist: mypy>=1.0.0; extra == 'dev'
34
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == 'dev'
35
+ Requires-Dist: pytest-cov>=4.0.0; extra == 'dev'
36
+ Requires-Dist: pytest>=7.0.0; extra == 'dev'
37
+ Requires-Dist: respx>=0.20.0; extra == 'dev'
38
+ Requires-Dist: ruff>=0.1.0; extra == 'dev'
39
+ Requires-Dist: types-requests>=2.28.0; extra == 'dev'
40
+ Provides-Extra: docs
41
+ Requires-Dist: mkdocs-material>=9.5.0; extra == 'docs'
42
+ Requires-Dist: mkdocs>=1.6.0; extra == 'docs'
43
+ Description-Content-Type: text/markdown
44
+
45
+ # MTN Cloud Python SDK
46
+
47
+ [![PyPI version](https://badge.fury.io/py/mtn-cloud.svg)](https://badge.fury.io/py/mtn-cloud)
48
+ [![Tests](https://github.com/mahveotm/mtn-cloud-python/actions/workflows/test.yml/badge.svg)](https://github.com/mahveotm/mtn-cloud-python/actions/workflows/test.yml)
49
+ [![Docs](https://github.com/mahveotm/mtn-cloud-python/actions/workflows/docs.yml/badge.svg)](https://github.com/mahveotm/mtn-cloud-python/actions/workflows/docs.yml)
50
+ [![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
51
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
52
+
53
+ A Modern Python SDK for [MTN Cloud](https://console.cloud.mtn.ng) (Morpheus) with typed models, clear resource managers, and practical workflows for compute, networking, storage, and archives.
54
+
55
+ Docs: [mtn-cloud-python](https://mahveotm.github.io/mtn-cloud-python/)
56
+
57
+ > **Disclaimer:** Unofficial community project. Not affiliated with MTN Nigeria.
58
+
59
+ ## Why You'll Like It
60
+
61
+ - Simple Pythonic API across core MTN Cloud resources
62
+ - Typed Pydantic models with IDE autocomplete
63
+ - Built-in retry behavior and timeout controls
64
+ - Token or username/password authentication
65
+ - Structured exceptions for better error handling
66
+ - Examples for real-world automation scripts
67
+
68
+ ## Installation
69
+
70
+ ```bash
71
+ pip install mtn-cloud
72
+ ```
73
+
74
+ ## Documentation
75
+
76
+ - [Docs Index](https://mahveotm.github.io/mtn-cloud-python/)
77
+ - [Quickstart](https://mahveotm.github.io/mtn-cloud-python/quickstart/)
78
+ - [Instances](https://mahveotm.github.io/mtn-cloud-python/instances/)
79
+ - [Networking](https://mahveotm.github.io/mtn-cloud-python/networking/)
80
+ - [Storage](https://mahveotm.github.io/mtn-cloud-python/storage/)
81
+ - [Advanced Cookbook](https://mahveotm.github.io/mtn-cloud-python/advanced-cookbook/)
82
+ - [API Overview](https://mahveotm.github.io/mtn-cloud-python/api-overview/)
83
+ - [Docstring Style Standard](https://mahveotm.github.io/mtn-cloud-python/docstring-style/)
84
+
85
+ ## Quick Start
86
+
87
+ ```python
88
+ from mtn_cloud import MTNCloud
89
+
90
+ cloud = MTNCloud(token="your-api-token")
91
+
92
+ # Verify auth and connectivity
93
+ user = cloud.whoami()
94
+ print(f"Connected as: {user.username}")
95
+ print("Ping:", cloud.ping())
96
+
97
+ # List a few running instances
98
+ running = cloud.instances.list(status="running", max_results=5)
99
+ for instance in running:
100
+ print(instance.id, instance.name, instance.status, instance.primary_ip)
101
+ ```
102
+
103
+ ## Authentication
104
+
105
+ ```python
106
+ from mtn_cloud import MTNCloud
107
+
108
+ # Option 1: token (recommended)
109
+ cloud = MTNCloud(token="your-api-token")
110
+
111
+ # Option 2: environment variable
112
+ # export MTN_CLOUD_TOKEN="your-api-token"
113
+ cloud = MTNCloud()
114
+
115
+ # Option 3: username/password
116
+ cloud = MTNCloud(username="user@example.com", password="your-password")
117
+ ```
118
+
119
+ Get your API token from MTN Cloud Console:
120
+ User Icon (top-right) -> User Settings -> API Access.
121
+
122
+ ## What You Can Do
123
+
124
+ ### 1. Discover Reference Data
125
+
126
+ Use these lookups before provisioning so your scripts stay deterministic.
127
+
128
+ ```python
129
+ # Groups (sites)
130
+ groups = cloud.groups.list()
131
+ for group in groups[:5]:
132
+ print(group.id, group.name)
133
+
134
+ # Clouds/zones
135
+ clouds = cloud.clouds.list_openstack()
136
+ for c in clouds[:5]:
137
+ print(c.id, c.name, c.type_code)
138
+
139
+ # Instance types
140
+ types = cloud.instance_types.list_os()
141
+ for t in types[:5]:
142
+ print(t.code, t.name, t.default_layout_id)
143
+
144
+ # Service plans
145
+ plans = cloud.plans.list()
146
+ for p in plans[:5]:
147
+ print(p.id, p.name, p.cores, p.memory_gb)
148
+ ```
149
+
150
+ ### 2. Create an Instance
151
+
152
+ ```python
153
+ instance = cloud.instances.create(
154
+ name="my-server",
155
+ cloud="MTNNG_CLOUD_AZ_1",
156
+ type="MTN-CS10",
157
+ group="MTNNG_CLOUD_AZ_1",
158
+ layout=327,
159
+ plan=6776,
160
+ labels=["production", "web"],
161
+ )
162
+
163
+ print(f"Created: {instance.id} {instance.name} ({instance.status})")
164
+ ```
165
+
166
+ ### 3. Manage an Instance
167
+
168
+ ```python
169
+ instance = cloud.instances.get(123)
170
+ print(instance.name, instance.status, instance.primary_ip)
171
+
172
+ # Action methods from model
173
+ instance.stop()
174
+ instance.start()
175
+ instance.restart()
176
+ instance.refresh()
177
+
178
+ # Or from resource manager
179
+ cloud.instances.resize(123, plan_id=6780)
180
+ cloud.instances.delete(123, force=True, preserve_volumes=True)
181
+ ```
182
+
183
+ ### 4. Work with Networks
184
+
185
+ ```python
186
+ # List networks
187
+ networks = cloud.networks.list(cloud_id=1)
188
+ for n in networks[:5]:
189
+ print(n.id, n.name, n.cidr)
190
+
191
+ # Create an OpenStack-focused network
192
+ network_types = cloud.networks.list_types(openstack_only=True)
193
+ new_network = cloud.networks.create(
194
+ name="mtn-prod-net",
195
+ cloud_id=1,
196
+ group_id=621,
197
+ type_id=network_types[0].id,
198
+ cidr="10.42.10.0/24",
199
+ gateway="10.42.10.1",
200
+ dns_primary="8.8.8.8",
201
+ visibility="private",
202
+ dhcp_server=True,
203
+ )
204
+
205
+ # Update and list subnets
206
+ cloud.networks.update(new_network.id, description="Production network")
207
+ subnets = cloud.networks.list_subnets(new_network.id)
208
+ print(f"Subnets: {len(subnets)}")
209
+ ```
210
+
211
+ ### 5. Work with Storage and Archives
212
+
213
+ ```python
214
+ # Create S3-compatible storage provider
215
+ storage = cloud.storage_buckets.create_s3(
216
+ name="my-s3-storage",
217
+ bucket_name="my-app-objects",
218
+ access_key="your-access-key",
219
+ secret_key="your-secret-key",
220
+ endpoint="https://ps1csp-s3.ict.mtn.com.ng:9021",
221
+ create_bucket=True,
222
+ )
223
+
224
+ # Create archive bucket linked to storage provider
225
+ archive = cloud.archive_buckets.create(
226
+ name="my-app-archives",
227
+ storage_provider_id=storage.id,
228
+ visibility="private",
229
+ )
230
+
231
+ # Upload one file
232
+ uploaded = cloud.archive_buckets.upload_file(
233
+ bucket_name=archive.name,
234
+ remote_path="/",
235
+ local_path="./backup.sql",
236
+ )
237
+ print(uploaded.id, uploaded.name)
238
+
239
+ # Upload a directory (preserves local folder structure)
240
+ summary = cloud.archive_buckets.upload_directory(
241
+ bucket_name=archive.name,
242
+ remote_path="/imports/",
243
+ local_directory="./reports",
244
+ recursive=True,
245
+ )
246
+ print(
247
+ f"scanned={summary.scanned_count} "
248
+ f"uploaded={summary.uploaded_count} "
249
+ f"failed={summary.failed_count} "
250
+ f"skipped={summary.skipped_count}"
251
+ )
252
+
253
+ # List and download
254
+ files = cloud.archive_buckets.list_files(bucket_name=archive.name, remote_path="/", full_tree=True)
255
+ if files:
256
+ content = cloud.archive_buckets.download_file(
257
+ bucket_name=archive.name,
258
+ remote_path=files[0].file_path or files[0].name,
259
+ )
260
+ print(f"Downloaded {len(content)} byte(s)")
261
+ ```
262
+
263
+ Storage vs archive model:
264
+ - `cloud.storage_buckets`: provider configuration (endpoint, credentials, backing bucket)
265
+ - `cloud.archive_buckets`: logical file container attached to a provider
266
+ - file operations happen through archive APIs
267
+
268
+
269
+ ## Error Handling
270
+
271
+ ```python
272
+ from mtn_cloud import (
273
+ AuthenticationError,
274
+ MTNCloudError,
275
+ NotFoundError,
276
+ RateLimitError,
277
+ ValidationError,
278
+ )
279
+
280
+ try:
281
+ cloud.instances.get(999999)
282
+ except NotFoundError:
283
+ print("Resource not found")
284
+ except AuthenticationError:
285
+ print("Authentication failed")
286
+ except ValidationError as exc:
287
+ print(f"Validation error: {exc}")
288
+ except RateLimitError as exc:
289
+ print(f"Rate limited, retry_after={exc.retry_after}")
290
+ except MTNCloudError as exc:
291
+ print(f"SDK/API error: {exc}")
292
+ ```
293
+
294
+ ## Configuration
295
+
296
+ Environment variables:
297
+
298
+ | Variable | Description | Default |
299
+ |----------|-------------|---------|
300
+ | `MTN_CLOUD_TOKEN` | API access token | - |
301
+ | `MTN_CLOUD_URL` | API base URL | `https://console.cloud.mtn.ng` |
302
+ | `MTN_CLOUD_TIMEOUT` | Request timeout in seconds | `30` |
303
+ | `MTN_CLOUD_MAX_RETRIES` | Maximum retry attempts | `3` |
304
+ | `MTN_CLOUD_RETRY_DELAY` | Retry backoff factor | `1.0` |
305
+ | `MTN_CLOUD_VERIFY_SSL` | Enable SSL verification | `true` |
306
+
307
+ Programmatic configuration:
308
+
309
+ ```python
310
+ from mtn_cloud import MTNCloud, MTNCloudConfig
311
+
312
+ config = MTNCloudConfig(
313
+ token="your-token",
314
+ timeout=60,
315
+ max_retries=5,
316
+ retry_delay=1.5,
317
+ verify_ssl=True,
318
+ )
319
+
320
+ cloud = MTNCloud(config=config)
321
+ ```
322
+
323
+ ## Examples
324
+
325
+ | Script | What it demonstrates |
326
+ |--------|-----------------------|
327
+ | `examples/basic_usage.py` | Auth, connectivity, resource listing |
328
+ | `examples/create_instance.py` | End-to-end instance creation scaffold |
329
+ | `examples/storage_archive_s3.py` | Storage provider + archive bucket + file ops |
330
+ | `examples/list_storage_buckets.py` | Storage bucket and archive bucket discovery |
331
+ | `examples/upload_archive_directory.py` | Bulk archive upload from local directory |
332
+ | `examples/copy_archive_file.py` | Archive file copy between buckets |
333
+
334
+ ## API Notes
335
+
336
+ - Some endpoints can be tenant-restricted in specific MTN Cloud environments.
337
+ - Build scripts to discover IDs dynamically (`list` + `get_by_name`) before create/update operations.
338
+
339
+ ## Contributing
340
+
341
+ Contributions are welcome. Open an issue or submit a PR.
342
+
343
+ ## License
344
+
345
+ MIT License. See [LICENSE](LICENSE) for details.
346
+
347
+ ## Links
348
+
349
+ - [MTN Cloud Console](https://console.cloud.mtn.ng)
350
+ - [MTN Cloud Guide](https://cloud.mtn.ng/documentation)
351
+ - [Morpheus API Documentation](https://apidocs.morpheusdata.com/)
352
+ - [GitHub Repository](https://github.com/mahveotm/mtn-cloud-python)
353
+ - [PyPI Package](https://pypi.org/project/mtn-cloud/)
@@ -0,0 +1,309 @@
1
+ # MTN Cloud Python SDK
2
+
3
+ [![PyPI version](https://badge.fury.io/py/mtn-cloud.svg)](https://badge.fury.io/py/mtn-cloud)
4
+ [![Tests](https://github.com/mahveotm/mtn-cloud-python/actions/workflows/test.yml/badge.svg)](https://github.com/mahveotm/mtn-cloud-python/actions/workflows/test.yml)
5
+ [![Docs](https://github.com/mahveotm/mtn-cloud-python/actions/workflows/docs.yml/badge.svg)](https://github.com/mahveotm/mtn-cloud-python/actions/workflows/docs.yml)
6
+ [![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
7
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
8
+
9
+ A Modern Python SDK for [MTN Cloud](https://console.cloud.mtn.ng) (Morpheus) with typed models, clear resource managers, and practical workflows for compute, networking, storage, and archives.
10
+
11
+ Docs: [mtn-cloud-python](https://mahveotm.github.io/mtn-cloud-python/)
12
+
13
+ > **Disclaimer:** Unofficial community project. Not affiliated with MTN Nigeria.
14
+
15
+ ## Why You'll Like It
16
+
17
+ - Simple Pythonic API across core MTN Cloud resources
18
+ - Typed Pydantic models with IDE autocomplete
19
+ - Built-in retry behavior and timeout controls
20
+ - Token or username/password authentication
21
+ - Structured exceptions for better error handling
22
+ - Examples for real-world automation scripts
23
+
24
+ ## Installation
25
+
26
+ ```bash
27
+ pip install mtn-cloud
28
+ ```
29
+
30
+ ## Documentation
31
+
32
+ - [Docs Index](https://mahveotm.github.io/mtn-cloud-python/)
33
+ - [Quickstart](https://mahveotm.github.io/mtn-cloud-python/quickstart/)
34
+ - [Instances](https://mahveotm.github.io/mtn-cloud-python/instances/)
35
+ - [Networking](https://mahveotm.github.io/mtn-cloud-python/networking/)
36
+ - [Storage](https://mahveotm.github.io/mtn-cloud-python/storage/)
37
+ - [Advanced Cookbook](https://mahveotm.github.io/mtn-cloud-python/advanced-cookbook/)
38
+ - [API Overview](https://mahveotm.github.io/mtn-cloud-python/api-overview/)
39
+ - [Docstring Style Standard](https://mahveotm.github.io/mtn-cloud-python/docstring-style/)
40
+
41
+ ## Quick Start
42
+
43
+ ```python
44
+ from mtn_cloud import MTNCloud
45
+
46
+ cloud = MTNCloud(token="your-api-token")
47
+
48
+ # Verify auth and connectivity
49
+ user = cloud.whoami()
50
+ print(f"Connected as: {user.username}")
51
+ print("Ping:", cloud.ping())
52
+
53
+ # List a few running instances
54
+ running = cloud.instances.list(status="running", max_results=5)
55
+ for instance in running:
56
+ print(instance.id, instance.name, instance.status, instance.primary_ip)
57
+ ```
58
+
59
+ ## Authentication
60
+
61
+ ```python
62
+ from mtn_cloud import MTNCloud
63
+
64
+ # Option 1: token (recommended)
65
+ cloud = MTNCloud(token="your-api-token")
66
+
67
+ # Option 2: environment variable
68
+ # export MTN_CLOUD_TOKEN="your-api-token"
69
+ cloud = MTNCloud()
70
+
71
+ # Option 3: username/password
72
+ cloud = MTNCloud(username="user@example.com", password="your-password")
73
+ ```
74
+
75
+ Get your API token from MTN Cloud Console:
76
+ User Icon (top-right) -> User Settings -> API Access.
77
+
78
+ ## What You Can Do
79
+
80
+ ### 1. Discover Reference Data
81
+
82
+ Use these lookups before provisioning so your scripts stay deterministic.
83
+
84
+ ```python
85
+ # Groups (sites)
86
+ groups = cloud.groups.list()
87
+ for group in groups[:5]:
88
+ print(group.id, group.name)
89
+
90
+ # Clouds/zones
91
+ clouds = cloud.clouds.list_openstack()
92
+ for c in clouds[:5]:
93
+ print(c.id, c.name, c.type_code)
94
+
95
+ # Instance types
96
+ types = cloud.instance_types.list_os()
97
+ for t in types[:5]:
98
+ print(t.code, t.name, t.default_layout_id)
99
+
100
+ # Service plans
101
+ plans = cloud.plans.list()
102
+ for p in plans[:5]:
103
+ print(p.id, p.name, p.cores, p.memory_gb)
104
+ ```
105
+
106
+ ### 2. Create an Instance
107
+
108
+ ```python
109
+ instance = cloud.instances.create(
110
+ name="my-server",
111
+ cloud="MTNNG_CLOUD_AZ_1",
112
+ type="MTN-CS10",
113
+ group="MTNNG_CLOUD_AZ_1",
114
+ layout=327,
115
+ plan=6776,
116
+ labels=["production", "web"],
117
+ )
118
+
119
+ print(f"Created: {instance.id} {instance.name} ({instance.status})")
120
+ ```
121
+
122
+ ### 3. Manage an Instance
123
+
124
+ ```python
125
+ instance = cloud.instances.get(123)
126
+ print(instance.name, instance.status, instance.primary_ip)
127
+
128
+ # Action methods from model
129
+ instance.stop()
130
+ instance.start()
131
+ instance.restart()
132
+ instance.refresh()
133
+
134
+ # Or from resource manager
135
+ cloud.instances.resize(123, plan_id=6780)
136
+ cloud.instances.delete(123, force=True, preserve_volumes=True)
137
+ ```
138
+
139
+ ### 4. Work with Networks
140
+
141
+ ```python
142
+ # List networks
143
+ networks = cloud.networks.list(cloud_id=1)
144
+ for n in networks[:5]:
145
+ print(n.id, n.name, n.cidr)
146
+
147
+ # Create an OpenStack-focused network
148
+ network_types = cloud.networks.list_types(openstack_only=True)
149
+ new_network = cloud.networks.create(
150
+ name="mtn-prod-net",
151
+ cloud_id=1,
152
+ group_id=621,
153
+ type_id=network_types[0].id,
154
+ cidr="10.42.10.0/24",
155
+ gateway="10.42.10.1",
156
+ dns_primary="8.8.8.8",
157
+ visibility="private",
158
+ dhcp_server=True,
159
+ )
160
+
161
+ # Update and list subnets
162
+ cloud.networks.update(new_network.id, description="Production network")
163
+ subnets = cloud.networks.list_subnets(new_network.id)
164
+ print(f"Subnets: {len(subnets)}")
165
+ ```
166
+
167
+ ### 5. Work with Storage and Archives
168
+
169
+ ```python
170
+ # Create S3-compatible storage provider
171
+ storage = cloud.storage_buckets.create_s3(
172
+ name="my-s3-storage",
173
+ bucket_name="my-app-objects",
174
+ access_key="your-access-key",
175
+ secret_key="your-secret-key",
176
+ endpoint="https://ps1csp-s3.ict.mtn.com.ng:9021",
177
+ create_bucket=True,
178
+ )
179
+
180
+ # Create archive bucket linked to storage provider
181
+ archive = cloud.archive_buckets.create(
182
+ name="my-app-archives",
183
+ storage_provider_id=storage.id,
184
+ visibility="private",
185
+ )
186
+
187
+ # Upload one file
188
+ uploaded = cloud.archive_buckets.upload_file(
189
+ bucket_name=archive.name,
190
+ remote_path="/",
191
+ local_path="./backup.sql",
192
+ )
193
+ print(uploaded.id, uploaded.name)
194
+
195
+ # Upload a directory (preserves local folder structure)
196
+ summary = cloud.archive_buckets.upload_directory(
197
+ bucket_name=archive.name,
198
+ remote_path="/imports/",
199
+ local_directory="./reports",
200
+ recursive=True,
201
+ )
202
+ print(
203
+ f"scanned={summary.scanned_count} "
204
+ f"uploaded={summary.uploaded_count} "
205
+ f"failed={summary.failed_count} "
206
+ f"skipped={summary.skipped_count}"
207
+ )
208
+
209
+ # List and download
210
+ files = cloud.archive_buckets.list_files(bucket_name=archive.name, remote_path="/", full_tree=True)
211
+ if files:
212
+ content = cloud.archive_buckets.download_file(
213
+ bucket_name=archive.name,
214
+ remote_path=files[0].file_path or files[0].name,
215
+ )
216
+ print(f"Downloaded {len(content)} byte(s)")
217
+ ```
218
+
219
+ Storage vs archive model:
220
+ - `cloud.storage_buckets`: provider configuration (endpoint, credentials, backing bucket)
221
+ - `cloud.archive_buckets`: logical file container attached to a provider
222
+ - file operations happen through archive APIs
223
+
224
+
225
+ ## Error Handling
226
+
227
+ ```python
228
+ from mtn_cloud import (
229
+ AuthenticationError,
230
+ MTNCloudError,
231
+ NotFoundError,
232
+ RateLimitError,
233
+ ValidationError,
234
+ )
235
+
236
+ try:
237
+ cloud.instances.get(999999)
238
+ except NotFoundError:
239
+ print("Resource not found")
240
+ except AuthenticationError:
241
+ print("Authentication failed")
242
+ except ValidationError as exc:
243
+ print(f"Validation error: {exc}")
244
+ except RateLimitError as exc:
245
+ print(f"Rate limited, retry_after={exc.retry_after}")
246
+ except MTNCloudError as exc:
247
+ print(f"SDK/API error: {exc}")
248
+ ```
249
+
250
+ ## Configuration
251
+
252
+ Environment variables:
253
+
254
+ | Variable | Description | Default |
255
+ |----------|-------------|---------|
256
+ | `MTN_CLOUD_TOKEN` | API access token | - |
257
+ | `MTN_CLOUD_URL` | API base URL | `https://console.cloud.mtn.ng` |
258
+ | `MTN_CLOUD_TIMEOUT` | Request timeout in seconds | `30` |
259
+ | `MTN_CLOUD_MAX_RETRIES` | Maximum retry attempts | `3` |
260
+ | `MTN_CLOUD_RETRY_DELAY` | Retry backoff factor | `1.0` |
261
+ | `MTN_CLOUD_VERIFY_SSL` | Enable SSL verification | `true` |
262
+
263
+ Programmatic configuration:
264
+
265
+ ```python
266
+ from mtn_cloud import MTNCloud, MTNCloudConfig
267
+
268
+ config = MTNCloudConfig(
269
+ token="your-token",
270
+ timeout=60,
271
+ max_retries=5,
272
+ retry_delay=1.5,
273
+ verify_ssl=True,
274
+ )
275
+
276
+ cloud = MTNCloud(config=config)
277
+ ```
278
+
279
+ ## Examples
280
+
281
+ | Script | What it demonstrates |
282
+ |--------|-----------------------|
283
+ | `examples/basic_usage.py` | Auth, connectivity, resource listing |
284
+ | `examples/create_instance.py` | End-to-end instance creation scaffold |
285
+ | `examples/storage_archive_s3.py` | Storage provider + archive bucket + file ops |
286
+ | `examples/list_storage_buckets.py` | Storage bucket and archive bucket discovery |
287
+ | `examples/upload_archive_directory.py` | Bulk archive upload from local directory |
288
+ | `examples/copy_archive_file.py` | Archive file copy between buckets |
289
+
290
+ ## API Notes
291
+
292
+ - Some endpoints can be tenant-restricted in specific MTN Cloud environments.
293
+ - Build scripts to discover IDs dynamically (`list` + `get_by_name`) before create/update operations.
294
+
295
+ ## Contributing
296
+
297
+ Contributions are welcome. Open an issue or submit a PR.
298
+
299
+ ## License
300
+
301
+ MIT License. See [LICENSE](LICENSE) for details.
302
+
303
+ ## Links
304
+
305
+ - [MTN Cloud Console](https://console.cloud.mtn.ng)
306
+ - [MTN Cloud Guide](https://cloud.mtn.ng/documentation)
307
+ - [Morpheus API Documentation](https://apidocs.morpheusdata.com/)
308
+ - [GitHub Repository](https://github.com/mahveotm/mtn-cloud-python)
309
+ - [PyPI Package](https://pypi.org/project/mtn-cloud/)