golem-vm-provider 0.1.12__py3-none-any.whl → 0.1.14__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: golem-vm-provider
3
- Version: 0.1.12
3
+ Version: 0.1.14
4
4
  Summary: VM on Golem Provider Node - Run your own provider node to offer VMs on the Golem Network
5
5
  Keywords: golem,vm,provider,cloud,decentralized
6
6
  Author: Phillip Jensen
@@ -2,11 +2,11 @@ provider/__init__.py,sha256=HO1fkPpZqPO3z8O8-eVIyx8xXSMIVuTR_b1YF0RtXOg,45
2
2
  provider/api/__init__.py,sha256=ssX1ugDqEPt8Fn04IymgmG-Ev8PiXLsCSaiZVvHQnec,344
3
3
  provider/api/models.py,sha256=JOzoNf1oE5N97UqTN5xuIrTkqn2tCHqPDaIzGA3jUyo,3513
4
4
  provider/api/routes.py,sha256=P27RQvNqFWn6PacRwr1PaVz-yv5KAWsp9KeORejkXSI,6452
5
- provider/config.py,sha256=6eixu6AgKKerZJVIRs24Pdno7S7rP1qyeKWlMPXYqY8,7547
5
+ provider/config.py,sha256=tq23K-FHjqQM0cu9GIjKi6_a96YHCEyqpprMwzK36oI,10344
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=_kZTDqOlkI7cuFCKhB_WvHN3vlxPpCWqEausdUMzYpM,10232
9
+ provider/main.py,sha256=nVuMxq6npioif4-bFXGjQWJCKdy6O5ZbtX3zxhCM3zI,9206
10
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
@@ -20,7 +20,7 @@ provider/vm/multipass.py,sha256=RLUqCeoYz4PG8RL7dBu_TzjNEAmgIz9NonBtSuYc4kw,1643
20
20
  provider/vm/name_mapper.py,sha256=MrshNeJ4Dw-WBsyiIVcn9N5xyOxaBKX4Yqhyh_m5IFg,4103
21
21
  provider/vm/port_manager.py,sha256=d03uwU76vx6LgADMN8ffBT9t400XQ3vtYlXr6cLIFN0,9831
22
22
  provider/vm/proxy_manager.py,sha256=cu0FPPbeCc3CR6NRE_CnLjiRg7xVdSFUylVUOL1g1sI,10154
23
- golem_vm_provider-0.1.12.dist-info/METADATA,sha256=HN8xlU_GQXT8uhZlH0EaCM68gm3IB3xHngUCSL9FJAo,10594
24
- golem_vm_provider-0.1.12.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88
25
- golem_vm_provider-0.1.12.dist-info/entry_points.txt,sha256=E4rCWo_Do_2zCG_GewNuftfVlHF_8b_OvioZre0dfeA,54
26
- golem_vm_provider-0.1.12.dist-info/RECORD,,
23
+ golem_vm_provider-0.1.14.dist-info/METADATA,sha256=a5GRzycDL9296fLDQnI1XHKA-gDOq10WVgNifEve5Ts,10594
24
+ golem_vm_provider-0.1.14.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88
25
+ golem_vm_provider-0.1.14.dist-info/entry_points.txt,sha256=E4rCWo_Do_2zCG_GewNuftfVlHF_8b_OvioZre0dfeA,54
26
+ golem_vm_provider-0.1.14.dist-info/RECORD,,
provider/config.py CHANGED
@@ -3,7 +3,10 @@ from pathlib import Path
3
3
  from typing import Optional
4
4
  import uuid
5
5
 
6
- from pydantic import BaseSettings, validator
6
+ from pydantic import BaseSettings, validator, Field
7
+ from .utils.logging import setup_logger
8
+
9
+ logger = setup_logger(__name__)
7
10
 
8
11
 
9
12
  class Settings(BaseSettings):
@@ -56,22 +59,41 @@ class Settings(BaseSettings):
56
59
 
57
60
  @validator("VM_DATA_DIR", pre=True)
58
61
  def resolve_vm_data_dir(cls, v: str) -> str:
59
- """Resolve VM data directory path."""
62
+ """Resolve and create VM data directory path."""
60
63
  if not v:
61
- return str(Path.home() / ".golem" / "provider" / "vms")
62
- path = Path(v)
63
- if not path.is_absolute():
64
- path = Path.home() / path
64
+ path = Path.home() / ".golem" / "provider" / "vms"
65
+ else:
66
+ path = Path(v)
67
+ if not path.is_absolute():
68
+ path = Path.home() / path
69
+
70
+ try:
71
+ path.mkdir(parents=True, exist_ok=True)
72
+ logger.debug(f"Created VM data directory at {path}")
73
+ except Exception as e:
74
+ logger.error(f"Failed to create VM data directory at {path}: {e}")
75
+ raise ValueError(f"Failed to create VM data directory: {e}")
76
+
65
77
  return str(path)
