kailash 0.8.4__py3-none-any.whl → 0.8.5__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.
- kailash/__init__.py +1 -7
- kailash/cli/__init__.py +11 -1
- kailash/cli/validation_audit.py +570 -0
- kailash/core/actors/supervisor.py +1 -1
- kailash/core/resilience/circuit_breaker.py +71 -1
- kailash/core/resilience/health_monitor.py +172 -0
- kailash/edge/compliance.py +33 -0
- kailash/edge/consistency.py +609 -0
- kailash/edge/coordination/__init__.py +30 -0
- kailash/edge/coordination/global_ordering.py +355 -0
- kailash/edge/coordination/leader_election.py +217 -0
- kailash/edge/coordination/partition_detector.py +296 -0
- kailash/edge/coordination/raft.py +485 -0
- kailash/edge/discovery.py +63 -1
- kailash/edge/migration/__init__.py +19 -0
- kailash/edge/migration/edge_migrator.py +832 -0
- kailash/edge/monitoring/__init__.py +21 -0
- kailash/edge/monitoring/edge_monitor.py +736 -0
- kailash/edge/prediction/__init__.py +10 -0
- kailash/edge/prediction/predictive_warmer.py +591 -0
- kailash/edge/resource/__init__.py +102 -0
- kailash/edge/resource/cloud_integration.py +796 -0
- kailash/edge/resource/cost_optimizer.py +949 -0
- kailash/edge/resource/docker_integration.py +919 -0
- kailash/edge/resource/kubernetes_integration.py +893 -0
- kailash/edge/resource/platform_integration.py +913 -0
- kailash/edge/resource/predictive_scaler.py +959 -0
- kailash/edge/resource/resource_analyzer.py +824 -0
- kailash/edge/resource/resource_pools.py +610 -0
- kailash/integrations/dataflow_edge.py +261 -0
- kailash/mcp_server/registry_integration.py +1 -1
- kailash/monitoring/__init__.py +18 -0
- kailash/monitoring/alerts.py +646 -0
- kailash/monitoring/metrics.py +677 -0
- kailash/nodes/__init__.py +2 -0
- kailash/nodes/ai/semantic_memory.py +2 -2
- kailash/nodes/base.py +545 -0
- kailash/nodes/edge/__init__.py +36 -0
- kailash/nodes/edge/base.py +240 -0
- kailash/nodes/edge/cloud_node.py +710 -0
- kailash/nodes/edge/coordination.py +239 -0
- kailash/nodes/edge/docker_node.py +825 -0
- kailash/nodes/edge/edge_data.py +582 -0
- kailash/nodes/edge/edge_migration_node.py +392 -0
- kailash/nodes/edge/edge_monitoring_node.py +421 -0
- kailash/nodes/edge/edge_state.py +673 -0
- kailash/nodes/edge/edge_warming_node.py +393 -0
- kailash/nodes/edge/kubernetes_node.py +652 -0
- kailash/nodes/edge/platform_node.py +766 -0
- kailash/nodes/edge/resource_analyzer_node.py +378 -0
- kailash/nodes/edge/resource_optimizer_node.py +501 -0
- kailash/nodes/edge/resource_scaler_node.py +397 -0
- kailash/nodes/ports.py +676 -0
- kailash/runtime/local.py +344 -1
- kailash/runtime/validation/__init__.py +20 -0
- kailash/runtime/validation/connection_context.py +119 -0
- kailash/runtime/validation/enhanced_error_formatter.py +202 -0
- kailash/runtime/validation/error_categorizer.py +164 -0
- kailash/runtime/validation/metrics.py +380 -0
- kailash/runtime/validation/performance.py +615 -0
- kailash/runtime/validation/suggestion_engine.py +212 -0
- kailash/testing/fixtures.py +2 -2
- kailash/workflow/builder.py +230 -4
- kailash/workflow/contracts.py +418 -0
- kailash/workflow/edge_infrastructure.py +369 -0
- kailash/workflow/migration.py +3 -3
- kailash/workflow/type_inference.py +669 -0
- {kailash-0.8.4.dist-info → kailash-0.8.5.dist-info}/METADATA +43 -27
- {kailash-0.8.4.dist-info → kailash-0.8.5.dist-info}/RECORD +73 -27
- kailash/nexus/__init__.py +0 -21
- kailash/nexus/cli/__init__.py +0 -5
- kailash/nexus/cli/__main__.py +0 -6
- kailash/nexus/cli/main.py +0 -176
- kailash/nexus/factory.py +0 -413
- kailash/nexus/gateway.py +0 -545
- {kailash-0.8.4.dist-info → kailash-0.8.5.dist-info}/WHEEL +0 -0
- {kailash-0.8.4.dist-info → kailash-0.8.5.dist-info}/entry_points.txt +0 -0
- {kailash-0.8.4.dist-info → kailash-0.8.5.dist-info}/licenses/LICENSE +0 -0
- {kailash-0.8.4.dist-info → kailash-0.8.5.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,913 @@
|
|
1
|
+
"""Unified platform integration for edge resource management."""
|
2
|
+
|
3
|
+
import asyncio
|
4
|
+
import json
|
5
|
+
from dataclasses import asdict, dataclass
|
6
|
+
from datetime import datetime, timedelta
|
7
|
+
from enum import Enum
|
8
|
+
from typing import Any, Callable, Dict, List, Optional, Union
|
9
|
+
|
10
|
+
from .cloud_integration import (
|
11
|
+
CloudIntegration,
|
12
|
+
CloudProvider,
|
13
|
+
InstanceSpec,
|
14
|
+
InstanceState,
|
15
|
+
)
|
16
|
+
from .cost_optimizer import CloudProvider as CostCloudProvider
|
17
|
+
from .cost_optimizer import (
|
18
|
+
CostOptimizer,
|
19
|
+
OptimizationStrategy,
|
20
|
+
)
|
21
|
+
from .docker_integration import (
|
22
|
+
ContainerSpec,
|
23
|
+
ContainerState,
|
24
|
+
DockerIntegration,
|
25
|
+
ServiceSpec,
|
26
|
+
)
|
27
|
+
from .kubernetes_integration import (
|
28
|
+
KubernetesIntegration,
|
29
|
+
KubernetesResource,
|
30
|
+
KubernetesResourceType,
|
31
|
+
)
|
32
|
+
from .predictive_scaler import PredictionHorizon, PredictiveScaler, ScalingStrategy
|
33
|
+
from .resource_analyzer import ResourceAnalyzer, ResourceMetric, ResourceType
|
34
|
+
|
35
|
+
|
36
|
+
class PlatformType(Enum):
|
37
|
+
"""Supported platform types."""
|
38
|
+
|
39
|
+
KUBERNETES = "kubernetes"
|
40
|
+
DOCKER = "docker"
|
41
|
+
CLOUD = "cloud"
|
42
|
+
EDGE_LOCAL = "edge_local"
|
43
|
+
|
44
|
+
|
45
|
+
class ResourceScope(Enum):
|
46
|
+
"""Resource scope levels."""
|
47
|
+
|
48
|
+
NODE = "node" # Single edge node
|
49
|
+
CLUSTER = "cluster" # Edge cluster
|
50
|
+
REGION = "region" # Geographic region
|
51
|
+
GLOBAL = "global" # All edge infrastructure
|
52
|
+
|
53
|
+
|
54
|
+
@dataclass
|
55
|
+
class PlatformConfig:
|
56
|
+
"""Platform configuration."""
|
57
|
+
|
58
|
+
platform_type: PlatformType
|
59
|
+
enabled: bool = True
|
60
|
+
config: Optional[Dict[str, Any]] = None
|
61
|
+
priority: int = 1 # Lower numbers = higher priority
|
62
|
+
|
63
|
+
def __post_init__(self):
|
64
|
+
if self.config is None:
|
65
|
+
self.config = {}
|
66
|
+
|
67
|
+
def to_dict(self) -> Dict[str, Any]:
|
68
|
+
"""Convert to dictionary."""
|
69
|
+
data = asdict(self)
|
70
|
+
data["platform_type"] = self.platform_type.value
|
71
|
+
return data
|
72
|
+
|
73
|
+
|
74
|
+
@dataclass
|
75
|
+
class ResourceRequest:
|
76
|
+
"""Unified resource request."""
|
77
|
+
|
78
|
+
request_id: str
|
79
|
+
edge_node: str
|
80
|
+
resource_type: str
|
81
|
+
resource_spec: Dict[str, Any]
|
82
|
+
platform_preference: Optional[PlatformType] = None
|
83
|
+
scope: ResourceScope = ResourceScope.NODE
|
84
|
+
tags: Optional[Dict[str, str]] = None
|
85
|
+
created_at: Optional[datetime] = None
|
86
|
+
|
87
|
+
def __post_init__(self):
|
88
|
+
if self.created_at is None:
|
89
|
+
self.created_at = datetime.now()
|
90
|
+
if self.tags is None:
|
91
|
+
self.tags = {}
|
92
|
+
|
93
|
+
def to_dict(self) -> Dict[str, Any]:
|
94
|
+
"""Convert to dictionary."""
|
95
|
+
data = asdict(self)
|
96
|
+
if self.platform_preference:
|
97
|
+
data["platform_preference"] = self.platform_preference.value
|
98
|
+
data["scope"] = self.scope.value
|
99
|
+
data["created_at"] = self.created_at.isoformat()
|
100
|
+
return data
|
101
|
+
|
102
|
+
|
103
|
+
@dataclass
|
104
|
+
class ResourceAllocation:
|
105
|
+
"""Resource allocation result."""
|
106
|
+
|
107
|
+
allocation_id: str
|
108
|
+
request_id: str
|
109
|
+
platform_type: PlatformType
|
110
|
+
resource_id: str
|
111
|
+
edge_node: str
|
112
|
+
resource_details: Dict[str, Any]
|
113
|
+
allocated_at: datetime
|
114
|
+
status: str = "allocated"
|
115
|
+
|
116
|
+
def to_dict(self) -> Dict[str, Any]:
|
117
|
+
"""Convert to dictionary."""
|
118
|
+
data = asdict(self)
|
119
|
+
data["platform_type"] = self.platform_type.value
|
120
|
+
data["allocated_at"] = self.allocated_at.isoformat()
|
121
|
+
return data
|
122
|
+
|
123
|
+
|
124
|
+
class PlatformIntegration:
|
125
|
+
"""Unified platform integration for edge resource management."""
|
126
|
+
|
127
|
+
def __init__(self):
|
128
|
+
# Platform integrations
|
129
|
+
self.kubernetes_integration: Optional[KubernetesIntegration] = None
|
130
|
+
self.docker_integration: Optional[DockerIntegration] = None
|
131
|
+
self.cloud_integration: Optional[CloudIntegration] = None
|
132
|
+
|
133
|
+
# Resource management
|
134
|
+
self.resource_analyzer: Optional[ResourceAnalyzer] = None
|
135
|
+
self.predictive_scaler: Optional[PredictiveScaler] = None
|
136
|
+
self.cost_optimizer: Optional[CostOptimizer] = None
|
137
|
+
|
138
|
+
# Platform configuration
|
139
|
+
self.platform_configs: Dict[PlatformType, PlatformConfig] = {}
|
140
|
+
|
141
|
+
# Resource tracking
|
142
|
+
self.resource_requests: Dict[str, ResourceRequest] = {}
|
143
|
+
self.resource_allocations: Dict[str, ResourceAllocation] = {}
|
144
|
+
|
145
|
+
# Background tasks
|
146
|
+
self._monitoring_task: Optional[asyncio.Task] = None
|
147
|
+
self._optimization_task: Optional[asyncio.Task] = None
|
148
|
+
|
149
|
+
# Configuration
|
150
|
+
self.monitoring_interval = 30 # seconds
|
151
|
+
self.optimization_interval = 300 # 5 minutes
|
152
|
+
self.auto_scaling_enabled = True
|
153
|
+
self.auto_optimization_enabled = True
|
154
|
+
|
155
|
+
# Event handlers
|
156
|
+
self.event_handlers: Dict[str, List[Callable]] = {}
|
157
|
+
|
158
|
+
async def initialize(self) -> Dict[str, Any]:
|
159
|
+
"""Initialize platform integration."""
|
160
|
+
try:
|
161
|
+
# Initialize resource management components
|
162
|
+
self.resource_analyzer = ResourceAnalyzer()
|
163
|
+
self.predictive_scaler = PredictiveScaler()
|
164
|
+
self.cost_optimizer = CostOptimizer()
|
165
|
+
|
166
|
+
# Start resource management services
|
167
|
+
await self.resource_analyzer.start()
|
168
|
+
await self.predictive_scaler.start()
|
169
|
+
await self.cost_optimizer.start()
|
170
|
+
|
171
|
+
return {
|
172
|
+
"status": "success",
|
173
|
+
"message": "Platform integration initialized successfully",
|
174
|
+
"initialized_at": datetime.now().isoformat(),
|
175
|
+
}
|
176
|
+
|
177
|
+
except Exception as e:
|
178
|
+
return {
|
179
|
+
"status": "error",
|
180
|
+
"error": f"Failed to initialize platform integration: {str(e)}",
|
181
|
+
}
|
182
|
+
|
183
|
+
async def register_kubernetes(
|
184
|
+
self,
|
185
|
+
kubeconfig_path: Optional[str] = None,
|
186
|
+
context_name: Optional[str] = None,
|
187
|
+
namespace: str = "default",
|
188
|
+
priority: int = 1,
|
189
|
+
) -> Dict[str, Any]:
|
190
|
+
"""Register Kubernetes platform."""
|
191
|
+
try:
|
192
|
+
self.kubernetes_integration = KubernetesIntegration(
|
193
|
+
kubeconfig_path=kubeconfig_path,
|
194
|
+
context_name=context_name,
|
195
|
+
namespace=namespace,
|
196
|
+
)
|
197
|
+
|
198
|
+
await self.kubernetes_integration.initialize()
|
199
|
+
|
200
|
+
self.platform_configs[PlatformType.KUBERNETES] = PlatformConfig(
|
201
|
+
platform_type=PlatformType.KUBERNETES,
|
202
|
+
enabled=True,
|
203
|
+
config={
|
204
|
+
"kubeconfig_path": kubeconfig_path,
|
205
|
+
"context_name": context_name,
|
206
|
+
"namespace": namespace,
|
207
|
+
},
|
208
|
+
priority=priority,
|
209
|
+
)
|
210
|
+
|
211
|
+
return {
|
212
|
+
"status": "success",
|
213
|
+
"platform": "kubernetes",
|
214
|
+
"message": "Kubernetes platform registered successfully",
|
215
|
+
}
|
216
|
+
|
217
|
+
except Exception as e:
|
218
|
+
return {
|
219
|
+
"status": "error",
|
220
|
+
"platform": "kubernetes",
|
221
|
+
"error": f"Failed to register Kubernetes: {str(e)}",
|
222
|
+
}
|
223
|
+
|
224
|
+
async def register_docker(
|
225
|
+
self,
|
226
|
+
docker_host: Optional[str] = None,
|
227
|
+
api_version: str = "auto",
|
228
|
+
timeout: int = 60,
|
229
|
+
priority: int = 2,
|
230
|
+
) -> Dict[str, Any]:
|
231
|
+
"""Register Docker platform."""
|
232
|
+
try:
|
233
|
+
self.docker_integration = DockerIntegration(
|
234
|
+
docker_host=docker_host, api_version=api_version, timeout=timeout
|
235
|
+
)
|
236
|
+
|
237
|
+
await self.docker_integration.initialize()
|
238
|
+
|
239
|
+
self.platform_configs[PlatformType.DOCKER] = PlatformConfig(
|
240
|
+
platform_type=PlatformType.DOCKER,
|
241
|
+
enabled=True,
|
242
|
+
config={
|
243
|
+
"docker_host": docker_host,
|
244
|
+
"api_version": api_version,
|
245
|
+
"timeout": timeout,
|
246
|
+
"swarm_enabled": self.docker_integration.swarm_enabled,
|
247
|
+
},
|
248
|
+
priority=priority,
|
249
|
+
)
|
250
|
+
|
251
|
+
return {
|
252
|
+
"status": "success",
|
253
|
+
"platform": "docker",
|
254
|
+
"message": "Docker platform registered successfully",
|
255
|
+
"swarm_enabled": self.docker_integration.swarm_enabled,
|
256
|
+
}
|
257
|
+
|
258
|
+
except Exception as e:
|
259
|
+
return {
|
260
|
+
"status": "error",
|
261
|
+
"platform": "docker",
|
262
|
+
"error": f"Failed to register Docker: {str(e)}",
|
263
|
+
}
|
264
|
+
|
265
|
+
async def register_cloud_provider(
|
266
|
+
self, provider: CloudProvider, config: Dict[str, Any], priority: int = 3
|
267
|
+
) -> Dict[str, Any]:
|
268
|
+
"""Register cloud platform."""
|
269
|
+
try:
|
270
|
+
if not self.cloud_integration:
|
271
|
+
self.cloud_integration = CloudIntegration()
|
272
|
+
|
273
|
+
if provider == CloudProvider.AWS:
|
274
|
+
self.cloud_integration.register_aws(
|
275
|
+
region=config.get("region", "us-west-2"),
|
276
|
+
profile_name=config.get("profile_name"),
|
277
|
+
)
|
278
|
+
elif provider == CloudProvider.GCP:
|
279
|
+
self.cloud_integration.register_gcp(
|
280
|
+
project_id=config["project_id"],
|
281
|
+
zone=config.get("zone", "us-central1-a"),
|
282
|
+
credentials_path=config.get("credentials_path"),
|
283
|
+
)
|
284
|
+
elif provider == CloudProvider.AZURE:
|
285
|
+
self.cloud_integration.register_azure(
|
286
|
+
subscription_id=config["subscription_id"],
|
287
|
+
resource_group=config["resource_group"],
|
288
|
+
)
|
289
|
+
else:
|
290
|
+
raise ValueError(f"Unsupported cloud provider: {provider}")
|
291
|
+
|
292
|
+
platform_config = PlatformConfig(
|
293
|
+
platform_type=PlatformType.CLOUD,
|
294
|
+
enabled=True,
|
295
|
+
config={"provider": provider.value, **config},
|
296
|
+
priority=priority,
|
297
|
+
)
|
298
|
+
|
299
|
+
# Store cloud provider-specific config
|
300
|
+
if PlatformType.CLOUD not in self.platform_configs:
|
301
|
+
self.platform_configs[PlatformType.CLOUD] = platform_config
|
302
|
+
else:
|
303
|
+
# Merge with existing cloud config
|
304
|
+
existing_config = self.platform_configs[PlatformType.CLOUD].config
|
305
|
+
existing_config[f"{provider.value}_config"] = config
|
306
|
+
|
307
|
+
return {
|
308
|
+
"status": "success",
|
309
|
+
"platform": "cloud",
|
310
|
+
"provider": provider.value,
|
311
|
+
"message": f"Cloud provider {provider.value} registered successfully",
|
312
|
+
}
|
313
|
+
|
314
|
+
except Exception as e:
|
315
|
+
return {
|
316
|
+
"status": "error",
|
317
|
+
"platform": "cloud",
|
318
|
+
"provider": provider.value if provider else "unknown",
|
319
|
+
"error": f"Failed to register cloud provider: {str(e)}",
|
320
|
+
}
|
321
|
+
|
322
|
+
async def allocate_resource(self, request: ResourceRequest) -> Dict[str, Any]:
|
323
|
+
"""Allocate resource using best available platform."""
|
324
|
+
try:
|
325
|
+
# Store request
|
326
|
+
self.resource_requests[request.request_id] = request
|
327
|
+
|
328
|
+
# Determine best platform for allocation
|
329
|
+
platform = await self._select_platform(request)
|
330
|
+
|
331
|
+
if not platform:
|
332
|
+
return {
|
333
|
+
"status": "error",
|
334
|
+
"error": "No suitable platform available for resource allocation",
|
335
|
+
}
|
336
|
+
|
337
|
+
# Allocate resource on selected platform
|
338
|
+
allocation_result = await self._allocate_on_platform(platform, request)
|
339
|
+
|
340
|
+
if allocation_result.get("status") == "success":
|
341
|
+
# Create allocation record
|
342
|
+
allocation = ResourceAllocation(
|
343
|
+
allocation_id=f"alloc-{request.request_id}",
|
344
|
+
request_id=request.request_id,
|
345
|
+
platform_type=platform,
|
346
|
+
resource_id=allocation_result.get("resource_id", "unknown"),
|
347
|
+
edge_node=request.edge_node,
|
348
|
+
resource_details=allocation_result.get("details", {}),
|
349
|
+
allocated_at=datetime.now(),
|
350
|
+
)
|
351
|
+
|
352
|
+
self.resource_allocations[allocation.allocation_id] = allocation
|
353
|
+
|
354
|
+
# Emit allocation event
|
355
|
+
await self._emit_event(
|
356
|
+
"resource_allocated",
|
357
|
+
{"allocation": allocation.to_dict(), "request": request.to_dict()},
|
358
|
+
)
|
359
|
+
|
360
|
+
return {
|
361
|
+
"status": "success",
|
362
|
+
"allocation_id": allocation.allocation_id,
|
363
|
+
"platform": platform.value,
|
364
|
+
"resource_id": allocation.resource_id,
|
365
|
+
"details": allocation_result,
|
366
|
+
}
|
367
|
+
else:
|
368
|
+
return allocation_result
|
369
|
+
|
370
|
+
except Exception as e:
|
371
|
+
return {
|
372
|
+
"status": "error",
|
373
|
+
"error": f"Failed to allocate resource: {str(e)}",
|
374
|
+
}
|
375
|
+
|
376
|
+
async def deallocate_resource(self, allocation_id: str) -> Dict[str, Any]:
|
377
|
+
"""Deallocate resource."""
|
378
|
+
try:
|
379
|
+
allocation = self.resource_allocations.get(allocation_id)
|
380
|
+
if not allocation:
|
381
|
+
return {
|
382
|
+
"status": "error",
|
383
|
+
"error": f"Allocation {allocation_id} not found",
|
384
|
+
}
|
385
|
+
|
386
|
+
# Deallocate on platform
|
387
|
+
result = await self._deallocate_on_platform(allocation)
|
388
|
+
|
389
|
+
if result.get("status") == "success":
|
390
|
+
# Remove allocation record
|
391
|
+
del self.resource_allocations[allocation_id]
|
392
|
+
|
393
|
+
# Emit deallocation event
|
394
|
+
await self._emit_event(
|
395
|
+
"resource_deallocated",
|
396
|
+
{
|
397
|
+
"allocation_id": allocation_id,
|
398
|
+
"allocation": allocation.to_dict(),
|
399
|
+
},
|
400
|
+
)
|
401
|
+
|
402
|
+
return {
|
403
|
+
"status": "success",
|
404
|
+
"allocation_id": allocation_id,
|
405
|
+
"message": "Resource deallocated successfully",
|
406
|
+
}
|
407
|
+
else:
|
408
|
+
return result
|
409
|
+
|
410
|
+
except Exception as e:
|
411
|
+
return {
|
412
|
+
"status": "error",
|
413
|
+
"error": f"Failed to deallocate resource: {str(e)}",
|
414
|
+
}
|
415
|
+
|
416
|
+
async def get_resource_status(self, allocation_id: str) -> Dict[str, Any]:
|
417
|
+
"""Get resource status."""
|
418
|
+
try:
|
419
|
+
allocation = self.resource_allocations.get(allocation_id)
|
420
|
+
if not allocation:
|
421
|
+
return {
|
422
|
+
"status": "error",
|
423
|
+
"error": f"Allocation {allocation_id} not found",
|
424
|
+
}
|
425
|
+
|
426
|
+
# Get status from platform
|
427
|
+
status = await self._get_platform_resource_status(allocation)
|
428
|
+
|
429
|
+
return {
|
430
|
+
"status": "success",
|
431
|
+
"allocation_id": allocation_id,
|
432
|
+
"platform": allocation.platform_type.value,
|
433
|
+
"resource_id": allocation.resource_id,
|
434
|
+
"resource_status": status,
|
435
|
+
}
|
436
|
+
|
437
|
+
except Exception as e:
|
438
|
+
return {
|
439
|
+
"status": "error",
|
440
|
+
"error": f"Failed to get resource status: {str(e)}",
|
441
|
+
}
|
442
|
+
|
443
|
+
async def list_allocations(
|
444
|
+
self,
|
445
|
+
edge_node: Optional[str] = None,
|
446
|
+
platform_type: Optional[PlatformType] = None,
|
447
|
+
) -> List[Dict[str, Any]]:
|
448
|
+
"""List resource allocations."""
|
449
|
+
try:
|
450
|
+
allocations = []
|
451
|
+
|
452
|
+
for allocation in self.resource_allocations.values():
|
453
|
+
# Apply filters
|
454
|
+
if edge_node and allocation.edge_node != edge_node:
|
455
|
+
continue
|
456
|
+
if platform_type and allocation.platform_type != platform_type:
|
457
|
+
continue
|
458
|
+
|
459
|
+
allocations.append(allocation.to_dict())
|
460
|
+
|
461
|
+
return allocations
|
462
|
+
|
463
|
+
except Exception as e:
|
464
|
+
raise RuntimeError(f"Failed to list allocations: {str(e)}")
|
465
|
+
|
466
|
+
async def optimize_resources(
|
467
|
+
self, scope: ResourceScope = ResourceScope.CLUSTER
|
468
|
+
) -> Dict[str, Any]:
|
469
|
+
"""Optimize resources across platforms."""
|
470
|
+
try:
|
471
|
+
if not self.cost_optimizer:
|
472
|
+
return {"status": "error", "error": "Cost optimizer not initialized"}
|
473
|
+
|
474
|
+
# Get optimization recommendations
|
475
|
+
optimizations = await self.cost_optimizer.optimize_costs(
|
476
|
+
strategy=OptimizationStrategy.BALANCE_COST_PERFORMANCE
|
477
|
+
)
|
478
|
+
|
479
|
+
optimization_results = []
|
480
|
+
for opt in optimizations:
|
481
|
+
# Apply optimization if beneficial
|
482
|
+
if opt.savings_percentage > 10: # 10% minimum savings
|
483
|
+
# Implementation would depend on optimization type
|
484
|
+
optimization_results.append(
|
485
|
+
{
|
486
|
+
"optimization_id": opt.optimization_id,
|
487
|
+
"savings": opt.estimated_savings,
|
488
|
+
"savings_percentage": opt.savings_percentage,
|
489
|
+
"applied": True,
|
490
|
+
}
|
491
|
+
)
|
492
|
+
|
493
|
+
return {
|
494
|
+
"status": "success",
|
495
|
+
"scope": scope.value,
|
496
|
+
"optimizations_applied": len(optimization_results),
|
497
|
+
"total_savings": sum(opt["savings"] for opt in optimization_results),
|
498
|
+
"details": optimization_results,
|
499
|
+
}
|
500
|
+
|
501
|
+
except Exception as e:
|
502
|
+
return {
|
503
|
+
"status": "error",
|
504
|
+
"error": f"Failed to optimize resources: {str(e)}",
|
505
|
+
}
|
506
|
+
|
507
|
+
async def scale_resources(
|
508
|
+
self, allocation_id: str, target_scale: int
|
509
|
+
) -> Dict[str, Any]:
|
510
|
+
"""Scale allocated resources."""
|
511
|
+
try:
|
512
|
+
allocation = self.resource_allocations.get(allocation_id)
|
513
|
+
if not allocation:
|
514
|
+
return {
|
515
|
+
"status": "error",
|
516
|
+
"error": f"Allocation {allocation_id} not found",
|
517
|
+
}
|
518
|
+
|
519
|
+
# Scale on platform
|
520
|
+
result = await self._scale_on_platform(allocation, target_scale)
|
521
|
+
|
522
|
+
if result.get("status") == "success":
|
523
|
+
# Emit scaling event
|
524
|
+
await self._emit_event(
|
525
|
+
"resource_scaled",
|
526
|
+
{
|
527
|
+
"allocation_id": allocation_id,
|
528
|
+
"target_scale": target_scale,
|
529
|
+
"platform": allocation.platform_type.value,
|
530
|
+
},
|
531
|
+
)
|
532
|
+
|
533
|
+
return result
|
534
|
+
|
535
|
+
except Exception as e:
|
536
|
+
return {"status": "error", "error": f"Failed to scale resource: {str(e)}"}
|
537
|
+
|
538
|
+
async def get_platform_status(self) -> Dict[str, Any]:
|
539
|
+
"""Get status of all registered platforms."""
|
540
|
+
try:
|
541
|
+
platform_status = {}
|
542
|
+
|
543
|
+
for platform_type, config in self.platform_configs.items():
|
544
|
+
status = {
|
545
|
+
"enabled": config.enabled,
|
546
|
+
"priority": config.priority,
|
547
|
+
"config": config.config,
|
548
|
+
}
|
549
|
+
|
550
|
+
# Get platform-specific status
|
551
|
+
if (
|
552
|
+
platform_type == PlatformType.KUBERNETES
|
553
|
+
and self.kubernetes_integration
|
554
|
+
):
|
555
|
+
cluster_info = await self.kubernetes_integration.get_cluster_info()
|
556
|
+
status["cluster_info"] = cluster_info
|
557
|
+
elif platform_type == PlatformType.DOCKER and self.docker_integration:
|
558
|
+
system_info = await self.docker_integration.get_system_info()
|
559
|
+
status["system_info"] = system_info
|
560
|
+
elif platform_type == PlatformType.CLOUD and self.cloud_integration:
|
561
|
+
providers = await self.cloud_integration.get_supported_providers()
|
562
|
+
status["supported_providers"] = providers
|
563
|
+
|
564
|
+
platform_status[platform_type.value] = status
|
565
|
+
|
566
|
+
return {
|
567
|
+
"status": "success",
|
568
|
+
"platforms": platform_status,
|
569
|
+
"total_platforms": len(platform_status),
|
570
|
+
}
|
571
|
+
|
572
|
+
except Exception as e:
|
573
|
+
return {
|
574
|
+
"status": "error",
|
575
|
+
"error": f"Failed to get platform status: {str(e)}",
|
576
|
+
}
|
577
|
+
|
578
|
+
async def start_monitoring(self) -> Dict[str, Any]:
|
579
|
+
"""Start platform monitoring."""
|
580
|
+
try:
|
581
|
+
if self._monitoring_task and not self._monitoring_task.done():
|
582
|
+
return {"status": "success", "message": "Monitoring already running"}
|
583
|
+
|
584
|
+
self._monitoring_task = asyncio.create_task(self._monitor_platforms())
|
585
|
+
|
586
|
+
if self.auto_optimization_enabled:
|
587
|
+
self._optimization_task = asyncio.create_task(
|
588
|
+
self._optimize_continuously()
|
589
|
+
)
|
590
|
+
|
591
|
+
return {
|
592
|
+
"status": "success",
|
593
|
+
"message": "Platform monitoring started",
|
594
|
+
"monitoring_interval": self.monitoring_interval,
|
595
|
+
"auto_optimization": self.auto_optimization_enabled,
|
596
|
+
}
|
597
|
+
|
598
|
+
except Exception as e:
|
599
|
+
return {"status": "error", "error": f"Failed to start monitoring: {str(e)}"}
|
600
|
+
|
601
|
+
async def stop_monitoring(self) -> Dict[str, Any]:
|
602
|
+
"""Stop platform monitoring."""
|
603
|
+
try:
|
604
|
+
if self._monitoring_task and not self._monitoring_task.done():
|
605
|
+
self._monitoring_task.cancel()
|
606
|
+
try:
|
607
|
+
await self._monitoring_task
|
608
|
+
except asyncio.CancelledError:
|
609
|
+
pass
|
610
|
+
|
611
|
+
if self._optimization_task and not self._optimization_task.done():
|
612
|
+
self._optimization_task.cancel()
|
613
|
+
try:
|
614
|
+
await self._optimization_task
|
615
|
+
except asyncio.CancelledError:
|
616
|
+
pass
|
617
|
+
|
618
|
+
return {"status": "success", "message": "Platform monitoring stopped"}
|
619
|
+
|
620
|
+
except Exception as e:
|
621
|
+
return {"status": "error", "error": f"Failed to stop monitoring: {str(e)}"}
|
622
|
+
|
623
|
+
def add_event_handler(self, event_type: str, handler: Callable) -> None:
|
624
|
+
"""Add event handler."""
|
625
|
+
if event_type not in self.event_handlers:
|
626
|
+
self.event_handlers[event_type] = []
|
627
|
+
self.event_handlers[event_type].append(handler)
|
628
|
+
|
629
|
+
def remove_event_handler(self, event_type: str, handler: Callable) -> None:
|
630
|
+
"""Remove event handler."""
|
631
|
+
if event_type in self.event_handlers:
|
632
|
+
self.event_handlers[event_type].remove(handler)
|
633
|
+
|
634
|
+
async def _select_platform(
|
635
|
+
self, request: ResourceRequest
|
636
|
+
) -> Optional[PlatformType]:
|
637
|
+
"""Select best platform for resource allocation."""
|
638
|
+
# Check platform preference
|
639
|
+
if (
|
640
|
+
request.platform_preference
|
641
|
+
and request.platform_preference in self.platform_configs
|
642
|
+
):
|
643
|
+
config = self.platform_configs[request.platform_preference]
|
644
|
+
if config.enabled:
|
645
|
+
return request.platform_preference
|
646
|
+
|
647
|
+
# Select by priority (lower number = higher priority)
|
648
|
+
available_platforms = [
|
649
|
+
(platform, config)
|
650
|
+
for platform, config in self.platform_configs.items()
|
651
|
+
if config.enabled
|
652
|
+
]
|
653
|
+
|
654
|
+
if not available_platforms:
|
655
|
+
return None
|
656
|
+
|
657
|
+
# Sort by priority
|
658
|
+
available_platforms.sort(key=lambda x: x[1].priority)
|
659
|
+
|
660
|
+
# For now, return highest priority platform
|
661
|
+
# In production, this would include resource availability checks
|
662
|
+
return available_platforms[0][0]
|
663
|
+
|
664
|
+
async def _allocate_on_platform(
|
665
|
+
self, platform: PlatformType, request: ResourceRequest
|
666
|
+
) -> Dict[str, Any]:
|
667
|
+
"""Allocate resource on specific platform."""
|
668
|
+
if platform == PlatformType.KUBERNETES and self.kubernetes_integration:
|
669
|
+
return await self._allocate_kubernetes_resource(request)
|
670
|
+
elif platform == PlatformType.DOCKER and self.docker_integration:
|
671
|
+
return await self._allocate_docker_resource(request)
|
672
|
+
elif platform == PlatformType.CLOUD and self.cloud_integration:
|
673
|
+
return await self._allocate_cloud_resource(request)
|
674
|
+
else:
|
675
|
+
return {
|
676
|
+
"status": "error",
|
677
|
+
"error": f"Platform {platform.value} not available or not supported",
|
678
|
+
}
|
679
|
+
|
680
|
+
async def _allocate_kubernetes_resource(
|
681
|
+
self, request: ResourceRequest
|
682
|
+
) -> Dict[str, Any]:
|
683
|
+
"""Allocate Kubernetes resource."""
|
684
|
+
try:
|
685
|
+
# Create Kubernetes resource from request
|
686
|
+
resource = KubernetesResource(
|
687
|
+
name=f"{request.edge_node}-{request.resource_type}",
|
688
|
+
namespace="default",
|
689
|
+
resource_type=KubernetesResourceType(request.resource_type),
|
690
|
+
spec=request.resource_spec,
|
691
|
+
edge_node=request.edge_node,
|
692
|
+
labels=request.tags,
|
693
|
+
)
|
694
|
+
|
695
|
+
result = await self.kubernetes_integration.create_resource(resource)
|
696
|
+
|
697
|
+
return {
|
698
|
+
"status": result.get("status", "unknown"),
|
699
|
+
"resource_id": f"{resource.namespace}/{resource.name}",
|
700
|
+
"details": result,
|
701
|
+
}
|
702
|
+
|
703
|
+
except Exception as e:
|
704
|
+
return {
|
705
|
+
"status": "error",
|
706
|
+
"error": f"Failed to allocate Kubernetes resource: {str(e)}",
|
707
|
+
}
|
708
|
+
|
709
|
+
async def _allocate_docker_resource(
|
710
|
+
self, request: ResourceRequest
|
711
|
+
) -> Dict[str, Any]:
|
712
|
+
"""Allocate Docker resource."""
|
713
|
+
try:
|
714
|
+
# Create Docker container from request
|
715
|
+
container_spec = ContainerSpec(
|
716
|
+
name=f"{request.edge_node}-{request.resource_type}",
|
717
|
+
image=request.resource_spec.get("image", "alpine:latest"),
|
718
|
+
environment=request.resource_spec.get("environment", {}),
|
719
|
+
ports=request.resource_spec.get("ports", {}),
|
720
|
+
volumes=request.resource_spec.get("volumes", {}),
|
721
|
+
labels=request.tags,
|
722
|
+
edge_node=request.edge_node,
|
723
|
+
)
|
724
|
+
|
725
|
+
result = await self.docker_integration.create_container(container_spec)
|
726
|
+
|
727
|
+
return {
|
728
|
+
"status": result.get("status", "unknown"),
|
729
|
+
"resource_id": result.get("container_id", "unknown"),
|
730
|
+
"details": result,
|
731
|
+
}
|
732
|
+
|
733
|
+
except Exception as e:
|
734
|
+
return {
|
735
|
+
"status": "error",
|
736
|
+
"error": f"Failed to allocate Docker resource: {str(e)}",
|
737
|
+
}
|
738
|
+
|
739
|
+
async def _allocate_cloud_resource(
|
740
|
+
self, request: ResourceRequest
|
741
|
+
) -> Dict[str, Any]:
|
742
|
+
"""Allocate cloud resource."""
|
743
|
+
try:
|
744
|
+
# Create cloud instance from request
|
745
|
+
spec = InstanceSpec(
|
746
|
+
name=f"{request.edge_node}-{request.resource_type}",
|
747
|
+
provider=CloudProvider.AWS, # Default, should be configurable
|
748
|
+
instance_type=request.resource_spec.get("instance_type", "t3.micro"),
|
749
|
+
image_id=request.resource_spec.get("image_id", "ami-0c02fb55956c7d316"),
|
750
|
+
region=request.resource_spec.get("region", "us-west-2"),
|
751
|
+
tags=request.tags,
|
752
|
+
edge_node=request.edge_node,
|
753
|
+
)
|
754
|
+
|
755
|
+
result = await self.cloud_integration.create_instance(spec)
|
756
|
+
|
757
|
+
return {
|
758
|
+
"status": result.get("status", "unknown"),
|
759
|
+
"resource_id": result.get("instance_id", "unknown"),
|
760
|
+
"details": result,
|
761
|
+
}
|
762
|
+
|
763
|
+
except Exception as e:
|
764
|
+
return {
|
765
|
+
"status": "error",
|
766
|
+
"error": f"Failed to allocate cloud resource: {str(e)}",
|
767
|
+
}
|
768
|
+
|
769
|
+
async def _deallocate_on_platform(
|
770
|
+
self, allocation: ResourceAllocation
|
771
|
+
) -> Dict[str, Any]:
|
772
|
+
"""Deallocate resource on platform."""
|
773
|
+
if (
|
774
|
+
allocation.platform_type == PlatformType.KUBERNETES
|
775
|
+
and self.kubernetes_integration
|
776
|
+
):
|
777
|
+
# Parse resource ID to get namespace and name
|
778
|
+
namespace, name = allocation.resource_id.split("/", 1)
|
779
|
+
return await self.kubernetes_integration.delete_resource(
|
780
|
+
name,
|
781
|
+
namespace,
|
782
|
+
KubernetesResourceType.DEPLOYMENT, # Should be stored in allocation
|
783
|
+
)
|
784
|
+
elif (
|
785
|
+
allocation.platform_type == PlatformType.DOCKER and self.docker_integration
|
786
|
+
):
|
787
|
+
return await self.docker_integration.remove_container(
|
788
|
+
allocation.resource_id
|
789
|
+
)
|
790
|
+
elif allocation.platform_type == PlatformType.CLOUD and self.cloud_integration:
|
791
|
+
return await self.cloud_integration.terminate_instance(
|
792
|
+
CloudProvider.AWS, # Should be stored in allocation
|
793
|
+
allocation.resource_id,
|
794
|
+
)
|
795
|
+
else:
|
796
|
+
return {
|
797
|
+
"status": "error",
|
798
|
+
"error": f"Platform {allocation.platform_type.value} not available",
|
799
|
+
}
|
800
|
+
|
801
|
+
async def _get_platform_resource_status(
|
802
|
+
self, allocation: ResourceAllocation
|
803
|
+
) -> Dict[str, Any]:
|
804
|
+
"""Get resource status from platform."""
|
805
|
+
if (
|
806
|
+
allocation.platform_type == PlatformType.KUBERNETES
|
807
|
+
and self.kubernetes_integration
|
808
|
+
):
|
809
|
+
namespace, name = allocation.resource_id.split("/", 1)
|
810
|
+
return await self.kubernetes_integration.get_resource_status(
|
811
|
+
name, namespace, KubernetesResourceType.DEPLOYMENT
|
812
|
+
)
|
813
|
+
elif (
|
814
|
+
allocation.platform_type == PlatformType.DOCKER and self.docker_integration
|
815
|
+
):
|
816
|
+
return await self.docker_integration.get_container_status(
|
817
|
+
allocation.resource_id
|
818
|
+
)
|
819
|
+
elif allocation.platform_type == PlatformType.CLOUD and self.cloud_integration:
|
820
|
+
return await self.cloud_integration.get_instance_status(
|
821
|
+
CloudProvider.AWS, allocation.resource_id
|
822
|
+
)
|
823
|
+
else:
|
824
|
+
return {
|
825
|
+
"status": "error",
|
826
|
+
"error": f"Platform {allocation.platform_type.value} not available",
|
827
|
+
}
|
828
|
+
|
829
|
+
async def _scale_on_platform(
|
830
|
+
self, allocation: ResourceAllocation, target_scale: int
|
831
|
+
) -> Dict[str, Any]:
|
832
|
+
"""Scale resource on platform."""
|
833
|
+
if (
|
834
|
+
allocation.platform_type == PlatformType.KUBERNETES
|
835
|
+
and self.kubernetes_integration
|
836
|
+
):
|
837
|
+
namespace, name = allocation.resource_id.split("/", 1)
|
838
|
+
return await self.kubernetes_integration.scale_deployment(
|
839
|
+
name, namespace, target_scale
|
840
|
+
)
|
841
|
+
elif (
|
842
|
+
allocation.platform_type == PlatformType.DOCKER and self.docker_integration
|
843
|
+
):
|
844
|
+
# Docker scaling would require service mode (Swarm)
|
845
|
+
return await self.docker_integration.scale_service(
|
846
|
+
allocation.resource_id, target_scale
|
847
|
+
)
|
848
|
+
elif allocation.platform_type == PlatformType.CLOUD and self.cloud_integration:
|
849
|
+
# Cloud scaling would require auto-scaling groups or similar
|
850
|
+
return {
|
851
|
+
"status": "not_implemented",
|
852
|
+
"message": "Cloud instance scaling not implemented",
|
853
|
+
}
|
854
|
+
else:
|
855
|
+
return {
|
856
|
+
"status": "error",
|
857
|
+
"error": f"Platform {allocation.platform_type.value} not available",
|
858
|
+
}
|
859
|
+
|
860
|
+
async def _emit_event(self, event_type: str, event_data: Dict[str, Any]) -> None:
|
861
|
+
"""Emit event to registered handlers."""
|
862
|
+
if event_type in self.event_handlers:
|
863
|
+
for handler in self.event_handlers[event_type]:
|
864
|
+
try:
|
865
|
+
if asyncio.iscoroutinefunction(handler):
|
866
|
+
await handler(event_data)
|
867
|
+
else:
|
868
|
+
handler(event_data)
|
869
|
+
except Exception as e:
|
870
|
+
# Log error but don't stop other handlers
|
871
|
+
print(f"Event handler error: {e}")
|
872
|
+
|
873
|
+
async def _monitor_platforms(self) -> None:
|
874
|
+
"""Monitor platforms continuously."""
|
875
|
+
while True:
|
876
|
+
try:
|
877
|
+
# Monitor platform health
|
878
|
+
platform_status = await self.get_platform_status()
|
879
|
+
|
880
|
+
# Monitor allocations
|
881
|
+
for allocation_id, allocation in list(
|
882
|
+
self.resource_allocations.items()
|
883
|
+
):
|
884
|
+
try:
|
885
|
+
status = await self._get_platform_resource_status(allocation)
|
886
|
+
# Update allocation status based on platform status
|
887
|
+
allocation.status = status.get("status", "unknown")
|
888
|
+
except Exception:
|
889
|
+
# Resource might have been deleted
|
890
|
+
pass
|
891
|
+
|
892
|
+
await asyncio.sleep(self.monitoring_interval)
|
893
|
+
|
894
|
+
except asyncio.CancelledError:
|
895
|
+
break
|
896
|
+
except Exception as e:
|
897
|
+
print(f"Platform monitoring error: {e}")
|
898
|
+
await asyncio.sleep(self.monitoring_interval)
|
899
|
+
|
900
|
+
async def _optimize_continuously(self) -> None:
|
901
|
+
"""Optimize resources continuously."""
|
902
|
+
while True:
|
903
|
+
try:
|
904
|
+
if self.auto_optimization_enabled:
|
905
|
+
await self.optimize_resources(ResourceScope.CLUSTER)
|
906
|
+
|
907
|
+
await asyncio.sleep(self.optimization_interval)
|
908
|
+
|
909
|
+
except asyncio.CancelledError:
|
910
|
+
break
|
911
|
+
except Exception as e:
|
912
|
+
print(f"Optimization error: {e}")
|
913
|
+
await asyncio.sleep(self.optimization_interval)
|