kailash 0.8.3__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.
Files changed (84) hide show
  1. kailash/__init__.py +1 -7
  2. kailash/cli/__init__.py +11 -1
  3. kailash/cli/validation_audit.py +570 -0
  4. kailash/core/actors/supervisor.py +1 -1
  5. kailash/core/resilience/circuit_breaker.py +71 -1
  6. kailash/core/resilience/health_monitor.py +172 -0
  7. kailash/edge/compliance.py +33 -0
  8. kailash/edge/consistency.py +609 -0
  9. kailash/edge/coordination/__init__.py +30 -0
  10. kailash/edge/coordination/global_ordering.py +355 -0
  11. kailash/edge/coordination/leader_election.py +217 -0
  12. kailash/edge/coordination/partition_detector.py +296 -0
  13. kailash/edge/coordination/raft.py +485 -0
  14. kailash/edge/discovery.py +63 -1
  15. kailash/edge/migration/__init__.py +19 -0
  16. kailash/edge/migration/edge_migrator.py +832 -0
  17. kailash/edge/monitoring/__init__.py +21 -0
  18. kailash/edge/monitoring/edge_monitor.py +736 -0
  19. kailash/edge/prediction/__init__.py +10 -0
  20. kailash/edge/prediction/predictive_warmer.py +591 -0
  21. kailash/edge/resource/__init__.py +102 -0
  22. kailash/edge/resource/cloud_integration.py +796 -0
  23. kailash/edge/resource/cost_optimizer.py +949 -0
  24. kailash/edge/resource/docker_integration.py +919 -0
  25. kailash/edge/resource/kubernetes_integration.py +893 -0
  26. kailash/edge/resource/platform_integration.py +913 -0
  27. kailash/edge/resource/predictive_scaler.py +959 -0
  28. kailash/edge/resource/resource_analyzer.py +824 -0
  29. kailash/edge/resource/resource_pools.py +610 -0
  30. kailash/integrations/dataflow_edge.py +261 -0
  31. kailash/mcp_server/registry_integration.py +1 -1
  32. kailash/monitoring/__init__.py +18 -0
  33. kailash/monitoring/alerts.py +646 -0
  34. kailash/monitoring/metrics.py +677 -0
  35. kailash/nodes/__init__.py +2 -0
  36. kailash/nodes/ai/__init__.py +17 -0
  37. kailash/nodes/ai/a2a.py +1914 -43
  38. kailash/nodes/ai/a2a_backup.py +1807 -0
  39. kailash/nodes/ai/hybrid_search.py +972 -0
  40. kailash/nodes/ai/semantic_memory.py +558 -0
  41. kailash/nodes/ai/streaming_analytics.py +947 -0
  42. kailash/nodes/base.py +545 -0
  43. kailash/nodes/edge/__init__.py +36 -0
  44. kailash/nodes/edge/base.py +240 -0
  45. kailash/nodes/edge/cloud_node.py +710 -0
  46. kailash/nodes/edge/coordination.py +239 -0
  47. kailash/nodes/edge/docker_node.py +825 -0
  48. kailash/nodes/edge/edge_data.py +582 -0
  49. kailash/nodes/edge/edge_migration_node.py +392 -0
  50. kailash/nodes/edge/edge_monitoring_node.py +421 -0
  51. kailash/nodes/edge/edge_state.py +673 -0
  52. kailash/nodes/edge/edge_warming_node.py +393 -0
  53. kailash/nodes/edge/kubernetes_node.py +652 -0
  54. kailash/nodes/edge/platform_node.py +766 -0
  55. kailash/nodes/edge/resource_analyzer_node.py +378 -0
  56. kailash/nodes/edge/resource_optimizer_node.py +501 -0
  57. kailash/nodes/edge/resource_scaler_node.py +397 -0
  58. kailash/nodes/ports.py +676 -0
  59. kailash/runtime/local.py +344 -1
  60. kailash/runtime/validation/__init__.py +20 -0
  61. kailash/runtime/validation/connection_context.py +119 -0
  62. kailash/runtime/validation/enhanced_error_formatter.py +202 -0
  63. kailash/runtime/validation/error_categorizer.py +164 -0
  64. kailash/runtime/validation/metrics.py +380 -0
  65. kailash/runtime/validation/performance.py +615 -0
  66. kailash/runtime/validation/suggestion_engine.py +212 -0
  67. kailash/testing/fixtures.py +2 -2
  68. kailash/workflow/builder.py +234 -8
  69. kailash/workflow/contracts.py +418 -0
  70. kailash/workflow/edge_infrastructure.py +369 -0
  71. kailash/workflow/migration.py +3 -3
  72. kailash/workflow/type_inference.py +669 -0
  73. {kailash-0.8.3.dist-info → kailash-0.8.5.dist-info}/METADATA +44 -27
  74. {kailash-0.8.3.dist-info → kailash-0.8.5.dist-info}/RECORD +78 -28
  75. kailash/nexus/__init__.py +0 -21
  76. kailash/nexus/cli/__init__.py +0 -5
  77. kailash/nexus/cli/__main__.py +0 -6
  78. kailash/nexus/cli/main.py +0 -176
  79. kailash/nexus/factory.py +0 -413
  80. kailash/nexus/gateway.py +0 -545
  81. {kailash-0.8.3.dist-info → kailash-0.8.5.dist-info}/WHEEL +0 -0
  82. {kailash-0.8.3.dist-info → kailash-0.8.5.dist-info}/entry_points.txt +0 -0
  83. {kailash-0.8.3.dist-info → kailash-0.8.5.dist-info}/licenses/LICENSE +0 -0
  84. {kailash-0.8.3.dist-info → kailash-0.8.5.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,501 @@
1
+ """Resource optimizer node for intelligent cost optimization.
2
+
3
+ This node integrates cost optimization capabilities into workflows,
4
+ providing multi-cloud cost analysis and optimization recommendations.
5
+ """
6
+
7
+ import asyncio
8
+ from datetime import datetime
9
+ from typing import Any, Dict, List, Optional
10
+
11
+ from kailash.edge.resource.cost_optimizer import (
12
+ CloudProvider,
13
+ CostMetric,
14
+ CostOptimization,
15
+ CostOptimizer,
16
+ InstanceType,
17
+ OptimizationStrategy,
18
+ )
19
+ from kailash.nodes.base import NodeParameter, register_node
20
+ from kailash.nodes.base_async import AsyncNode
21
+
22
+
23
+ @register_node()
24
+ class ResourceOptimizerNode(AsyncNode):
25
+ """Node for cost optimization operations.
26
+
27
+ This node provides comprehensive cost analysis and optimization
28
+ for edge computing resources across multiple cloud providers.
29
+
30
+ Example:
31
+ >>> # Record cost data
32
+ >>> result = await optimizer_node.execute_async(
33
+ ... operation="record_cost",
34
+ ... edge_node="edge-west-1",
35
+ ... resource_type="cpu",
36
+ ... provider="aws",
37
+ ... instance_type="on_demand",
38
+ ... cost_per_hour=0.10,
39
+ ... usage_hours=24
40
+ ... )
41
+
42
+ >>> # Optimize costs
43
+ >>> result = await optimizer_node.execute_async(
44
+ ... operation="optimize_costs",
45
+ ... strategy="balance_cost_performance",
46
+ ... edge_nodes=["edge-west-1", "edge-west-2"]
47
+ ... )
48
+
49
+ >>> # Get spot recommendations
50
+ >>> result = await optimizer_node.execute_async(
51
+ ... operation="get_spot_recommendations",
52
+ ... edge_nodes=["edge-west-1"]
53
+ ... )
54
+
55
+ >>> # Calculate ROI
56
+ >>> result = await optimizer_node.execute_async(
57
+ ... operation="calculate_roi",
58
+ ... optimization_id="opt_12345",
59
+ ... implementation_cost=500.0
60
+ ... )
61
+ """
62
+
63
+ def __init__(self, **kwargs):
64
+ """Initialize resource optimizer node."""
65
+ super().__init__(**kwargs)
66
+
67
+ # Extract configuration
68
+ cost_history_days = kwargs.get("cost_history_days", 30)
69
+ optimization_interval = kwargs.get("optimization_interval", 3600)
70
+ savings_threshold = kwargs.get("savings_threshold", 0.1)
71
+ risk_tolerance = kwargs.get("risk_tolerance", "medium")
72
+
73
+ # Initialize optimizer
74
+ self.optimizer = CostOptimizer(
75
+ cost_history_days=cost_history_days,
76
+ optimization_interval=optimization_interval,
77
+ savings_threshold=savings_threshold,
78
+ risk_tolerance=risk_tolerance,
79
+ )
80
+
81
+ self._optimizer_started = False
82
+
83
+ @property
84
+ def input_parameters(self) -> Dict[str, NodeParameter]:
85
+ """Define input parameters."""
86
+ return {
87
+ "operation": NodeParameter(
88
+ name="operation",
89
+ type=str,
90
+ required=True,
91
+ description="Operation to perform (record_cost, optimize_costs, get_spot_recommendations, get_reservation_recommendations, calculate_roi, get_cost_forecast, start_optimizer, stop_optimizer)",
92
+ ),
93
+ # For record_cost
94
+ "edge_node": NodeParameter(
95
+ name="edge_node",
96
+ type=str,
97
+ required=False,
98
+ description="Edge node identifier",
99
+ ),
100
+ "resource_type": NodeParameter(
101
+ name="resource_type",
102
+ type=str,
103
+ required=False,
104
+ description="Type of resource",
105
+ ),
106
+ "provider": NodeParameter(
107
+ name="provider",
108
+ type=str,
109
+ required=False,
110
+ description="Cloud provider (aws, gcp, azure, alibaba, edge_local)",
111
+ ),
112
+ "instance_type": NodeParameter(
113
+ name="instance_type",
114
+ type=str,
115
+ required=False,
116
+ description="Instance pricing type (on_demand, spot, reserved, savings_plan, dedicated)",
117
+ ),
118
+ "cost_per_hour": NodeParameter(
119
+ name="cost_per_hour",
120
+ type=float,
121
+ required=False,
122
+ description="Cost per hour for the resource",
123
+ ),
124
+ "usage_hours": NodeParameter(
125
+ name="usage_hours",
126
+ type=float,
127
+ required=False,
128
+ description="Hours of usage",
129
+ ),
130
+ "currency": NodeParameter(
131
+ name="currency",
132
+ type=str,
133
+ required=False,
134
+ default="USD",
135
+ description="Currency for costs",
136
+ ),
137
+ # For optimize_costs
138
+ "strategy": NodeParameter(
139
+ name="strategy",
140
+ type=str,
141
+ required=False,
142
+ default="balance_cost_performance",
143
+ description="Optimization strategy (minimize_cost, balance_cost_performance, maximize_performance, predictable_cost, risk_averse)",
144
+ ),
145
+ "edge_nodes": NodeParameter(
146
+ name="edge_nodes",
147
+ type=list,
148
+ required=False,
149
+ description="Specific edge nodes to optimize",
150
+ ),
151
+ # For recommendations
152
+ "providers": NodeParameter(
153
+ name="providers",
154
+ type=list,
155
+ required=False,
156
+ description="Specific providers to analyze",
157
+ ),
158
+ # For ROI calculation
159
+ "optimization_id": NodeParameter(
160
+ name="optimization_id",
161
+ type=str,
162
+ required=False,
163
+ description="Optimization ID for ROI calculation",
164
+ ),
165
+ "implementation_cost": NodeParameter(
166
+ name="implementation_cost",
167
+ type=float,
168
+ required=False,
169
+ default=0.0,
170
+ description="One-time implementation cost",
171
+ ),
172
+ # For forecast
173
+ "forecast_months": NodeParameter(
174
+ name="forecast_months",
175
+ type=int,
176
+ required=False,
177
+ default=12,
178
+ description="Months to forecast",
179
+ ),
180
+ "include_optimizations": NodeParameter(
181
+ name="include_optimizations",
182
+ type=bool,
183
+ required=False,
184
+ default=True,
185
+ description="Include optimization impact in forecast",
186
+ ),
187
+ # Configuration
188
+ "cost_history_days": NodeParameter(
189
+ name="cost_history_days",
190
+ type=int,
191
+ required=False,
192
+ default=30,
193
+ description="Days of cost history to analyze",
194
+ ),
195
+ "optimization_interval": NodeParameter(
196
+ name="optimization_interval",
197
+ type=int,
198
+ required=False,
199
+ default=3600,
200
+ description="How often to run optimization (seconds)",
201
+ ),
202
+ "savings_threshold": NodeParameter(
203
+ name="savings_threshold",
204
+ type=float,
205
+ required=False,
206
+ default=0.1,
207
+ description="Minimum savings percentage (0-1)",
208
+ ),
209
+ "risk_tolerance": NodeParameter(
210
+ name="risk_tolerance",
211
+ type=str,
212
+ required=False,
213
+ default="medium",
214
+ description="Risk tolerance (low, medium, high)",
215
+ ),
216
+ }
217
+
218
+ @property
219
+ def output_parameters(self) -> Dict[str, NodeParameter]:
220
+ """Define output parameters."""
221
+ return {
222
+ "status": NodeParameter(
223
+ name="status", type=str, description="Operation status"
224
+ ),
225
+ "optimizations": NodeParameter(
226
+ name="optimizations",
227
+ type=list,
228
+ required=False,
229
+ description="Cost optimization recommendations",
230
+ ),
231
+ "spot_recommendations": NodeParameter(
232
+ name="spot_recommendations",
233
+ type=list,
234
+ required=False,
235
+ description="Spot instance recommendations",
236
+ ),
237
+ "reservation_recommendations": NodeParameter(
238
+ name="reservation_recommendations",
239
+ type=list,
240
+ required=False,
241
+ description="Reserved capacity recommendations",
242
+ ),
243
+ "roi_analysis": NodeParameter(
244
+ name="roi_analysis",
245
+ type=dict,
246
+ required=False,
247
+ description="ROI analysis results",
248
+ ),
249
+ "cost_forecast": NodeParameter(
250
+ name="cost_forecast",
251
+ type=dict,
252
+ required=False,
253
+ description="Cost forecast with optimizations",
254
+ ),
255
+ "cost_recorded": NodeParameter(
256
+ name="cost_recorded",
257
+ type=bool,
258
+ required=False,
259
+ description="Whether cost was recorded",
260
+ ),
261
+ "total_savings": NodeParameter(
262
+ name="total_savings",
263
+ type=float,
264
+ required=False,
265
+ description="Total estimated savings",
266
+ ),
267
+ "optimizer_active": NodeParameter(
268
+ name="optimizer_active",
269
+ type=bool,
270
+ required=False,
271
+ description="Whether optimizer is active",
272
+ ),
273
+ }
274
+
275
+ def get_parameters(self) -> Dict[str, NodeParameter]:
276
+ """Get all node parameters for compatibility."""
277
+ return self.input_parameters
278
+
279
+ async def async_run(self, **kwargs) -> Dict[str, Any]:
280
+ """Execute cost optimization operation."""
281
+ operation = kwargs["operation"]
282
+
283
+ try:
284
+ if operation == "record_cost":
285
+ return await self._record_cost(kwargs)
286
+ elif operation == "optimize_costs":
287
+ return await self._optimize_costs(kwargs)
288
+ elif operation == "get_spot_recommendations":
289
+ return await self._get_spot_recommendations(kwargs)
290
+ elif operation == "get_reservation_recommendations":
291
+ return await self._get_reservation_recommendations(kwargs)
292
+ elif operation == "calculate_roi":
293
+ return await self._calculate_roi(kwargs)
294
+ elif operation == "get_cost_forecast":
295
+ return await self._get_cost_forecast(kwargs)
296
+ elif operation == "start_optimizer":
297
+ return await self._start_optimizer()
298
+ elif operation == "stop_optimizer":
299
+ return await self._stop_optimizer()
300
+ else:
301
+ raise ValueError(f"Unknown operation: {operation}")
302
+
303
+ except Exception as e:
304
+ self.logger.error(f"Cost optimization operation failed: {str(e)}")
305
+ return {"status": "error", "error": str(e)}
306
+
307
+ async def _record_cost(self, kwargs: Dict[str, Any]) -> Dict[str, Any]:
308
+ """Record cost data."""
309
+ # Parse provider
310
+ provider_str = kwargs.get("provider", "aws")
311
+ try:
312
+ provider = CloudProvider(provider_str)
313
+ except ValueError:
314
+ provider = CloudProvider.AWS
315
+
316
+ # Parse instance type
317
+ instance_type_str = kwargs.get("instance_type", "on_demand")
318
+ try:
319
+ instance_type = InstanceType(instance_type_str)
320
+ except ValueError:
321
+ instance_type = InstanceType.ON_DEMAND
322
+
323
+ # Calculate total cost
324
+ cost_per_hour = kwargs.get("cost_per_hour", 0.0)
325
+ usage_hours = kwargs.get("usage_hours", 0.0)
326
+ total_cost = cost_per_hour * usage_hours
327
+
328
+ # Create cost metric
329
+ cost_metric = CostMetric(
330
+ timestamp=datetime.now(),
331
+ edge_node=kwargs.get("edge_node", "unknown"),
332
+ resource_type=kwargs.get("resource_type", "unknown"),
333
+ provider=provider,
334
+ instance_type=instance_type,
335
+ cost_per_hour=cost_per_hour,
336
+ usage_hours=usage_hours,
337
+ total_cost=total_cost,
338
+ currency=kwargs.get("currency", "USD"),
339
+ )
340
+
341
+ # Record cost
342
+ await self.optimizer.record_cost(cost_metric)
343
+
344
+ return {
345
+ "status": "success",
346
+ "cost_recorded": True,
347
+ "total_cost": total_cost,
348
+ "cost_metric": cost_metric.to_dict(),
349
+ }
350
+
351
+ async def _optimize_costs(self, kwargs: Dict[str, Any]) -> Dict[str, Any]:
352
+ """Generate cost optimizations."""
353
+ # Parse strategy
354
+ strategy_str = kwargs.get("strategy", "balance_cost_performance")
355
+ try:
356
+ strategy = OptimizationStrategy(strategy_str)
357
+ except ValueError:
358
+ strategy = OptimizationStrategy.BALANCE_COST_PERFORMANCE
359
+
360
+ # Get optimization recommendations
361
+ optimizations = await self.optimizer.optimize_costs(
362
+ strategy=strategy, edge_nodes=kwargs.get("edge_nodes")
363
+ )
364
+
365
+ # Calculate total savings
366
+ total_savings = sum(opt.estimated_savings for opt in optimizations)
367
+
368
+ return {
369
+ "status": "success",
370
+ "optimizations": [opt.to_dict() for opt in optimizations],
371
+ "optimization_count": len(optimizations),
372
+ "total_savings": total_savings,
373
+ "average_savings_percentage": (
374
+ sum(opt.savings_percentage for opt in optimizations)
375
+ / len(optimizations)
376
+ if optimizations
377
+ else 0
378
+ ),
379
+ }
380
+
381
+ async def _get_spot_recommendations(self, kwargs: Dict[str, Any]) -> Dict[str, Any]:
382
+ """Get spot instance recommendations."""
383
+ recommendations = await self.optimizer.get_spot_recommendations(
384
+ edge_nodes=kwargs.get("edge_nodes")
385
+ )
386
+
387
+ # Calculate total potential savings
388
+ total_savings = sum(rec.potential_savings for rec in recommendations)
389
+
390
+ return {
391
+ "status": "success",
392
+ "spot_recommendations": [rec.to_dict() for rec in recommendations],
393
+ "recommendation_count": len(recommendations),
394
+ "total_potential_savings": total_savings,
395
+ "average_savings_percentage": (
396
+ sum(
397
+ rec.potential_savings / rec.current_on_demand_cost * 100
398
+ for rec in recommendations
399
+ if rec.current_on_demand_cost > 0
400
+ )
401
+ / len(recommendations)
402
+ if recommendations
403
+ else 0
404
+ ),
405
+ }
406
+
407
+ async def _get_reservation_recommendations(
408
+ self, kwargs: Dict[str, Any]
409
+ ) -> Dict[str, Any]:
410
+ """Get reserved capacity recommendations."""
411
+ # Parse providers
412
+ provider_strs = kwargs.get("providers", [])
413
+ providers = []
414
+
415
+ for p_str in provider_strs:
416
+ try:
417
+ providers.append(CloudProvider(p_str))
418
+ except ValueError:
419
+ continue
420
+
421
+ recommendations = await self.optimizer.get_reservation_recommendations(
422
+ providers=providers if providers else None
423
+ )
424
+
425
+ # Calculate total savings
426
+ total_savings = sum(rec.total_savings for rec in recommendations)
427
+
428
+ return {
429
+ "status": "success",
430
+ "reservation_recommendations": [rec.to_dict() for rec in recommendations],
431
+ "recommendation_count": len(recommendations),
432
+ "total_potential_savings": total_savings,
433
+ "average_savings_percentage": (
434
+ sum(
435
+ rec.total_savings / rec.on_demand_equivalent * 100
436
+ for rec in recommendations
437
+ if rec.on_demand_equivalent > 0
438
+ )
439
+ / len(recommendations)
440
+ if recommendations
441
+ else 0
442
+ ),
443
+ }
444
+
445
+ async def _calculate_roi(self, kwargs: Dict[str, Any]) -> Dict[str, Any]:
446
+ """Calculate ROI for an optimization."""
447
+ optimization_id = kwargs.get("optimization_id")
448
+ implementation_cost = kwargs.get("implementation_cost", 0.0)
449
+
450
+ if not optimization_id:
451
+ return {"status": "error", "error": "optimization_id is required"}
452
+
453
+ # Find the optimization
454
+ optimization = None
455
+ for opt in self.optimizer.optimizations:
456
+ if opt.optimization_id == optimization_id:
457
+ optimization = opt
458
+ break
459
+
460
+ if not optimization:
461
+ return {
462
+ "status": "error",
463
+ "error": f"Optimization {optimization_id} not found",
464
+ }
465
+
466
+ # Calculate ROI
467
+ roi_analysis = await self.optimizer.calculate_roi(
468
+ optimization=optimization, implementation_cost=implementation_cost
469
+ )
470
+
471
+ return {"status": "success", "roi_analysis": roi_analysis}
472
+
473
+ async def _get_cost_forecast(self, kwargs: Dict[str, Any]) -> Dict[str, Any]:
474
+ """Get cost forecast."""
475
+ forecast = await self.optimizer.get_cost_forecast(
476
+ forecast_months=kwargs.get("forecast_months", 12),
477
+ include_optimizations=kwargs.get("include_optimizations", True),
478
+ )
479
+
480
+ return {"status": "success", "cost_forecast": forecast}
481
+
482
+ async def _start_optimizer(self) -> Dict[str, Any]:
483
+ """Start background optimizer."""
484
+ if not self._optimizer_started:
485
+ await self.optimizer.start()
486
+ self._optimizer_started = True
487
+
488
+ return {"status": "success", "optimizer_active": True}
489
+
490
+ async def _stop_optimizer(self) -> Dict[str, Any]:
491
+ """Stop background optimizer."""
492
+ if self._optimizer_started:
493
+ await self.optimizer.stop()
494
+ self._optimizer_started = False
495
+
496
+ return {"status": "success", "optimizer_active": False}
497
+
498
+ async def cleanup(self):
499
+ """Clean up resources."""
500
+ if self._optimizer_started:
501
+ await self.optimizer.stop()