golem-vm-provider 0.1.26__tar.gz → 0.1.27__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 (41) hide show
  1. {golem_vm_provider-0.1.26 → golem_vm_provider-0.1.27}/PKG-INFO +7 -2
  2. {golem_vm_provider-0.1.26 → golem_vm_provider-0.1.27}/README.md +5 -1
  3. {golem_vm_provider-0.1.26 → golem_vm_provider-0.1.27}/provider/api/models.py +7 -7
  4. golem_vm_provider-0.1.27/provider/api/routes.py +146 -0
  5. {golem_vm_provider-0.1.26 → golem_vm_provider-0.1.27}/provider/config.py +50 -28
  6. golem_vm_provider-0.1.27/provider/container.py +84 -0
  7. golem_vm_provider-0.1.27/provider/discovery/__init__.py +12 -0
  8. {golem_vm_provider-0.1.26 → golem_vm_provider-0.1.27}/provider/discovery/advertiser.py +41 -63
  9. {golem_vm_provider-0.1.26 → golem_vm_provider-0.1.27}/provider/discovery/golem_base_advertiser.py +12 -6
  10. golem_vm_provider-0.1.27/provider/discovery/resource_monitor.py +34 -0
  11. {golem_vm_provider-0.1.26 → golem_vm_provider-0.1.27}/provider/discovery/resource_tracker.py +1 -1
  12. golem_vm_provider-0.1.27/provider/discovery/service.py +24 -0
  13. golem_vm_provider-0.1.27/provider/main.py +189 -0
  14. golem_vm_provider-0.1.27/provider/service.py +67 -0
  15. golem_vm_provider-0.1.27/provider/utils/__init__.py +0 -0
  16. {golem_vm_provider-0.1.26 → golem_vm_provider-0.1.27}/provider/utils/logging.py +11 -27
  17. {golem_vm_provider-0.1.26 → golem_vm_provider-0.1.27}/provider/utils/port_display.py +6 -8
  18. {golem_vm_provider-0.1.26 → golem_vm_provider-0.1.27}/provider/utils/retry.py +39 -0
  19. {golem_vm_provider-0.1.26 → golem_vm_provider-0.1.27}/provider/vm/__init__.py +1 -1
  20. {golem_vm_provider-0.1.26 → golem_vm_provider-0.1.27}/provider/vm/models.py +8 -7
  21. golem_vm_provider-0.1.27/provider/vm/multipass.py +19 -0
  22. golem_vm_provider-0.1.27/provider/vm/multipass_adapter.py +221 -0
  23. {golem_vm_provider-0.1.26 → golem_vm_provider-0.1.27}/provider/vm/name_mapper.py +5 -5
  24. {golem_vm_provider-0.1.26 → golem_vm_provider-0.1.27}/provider/vm/port_manager.py +24 -6
  25. golem_vm_provider-0.1.27/provider/vm/provider.py +48 -0
  26. {golem_vm_provider-0.1.26 → golem_vm_provider-0.1.27}/provider/vm/proxy_manager.py +1 -1
  27. golem_vm_provider-0.1.27/provider/vm/service.py +91 -0
  28. {golem_vm_provider-0.1.26 → golem_vm_provider-0.1.27}/pyproject.toml +4 -1
  29. golem_vm_provider-0.1.26/provider/api/routes.py +0 -152
  30. golem_vm_provider-0.1.26/provider/discovery/__init__.py +0 -6
  31. golem_vm_provider-0.1.26/provider/main.py +0 -288
  32. golem_vm_provider-0.1.26/provider/vm/multipass.py +0 -437
  33. {golem_vm_provider-0.1.26 → golem_vm_provider-0.1.27}/provider/__init__.py +0 -0
  34. {golem_vm_provider-0.1.26 → golem_vm_provider-0.1.27}/provider/api/__init__.py +0 -0
  35. {golem_vm_provider-0.1.26 → golem_vm_provider-0.1.27}/provider/discovery/golem_base_utils.py +0 -0
  36. {golem_vm_provider-0.1.26 → golem_vm_provider-0.1.27}/provider/network/port_verifier.py +0 -0
  37. {golem_vm_provider-0.1.26 → golem_vm_provider-0.1.27}/provider/security/ethereum.py +0 -0
  38. {golem_vm_provider-0.1.26 → golem_vm_provider-0.1.27}/provider/security/faucet.py +0 -0
  39. {golem_vm_provider-0.1.26 → golem_vm_provider-0.1.27}/provider/utils/ascii_art.py +0 -0
  40. {golem_vm_provider-0.1.26 → golem_vm_provider-0.1.27}/provider/utils/setup.py +0 -0
  41. {golem_vm_provider-0.1.26 → golem_vm_provider-0.1.27}/provider/vm/cloud_init.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: golem-vm-provider