66
78
 
67
79
  @validator("SSH_KEY_DIR", pre=True)
68
80
  def resolve_ssh_key_dir(cls, v: str) -> str:
69
- """Resolve SSH key directory path."""
81
+ """Resolve and create SSH key directory path with secure permissions."""
70
82
  if not v:
71
- return str(Path.home() / ".golem" / "provider" / "ssh")
72
- path = Path(v)
73
- if not path.is_absolute():
74
- path = Path.home() / path
83
+ path = Path.home() / ".golem" / "provider" / "ssh"
84
+ else:
85
+ path = Path(v)
86
+ if not path.is_absolute():
87
+ path = Path.home() / path
88
+
89
+ try:
90
+ path.mkdir(parents=True, exist_ok=True)
91
+ path.chmod(0o700) # Secure permissions for SSH keys
92
+ logger.debug(f"Created SSH key directory at {path} with secure permissions")
93
+ except Exception as e:
94
+ logger.error(f"Failed to create SSH key directory at {path}: {e}")
95
+ raise ValueError(f"Failed to create SSH key directory: {e}")
96
+
75
97
  return str(path)
76
98
 
77
99
  # Resource Settings
@@ -88,98 +110,129 @@ class Settings(BaseSettings):
88
110
  RATE_LIMIT_PER_MINUTE: int = 100
89
111
 
90
112
  # Multipass Settings
91
- MULTIPASS_BINARY_PATH: str = ""
113
+ MULTIPASS_BINARY_PATH: str = Field(
114
+ default="",
115
+ description="Path to multipass binary"
116
+ )
92
117
 
93
- @validator("MULTIPASS_BINARY_PATH", pre=True)
118
+ @validator("MULTIPASS_BINARY_PATH")
94
119
  def detect_multipass_path(cls, v: str) -> str:
95
120
  """Detect and validate Multipass binary path."""
121
+ import platform
122
+ import subprocess
123
+
124
+ def validate_path(path: str) -> bool:
125
+ """Validate that a path exists and is executable."""
126
+ return os.path.isfile(path) and os.access(path, os.X_OK)
127
+
128
+ # If path provided via environment variable, ONLY validate that path
96
129
  if v:
97
- path = v
98
- else:
99
- import platform
100
- import subprocess
101
-
102
- system = platform.system().lower()
103
- binary_name = "multipass.exe" if system == "windows" else "multipass"
104
-
105
- # Try to find multipass based on OS
106
- if system == "linux":
107
- # First try to find snap
108
- try:
109
- snap_result = subprocess.run(
110
- ["which", "snap"],
111
- capture_output=True,
112
- text=True
113
- )
114
- if snap_result.returncode == 0:
115
- # If snap exists, check if multipass is installed
116
- snap_path = "/snap/bin/multipass"
117
- if os.path.isfile(snap_path) and os.access(snap_path, os.X_OK):
118
- return snap_path
119
- except subprocess.SubprocessError:
120
- pass
130
+ logger.info(f"Checking multipass binary at: {v}")
131
+ if not validate_path(v):
132
+ msg = f"Invalid multipass binary path: {v} (not found or not executable)"
133
+ logger.error(msg)
134
+ raise ValueError(msg)
135
+ logger.info(f"✓ Found valid multipass binary at: {v}")
136
+ return v
137
+
138
+ logger.info("No multipass path provided, attempting auto-detection...")
139
+ system = platform.system().lower()
140
+ logger.info(f"Detected OS: {system}")
141
+ binary_name = "multipass.exe" if system == "windows" else "multipass"
142
+
143
+ # Try to find multipass based on OS
144
+ if system == "linux":
145
+ logger.info("Checking for snap installation...")
146
+ # First try to find snap and check if multipass is installed
147
+ try:
148
+ # Check if snap exists
149
+ snap_result = subprocess.run(
150
+ ["which", "snap"],
151
+ capture_output=True,
152
+ text=True,
153
+ check=True
154
+ )
155
+ if snap_result.returncode == 0:
156
+ logger.info("✓ Found snap, checking for multipass installation...")
157
+ # Check if multipass is installed via snap
158
+ try:
159
+ snap_list = subprocess.run(
160
+ ["snap", "list", "multipass"],
161
+ capture_output=True,
162
+ text=True,
163
+ check=True
164
+ )
165
+ if snap_list.returncode == 0:
166
+ snap_path = "/snap/bin/multipass"
167
+ if validate_path(snap_path):
168
+ logger.info(f"✓ Found multipass via snap at {snap_path}")
169
+ return snap_path
170
+ except subprocess.CalledProcessError:
171
+ logger.info("✗ Multipass not installed via snap")
172
+ pass
173
+ except subprocess.CalledProcessError:
174
+ logger.info("✗ Snap not found")
175
+ pass
121
176
 
