golem-vm-provider 0.1.1__py3-none-any.whl → 0.1.2__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.
- {golem_vm_provider-0.1.1.dist-info → golem_vm_provider-0.1.2.dist-info}/METADATA +1 -1
- {golem_vm_provider-0.1.1.dist-info → golem_vm_provider-0.1.2.dist-info}/RECORD +9 -9
- provider/main.py +73 -40
- provider/network/port_verifier.py +36 -19
- provider/utils/port_display.py +46 -17
- provider/vm/port_manager.py +35 -10
- provider/vm/proxy_manager.py +44 -12
- {golem_vm_provider-0.1.1.dist-info → golem_vm_provider-0.1.2.dist-info}/WHEEL +0 -0
- {golem_vm_provider-0.1.1.dist-info → golem_vm_provider-0.1.2.dist-info}/entry_points.txt +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: golem-vm-provider
|
3
|
-
Version: 0.1.
|
3
|
+
Version: 0.1.2
|
4
4
|
Summary: VM on Golem Provider Node - Run your own provider node to offer VMs on the Golem Network
|
5
5
|
Home-page: https://github.com/cryptobench/vm-on-golem
|
6
6
|
Keywords: golem,vm,provider,cloud,decentralized
|
@@ -6,21 +6,21 @@ provider/config.py,sha256=Q6xmU6cPRBUYkVusv-Fc1U4ekr4OYLXfOfEtaWL9miM,5000
|
|
6
6
|
provider/discovery/__init__.py,sha256=VR3NRoQtZRH5Vs8FG7jnGLR7p7wn7XeZdLaBb3t8e1g,123
|
7
7
|
provider/discovery/advertiser.py,sha256=yv7RbRf1K43qOLAEa2Olj9hhN8etl2qsBuoHok0xoVs,6784
|
8
8
|
provider/discovery/resource_tracker.py,sha256=8dYhJxoe_jLRwisHoA0jr575YhUKmLIqSXfW88KshcQ,6000
|
9
|
-
provider/main.py,sha256=
|
10
|
-
provider/network/port_verifier.py,sha256=
|
9
|
+
provider/main.py,sha256=_kZTDqOlkI7cuFCKhB_WvHN3vlxPpCWqEausdUMzYpM,10232
|
10
|
+
provider/network/port_verifier.py,sha256=AUtBGuZdfq9Jt4BRDuYesh5YEmwneEzYUgIw-uajZhA,12977
|
11
11
|
provider/security/ethereum.py,sha256=SDRDbcjynbVy44kNnxlDcYLL0BZ3Qnc0DvmneQ-WKLE,1383
|
12
12
|
provider/utils/ascii_art.py,sha256=ykBFsztk57GIiz1NJ-EII5UvN74iECqQL4h9VmiW6Z8,3161
|
13
13
|
provider/utils/logging.py,sha256=C_elr0sJROHKQgErYpHJQvfujgh0k4Zf2gg8ZKfrmVk,2590
|
14
|
-
provider/utils/port_display.py,sha256=
|
14
|
+
provider/utils/port_display.py,sha256=5d_604Eo-82dqx_yV2ZScq7bKQ8IsXacc-yXC_KAz3A,11031
|
15
15
|
provider/utils/retry.py,sha256=ekP2ucaSJNN-lBcrIvyHa4QYPKNITMl1a5V1X6BBvsw,1560
|
16
16
|
provider/vm/__init__.py,sha256=JGs50tUmzOR1rQ_w4fMY_3XWylmiA1G7KKWZkVw51mY,501
|
17
17
|
provider/vm/cloud_init.py,sha256=o2CWLjl1ZN9fSEFHAWO-glh7BW-DxAMSe0MbqhzKNTg,1709
|
18
18
|
provider/vm/models.py,sha256=zkfvP5Z50SPDNajwZTt9NTDIMRQIsZLvSOsuirHEcJM,6256
|
19
19
|
provider/vm/multipass.py,sha256=kS0HkKZT6--YEjxxdr4Ot0oF24T128hLrq-STKsuCK4,16406
|
20
20
|
provider/vm/name_mapper.py,sha256=MrshNeJ4Dw-WBsyiIVcn9N5xyOxaBKX4Yqhyh_m5IFg,4103
|
21
|
-
provider/vm/port_manager.py,sha256=
|
22
|
-
provider/vm/proxy_manager.py,sha256=
|
23
|
-
golem_vm_provider-0.1.
|
24
|
-
golem_vm_provider-0.1.
|
25
|
-
golem_vm_provider-0.1.
|
26
|
-
golem_vm_provider-0.1.
|
21
|
+
provider/vm/port_manager.py,sha256=e9qQCNSQX5KcY4zxnkCRBRvzXq4hjcY4nuQJ8yygsag,8423
|
22
|
+
provider/vm/proxy_manager.py,sha256=nLcs9Nane3ANvfgvHL4ZPytTuHCqG1ArQ-_ZSyMaDyQ,10188
|
23
|
+
golem_vm_provider-0.1.2.dist-info/METADATA,sha256=Gw7qPoo4J1aV2EhdhSG-GkmlkJdhwancofLL7ubF9yA,10449
|
24
|
+
golem_vm_provider-0.1.2.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
|
25
|
+
golem_vm_provider-0.1.2.dist-info/entry_points.txt,sha256=E4rCWo_Do_2zCG_GewNuftfVlHF_8b_OvioZre0dfeA,54
|
26
|
+
golem_vm_provider-0.1.2.dist-info/RECORD,,
|
provider/main.py
CHANGED
@@ -18,10 +18,8 @@ app = FastAPI(title="VM on Golem Provider")
|
|
18
18
|
async def setup_provider() -> None:
|
19
19
|
"""Setup and initialize the provider components."""
|
20
20
|
try:
|
21
|
-
#
|
22
|
-
|
23
|
-
port_manager = PortManager()
|
24
|
-
app.state.port_manager = port_manager
|
21
|
+
# Port manager is already initialized and verified in startup_event
|
22
|
+
port_manager = app.state.port_manager
|
25
23
|
|
26
24
|
# Create resource tracker
|
27
25
|
logger.process("🔄 Initializing resource tracker...")
|
@@ -108,10 +106,48 @@ async def cleanup_provider() -> None:
|
|
108
106
|
@app.on_event("startup")
|
109
107
|
async def startup_event():
|
110
108
|
"""Handle application startup."""
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
109
|
+
try:
|
110
|
+
# Display startup animation
|
111
|
+
await startup_animation()
|
112
|
+
|
113
|
+
# Verify ports first
|
114
|
+
from .vm.port_manager import PortManager
|
115
|
+
from .utils.port_display import PortVerificationDisplay
|
116
|
+
from .config import settings
|
117
|
+
|
118
|
+
display = PortVerificationDisplay(
|
119
|
+
provider_port=settings.PORT,
|
120
|
+
port_range_start=settings.PORT_RANGE_START,
|
121
|
+
port_range_end=settings.PORT_RANGE_END
|
122
|
+
)
|
123
|
+
display.print_header()
|
124
|
+
|
125
|
+
# Initialize port manager
|
126
|
+
logger.process("🔄 Verifying port accessibility...")
|
127
|
+
port_manager = PortManager(
|
128
|
+
start_port=settings.PORT_RANGE_START,
|
129
|
+
end_port=settings.PORT_RANGE_END,
|
130
|
+
discovery_port=settings.PORT
|
131
|
+
)
|
132
|
+
if not await port_manager.initialize():
|
133
|
+
logger.error("Port verification failed. Please ensure:")
|
134
|
+
logger.error(f"1. Port {settings.PORT} is accessible for provider access")
|
135
|
+
logger.error(f"2. Some ports in range {settings.PORT_RANGE_START}-{settings.PORT_RANGE_END} are accessible for VM access")
|
136
|
+
logger.error("3. Your firewall/router is properly configured")
|
137
|
+
raise RuntimeError("Port verification failed")
|
138
|
+
|
139
|
+
logger.success(f"✅ Port verification successful - {len(port_manager.verified_ports)} ports available")
|
140
|
+
|
141
|
+
# Store port manager in app state for later use
|
142
|
+
app.state.port_manager = port_manager
|
143
|
+
|
144
|
+
# Initialize provider
|
145
|
+
await setup_provider()
|
146
|
+
except Exception as e:
|
147
|
+
logger.error(f"Startup failed: {e}")
|
148
|
+
# Ensure proper cleanup
|
149
|
+
await cleanup_provider()
|
150
|
+
raise
|
115
151
|
|
116
152
|
@app.on_event("shutdown")
|
117
153
|
async def shutdown_event():
|
@@ -163,40 +199,37 @@ def check_requirements():
|
|
163
199
|
|
164
200
|
return True
|
165
201
|
|
166
|
-
async def
|
167
|
-
"""Verify port
|
168
|
-
from .vm.port_manager import PortManager
|
169
|
-
from .utils.port_display import PortVerificationDisplay
|
170
|
-
from .config import settings
|
202
|
+
async def verify_provider_port(port: int) -> bool:
|
203
|
+
"""Verify that the provider port is available for binding.
|
171
204
|
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
logger.
|
188
|
-
|
189
|
-
|
190
|
-
logger.error("
|
205
|
+
Args:
|
206
|
+
port: The port to verify
|
207
|
+
|
208
|
+
Returns:
|
209
|
+
bool: True if the port is available, False otherwise
|
210
|
+
"""
|
211
|
+
try:
|
212
|
+
# Try to create a temporary listener
|
213
|
+
server = await asyncio.start_server(
|
214
|
+
lambda r, w: None, # Empty callback
|
215
|
+
'0.0.0.0',
|
216
|
+
port
|
217
|
+
)
|
218
|
+
server.close()
|
219
|
+
await server.wait_closed()
|
220
|
+
logger.info(f"✅ Provider port {port} is available")
|
221
|
+
return True
|
222
|
+
except Exception as e:
|
223
|
+
logger.error(f"❌ Provider port {port} is not available: {e}")
|
224
|
+
logger.error("Please ensure:")
|
225
|
+
logger.error(f"1. Port {port} is not in use by another application")
|
226
|
+
logger.error("2. You have permission to bind to this port")
|
227
|
+
logger.error("3. Your firewall allows binding to this port")
|
191
228
|
return False
|
192
|
-
|
193
|
-
logger.success(f"✅ Port verification successful - {len(port_manager.verified_ports)} ports available")
|
194
|
-
return True
|
195
229
|
|
196
230
|
def start():
|
197
231
|
"""Start the provider server."""
|
198
232
|
import sys
|
199
|
-
import asyncio
|
200
233
|
from pathlib import Path
|
201
234
|
from dotenv import load_dotenv
|
202
235
|
import uvicorn
|
@@ -221,10 +254,10 @@ def start():
|
|
221
254
|
if not check_requirements():
|
222
255
|
logger.error("Requirements check failed")
|
223
256
|
sys.exit(1)
|
224
|
-
|
225
|
-
# Verify
|
226
|
-
if not asyncio.run(
|
227
|
-
logger.error("
|
257
|
+
|
258
|
+
# Verify provider port is available
|
259
|
+
if not asyncio.run(verify_provider_port(settings.PORT)):
|
260
|
+
logger.error(f"Provider port {settings.PORT} is not available")
|
228
261
|
sys.exit(1)
|
229
262
|
|
230
263
|
# Configure uvicorn logging
|
@@ -165,37 +165,53 @@ class PortVerifier:
|
|
165
165
|
attempts.append(ServerAttempt(
|
166
166
|
server=server,
|
167
167
|
success=False,
|
168
|
-
error="Server returned unsuccessful response"
|
168
|
+
error=f"Server {server} returned unsuccessful response"
|
169
169
|
))
|
170
170
|
else:
|
171
171
|
attempts.append(ServerAttempt(
|
172
172
|
server=server,
|
173
173
|
success=False,
|
174
|
-
error=f"Server returned status {response.status}"
|
174
|
+
error=f"Server {server} returned status {response.status}"
|
175
175
|
))
|
176
176
|
except asyncio.TimeoutError:
|
177
|
+
error_msg = f"Connection to {server} timed out after 30 seconds"
|
177
178
|
attempts.append(ServerAttempt(
|
178
179
|
server=server,
|
179
180
|
success=False,
|
180
|
-
error=
|
181
|
+
error=error_msg
|
181
182
|
))
|
182
|
-
logger.warning(f"
|
183
|
+
logger.warning(f"{error_msg}. Please ensure the port check server is running and accessible.")
|
184
|
+
except aiohttp.ClientConnectorError as e:
|
185
|
+
error_msg = f"Could not connect to {server}: Connection refused"
|
186
|
+
attempts.append(ServerAttempt(
|
187
|
+
server=server,
|
188
|
+
success=False,
|
189
|
+
error=error_msg
|
190
|
+
))
|
191
|
+
logger.warning(f"{error_msg}. Please ensure the port check server is running.")
|
183
192
|
except Exception as e:
|
193
|
+
error_msg = f"Failed to verify ports with {server}: {str(e)}"
|
184
194
|
attempts.append(ServerAttempt(
|
185
195
|
server=server,
|
186
196
|
success=False,
|
187
|
-
error=
|
197
|
+
error=error_msg
|
188
198
|
))
|
189
|
-
logger.warning(
|
199
|
+
logger.warning(error_msg)
|
190
200
|
|
191
201
|
# If no successful verifications, mark all ports as inaccessible
|
192
202
|
if not any(result.accessible for result in results.values()):
|
193
|
-
|
203
|
+
error_msg = (
|
204
|
+
"Failed to verify ports with any server. Please ensure:\n"
|
205
|
+
"1. At least one port check server is running and accessible\n"
|
206
|
+
"2. Your network connection is stable\n"
|
207
|
+
"3. The server URLs are correct"
|
208
|
+
)
|
209
|
+
logger.error(error_msg)
|
194
210
|
results = {
|
195
211
|
port: PortVerificationResult(
|
196
212
|
port=port,
|
197
213
|
accessible=False,
|
198
|
-
error=
|
214
|
+
error=error_msg,
|
199
215
|
attempts=[] # Will be filled below
|
200
216
|
)
|
201
217
|
for port in ports
|
@@ -254,9 +270,11 @@ class PortVerifier:
|
|
254
270
|
Returns:
|
255
271
|
Dictionary mapping ports to their verification results
|
256
272
|
"""
|
257
|
-
#
|
258
|
-
|
259
|
-
|
273
|
+
# Only verify the ports provided - discovery port is handled separately
|
274
|
+
logger.info(f"Verifying {len(ports)} SSH ports...")
|
275
|
+
if not ports:
|
276
|
+
logger.warning("No ports to verify")
|
277
|
+
return {}
|
260
278
|
|
261
279
|
# First verify ports with local binding
|
262
280
|
logger.info("Checking local port availability...")
|
@@ -267,7 +285,7 @@ class PortVerifier:
|
|
267
285
|
port: PortVerificationResult(
|
268
286
|
port=port,
|
269
287
|
accessible=False,
|
270
|
-
error="
|
288
|
+
error=f"Port {port} could not be bound locally"
|
271
289
|
)
|
272
290
|
for port in ports
|
273
291
|
}
|
@@ -276,12 +294,11 @@ class PortVerifier:
|
|
276
294
|
logger.info("Starting external port verification...")
|
277
295
|
results = await self.verify_external_access(local_available)
|
278
296
|
|
279
|
-
# Log
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
logger.error(f"Discovery port {self.discovery_port} verification failed: {result.error}")
|
297
|
+
# Log verification results
|
298
|
+
accessible_ports = [port for port, result in results.items() if result.accessible]
|
299
|
+
if accessible_ports:
|
300
|
+
logger.info(f"Successfully verified {len(accessible_ports)} SSH ports: {', '.join(map(str, sorted(accessible_ports)))}")
|
301
|
+
else:
|
302
|
+
logger.warning("No SSH ports were verified as accessible")
|
286
303
|
|
287
304
|
return results
|
provider/utils/port_display.py
CHANGED
@@ -58,23 +58,29 @@ class PortVerificationDisplay:
|
|
58
58
|
print("\n📡 Provider Accessibility (Required)")
|
59
59
|
print("--------------------------------")
|
60
60
|
|
61
|
-
await self.animate_verification("
|
61
|
+
await self.animate_verification("Verifying provider port status...")
|
62
62
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
if result.accessible:
|
69
|
-
print("└─ Access: External ✓ | Internal ✓")
|
70
|
-
print("└─ Requestors can discover and connect to your provider")
|
63
|
+
if result.verified_by == "local_verification":
|
64
|
+
print(f"[✅ Ready] Port {self.provider_port}")
|
65
|
+
print("└─ Status: Port available and bound")
|
66
|
+
print("└─ Access: Local binding successful")
|
67
|
+
print("└─ Provider can start and accept connections")
|
71
68
|
else:
|
72
|
-
|
73
|
-
print("
|
69
|
+
status_badge = "✅ Accessible" if result.accessible else "❌ Not Accessible"
|
70
|
+
print(f"[{status_badge}] Port {self.provider_port}")
|
71
|
+
print(f"└─ Status: {'Accessible' if result.accessible else 'Not Accessible'}")
|
74
72
|
|
75
|
-
|
76
|
-
|
77
|
-
|
73
|
+
# Show external/internal access
|
74
|
+
if result.accessible:
|
75
|
+
print("└─ Access: External ✓ | Internal ✓")
|
76
|
+
print("└─ Requestors can discover and connect to your provider")
|
77
|
+
else:
|
78
|
+
print("└─ Access: External ✗ | Internal ✗")
|
79
|
+
print("└─ Requestors cannot discover or connect to your provider")
|
80
|
+
|
81
|
+
# Show verification server if successful
|
82
|
+
if result.verified_by:
|
83
|
+
print(f"└─ Verified By: {result.verified_by}")
|
78
84
|
|
79
85
|
async def print_ssh_status(self, results: Dict[int, PortVerificationResult]):
|
80
86
|
"""Print SSH ports status with progress bar.
|
@@ -171,7 +177,7 @@ class PortVerificationDisplay:
|
|
171
177
|
|
172
178
|
print("\nNeed help? Visit our troubleshooting guide: docs.golem.network/ports")
|
173
179
|
|
174
|
-
def print_summary(self, discovery_result: PortVerificationResult,
|
180
|
+
def print_summary(self, discovery_result: Optional[PortVerificationResult],
|
175
181
|
ssh_results: Dict[int, PortVerificationResult]):
|
176
182
|
"""Print a precise, actionable summary of the verification status.
|
177
183
|
|
@@ -181,17 +187,38 @@ class PortVerificationDisplay:
|
|
181
187
|
"""
|
182
188
|
print("\n🎯 Current Status:", end=" ")
|
183
189
|
|
190
|
+
if discovery_result is None:
|
191
|
+
print("Verification Failed")
|
192
|
+
print(f"└─ Error: Discovery port {self.provider_port} verification failed")
|
193
|
+
print("└─ Impact: Provider cannot start without discovery port access")
|
194
|
+
print(f"└─ Fix: Ensure port {self.provider_port} is available and not in use")
|
195
|
+
return
|
196
|
+
|
184
197
|
accessible_ssh_ports = [port for port, result in ssh_results.items() if result.accessible]
|
185
198
|
|
186
199
|
if not discovery_result.accessible:
|
187
200
|
print("Provider Not Discoverable")
|
188
|
-
print(f"└─
|
201
|
+
print(f"└─ Error: {discovery_result.error or f'Port {self.provider_port} is not accessible'}")
|
189
202
|
print("└─ Impact: Requestors cannot find or connect to your provider")
|
190
203
|
print(f"└─ Fix: Configure port forwarding for port {self.provider_port}")
|
204
|
+
if discovery_result.attempts:
|
205
|
+
print("\n📋 Verification Attempts")
|
206
|
+
print("--------------------")
|
207
|
+
for attempt in discovery_result.attempts:
|
208
|
+
status = "✅" if attempt.success else "❌"
|
209
|
+
print(f"{status} {attempt.server}")
|
210
|
+
if not attempt.success and attempt.error:
|
211
|
+
print(f" └─ Error: {attempt.error}")
|
212
|
+
print("\n🔍 Troubleshooting Tips")
|
213
|
+
print("-------------------")
|
214
|
+
print("1. Check if port check servers are running")
|
215
|
+
print("2. Verify your network connection")
|
216
|
+
print("3. Ensure no firewall is blocking the connections")
|
217
|
+
print("\nFor detailed setup instructions, visit: docs.golem.network/provider/ports")
|
191
218
|
|
192
219
|
elif not accessible_ssh_ports:
|
193
220
|
print("VMs Not Accessible")
|
194
|
-
print("└─
|
221
|
+
print("└─ Error: No VM access ports are available")
|
195
222
|
print("└─ Impact: Requestors will not be able to access their rented VMs")
|
196
223
|
print(f"└─ Fix: Configure port forwarding for range {self.port_range_start}-{self.port_range_end}")
|
197
224
|
|
@@ -202,3 +229,5 @@ class PortVerificationDisplay:
|
|
202
229
|
print(f"└─ Capacity: Can handle up to {len(accessible_ssh_ports)} concurrent VMs")
|
203
230
|
if len(accessible_ssh_ports) <= 5:
|
204
231
|
print("└─ Recommendation: Open more ports for higher capacity")
|
232
|
+
if discovery_result.verified_by:
|
233
|
+
print(f"└─ Verified By: {discovery_result.verified_by}")
|
provider/vm/port_manager.py
CHANGED
@@ -7,7 +7,7 @@ from typing import Optional, Set, List, Dict
|
|
7
7
|
from threading import Lock
|
8
8
|
|
9
9
|
from ..config import settings
|
10
|
-
from ..network.port_verifier import PortVerifier, PortVerificationResult
|
10
|
+
from ..network.port_verifier import PortVerifier, PortVerificationResult, ServerAttempt
|
11
11
|
from ..utils.port_display import PortVerificationDisplay
|
12
12
|
|
13
13
|
logger = logging.getLogger(__name__)
|
@@ -40,10 +40,10 @@ class PortManager:
|
|
40
40
|
|
41
41
|
# Initialize port verifier with default servers
|
42
42
|
self.port_check_servers = port_check_servers or [
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
"http://
|
43
|
+
"http://localhost:9000", # Local development server
|
44
|
+
"http://portcheck1.golem.network:7466", # Production servers
|
45
|
+
"http://portcheck2.golem.network:7466",
|
46
|
+
"http://portcheck3.golem.network:7466"
|
47
47
|
]
|
48
48
|
self.discovery_port = discovery_port or settings.PORT
|
49
49
|
self.port_verifier = PortVerifier(
|
@@ -68,18 +68,43 @@ class PortManager:
|
|
68
68
|
)
|
69
69
|
display.print_header()
|
70
70
|
|
71
|
-
#
|
72
|
-
|
73
|
-
logger.info(f"
|
71
|
+
# Only verify SSH ports since provider port was already verified
|
72
|
+
ssh_ports = list(range(self.start_port, self.end_port))
|
73
|
+
logger.info(f"Starting port verification...")
|
74
|
+
logger.info(f"SSH ports range: {self.start_port}-{self.end_port}")
|
75
|
+
logger.info(f"Using port check servers: {', '.join(self.port_check_servers)}")
|
74
76
|
|
75
|
-
results = await self.port_verifier.verify_ports(
|
77
|
+
results = await self.port_verifier.verify_ports(ssh_ports)
|
76
78
|
|
79
|
+
# Add provider port as verified since we already checked it
|
80
|
+
results[self.discovery_port] = PortVerificationResult(
|
81
|
+
port=self.discovery_port,
|
82
|
+
accessible=True,
|
83
|
+
verified_by="local_verification",
|
84
|
+
attempts=[ServerAttempt(server="local_verification", success=True)]
|
85
|
+
)
|
86
|
+
|
87
|
+
# Check if discovery port was verified
|
88
|
+
if self.discovery_port not in results:
|
89
|
+
error_msg = f"Port {self.discovery_port} verification failed"
|
90
|
+
logger.error(error_msg)
|
91
|
+
display.print_summary(
|
92
|
+
PortVerificationResult(
|
93
|
+
port=self.discovery_port,
|
94
|
+
accessible=False,
|
95
|
+
error=error_msg
|
96
|
+
),
|
97
|
+
{}
|
98
|
+
)
|
99
|
+
return False
|
100
|
+
|
77
101
|
# Display discovery port status with animation
|
78
102
|
discovery_result = results[self.discovery_port]
|
79
103
|
await display.print_discovery_status(discovery_result)
|
80
104
|
|
81
105
|
if not discovery_result.accessible:
|
82
|
-
|
106
|
+
error_msg = discovery_result.error or f"Port {self.discovery_port} is not accessible"
|
107
|
+
logger.error(f"Failed to verify discovery port: {error_msg}")
|
83
108
|
# Print summary before returning
|
84
109
|
display.print_summary(discovery_result, {})
|
85
110
|
return False
|
provider/vm/proxy_manager.py
CHANGED
@@ -58,8 +58,16 @@ class SSHProxyProtocol(Protocol):
|
|
58
58
|
"""Handle connection loss."""
|
59
59
|
if exc:
|
60
60
|
logger.error(f"Client connection lost with error: {exc}")
|
61
|
-
|
62
|
-
|
61
|
+
|
62
|
+
# Ensure target connection is properly closed
|
63
|
+
if self.target_transport:
|
64
|
+
if not self.target_transport.is_closing():
|
65
|
+
self.target_transport.close()
|
66
|
+
self.target_transport = None
|
67
|
+
|
68
|
+
# Clear any buffered data
|
69
|
+
if self.buffer:
|
70
|
+
self.buffer.clear()
|
63
71
|
|
64
72
|
class SSHTargetProtocol(Protocol):
|
65
73
|
"""Protocol for handling target SSH connections."""
|
@@ -82,9 +90,12 @@ class SSHTargetProtocol(Protocol):
|
|
82
90
|
"""Handle connection loss."""
|
83
91
|
if exc:
|
84
92
|
logger.error(f"Target connection lost with error: {exc}")
|
85
|
-
|
86
|
-
|
87
|
-
|
93
|
+
|
94
|
+
# Ensure client connection is properly closed
|
95
|
+
if self.client_protocol and self.client_protocol.transport:
|
96
|
+
if not self.client_protocol.transport.is_closing():
|
97
|
+
self.client_protocol.transport.close()
|
98
|
+
self.client_protocol.transport = None
|
88
99
|
|
89
100
|
class ProxyServer:
|
90
101
|
"""Manages a single proxy server instance."""
|
@@ -120,9 +131,15 @@ class ProxyServer:
|
|
120
131
|
async def stop(self) -> None:
|
121
132
|
"""Stop the proxy server."""
|
122
133
|
if self.server:
|
123
|
-
|
124
|
-
|
125
|
-
|
134
|
+
try:
|
135
|
+
# Close the server
|
136
|
+
self.server.close()
|
137
|
+
await self.server.wait_closed()
|
138
|
+
logger.info(f"Proxy server on port {self.listen_port} stopped")
|
139
|
+
except Exception as e:
|
140
|
+
logger.error(f"Error stopping proxy server on port {self.listen_port}: {e}")
|
141
|
+
finally:
|
142
|
+
self.server = None
|
126
143
|
|
127
144
|
class PythonProxyManager:
|
128
145
|
"""Manages proxy servers for VM SSH access."""
|
@@ -230,10 +247,25 @@ class PythonProxyManager:
|
|
230
247
|
|
231
248
|
async def cleanup(self) -> None:
|
232
249
|
"""Remove all proxy configurations."""
|
233
|
-
|
234
|
-
|
250
|
+
cleanup_errors = []
|
251
|
+
|
252
|
+
# Stop all proxy servers
|
253
|
+
for vm_id in list(self._proxies.keys()):
|
254
|
+
try:
|
235
255
|
await self.remove_vm(vm_id)
|
256
|
+
except Exception as e:
|
257
|
+
cleanup_errors.append(f"Failed to remove proxy for VM {vm_id}: {e}")
|
258
|
+
|
259
|
+
try:
|
236
260
|
self._save_state()
|
237
|
-
logger.info("Cleaned up all proxy configurations")
|
238
261
|
except Exception as e:
|
239
|
-
|
262
|
+
cleanup_errors.append(f"Failed to save state: {e}")
|
263
|
+
|
264
|
+
if cleanup_errors:
|
265
|
+
error_msg = "\n".join(cleanup_errors)
|
266
|
+
logger.error(f"Errors during proxy cleanup:\n{error_msg}")
|
267
|
+
else:
|
268
|
+
logger.info("Cleaned up all proxy configurations")
|
269
|
+
|
270
|
+
# Clear internal state
|
271
|
+
self._proxies.clear()
|
File without changes
|
File without changes
|