3
- Version: 0.1.26
3
+ Version: 0.1.27
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
@@ -17,6 +17,7 @@ Classifier: Topic :: System :: Distributed Computing
17
17
  Requires-Dist: aiohttp (>=3.8.1,<4.0.0)
18
18
  Requires-Dist: colorlog (>=6.8.0,<7.0.0)
19
19
  Requires-Dist: cryptography (>=3.4.7,<4.0.0)
20
+ Requires-Dist: dependency-injector (>=4.41.0,<5.0.0)
20
21
  Requires-Dist: eth-account (>=0.13.6,<0.14.0)
21
22
  Requires-Dist: fastapi (>=0.103.0,<0.104.0)
22
23
  Requires-Dist: golem-base-sdk (==0.1.0)
@@ -275,7 +276,11 @@ Response:
275
276
  ### Starting the Provider
276
277
 
277
278
  ```bash
278
- poetry run python run.py
279
+ # To run in production mode
280
+ poetry run golem-provider start
281
+
282
+ # To run in development mode
283
+ poetry run golem-provider dev
279
284
  ```
280
285
 
281
286
  The provider will:
@@ -235,7 +235,11 @@ Response:
235
235
  ### Starting the Provider
236
236
 
237
237
  ```bash
238
- poetry run python run.py
238
+ # To run in production mode
239
+ poetry run golem-provider start
240
+
241
+ # To run in development mode
242
+ poetry run golem-provider dev
239
243
  ```
240
244
 
241
245
  The provider will:
@@ -1,4 +1,4 @@
1
- from pydantic import BaseModel, Field, validator
1
+ from pydantic import BaseModel, Field, field_validator
2
2
  from typing import Dict, Optional, List, Any
3
3
  from datetime import datetime
4
4
 
@@ -18,14 +18,14 @@ class CreateVMRequest(BaseModel):
18
18
  ssh_key: str = Field(..., pattern="^(ssh-rsa|ssh-ed25519) ",
19
19
  description="SSH public key for VM access")
20
20
 
21
- @validator("name")
21
+ @field_validator("name")
22
22
  def validate_name(cls, v: str) -> str:
23
23
  """Validate VM name."""
24
24
  if "--" in v:
25
25
  raise ValueError("VM name cannot contain consecutive hyphens")
26
26
  return v
27
27
 
28
- @validator("resources", pre=True)
28
+ @field_validator("resources", mode='before')
29
29
  def validate_resources(cls, v: Optional[Dict[str, Any]], values: Dict[str, Any]) -> VMResources:
30
30
  """Validate and set resources."""
31
31
  logger.debug(f"Validating resources input: {v}")
@@ -43,10 +43,10 @@ class CreateVMRequest(BaseModel):
43
43
  return v
44
44
 
45
45
  # If size provided, use that
46
- if "size" in values and values["size"] is not None:
47
- result = VMResources.from_size(values["size"])
46
+ if "size" in values.data and values.data["size"] is not None:
47
+ result = VMResources.from_size(values.data["size"])
48
48
  logger.debug(
49
- f"Created resources from size {values['size']}: {result}")
49
+ f"Created resources from size {values.data['size']}: {result}")
50
50
  return result