122
- # Common Linux paths
123
- search_paths = [
124
- "/usr/local/bin",
125
- "/usr/bin",
126
- "/snap/bin"
127
- ]
177
+ # Common Linux paths if snap installation not found
178
+ search_paths = [
179
+ "/usr/local/bin",
180
+ "/usr/bin",
181
+ "/snap/bin"
182
+ ]
183
+ logger.info(f"Checking common Linux paths: {', '.join(search_paths)}")
128
184
 
129
- elif system == "darwin": # macOS
130
- search_paths = [
131
- "/opt/homebrew/bin", # M1 Mac
132
- "/usr/local/bin", # Intel Mac
133
- "/opt/local/bin" # MacPorts
134
- ]
185
+ elif system == "darwin": # macOS
186
+ search_paths = [
187
+ "/opt/homebrew/bin", # M1 Mac
188
+ "/usr/local/bin", # Intel Mac
189
+ "/opt/local/bin" # MacPorts
190
+ ]
191
+ logger.info(f"Checking macOS paths: {', '.join(search_paths)}")
135
192
 
136
- elif system == "windows":
137
- search_paths = [
138
- os.path.expandvars(r"%ProgramFiles%\Multipass"),
139
- os.path.expandvars(r"%ProgramFiles(x86)%\Multipass"),
140
- os.path.expandvars(r"%LocalAppData%\Multipass")
141
- ]
193
+ elif system == "windows":
194
+ search_paths = [
195
+ os.path.expandvars(r"%ProgramFiles%\Multipass"),
196
+ os.path.expandvars(r"%ProgramFiles(x86)%\Multipass"),
197
+ os.path.expandvars(r"%LocalAppData%\Multipass")
198
+ ]
199
+ logger.info(f"Checking Windows paths: {', '.join(search_paths)}")
142
200
 
143
- else:
144
- search_paths = ["/usr/local/bin", "/usr/bin"]
145
-
146
- # Search for multipass binary in OS-specific paths
147
- for directory in search_paths:
148
- path = os.path.join(directory, binary_name)
149
- if os.path.isfile(path) and os.access(path, os.X_OK):
150
- return path
151
-
152
- # OS-specific installation instructions
153
- if system == "linux":
154
- raise ValueError(
155
- "Multipass binary not found. Please install using:\n"
156
- "sudo snap install multipass\n"
157
- "Or set GOLEM_PROVIDER_MULTIPASS_BINARY_PATH to your Multipass binary path."
158
- )
159
- elif system == "darwin":
160
- raise ValueError(
161
- "Multipass binary not found. Please install using:\n"
162
- "brew install multipass\n"
163
- "Or set GOLEM_PROVIDER_MULTIPASS_BINARY_PATH to your Multipass binary path."
164
- )
165
- elif system == "windows":
166
- raise ValueError(
167
- "Multipass binary not found. Please install from:\n"
168
- "Microsoft Store or https://multipass.run/download/windows\n"
169
- "Or set GOLEM_PROVIDER_MULTIPASS_BINARY_PATH to your Multipass binary path."
170
- )
171
- else:
172
- raise ValueError(
173
- "Multipass binary not found. Please install Multipass or set "
174
- "GOLEM_PROVIDER_MULTIPASS_BINARY_PATH to your Multipass binary path."
175
- )
201
+ else:
202
+ search_paths = ["/usr/local/bin", "/usr/bin"]
203
+ logger.info(f"Checking default paths: {', '.join(search_paths)}")
176
204
 
