golem-vm-provider 0.1.1__tar.gz → 0.1.2__tar.gz

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 (25) hide show
  1. {golem_vm_provider-0.1.1 → golem_vm_provider-0.1.2}/PKG-INFO +1 -1
  2. {golem_vm_provider-0.1.1 → golem_vm_provider-0.1.2}/provider/main.py +73 -40
  3. {golem_vm_provider-0.1.1 → golem_vm_provider-0.1.2}/provider/network/port_verifier.py +36 -19
  4. {golem_vm_provider-0.1.1 → golem_vm_provider-0.1.2}/provider/utils/port_display.py +46 -17
  5. {golem_vm_provider-0.1.1 → golem_vm_provider-0.1.2}/provider/vm/port_manager.py +35 -10
  6. {golem_vm_provider-0.1.1 → golem_vm_provider-0.1.2}/provider/vm/proxy_manager.py +44 -12
  7. {golem_vm_provider-0.1.1 → golem_vm_provider-0.1.2}/pyproject.toml +1 -1
  8. {golem_vm_provider-0.1.1 → golem_vm_provider-0.1.2}/README.md +0 -0
  9. {golem_vm_provider-0.1.1 → golem_vm_provider-0.1.2}/provider/__init__.py +0 -0
  10. {golem_vm_provider-0.1.1 → golem_vm_provider-0.1.2}/provider/api/__init__.py +0 -0
  11. {golem_vm_provider-0.1.1 → golem_vm_provider-0.1.2}/provider/api/models.py +0 -0
  12. {golem_vm_provider-0.1.1 → golem_vm_provider-0.1.2}/provider/api/routes.py +0 -0
  13. {golem_vm_provider-0.1.1 → golem_vm_provider-0.1.2}/provider/config.py +0 -0
  14. {golem_vm_provider-0.1.1 → golem_vm_provider-0.1.2}/provider/discovery/__init__.py +0 -0
  15. {golem_vm_provider-0.1.1 → golem_vm_provider-0.1.2}/provider/discovery/advertiser.py +0 -0
  16. {golem_vm_provider-0.1.1 → golem_vm_provider-0.1.2}/provider/discovery/resource_tracker.py +0 -0
  17. {golem_vm_provider-0.1.1 → golem_vm_provider-0.1.2}/provider/security/ethereum.py +0 -0
  18. {golem_vm_provider-0.1.1 → golem_vm_provider-0.1.2}/provider/utils/ascii_art.py +0 -0
  19. {golem_vm_provider-0.1.1 → golem_vm_provider-0.1.2}/provider/utils/logging.py +0 -0
  20. {golem_vm_provider-0.1.1 → golem_vm_provider-0.1.2}/provider/utils/retry.py +0 -0
  21. {golem_vm_provider-0.1.1 → golem_vm_provider-0.1.2}/provider/vm/__init__.py +0 -0
  22. {golem_vm_provider-0.1.1 → golem_vm_provider-0.1.2}/provider/vm/cloud_init.py +0 -0
  23. {golem_vm_provider-0.1.1 → golem_vm_provider-0.1.2}/provider/vm/models.py +0 -0
  24. {golem_vm_provider-0.1.1 → golem_vm_provider-0.1.2}/provider/vm/multipass.py +0 -0
  25. {golem_vm_provider-0.1.1 → golem_vm_provider-0.1.2}/provider/vm/name_mapper.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: golem-vm-provider
