Coverage for src / osiris_cli / cloud_manager.py: 0%
144 statements
« prev ^ index » next coverage.py v7.13.0, created at 2025-12-27 17:41 +0200
« prev ^ index » next coverage.py v7.13.0, created at 2025-12-27 17:41 +0200
1"""
2Cloud CLI Manager for Osiris
4Unified interface for AWS, GCP, and Azure cloud operations.
5Wraps existing cloud CLIs with AI-friendly abstractions.
6"""
8import subprocess
9import json
10from typing import Dict, List, Any, Optional
11from enum import Enum
12from dataclasses import dataclass
14from .logger import get_logger
15from .errors import CloudError, CloudAuthenticationError, CloudResourceNotFoundError
17logger = get_logger()
20class CloudProvider(Enum):
21 """Supported cloud providers"""
22 AWS = "aws"
23 GCP = "gcp"
24 AZURE = "azure"
27@dataclass
28class CloudResource:
29 """Generic cloud resource representation"""
30 provider: CloudProvider
31 resource_type: str
32 resource_id: str
33 name: Optional[str] = None
34 status: Optional[str] = None
35 region: Optional[str] = None
36 metadata: Dict[str, Any] = None
39class CloudManager:
40 """
41 Unified cloud operations manager.
43 Features:
44 - AWS CLI wrapper (boto3 + aws cli)
45 - GCP CLI wrapper (gcloud)
46 - Azure CLI wrapper (az)
47 - Natural language to CLI translation
48 - Resource management
49 """
51 def __init__(self):
52 """Initialize cloud manager"""
53 self.authenticated = {
54 CloudProvider.AWS: False,
55 CloudProvider.GCP: False,
56 CloudProvider.AZURE: False
57 }
58 logger.info("Cloud manager initialized")
60 def check_cli_available(self, provider: CloudProvider) -> bool:
61 """Check if cloud CLI is available"""
62 cli_commands = {
63 CloudProvider.AWS: "aws --version",
64 CloudProvider.GCP: "gcloud --version",
65 CloudProvider.AZURE: "az --version"
66 }
68 try:
69 cmd = cli_commands[provider]
70 subprocess.run(
71 cmd.split(),
72 capture_output=True,
73 check=True,
74 timeout=5
75 )
76 return True
77 except Exception as e:
78 logger.warning(f"{provider.value} CLI not available: {e}")
79 return False
81 def check_authentication(self, provider: CloudProvider) -> bool:
82 """Check if authenticated with cloud provider"""
83 try:
84 if provider == CloudProvider.AWS:
85 result = subprocess.run(
86 ["aws", "sts", "get-caller-identity"],
87 capture_output=True,
88 timeout=10
89 )
90 self.authenticated[provider] = result.returncode == 0
92 elif provider == CloudProvider.GCP:
93 result = subprocess.run(
94 ["gcloud", "auth", "list"],
95 capture_output=True,
96 timeout=10
97 )
98 self.authenticated[provider] = result.returncode == 0
100 elif provider == CloudProvider.AZURE:
101 result = subprocess.run(
102 ["az", "account", "show"],
103 capture_output=True,
104 timeout=10
105 )
106 self.authenticated[provider] = result.returncode == 0
108 return self.authenticated[provider]
110 except Exception as e:
111 logger.error(f"Auth check failed for {provider.value}: {e}")
112 return False
114 # AWS Operations
115 def aws_list_ec2(self, region: str = "us-east-1") -> Dict[str, Any]:
116 """List AWS EC2 instances"""
117 if not self.check_authentication(CloudProvider.AWS):
118 raise CloudAuthenticationError("AWS")
120 try:
121 result = subprocess.run(
122 [
123 "aws", "ec2", "describe-instances",
124 "--region", region,
125 "--output", "json"
126 ],
127 capture_output=True,
128 text=True,
129 timeout=30,
130 check=True
131 )
133 data = json.loads(result.stdout)
134 instances = []
136 for reservation in data.get("Reservations", []):
137 for instance in reservation.get("Instances", []):
138 instances.append({
139 "id": instance.get("InstanceId"),
140 "type": instance.get("InstanceType"),
141 "state": instance.get("State", {}).get("Name"),
142 "public_ip": instance.get("PublicIpAddress"),
143 "private_ip": instance.get("PrivateIpAddress"),
144 "launch_time": instance.get("LaunchTime")
145 })
147 return {
148 "success": True,
149 "provider": "aws",
150 "resource_type": "ec2_instances",
151 "region": region,
152 "count": len(instances),
153 "instances": instances
154 }
156 except subprocess.CalledProcessError as e:
157 logger.error(f"AWS EC2 list failed: {e}")
158 raise CloudError(f"Failed to list EC2 instances: {e.stderr}")
159 except Exception as e:
160 logger.error(f"AWS operation failed: {e}")
161 raise CloudError(str(e))
163 def aws_list_s3(self) -> Dict[str, Any]:
164 """List AWS S3 buckets"""
165 if not self.check_authentication(CloudProvider.AWS):
166 raise CloudAuthenticationError("AWS")
168 try:
169 result = subprocess.run(
170 ["aws", "s3api", "list-buckets", "--output", "json"],
171 capture_output=True,
172 text=True,
173 timeout=30,
174 check=True
175 )
177 data = json.loads(result.stdout)
178 buckets = [
179 {
180 "name": b.get("Name"),
181 "created": b.get("CreationDate")
182 }
183 for b in data.get("Buckets", [])
184 ]
186 return {
187 "success": True,
188 "provider": "aws",
189 "resource_type": "s3_buckets",
190 "count": len(buckets),
191 "buckets": buckets
192 }
194 except Exception as e:
195 logger.error(f"AWS S3 list failed: {e}")
196 raise CloudError(str(e))
198 def aws_list_lambda(self, region: str = "us-east-1") -> Dict[str, Any]:
199 """List AWS Lambda functions"""
200 if not self.check_authentication(CloudProvider.AWS):
201 raise CloudAuthenticationError("AWS")
203 try:
204 result = subprocess.run(
205 [
206 "aws", "lambda", "list-functions",
207 "--region", region,
208 "--output", "json"
209 ],
210 capture_output=True,
211 text=True,
212 timeout=30,
213 check=True
214 )
216 data = json.loads(result.stdout)
217 functions = [
218 {
219 "name": f.get("FunctionName"),
220 "runtime": f.get("Runtime"),
221 "memory": f.get("MemorySize"),
222 "timeout": f.get("Timeout"),
223 "last_modified": f.get("LastModified")
224 }
225 for f in data.get("Functions", [])
226 ]
228 return {
229 "success": True,
230 "provider": "aws",
231 "resource_type": "lambda_functions",
232 "region": region,
233 "count": len(functions),
234 "functions": functions
235 }
237 except Exception as e:
238 logger.error(f"AWS Lambda list failed: {e}")
239 raise CloudError(str(e))
241 # GCP Operations
242 def gcp_list_compute(self, project: str, zone: str = "us-central1-a") -> Dict[str, Any]:
243 """List GCP Compute Engine instances"""
244 if not self.check_authentication(CloudProvider.GCP):
245 raise CloudAuthenticationError("GCP")
247 try:
248 result = subprocess.run(
249 [
250 "gcloud", "compute", "instances", "list",
251 "--project", project,
252 "--zones", zone,
253 "--format", "json"
254 ],
255 capture_output=True,
256 text=True,
257 timeout=30,
258 check=True
259 )
261 instances = json.loads(result.stdout)
263 parsed = [
264 {
265 "name": i.get("name"),
266 "machine_type": i.get("machineType", "").split("/")[-1],
267 "status": i.get("status"),
268 "zone": i.get("zone", "").split("/")[-1],
269 "external_ip": i.get("networkInterfaces", [{}])[0].get("accessConfigs", [{}])[0].get("natIP")
270 }
271 for i in instances
272 ]
274 return {
275 "success": True,
276 "provider": "gcp",
277 "resource_type": "compute_instances",
278 "project": project,
279 "zone": zone,
280 "count": len(parsed),
281 "instances": parsed
282 }
284 except Exception as e:
285 logger.error(f"GCP Compute list failed: {e}")
286 raise CloudError(str(e))
288 def gcp_list_storage(self, project: str) -> Dict[str, Any]:
289 """List GCP Cloud Storage buckets"""
290 if not self.check_authentication(CloudProvider.GCP):
291 raise CloudAuthenticationError("GCP")
293 try:
294 result = subprocess.run(
295 [
296 "gcloud", "storage", "buckets", "list",
297 "--project", project,
298 "--format", "json"
299 ],
300 capture_output=True,
301 text=True,
302 timeout=30,
303 check=True
304 )
306 buckets = json.loads(result.stdout)
308 parsed = [
309 {
310 "name": b.get("name"),
311 "location": b.get("location"),
312 "storage_class": b.get("storageClass"),
313 "created": b.get("timeCreated")
314 }
315 for b in buckets
316 ]
318 return {
319 "success": True,
320 "provider": "gcp",
321 "resource_type": "storage_buckets",
322 "project": project,
323 "count": len(parsed),
324 "buckets": parsed
325 }
327 except Exception as e:
328 logger.error(f"GCP Storage list failed: {e}")
329 raise CloudError(str(e))
331 # Azure Operations
332 def azure_list_vms(self, resource_group: Optional[str] = None) -> Dict[str, Any]:
333 """List Azure Virtual Machines"""
334 if not self.check_authentication(CloudProvider.AZURE):
335 raise CloudAuthenticationError("Azure")
337 try:
338 cmd = ["az", "vm", "list", "--output", "json"]
339 if resource_group:
340 cmd.extend(["--resource-group", resource_group])
342 result = subprocess.run(
343 cmd,
344 capture_output=True,
345 text=True,
346 timeout=30,
347 check=True
348 )
350 vms = json.loads(result.stdout)
352 parsed = [
353 {
354 "name": vm.get("name"),
355 "resource_group": vm.get("resourceGroup"),
356 "location": vm.get("location"),
357 "vm_size": vm.get("hardwareProfile", {}).get("vmSize"),
358 "os": vm.get("storageProfile", {}).get("osDisk", {}).get("osType"),
359 "provisioning_state": vm.get("provisioningState")
360 }
361 for vm in vms
362 ]
364 return {
365 "success": True,
366 "provider": "azure",
367 "resource_type": "virtual_machines",
368 "resource_group": resource_group,
369 "count": len(parsed),
370 "vms": parsed
371 }
373 except Exception as e:
374 logger.error(f"Azure VM list failed: {e}")
375 raise CloudError(str(e))
377 def azure_list_storage(self, resource_group: Optional[str] = None) -> Dict[str, Any]:
378 """List Azure Storage accounts"""
379 if not self.check_authentication(CloudProvider.AZURE):
380 raise CloudAuthenticationError("Azure")
382 try:
383 cmd = ["az", "storage", "account", "list", "--output", "json"]
384 if resource_group:
385 cmd.extend(["--resource-group", resource_group])
387 result = subprocess.run(
388 cmd,
389 capture_output=True,
390 text=True,
391 timeout=30,
392 check=True
393 )
395 accounts = json.loads(result.stdout)
397 parsed = [
398 {
399 "name": acc.get("name"),
400 "resource_group": acc.get("resourceGroup"),
401 "location": acc.get("location"),
402 "sku": acc.get("sku", {}).get("name"),
403 "kind": acc.get("kind"),
404 "created": acc.get("creationTime")
405 }
406 for acc in accounts
407 ]
409 return {
410 "success": True,
411 "provider": "azure",
412 "resource_type": "storage_accounts",
413 "resource_group": resource_group,
414 "count": len(parsed),
415 "accounts": parsed
416 }
418 except Exception as e:
419 logger.error(f"Azure Storage list failed: {e}")
420 raise CloudError(str(e))
422 def get_provider_status(self) -> Dict[str, Any]:
423 """Get status of all cloud providers"""
424 status = {}
426 for provider in CloudProvider:
427 status[provider.value] = {
428 "cli_available": self.check_cli_available(provider),
429 "authenticated": self.check_authentication(provider)
430 }
432 return status
435# Global cloud manager instance
436cloud_manager = CloudManager()