177
- # Validate the path
178
- if not os.path.isfile(path):
179
- raise ValueError(f"Multipass binary not found at: {path}")
180
- if not os.access(path, os.X_OK):
181
- raise ValueError(f"Multipass binary at {path} is not executable")
182
- return path
205
+ # Search for multipass binary in OS-specific paths
206
+ for directory in search_paths:
207
+ path = os.path.join(directory, binary_name)
208
+ if validate_path(path):
209
+ logger.info(f" Found valid multipass binary at: {path}")
210
+ return path
211
+
212
+ # OS-specific installation instructions
213
+ if system == "linux":
214
+ raise ValueError(
215
+ "Multipass binary not found. Please install using:\n"
216
+ "sudo snap install multipass\n"
217
+ "Or set GOLEM_PROVIDER_MULTIPASS_BINARY_PATH to your Multipass binary path."
218
+ )
219
+ elif system == "darwin":
220
+ raise ValueError(
221
+ "Multipass binary not found. Please install using:\n"
222
+ "brew install multipass\n"
223
+ "Or set GOLEM_PROVIDER_MULTIPASS_BINARY_PATH to your Multipass binary path."
224
+ )
225
+ elif system == "windows":
226
+ raise ValueError(
227
+ "Multipass binary not found. Please install from:\n"
228
+ "Microsoft Store or https://multipass.run/download/windows\n"
229
+ "Or set GOLEM_PROVIDER_MULTIPASS_BINARY_PATH to your Multipass binary path."
230
+ )
231
+ else:
232
+ raise ValueError(
233
+ "Multipass binary not found. Please install Multipass or set "
234
+ "GOLEM_PROVIDER_MULTIPASS_BINARY_PATH to your Multipass binary path."
235
+ )
183
236
 
184
237
  # Proxy Settings
185
238
  PORT_RANGE_START: int = 50800
@@ -189,12 +242,21 @@ class Settings(BaseSettings):
189
242
 
190
243
  @validator("PROXY_STATE_DIR", pre=True)
191
244
  def resolve_proxy_state_dir(cls, v: str) -> str:
192
- """Resolve proxy state directory path."""
245
+ """Resolve and create proxy state directory path."""
193
246
  if not v:
194
- return str(Path.home() / ".golem" / "provider" / "proxy")
195
- path = Path(v)
196
- if not path.is_absolute():
197
- path = Path.home() / path
247
+ path = Path.home() / ".golem" / "provider" / "proxy"
248
+ else:
249
+ path = Path(v)
250
+ if not path.is_absolute():
251
+ path = Path.home() / path
252
+
253
+ try:
254
+ path.mkdir(parents=True, exist_ok=True)
255
+ logger.debug(f"Created proxy state directory at {path}")
256
+ except Exception as e:
257
+ logger.error(f"Failed to create proxy state directory at {path}: {e}")
258
+ raise ValueError(f"Failed to create proxy state directory: {e}")
259
+
198
260
  return str(path)
199
261
 
200
262
  @validator("PUBLIC_IP", pre=True)
provider/main.py CHANGED
@@ -163,41 +163,13 @@ __all__ = ["app", "start"]
163
163
 
164
164
  def check_requirements():
165
165
  """Check if all requirements are met."""
166
- import os
167
- from pathlib import Path
168
-
169
- # Check if multipass is installed
170
- multipass_path = os.environ.get('GOLEM_PROVIDER_MULTIPASS_BINARY_PATH', '/usr/local/bin/multipass')
171
- if not Path(multipass_path).exists():
172
- logger.error(f"Multipass binary not found at {multipass_path}")
173
- return False
174
-
175
- # Check required directories
176
- vm_data_dir = os.environ.get(
177
- 'GOLEM_PROVIDER_VM_DATA_DIR',
178
- str(Path.home() / '.golem' / 'provider' / 'vms')
179
- )
180
- ssh_key_dir = os.environ.get(
181
- 'GOLEM_PROVIDER_SSH_KEY_DIR',
182
- str(Path.home() / '.golem' / 'provider' / 'ssh')
183
- )
184
- proxy_state_dir = os.environ.get(
185
- 'GOLEM_PROVIDER_PROXY_STATE_DIR',
186
- str(Path.home() / '.golem' / 'provider' / 'proxy')
187
- )
188
-
189
166
  try:
190
- # Create and secure directories
191
- for directory in [vm_data_dir, ssh_key_dir, proxy_state_dir]:
192
- path = Path(directory)
193
- path.mkdir(parents=True, exist_ok=True)
194
- if directory == ssh_key_dir:
195
- path.chmod(0o700) # Secure permissions for SSH keys
167
+ # Import settings to trigger validation
168
+ from .config import settings
169
+ return True
196
170
  except Exception as e:
197
- logger.error(f"Failed to create required directories: {e}")
171
+ logger.error(f"Requirements check failed: {e}")
198
172
  return False
199
-
200
- return True
201
173
 
202
174
  async def verify_provider_port(port: int) -> bool:
203
175
  """Verify that the provider port is available for binding.