3
- Version: 0.1.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
@@ -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
- # Initialize port manager (verification already done in run.py)
22
- logger.process("🔄 Initializing port manager...")
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
- # Display startup animation
112
- await startup_animation()
113
- # Initialize provider
114
- await setup_provider()
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 verify_ports():
167
- """Verify port accessibility before starting server."""
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
- display = PortVerificationDisplay(
173
- provider_port=settings.PORT,
174
- port_range_start=settings.PORT_RANGE_START,
175
- port_range_end=settings.PORT_RANGE_END
176
- )
177
- display.print_header()
178
-
179
- # Initialize port manager
180
- logger.process("🔄 Verifying port accessibility...")
181
- port_manager = PortManager(
182
- start_port=settings.PORT_RANGE_START,
183
- end_port=settings.PORT_RANGE_END,
184
- discovery_port=settings.PORT
185
- )
186
- if not await port_manager.initialize():
187
- logger.error("Port verification failed. Please ensure:")
188
- logger.error(f"1. Port {settings.PORT} is accessible for provider access")
189
- logger.error(f"2. Some ports in range {settings.PORT_RANGE_START}-{settings.PORT_RANGE_END} are accessible for VM access")
190
- logger.error("3. Your firewall/router is properly configured")
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 ports before starting server
226
- if not asyncio.run(verify_ports()):
227
- logger.error("Port verification failed")
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="Connection timed out"
181
+ error=error_msg
181
182
  ))
182
- logger.warning(f"Timeout while verifying ports with {server}")
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=str(e)
197
+ error=error_msg
188
198
  ))
189
- logger.warning(f"Failed to verify ports with {server}: {e}")
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
- logger.error("Failed to verify ports with any server")
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="Failed to verify with any port check server",
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
- # Separate discovery port from other ports
258
- other_ports = [p for p in ports if p != self.discovery_port]
259
- discovery_port_included = self.discovery_port in ports
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="Failed to bind locally"
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 detailed results for discovery port
280
- if discovery_port_included and self.discovery_port in results:
281
- result = results[self.discovery_port]
282
- if result.accessible:
283
- logger.info(f"Discovery port {self.discovery_port} verified successfully by {result.verified_by}")
284
- else:
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
@@ -58,23 +58,29 @@ class PortVerificationDisplay:
58
58
  print("\n📡 Provider Accessibility (Required)")
59
59
  print("--------------------------------")
60
60
 
61
- await self.animate_verification("Checking provider accessibility...")
61
+ await self.animate_verification("Verifying provider port status...")
62
62
 
63
- status_badge = "✅ Accessible" if result.accessible else "❌ Not Accessible"
64
- print(f"[{status_badge}] Port {self.provider_port}")
65
- print(f"└─ Status: {'Accessible' if result.accessible else 'Not Accessible'}")
66
-
67
- # Show external/internal access
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
- print("└─ Access: External | Internal ")
73
- print("└─ Requestors cannot discover or connect to your provider")
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
- # Show verification server if successful
76
- if result.verified_by:
77
- print(f"└─ Verified By: {result.verified_by}")
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"└─ Reason: Port {self.provider_port} is not accessible")
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("└─ Reason: No VM access ports are available")
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}")
@@ -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
- # "http://portcheck1.golem.network:7466",
44
- # "http://portcheck2.golem.network:7466",
45
- # "http://portcheck3.golem.network:7466",
46
- "http://localhost:9000" # Fallback for local development
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
- # Verify all ports together (discovery port and SSH ports)
72
- all_ports = [self.discovery_port] + list(range(self.start_port, self.end_port))
73
- logger.info(f"Verifying all ports: discovery port {self.discovery_port} and SSH ports {self.start_port}-{self.end_port}...")
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(all_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
- logger.error(f"Failed to verify discovery port: {discovery_result.error}")
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
@@ -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
- if self.target_transport and not self.target_transport.is_closing():
62
- self.target_transport.close()
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
- if (self.client_protocol.transport and
86
- not self.client_protocol.transport.is_closing()):
87
- self.client_protocol.transport.close()
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
- self.server.close()
124
- await self.server.wait_closed()
125
- logger.info(f"Proxy server on port {self.listen_port} stopped")
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
- try:
234
- for vm_id in list(self._proxies.keys()):
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
- logger.error(f"Failed to cleanup proxy configurations: {e}")
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()
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "golem-vm-provider"
3
- version = "0.1.1"
3
+ version = "0.1.2"
4
4
  description = "VM on Golem Provider Node - Run your own provider node to offer VMs on the Golem Network"
5
5
  authors = ["Phillip Jensen <phillip+vm-on-golem@golemgrid.com>"]
6
6
  readme = "README.md"