51
51
 
52
52
  # Only use defaults if nothing provided
@@ -57,7 +57,7 @@ class CreateVMRequest(BaseModel):
57
57
  except Exception as e:
58
58
  logger.error(f"Error validating resources: {e}")
59
59
  logger.error(f"Input value: {v}")
60
- logger.error(f"Values dict: {values}")
60
+ logger.error(f"Values dict: {values.data}")
61
61
  raise ValueError(f"Invalid resource configuration: {str(e)}")
62
62
 
63
63
 
@@ -0,0 +1,146 @@
1
+ import json
2
+ from typing import List
3
+ from pathlib import Path
4
+ from fastapi import APIRouter, HTTPException, Request
5
+
6
+ from dependency_injector.wiring import inject, Provide
7
+ from fastapi import APIRouter, HTTPException, Depends
8
+
9
+ from ..config import Settings
10
+ from ..container import Container
11
+ from ..utils.logging import setup_logger
12
+ from ..utils.ascii_art import vm_creation_animation, vm_status_change
13
+ from ..vm.models import VMInfo, VMAccessInfo, VMConfig, VMResources, VMNotFoundError
14
+ from .models import CreateVMRequest
15
+ from ..vm.service import VMService
16
+ from ..vm.multipass_adapter import MultipassError
17
+
18
+ logger = setup_logger(__name__)
19
+ router = APIRouter()
20
+
21
+
22
+ @router.post("/vms", response_model=VMInfo)
23
+ @inject
24
+ async def create_vm(
25
+ request: CreateVMRequest,
26
+ vm_service: VMService = Depends(Provide[Container.vm_service]),
27
+ settings: Settings = Depends(Provide[Container.config]),
28
+ ) -> VMInfo:
29
+ """Create a new VM."""
30
+ try:
31
+ logger.info(f"📥 Received VM creation request for '{request.name}'")
32
+
33
+ resources = request.resources or VMResources()
34
+
35
+ # Create VM config
36
+ config = VMConfig(
37
+ name=request.name,
38
+ image=request.image or settings["DEFAULT_VM_IMAGE"],
39
+ resources=resources,
40
+ ssh_key=request.ssh_key
41
+ )
42
+
43
+ vm_info = await vm_service.create_vm(config)
44
+ await vm_creation_animation(request.name)
45
+ return vm_info
46
+ except MultipassError as e:
47
+ logger.error(f"Failed to create VM: {e}")
48
+ raise HTTPException(status_code=500, detail=str(e))
49
+ except Exception as e:
50
+ logger.error(f"An unexpected error occurred: {e}")
51
+ raise HTTPException(status_code=500, detail="An unexpected error occurred")
52
+
53
+
54
+ @router.get("/vms", response_model=List[VMInfo])
55
+ @inject
56
+ async def list_vms(
57
+ vm_service: VMService = Depends(Provide[Container.vm_service]),
58
+ ) -> List[VMInfo]:
59
+ """List all VMs."""
60
+ try:
61
+ logger.info("📋 Listing all VMs")
62
+ return await vm_service.list_vms()
63
+ except MultipassError as e:
64
+ logger.error(f"Failed to list VMs: {e}")
65
+ raise HTTPException(status_code=500, detail=str(e))
66
+ except Exception as e:
67
+ logger.error(f"An unexpected error occurred: {e}")
68
+ raise HTTPException(status_code=500, detail="An unexpected error occurred")
69
+
70
+
71
+ @router.get("/vms/{requestor_name}", response_model=VMInfo)
72
+ @inject
73
+ async def get_vm_status(
74
+ requestor_name: str,
75
+ vm_service: VMService = Depends(Provide[Container.vm_service]),
76
+ ) -> VMInfo:
77
+ """Get VM status."""
78
+ try:
79
+ logger.info(f"🔍 Getting status for VM '{requestor_name}'")
80
+ status = await vm_service.get_vm_status(requestor_name)
81
+ vm_status_change(requestor_name, status.status.value)
82
+ return status
83
+ except VMNotFoundError as e:
84
+ logger.error(f"VM not found: {e}")
85
+ raise HTTPException(status_code=404, detail=str(e))
86
+ except MultipassError as e:
87
+ logger.error(f"Failed to get VM status: {e}")
88
+ raise HTTPException(status_code=500, detail=str(e))
89
+ except Exception as e:
90
+ logger.error(f"An unexpected error occurred: {e}")
91
+ raise HTTPException(status_code=500, detail="An unexpected error occurred")
92
+
93
+
94
+ @router.get("/vms/{requestor_name}/access", response_model=VMAccessInfo)
95
+ @inject
96
+ async def get_vm_access(
97
+ requestor_name: str,
98
+ vm_service: VMService = Depends(Provide[Container.vm_service]),
99
+ settings: Settings = Depends(Provide[Container.config]),
100
+ ) -> VMAccessInfo:
101
+ """Get VM access information."""
102
+ try:
103
+ vm = await vm_service.get_vm_status(requestor_name)
104
+ if not vm:
105
+ raise HTTPException(404, "VM not found")
106
+
107
+ multipass_name = await vm_service.name_mapper.get_multipass_name(requestor_name)
108
+ if not multipass_name:
109
+ raise HTTPException(404, "VM mapping not found")
110
+
111
+ return VMAccessInfo(
112
+ ssh_host=settings["PUBLIC_IP"] or "localhost",
113
+ ssh_port=vm.ssh_port,
114
+ vm_id=requestor_name,
115
+ multipass_name=multipass_name
116
+ )
117
+ except MultipassError as e:
118
+ logger.error(f"Failed to get VM access info: {e}")
119
+ raise HTTPException(status_code=500, detail=str(e))
120
+ except Exception as e:
121
+ logger.error(f"An unexpected error occurred: {e}")
122
+ raise HTTPException(status_code=500, detail="An unexpected error occurred")
123
+
124
+
125
+ @router.delete("/vms/{requestor_name}")
126
+ @inject
127
+ async def delete_vm(
128
+ requestor_name: str,
129
+ vm_service: VMService = Depends(Provide[Container.vm_service]),
130
+ ) -> None:
131
+ """Delete a VM."""
132
+ try:
133
+ logger.process(f"🗑️ Deleting VM '{requestor_name}'")
134
+ vm_status_change(requestor_name, "STOPPING", "Cleanup in progress")
135
+ await vm_service.delete_vm(requestor_name)
136
+ vm_status_change(requestor_name, "TERMINATED", "Cleanup complete")
137
+ logger.success(f"✨ Successfully deleted VM '{requestor_name}'")
138
+ except VMNotFoundError as e:
139
+ logger.error(f"VM not found: {e}")
140
+ raise HTTPException(status_code=404, detail=str(e))
141
+ except MultipassError as e:
142
+ logger.error(f"Failed to delete VM: {e}")
143
+ raise HTTPException(status_code=500, detail=str(e))
144
+ except Exception as e:
145
+ logger.error(f"An unexpected error occurred: {e}")
146
+ raise HTTPException(status_code=500, detail="An unexpected error occurred")
@@ -2,9 +2,10 @@ import os
2
2
  from pathlib import Path
