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.
- 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/__init__.py +17 -0
- kailash/nodes/ai/a2a.py +1914 -43
- kailash/nodes/ai/a2a_backup.py +1807 -0
- kailash/nodes/ai/hybrid_search.py +972 -0
- kailash/nodes/ai/semantic_memory.py +558 -0
- kailash/nodes/ai/streaming_analytics.py +947 -0
- 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 +234 -8
- 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.3.dist-info → kailash-0.8.5.dist-info}/METADATA +44 -27
- {kailash-0.8.3.dist-info → kailash-0.8.5.dist-info}/RECORD +78 -28
- 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.3.dist-info → kailash-0.8.5.dist-info}/WHEEL +0 -0
- {kailash-0.8.3.dist-info → kailash-0.8.5.dist-info}/entry_points.txt +0 -0
- {kailash-0.8.3.dist-info → kailash-0.8.5.dist-info}/licenses/LICENSE +0 -0
- {kailash-0.8.3.dist-info → kailash-0.8.5.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,240 @@
|
|
1
|
+
"""Base edge-aware node with location awareness and compliance routing."""
|
2
|
+
|
3
|
+
import asyncio
|
4
|
+
from typing import Any, Dict, List, Optional
|
5
|
+
|
6
|
+
from kailash.edge.compliance import ComplianceRouter, DataClassification
|
7
|
+
from kailash.edge.discovery import EdgeDiscovery, EdgeSelectionStrategy
|
8
|
+
from kailash.edge.location import EdgeLocation
|
9
|
+
from kailash.nodes.base_async import AsyncNode
|
10
|
+
|
11
|
+
|
12
|
+
class EdgeNode(AsyncNode):
|
13
|
+
"""Base node with edge computing awareness.
|
14
|
+
|
15
|
+
Extends AsyncNode with:
|
16
|
+
- Edge location awareness
|
17
|
+
- Automatic edge selection
|
18
|
+
- Compliance-aware routing
|
19
|
+
- Migration capabilities
|
20
|
+
"""
|
21
|
+
|
22
|
+
def __init__(self, **config):
|
23
|
+
"""Initialize edge-aware node.
|
24
|
+
|
25
|
+
Args:
|
26
|
+
edge_strategy: Edge selection strategy (latency|cost|balanced|compliance)
|
27
|
+
preferred_locations: List of preferred edge location names
|
28
|
+
compliance_zones: List of required compliance zones (gdpr, ccpa, etc.)
|
29
|
+
enable_migration: Whether to enable edge migration capabilities
|
30
|
+
**config: Additional node configuration
|
31
|
+
"""
|
32
|
+
self.edge_strategy = EdgeSelectionStrategy(
|
33
|
+
config.pop("edge_strategy", "balanced")
|
34
|
+
)
|
35
|
+
self.preferred_locations = config.pop("preferred_locations", [])
|
36
|
+
self.compliance_zones = config.pop("compliance_zones", [])
|
37
|
+
self.enable_migration = config.pop("enable_migration", True)
|
38
|
+
|
39
|
+
# Check for injected infrastructure (from WorkflowBuilder)
|
40
|
+
edge_infrastructure = config.pop("_edge_infrastructure", None)
|
41
|
+
|
42
|
+
if edge_infrastructure:
|
43
|
+
# Use shared infrastructure from WorkflowBuilder
|
44
|
+
self.edge_discovery = edge_infrastructure.get_discovery()
|
45
|
+
self.compliance_router = edge_infrastructure.get_compliance_router()
|
46
|
+
self._shared_infrastructure = edge_infrastructure
|
47
|
+
else:
|
48
|
+
# Standalone mode - create own infrastructure (backward compatibility)
|
49
|
+
self.edge_discovery = EdgeDiscovery()
|
50
|
+
self.compliance_router = ComplianceRouter()
|
51
|
+
self._shared_infrastructure = None
|
52
|
+
|
53
|
+
self.current_edge: Optional[EdgeLocation] = None
|
54
|
+
|
55
|
+
super().__init__(**config)
|
56
|
+
|
57
|
+
async def initialize(self):
|
58
|
+
"""Initialize edge infrastructure."""
|
59
|
+
# No need to call super().initialize() as AsyncNode doesn't have it
|
60
|
+
|
61
|
+
# Start edge discovery only if not using shared infrastructure
|
62
|
+
if not self._shared_infrastructure:
|
63
|
+
await self.edge_discovery.start_discovery()
|
64
|
+
|
65
|
+
# Select initial edge
|
66
|
+
self.current_edge = await self._select_edge()
|
67
|
+
|
68
|
+
if not self.current_edge:
|
69
|
+
raise RuntimeError("No suitable edge location found")
|
70
|
+
|
71
|
+
async def _select_edge(
|
72
|
+
self, data: Optional[Dict[str, Any]] = None
|
73
|
+
) -> Optional[EdgeLocation]:
|
74
|
+
"""Select optimal edge location based on strategy and constraints.
|
75
|
+
|
76
|
+
Args:
|
77
|
+
data: Optional data for compliance classification
|
78
|
+
|
79
|
+
Returns:
|
80
|
+
Selected edge location or None
|
81
|
+
"""
|
82
|
+
# Get all available edges
|
83
|
+
edges = self.edge_discovery.get_all_edges()
|
84
|
+
|
85
|
+
# Filter by preferred locations if specified
|
86
|
+
if self.preferred_locations:
|
87
|
+
edges = [e for e in edges if e.name in self.preferred_locations]
|
88
|
+
|
89
|
+
# Filter by compliance if data provided
|
90
|
+
if data and self.compliance_zones:
|
91
|
+
data_class = self.compliance_router.classify_data(data)
|
92
|
+
edges = [
|
93
|
+
e
|
94
|
+
for e in edges
|
95
|
+
if self.compliance_router.is_compliant_location(
|
96
|
+
e, data_class, self.compliance_zones
|
97
|
+
)
|
98
|
+
]
|
99
|
+
|
100
|
+
# Apply edge selection strategy
|
101
|
+
if not edges:
|
102
|
+
return None
|
103
|
+
|
104
|
+
# If we've already filtered edges, select from the filtered list
|
105
|
+
# based on the strategy
|
106
|
+
if self.edge_strategy == EdgeSelectionStrategy.LATENCY_OPTIMAL:
|
107
|
+
# Select edge with lowest latency
|
108
|
+
return min(edges, key=lambda e: e.metrics.latency_p50_ms)
|
109
|
+
elif self.edge_strategy == EdgeSelectionStrategy.COST_OPTIMAL:
|
110
|
+
# Select edge with lowest cost
|
111
|
+
return min(edges, key=lambda e: e.metrics.compute_cost_per_hour)
|
112
|
+
elif self.edge_strategy == EdgeSelectionStrategy.COMPLIANCE_FIRST:
|
113
|
+
# Already filtered for compliance, pick first
|
114
|
+
return edges[0]
|
115
|
+
elif self.edge_strategy == EdgeSelectionStrategy.CAPACITY_OPTIMAL:
|
116
|
+
# Select edge with most capacity
|
117
|
+
return max(
|
118
|
+
edges,
|
119
|
+
key=lambda e: e.capabilities.cpu_cores
|
120
|
+
* (1 - e.metrics.cpu_utilization),
|
121
|
+
)
|
122
|
+
else: # BALANCED or others
|
123
|
+
# Simple balanced selection - pick edge with best combined score
|
124
|
+
return min(
|
125
|
+
edges,
|
126
|
+
key=lambda e: e.metrics.latency_p50_ms
|
127
|
+
* e.metrics.compute_cost_per_hour,
|
128
|
+
)
|
129
|
+
|
130
|
+
async def migrate_to_edge(
|
131
|
+
self, target_edge: EdgeLocation, state_data: Optional[Dict[str, Any]] = None
|
132
|
+
) -> bool:
|
133
|
+
"""Migrate this node to a different edge location.
|
134
|
+
|
135
|
+
Args:
|
136
|
+
target_edge: Target edge location
|
137
|
+
state_data: Optional state to migrate
|
138
|
+
|
139
|
+
Returns:
|
140
|
+
Success status
|
141
|
+
"""
|
142
|
+
if not self.enable_migration:
|
143
|
+
return False
|
144
|
+
|
145
|
+
try:
|
146
|
+
# Prepare for migration
|
147
|
+
await self._prepare_migration(target_edge, state_data)
|
148
|
+
|
149
|
+
# Perform migration
|
150
|
+
old_edge = self.current_edge
|
151
|
+
self.current_edge = target_edge
|
152
|
+
|
153
|
+
# Cleanup old edge
|
154
|
+
if old_edge:
|
155
|
+
await self._cleanup_edge(old_edge)
|
156
|
+
|
157
|
+
return True
|
158
|
+
|
159
|
+
except Exception as e:
|
160
|
+
self.logger.error(f"Migration failed: {e}")
|
161
|
+
return False
|
162
|
+
|
163
|
+
async def _prepare_migration(
|
164
|
+
self, target_edge: EdgeLocation, state_data: Optional[Dict[str, Any]]
|
165
|
+
):
|
166
|
+
"""Prepare for edge migration."""
|
167
|
+
# Override in subclasses for specific preparation
|
168
|
+
pass
|
169
|
+
|
170
|
+
async def _cleanup_edge(self, edge: EdgeLocation):
|
171
|
+
"""Cleanup after migrating away from an edge."""
|
172
|
+
# Override in subclasses for specific cleanup
|
173
|
+
pass
|
174
|
+
|
175
|
+
async def get_edge_metrics(self) -> Dict[str, Any]:
|
176
|
+
"""Get current edge performance metrics."""
|
177
|
+
if not self.current_edge:
|
178
|
+
return {}
|
179
|
+
|
180
|
+
return {
|
181
|
+
"edge_name": self.current_edge.name,
|
182
|
+
"edge_region": self.current_edge.region,
|
183
|
+
"latency_ms": self.current_edge.metrics.latency_p50_ms,
|
184
|
+
"cpu_usage": self.current_edge.metrics.cpu_utilization,
|
185
|
+
"memory_usage": self.current_edge.metrics.memory_utilization,
|
186
|
+
"request_count": self.current_edge.metrics.throughput_rps,
|
187
|
+
"error_rate": self.current_edge.metrics.error_rate,
|
188
|
+
}
|
189
|
+
|
190
|
+
def is_compliant_for_data(
|
191
|
+
self, data: Dict[str, Any], required_zones: Optional[List[str]] = None
|
192
|
+
) -> bool:
|
193
|
+
"""Check if current edge is compliant for given data.
|
194
|
+
|
195
|
+
Args:
|
196
|
+
data: Data to check compliance for
|
197
|
+
required_zones: Override compliance zones
|
198
|
+
|
199
|
+
Returns:
|
200
|
+
Compliance status
|
201
|
+
"""
|
202
|
+
if not self.current_edge:
|
203
|
+
return False
|
204
|
+
|
205
|
+
zones = required_zones or self.compliance_zones
|
206
|
+
if not zones:
|
207
|
+
return True
|
208
|
+
|
209
|
+
data_class = self.compliance_router.classify_data(data)
|
210
|
+
return self.compliance_router.is_compliant_location(
|
211
|
+
self.current_edge, data_class, zones
|
212
|
+
)
|
213
|
+
|
214
|
+
async def ensure_compliance(
|
215
|
+
self, data: Dict[str, Any], required_zones: Optional[List[str]] = None
|
216
|
+
) -> bool:
|
217
|
+
"""Ensure node is at compliant edge for data.
|
218
|
+
|
219
|
+
Migrates to compliant edge if necessary.
|
220
|
+
|
221
|
+
Args:
|
222
|
+
data: Data requiring compliance
|
223
|
+
required_zones: Override compliance zones
|
224
|
+
|
225
|
+
Returns:
|
226
|
+
Success status
|
227
|
+
"""
|
228
|
+
zones = required_zones or self.compliance_zones
|
229
|
+
|
230
|
+
# Check current compliance
|
231
|
+
if self.is_compliant_for_data(data, zones):
|
232
|
+
return True
|
233
|
+
|
234
|
+
# Find compliant edge
|
235
|
+
compliant_edge = await self._select_edge(data)
|
236
|
+
if not compliant_edge:
|
237
|
+
return False
|
238
|
+
|
239
|
+
# Migrate to compliant edge
|
240
|
+
return await self.migrate_to_edge(compliant_edge)
|