mtn-cloud 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
mtn_cloud/__init__.py ADDED
@@ -0,0 +1,72 @@
1
+ """
2
+ MTN Cloud Python SDK
3
+ ====================
4
+
5
+ A community-maintained Python SDK for interacting with MTN Cloud (Morpheus).
6
+
7
+ Quick Start:
8
+ ```python
9
+ from mtn_cloud import MTNCloud
10
+
11
+ # Initialize client
12
+ cloud = MTNCloud(token="your-api-token")
13
+
14
+ # List instances
15
+ for instance in cloud.instances.list():
16
+ print(f"{instance.name}: {instance.status}")
17
+
18
+ # Create an instance
19
+ instance = cloud.instances.create(
20
+ name="my-app",
21
+ cloud_id=1,
22
+ group_id=1,
23
+ instance_type_code="MTN-CS10",
24
+ plan_id=6923,
25
+ layout_id=327,
26
+ )
27
+
28
+ # Instance actions
29
+ instance.stop()
30
+ instance.start()
31
+ instance.delete()
32
+ ```
33
+
34
+ Environment Variables:
35
+ MTN_CLOUD_TOKEN: API access token
36
+ MTN_CLOUD_URL: API URL (defaults to https://console.cloud.mtn.ng)
37
+
38
+ Author: Marvellous Osuolale
39
+ License: MIT
40
+ """
41
+
42
+ from mtn_cloud.client import MTNCloud
43
+ from mtn_cloud.config import MTNCloudConfig
44
+ from mtn_cloud.exceptions import (
45
+ AuthenticationError,
46
+ ForbiddenError,
47
+ MTNCloudError,
48
+ NotFoundError,
49
+ RateLimitError,
50
+ ServerError,
51
+ TimeoutError,
52
+ ValidationError,
53
+ )
54
+
55
+ __version__ = "0.1.0"
56
+ __author__ = "Marvellous Osuolale"
57
+ __license__ = "MIT"
58
+ __all__ = [
59
+ # Main client
60
+ "MTNCloud",
61
+ # Configuration
62
+ "MTNCloudConfig",
63
+ # Exceptions
64
+ "MTNCloudError",
65
+ "AuthenticationError",
66
+ "NotFoundError",
67
+ "ValidationError",
68
+ "RateLimitError",
69
+ "ServerError",
70
+ "ForbiddenError",
71
+ "TimeoutError",
72
+ ]
mtn_cloud/client.py ADDED
@@ -0,0 +1,278 @@
1
+ """
2
+ MTN Cloud Client
3
+ ================
4
+
5
+ Main client class for interacting with MTN Cloud.
6
+ """
7
+
8
+ from typing import Any
9
+
10
+ from mtn_cloud.config import MTNCloudConfig
11
+ from mtn_cloud.http import HTTPClient
12
+ from mtn_cloud.models.user import User
13
+ from mtn_cloud.resources.clouds import CloudsResource
14
+ from mtn_cloud.resources.groups import GroupsResource
15
+ from mtn_cloud.resources.instances import InstancesResource
16
+ from mtn_cloud.resources.networks import NetworksResource
17
+ from mtn_cloud.resources.plans import PlansResource
18
+
19
+
20
+ class MTNCloud:
21
+ """
22
+ MTN Cloud client for interacting with the Morpheus API.
23
+
24
+ This is the main entry point for the SDK. Initialize with your
25
+ API token or credentials to start making API calls.
26
+
27
+ Example:
28
+ ```python
29
+ from mtn_cloud import MTNCloud
30
+
31
+ # Initialize with token
32
+ cloud = MTNCloud(token="your-api-token")
33
+
34
+ # Or with username/password
35
+ cloud = MTNCloud(
36
+ username="user@example.com",
37
+ password="your-password",
38
+ )
39
+
40
+ # List instances
41
+ for instance in cloud.instances.list():
42
+ print(f"{instance.name}: {instance.status}")
43
+
44
+ # Create an instance
45
+ instance = cloud.instances.create(
46
+ name="my-app",
47
+ cloud_id=1,
48
+ group_id=1,
49
+ instance_type_code="MTN-CS10",
50
+ layout_id=327,
51
+ plan_id=6923,
52
+ )
53
+
54
+ # Use as context manager
55
+ with MTNCloud(token="xxx") as cloud:
56
+ instances = cloud.instances.list()
57
+ ```
58
+
59
+ Attributes:
60
+ instances: Manage compute instances
61
+ networks: Manage networks
62
+ groups: Manage groups (sites)
63
+ clouds: Manage clouds (zones)
64
+ plans: Manage service plans
65
+
66
+ Environment Variables:
67
+ MTN_CLOUD_TOKEN: API access token
68
+ MTN_CLOUD_URL: API URL (default: https://console.cloud.mtn.ng)
69
+ MTN_CLOUD_TIMEOUT: Request timeout in seconds
70
+ """
71
+
72
+ def __init__(
73
+ self,
74
+ token: str | None = None,
75
+ username: str | None = None,
76
+ password: str | None = None,
77
+ url: str | None = None,
78
+ timeout: float | None = None,
79
+ verify_ssl: bool = True,
80
+ config: MTNCloudConfig | None = None,
81
+ ) -> None:
82
+ """
83
+ Initialize the MTN Cloud client.
84
+
85
+ Args:
86
+ token: API access token
87
+ username: Username for authentication
88
+ password: Password for authentication
89
+ url: API base URL (default: https://console.cloud.mtn.ng)
90
+ timeout: Request timeout in seconds
91
+ verify_ssl: Verify SSL certificates
92
+ config: Full configuration object (overrides other args)
93
+ """
94
+ # Build config from arguments or use provided config
95
+ if config:
96
+ self._config = config
97
+ else:
98
+ config_kwargs: dict[str, Any] = {}
99
+
100
+ if token:
101
+ config_kwargs["token"] = token
102
+ if username:
103
+ config_kwargs["username"] = username
104
+ if password:
105
+ config_kwargs["password"] = password
106
+ if url:
107
+ config_kwargs["url"] = url
108
+ if timeout:
109
+ config_kwargs["timeout"] = timeout
110
+ if not verify_ssl:
111
+ config_kwargs["verify_ssl"] = verify_ssl
112
+
113
+ self._config = MTNCloudConfig(**config_kwargs)
114
+
115
+ # Initialize HTTP client
116
+ self._http = HTTPClient(self._config)
117
+
118
+ # Initialize resource managers
119
+ self._instances: InstancesResource | None = None
120
+ self._networks: NetworksResource | None = None
121
+ self._groups: GroupsResource | None = None
122
+ self._clouds: CloudsResource | None = None
123
+ self._plans: PlansResource | None = None
124
+
125
+ @property
126
+ def instances(self) -> InstancesResource:
127
+ """
128
+ Access the instances resource manager.
129
+
130
+ Example:
131
+ ```python
132
+ # List instances
133
+ instances = cloud.instances.list()
134
+
135
+ # Create instance
136
+ instance = cloud.instances.create(...)
137
+
138
+ # Get instance
139
+ instance = cloud.instances.get(123)
140
+ ```
141
+ """
142
+ if self._instances is None:
143
+ self._instances = InstancesResource(self._http)
144
+ return self._instances
145
+
146
+ @property
147
+ def networks(self) -> NetworksResource:
148
+ """
149
+ Access the networks resource manager.
150
+
151
+ Example:
152
+ ```python
153
+ # List networks
154
+ networks = cloud.networks.list()
155
+
156
+ # Get network
157
+ network = cloud.networks.get(123)
158
+ ```
159
+ """
160
+ if self._networks is None:
161
+ self._networks = NetworksResource(self._http)
162
+ return self._networks
163
+
164
+ @property
165
+ def groups(self) -> GroupsResource:
166
+ """
167
+ Access the groups resource manager.
168
+
169
+ Example:
170
+ ```python
171
+ # List groups
172
+ groups = cloud.groups.list()
173
+
174
+ # Get group
175
+ group = cloud.groups.get(1)
176
+ ```
177
+ """
178
+ if self._groups is None:
179
+ self._groups = GroupsResource(self._http)
180
+ return self._groups
181
+
182
+ @property
183
+ def clouds(self) -> CloudsResource:
184
+ """
185
+ Access the clouds resource manager.
186
+
187
+ Example:
188
+ ```python
189
+ # List clouds
190
+ clouds = cloud.clouds.list()
191
+
192
+ # Get cloud
193
+ c = cloud.clouds.get(1)
194
+ ```
195
+ """
196
+ if self._clouds is None:
197
+ self._clouds = CloudsResource(self._http)
198
+ return self._clouds
199
+
200
+ @property
201
+ def plans(self) -> PlansResource:
202
+ """
203
+ Access the service plans resource manager.
204
+
205
+ Example:
206
+ ```python
207
+ # List plans
208
+ plans = cloud.plans.list()
209
+
210
+ # Get plan
211
+ plan = cloud.plans.get(6923)
212
+ ```
213
+ """
214
+ if self._plans is None:
215
+ self._plans = PlansResource(self._http)
216
+ return self._plans
217
+
218
+ def whoami(self) -> User:
219
+ """
220
+ Get the current authenticated user.
221
+
222
+ Returns:
223
+ Current user information
224
+
225
+ Example:
226
+ ```python
227
+ user = cloud.whoami()
228
+ print(f"Logged in as: {user.username}")
229
+ print(f"Email: {user.email}")
230
+ ```
231
+ """
232
+ response = self._http.get("/whoami")
233
+ user_data = response.get("user", response)
234
+ return User.model_validate(user_data)
235
+
236
+ def ping(self) -> bool:
237
+ """
238
+ Check if the API is reachable and authentication is valid.
239
+
240
+ Returns:
241
+ True if connection is successful
242
+
243
+ Example:
244
+ ```python
245
+ if cloud.ping():
246
+ print("Connected!")
247
+ ```
248
+ """
249
+ try:
250
+ self.whoami()
251
+ return True
252
+ except Exception:
253
+ return False
254
+
255
+ @property
256
+ def config(self) -> MTNCloudConfig:
257
+ """Get the current configuration."""
258
+ return self._config
259
+
260
+ @property
261
+ def api_url(self) -> str:
262
+ """Get the API URL."""
263
+ return self._config.api_url
264
+
265
+ def close(self) -> None:
266
+ """Close the HTTP session."""
267
+ self._http.close()
268
+
269
+ def __enter__(self) -> "MTNCloud":
270
+ """Context manager entry."""
271
+ return self
272
+
273
+ def __exit__(self, *args: Any) -> None:
274
+ """Context manager exit."""
275
+ self.close()
276
+
277
+ def __repr__(self) -> str:
278
+ return f"<MTNCloud url={self._config.url!r}>"
mtn_cloud/config.py ADDED
@@ -0,0 +1,143 @@
1
+ """
2
+ MTN Cloud SDK Configuration
3
+ ===========================
4
+
5
+ Configuration management using pydantic-settings.
6
+ Supports environment variables and explicit configuration.
7
+ """
8
+
9
+ from pydantic import Field, field_validator
10
+ from pydantic_settings import BaseSettings, SettingsConfigDict
11
+
12
+
13
+ class MTNCloudConfig(BaseSettings):
14
+ """
15
+ Configuration for the MTN Cloud SDK.
16
+
17
+ Configuration can be provided via:
18
+ 1. Constructor arguments
19
+ 2. Environment variables (prefixed with MTN_CLOUD_)
20
+ 3. Default values
21
+
22
+ Example:
23
+ ```python
24
+ # From environment: MTN_CLOUD_TOKEN=xxx
25
+ config = MTNCloudConfig()
26
+
27
+ # Explicit configuration
28
+ config = MTNCloudConfig(
29
+ token="your-token",
30
+ timeout=60,
31
+ )
32
+ ```
33
+
34
+ Environment Variables:
35
+ MTN_CLOUD_TOKEN: API access token
36
+ MTN_CLOUD_URL: API base URL
37
+ MTN_CLOUD_TIMEOUT: Request timeout in seconds
38
+ MTN_CLOUD_MAX_RETRIES: Maximum retry attempts
39
+ MTN_CLOUD_VERIFY_SSL: Enable/disable SSL verification
40
+ """
41
+
42
+ model_config = SettingsConfigDict(
43
+ env_prefix="MTN_CLOUD_",
44
+ env_file=".env",
45
+ env_file_encoding="utf-8",
46
+ case_sensitive=False,
47
+ extra="ignore",
48
+ )
49
+
50
+ # Authentication
51
+ token: str | None = Field(
52
+ default=None,
53
+ description="MTN Cloud API access token",
54
+ )
55
+
56
+ username: str | None = Field(
57
+ default=None,
58
+ description="MTN Cloud username (alternative to token)",
59
+ )
60
+
61
+ password: str | None = Field(
62
+ default=None,
63
+ description="MTN Cloud password (use with username)",
64
+ )
65
+
66
+ # API Configuration
67
+ url: str = Field(
68
+ default="https://console.cloud.mtn.ng",
69
+ description="MTN Cloud API base URL",
70
+ )
71
+
72
+ api_version: str = Field(
73
+ default="v1",
74
+ description="API version (not currently used, for future)",
75
+ )
76
+
77
+ # Request Configuration
78
+ timeout: float = Field(
79
+ default=30.0,
80
+ ge=1.0,
81
+ le=300.0,
82
+ description="Request timeout in seconds",
83
+ )
84
+
85
+ max_retries: int = Field(
86
+ default=3,
87
+ ge=0,
88
+ le=10,
89
+ description="Maximum number of retry attempts",
90
+ )
91
+
92
+ retry_delay: float = Field(
93
+ default=1.0,
94
+ ge=0.1,
95
+ le=60.0,
96
+ description="Base delay between retries (exponential backoff)",
97
+ )
98
+
99
+ # SSL Configuration
100
+ verify_ssl: bool = Field(
101
+ default=True,
102
+ description="Verify SSL certificates",
103
+ )
104
+
105
+ # Client Configuration
106
+ user_agent: str = Field(
107
+ default="mtn-cloud-python/0.1.0",
108
+ description="User-Agent header for API requests",
109
+ )
110
+
111
+ # Debug
112
+ debug: bool = Field(
113
+ default=False,
114
+ description="Enable debug logging",
115
+ )
116
+
117
+ @field_validator("url")
118
+ @classmethod
119
+ def validate_url(cls, v: str) -> str:
120
+ """Ensure URL doesn't have trailing slash."""
121
+ return v.rstrip("/")
122
+
123
+ @property
124
+ def api_url(self) -> str:
125
+ """Get the full API URL."""
126
+ return f"{self.url}/api"
127
+
128
+ @property
129
+ def has_credentials(self) -> bool:
130
+ """Check if any authentication credentials are configured."""
131
+ return bool(self.token or (self.username and self.password))
132
+
133
+ def get_auth_method(self) -> str:
134
+ """Determine the authentication method to use."""
135
+ if self.token:
136
+ return "token"
137
+ elif self.username and self.password:
138
+ return "credentials"
139
+ return "none"
140
+
141
+
142
+ # Default configuration instance
143
+ default_config = MTNCloudConfig()