3
3
  from typing import Optional
4
4
  import uuid
5
+ import socket
5
6
 
6
7
  from pydantic_settings import BaseSettings
7
- from pydantic import validator, Field
8
+ from pydantic import field_validator, Field
8
9
  from .utils.logging import setup_logger
9
10
 
10
11
  logger = setup_logger(__name__)
@@ -24,10 +25,10 @@ class Settings(BaseSettings):
24
25
  def DEV_MODE(self) -> bool:
25
26
  return self.ENVIRONMENT == "development"
26
27
 
27
- @validator("SKIP_PORT_VERIFICATION", always=True)
28
+ @field_validator("SKIP_PORT_VERIFICATION", mode='before')
28
29
  def set_skip_verification(cls, v: bool, values: dict) -> bool:
29
30
  """Set skip verification based on debug mode."""
30
- return v or values.get("DEBUG", False)
31
+ return v or values.data.get("DEBUG", False)
31
32
 
32
33
  # Provider Settings
33
34
  PROVIDER_NAME: str = "golem-provider"
@@ -39,7 +40,7 @@ class Settings(BaseSettings):
39
40
  CAPTCHA_URL: str = "https://cap.gobas.me"
40
41
  CAPTCHA_API_KEY: str = "05381a2cef5e"
41
42
 
42
- @validator("ETHEREUM_KEY_DIR", pre=True)
43
+ @field_validator("ETHEREUM_KEY_DIR", mode='before')
43
44
  def resolve_key_dir(cls, v: str) -> str:
44
45
  """Resolve Ethereum key directory path."""
45
46
  if not v:
@@ -49,7 +50,7 @@ class Settings(BaseSettings):
49
50
  path = Path.home() / path
50
51
  return str(path)
51
52
 
52
- @validator("ETHEREUM_PRIVATE_KEY", always=True)
53
+ @field_validator("ETHEREUM_PRIVATE_KEY", mode='before')
53
54
  def get_private_key(cls, v: Optional[str], values: dict) -> str:
54
55
  """Get private key from key file if not provided."""
55
56
  from provider.security.ethereum import EthereumIdentity
@@ -57,17 +58,17 @@ class Settings(BaseSettings):
57
58
  if v:
58
59
  return v
59
60
 
60
- key_dir = values.get("ETHEREUM_KEY_DIR")
61
+ key_dir = values.data.get("ETHEREUM_KEY_DIR")
61
62
  identity = EthereumIdentity(key_dir)
62
63
  _, private_key = identity.get_or_create_identity()
63
64
  return private_key
64
65
 
65
- @validator("PROVIDER_ID", always=True)
66
+ @field_validator("PROVIDER_ID", mode='before')
66
67
  def get_provider_id(cls, v: str, values: dict) -> str:
67
68
  """Get provider ID from private key."""
68
69
  from eth_account import Account
69
70
 
70
- private_key = values.get("ETHEREUM_PRIVATE_KEY")
71
+ private_key = values.data.get("ETHEREUM_PRIVATE_KEY")
71
72
  if not private_key:
72
73
  raise ValueError("ETHEREUM_PRIVATE_KEY is not set")
73
74
 
@@ -83,16 +84,16 @@ class Settings(BaseSettings):
83
84
 
84
85
  return provider_id_from_key
85
86
 
86
- @validator("PROVIDER_NAME", always=True)
87
+ @field_validator("PROVIDER_NAME", mode='before')
87
88
  def set_provider_name(cls, v: str, values: dict) -> str:
88
89
  """Prefix provider name with DEVMODE if in development."""
89
- if values.get("ENVIRONMENT") == "development":
90
+ if values.data.get("ENVIRONMENT") == "development":
90
91
  return f"DEVMODE-{v}"
91
92
  return v
92
93
 
93
94
  # Discovery Service Settings
94
95
  DISCOVERY_URL: str = "http://195.201.39.101:9001"
95
- DISCOVERY_DRIVER: str = "golem-base" # or "legacy"
96
+ ADVERTISER_TYPE: str = "golem_base" # or "discovery_server"
96
97
  ADVERTISEMENT_INTERVAL: int = 240 # seconds
97
98
 
98
99
  # Golem Base Settings
@@ -107,7 +108,7 @@ class Settings(BaseSettings):
107
108
  CLOUD_INIT_DIR: str = ""
108
109
  CLOUD_INIT_FALLBACK_DIR: str = "" # Will be set to a temp directory if needed
109
110
 
110
- @validator("CLOUD_INIT_DIR", pre=True)
111
+ @field_validator("CLOUD_INIT_DIR", mode='before')
111
112
  def resolve_cloud_init_dir(cls, v: str) -> str:
112
113
  """Resolve and create cloud-init directory path."""
113
114
  import platform
@@ -190,7 +191,7 @@ class Settings(BaseSettings):
190
191
  logger.error(f"Failed to create cloud-init directory at {path}: {e}")
191
192
  raise ValueError(f"Failed to create cloud-init directory: {e}")
192
193
 
193
- @validator("VM_DATA_DIR", pre=True)
194
+ @field_validator("VM_DATA_DIR", mode='before')
194
195
  def resolve_vm_data_dir(cls, v: str) -> str:
195
196
  """Resolve and create VM data directory path."""
196
197
  if not v:
@@ -209,7 +210,7 @@ class Settings(BaseSettings):
209
210
 
210
211
  return str(path)
211
212
 
212
- @validator("SSH_KEY_DIR", pre=True)
213
+ @field_validator("SSH_KEY_DIR", mode='before')
213
214
  def resolve_ssh_key_dir(cls, v: str) -> str:
214
215
  """Resolve and create SSH key directory path with secure permissions."""
215
216
  if not v:
@@ -248,7 +249,7 @@ class Settings(BaseSettings):
248
249
  description="Path to multipass binary"
249
250
  )
250
251
 
251
- @validator("MULTIPASS_BINARY_PATH")
252
+ @field_validator("MULTIPASS_BINARY_PATH")
252
253
  def detect_multipass_path(cls, v: str) -> str:
253
254
  """Detect and validate Multipass binary path."""
254
255
  import platform
@@ -373,7 +374,7 @@ class Settings(BaseSettings):
373
374
  PROXY_STATE_DIR: str = ""
374
375
  PUBLIC_IP: Optional[str] = None
375
376
 
376
- @validator("PROXY_STATE_DIR", pre=True)
377
+ @field_validator("PROXY_STATE_DIR", mode='before')
377
378
  def resolve_proxy_state_dir(cls, v: str) -> str:
378
379
  """Resolve and create proxy state directory path."""
379
380
  if not v:
@@ -392,26 +393,47 @@ class Settings(BaseSettings):
392
393
 
393
394
  return str(path)
394
395
 
395
- @validator("PUBLIC_IP", pre=True)
396
+ @field_validator("PUBLIC_IP", mode='before')
396
397
  def get_public_ip(cls, v: Optional[str], values: dict) -> Optional[str]:
397
398
  """Get public IP if set to 'auto'."""
399
+ if values.data.get("ENVIRONMENT") == "development":
400
+ try:
401
+ hostname = socket.gethostname()
402
+ ips = socket.gethostbyname_ex(hostname)[2]
403
+ local_ips = [ip for ip in ips if not ip.startswith("127.")]
404
+ if local_ips:
405
+ ip = local_ips[0]
406
+ logger.info(f"Found local IP for development: {ip}")
407
+ return ip
408
+ except socket.gaierror:
409
+ pass
410
+
411
+ s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
412
+ try:
413
+ s.connect(('8.8.8.8', 80))
414
+ IP = s.getsockname()[0]
415
+ if IP:
416
+ logger.info(f"Found local IP for development: {IP}")
417
+ return IP
418
+ except Exception:
419
+ pass
420
+ finally:
421
+ s.close()
422
+
423
+ raise ValueError("Could not determine local IP address in development mode. "
424
+ "Please ensure you have a valid network connection.")
398
425
  if v == "auto":
399
- if values.get("ENVIRONMENT") == "development":
400
- import socket
401
- try:
402
- s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
403
- s.connect(("8.8.8.8", 80))
404
- local_ip = s.getsockname()[0]
405
- s.close()
406
- return local_ip
407
- except Exception:
408
- return "127.0.0.1"
409
426
  try:
410
427
  import requests
411
428
  response = requests.get("https://api.ipify.org")
412
- return response.text.strip()
429
+ ip = response.text.strip()
430
+ logger.info(f"Found public IP: {ip}")
431
+ return ip
413
432
  except Exception:
414
433
  return None
434
+
435
+ if v:
436
+ logger.info(f"Using manually provided IP: {v}")
415
437
  return v
416
438
 
417
439
  class Config:
@@ -0,0 +1,84 @@
1
+ import os
2
+ from dependency_injector import containers, providers
3
+ from pathlib import Path
4
+
5
+ from .config import settings
6
+ from .discovery.resource_tracker import ResourceTracker
7
+ from .discovery.golem_base_advertiser import GolemBaseAdvertiser
8
+ from .discovery.advertiser import DiscoveryServerAdvertiser
9
+ from .discovery.service import AdvertisementService
10
+ from .service import ProviderService
11
+ from .vm.multipass_adapter import MultipassAdapter
12
+ from .vm.service import VMService
13
+ from .vm.name_mapper import VMNameMapper
14
+ from .vm.port_manager import PortManager
15
+ from .vm.proxy_manager import PythonProxyManager
16
+
17
+
18
+ class Container(containers.DeclarativeContainer):
19
+ """Dependency injection container."""
20
+
21
+ config = providers.Configuration()
22
+
23
+ resource_tracker = providers.Singleton(ResourceTracker)
24
+
25
+ advertiser = providers.Selector(
26
+ config.ADVERTISER_TYPE,
27
+ golem_base=providers.Singleton(
28
+ GolemBaseAdvertiser,
29
+ resource_tracker=resource_tracker,
30
+ ),
31
+ discovery_server=providers.Singleton(
32
+ DiscoveryServerAdvertiser,
33
+ resource_tracker=resource_tracker,
34
+ ),
35
+ )
36
+
37
+ advertisement_service = providers.Singleton(
38
+ AdvertisementService,
39
+ advertiser=advertiser,
40
+ )
41
+
42
+ vm_name_mapper = providers.Singleton(
43
+ VMNameMapper,
44
+ db_path=Path(settings.VM_DATA_DIR) / "vm_names.json",
45
+ )
46
+
47
+ port_manager = providers.Singleton(
48
+ PortManager,
49
+ start_port=config.PORT_RANGE_START,
50
+ end_port=config.PORT_RANGE_END,
51
+ state_file=providers.Callable(
52
+ os.path.join,
53
+ config.PROXY_STATE_DIR,
54
+ "ports.json"
55
+ ),
56
+ discovery_port=config.PORT,
57
+ skip_verification=config.SKIP_PORT_VERIFICATION,
58
+ )
59
+
60
+ proxy_manager = providers.Singleton(
61
+ PythonProxyManager,
62
+ port_manager=port_manager,
63
+ name_mapper=vm_name_mapper,
64
+ )
65
+
66
+ vm_provider = providers.Singleton(
67
+ MultipassAdapter,
68
+ proxy_manager=proxy_manager,
69
+ name_mapper=vm_name_mapper,
70
+ )
71
+
72
+ vm_service = providers.Singleton(
73
+ VMService,
74
+ provider=vm_provider,
75
+ resource_tracker=resource_tracker,
76
+ name_mapper=vm_name_mapper,
77
+ )
78
+
79
+ provider_service = providers.Singleton(
80
+ ProviderService,
81
+ vm_service=vm_service,
82
+ advertisement_service=advertisement_service,
83
+ port_manager=port_manager,
84
+ )
@@ -0,0 +1,12 @@
1
+ from .advertiser import Advertiser, DiscoveryServerAdvertiser
2
+ from .golem_base_advertiser import GolemBaseAdvertiser
3
+ from .resource_monitor import ResourceMonitor
4
+ from .service import AdvertisementService
5
+
6
+ __all__ = [
7
+ "Advertiser",
8
+ "DiscoveryServerAdvertiser",
9
+ "GolemBaseAdvertiser",
10
+ "ResourceMonitor",
11
+ "AdvertisementService",
12
+ ]