golem-vm-provider 0.1.34__py3-none-any.whl → 0.1.36__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.34
3
+ Version: 0.1.36
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
@@ -271,10 +271,11 @@ Response:
271
271
  - List VMs: `GET /api/v1/vms`
272
272
  - Get VM Status: `GET /api/v1/vms/{vm_id}`
273
273
  - Delete VM: `DELETE /api/v1/vms/{vm_id}`
274
+ - Stop VM: `POST /api/v1/vms/{vm_id}/stop`
274
275
  - Get Access Info: `GET /api/v1/vms/{vm_id}/access`
275
-
276
- ## Operations
277
-
276
+
277
+ ## Operations
278
+
278
279
  ### Starting the Provider
279
280
 
280
281
  ```bash
@@ -1,8 +1,8 @@
1
1
  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=hTQYzVZHJ-SD_pIpoV0KbPUghR-PUY9YKyUlETstwuQ,3567
4
- provider/api/routes.py,sha256=0_bh3Oh_5f__9wX6Fqb2Hray4YZAStzmlienyV__Sbs,5459
5
- provider/config.py,sha256=9POtsNbRYDcVW1XGTv6szosKOR5h-41-lHXnJ2_5coM,17856
4
+ provider/api/routes.py,sha256=ZNXRunNYTu9CC1XcknOx3gHQMDEyXtVMC3fArXPJkt0,6434
5
+ provider/config.py,sha256=GV-YRB9eUQXaZNFkYZRVwOSmD9BBBqtctcUw7cV8xsE,18722
6
6
  provider/container.py,sha256=u8A1FuG2targtBBqQlSiPW1yCTOm1tbrRQh8sIHstiM,2442
7
7
  provider/discovery/__init__.py,sha256=Y6o8RxGevBpuQS3k32y-zSVbP6HBXG3veBl9ElVPKaU,349
8
8
  provider/discovery/advertiser.py,sha256=2-khnnzaaftiV1QfJoILkzX-ipa3m1PxSdNd7gy7Y0A,5672
@@ -11,7 +11,7 @@ provider/discovery/golem_base_utils.py,sha256=xk7vznhMgzrn0AuGyk6-9N9ukp9oPdBbbk
11
11
  provider/discovery/resource_monitor.py,sha256=AmiEc7yBGEGXCunQ-QKmVgosDX3gOhK1Y58LJZXrwAs,949
12
12
  provider/discovery/resource_tracker.py,sha256=MP7IXd3aIMsjB4xz5Oj9zFDTEnvrnw-Cyxpl33xcJcc,6006
13
13
  provider/discovery/service.py,sha256=qU_fa8znPDNk-fQZ6Z3x6HDTbopK6RgfC_D8rixqBmY,709
14
- provider/main.py,sha256=0xN6cdtiS8quCB0bswdksSEExb3yeAFrWIbLMMbUJ-U,6668
14
+ provider/main.py,sha256=LvpJxkOS3dKLJu4Ef80jS9Umtm1vX7Pf0We68-uGp1A,6630
15
15
  provider/network/port_verifier.py,sha256=3l6WNwBHydggJRFYkAsuBp1eCxaU619kjWuM-zSVj2o,13267
16
16
  provider/security/ethereum.py,sha256=EwPZj4JR8OEpto6LhKjuuT3Z9pBX6P7-UQaqJtqFkYQ,1242
17
17
  provider/security/faucet.py,sha256=O2DgP3bIrRUm9tdLCdgnda9em0rPyeW42sWhO1EQJaA,5363
@@ -31,8 +31,8 @@ provider/vm/name_mapper.py,sha256=14nKfCjJ1WkXfC4vnCYIxNGQUwcl2vcxrJYUAz4fL40,40
31
31
  provider/vm/port_manager.py,sha256=iYSwjTjD_ziOhG8aI7juKHw1OwwRUTJQyQoRUNQvz9w,12514
32
32
  provider/vm/provider.py,sha256=A7QN89EJjcSS40_SmKeinG1Jp_NGffJaLse-XdKciAs,1164
33
33
  provider/vm/proxy_manager.py,sha256=n4NTsyz2rtrvjtf_ceKBk-g2q_mzqPwruB1q7UlQVBc,14928
34
- provider/vm/service.py,sha256=VpWhUuVtsmz9yUIiCT7XSoA0aA89I_4-g3JKbaGrryw,3651
35
- golem_vm_provider-0.1.34.dist-info/METADATA,sha256=6bTkURNjTE4PXmSOCrWXQAHgyEnqaUpqVW2_S8CJrbo,10895
36
- golem_vm_provider-0.1.34.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
37
- golem_vm_provider-0.1.34.dist-info/entry_points.txt,sha256=iFUajRxfViYkFcPMPv2EIjYm-BLOp86LJj_IjCwwZUw,74
38
- golem_vm_provider-0.1.34.dist-info/RECORD,,
34
+ provider/vm/service.py,sha256=7MjJM4l3wylcBlOuADEVab6R5HfT5HInOFZuEGcoV3I,3982
35
+ golem_vm_provider-0.1.36.dist-info/METADATA,sha256=DEe7_P0heVQmD49QA2yr-5cShYpOV2g03zaC8JJDudk,10943
36
+ golem_vm_provider-0.1.36.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
37
+ golem_vm_provider-0.1.36.dist-info/entry_points.txt,sha256=iFUajRxfViYkFcPMPv2EIjYm-BLOp86LJj_IjCwwZUw,74
38
+ golem_vm_provider-0.1.36.dist-info/RECORD,,
provider/api/routes.py CHANGED
@@ -122,6 +122,30 @@ async def get_vm_access(
122
122
  raise HTTPException(status_code=500, detail="An unexpected error occurred")
123
123
 
124
124
 
125
+ @router.post("/vms/{requestor_name}/stop", response_model=VMInfo)
126
+ @inject
127
+ async def stop_vm(
128
+ requestor_name: str,
129
+ vm_service: VMService = Depends(Provide[Container.vm_service]),
130
+ ) -> VMInfo:
131
+ """Stop a VM."""
132
+ try:
133
+ logger.process(f"🛑 Stopping VM '{requestor_name}'")
134
+ vm_info = await vm_service.stop_vm(requestor_name)
135
+ vm_status_change(requestor_name, vm_info.status.value, "VM stopped")
136
+ logger.success(f"✨ Successfully stopped VM '{requestor_name}'")
137
+ return vm_info
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 stop 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")
147
+
148
+
125
149
  @router.delete("/vms/{requestor_name}")
126
150
  @inject
127
151
  async def delete_vm(
provider/config.py CHANGED
@@ -11,6 +11,37 @@ from .utils.logging import setup_logger
11
11
  logger = setup_logger(__name__)
12
12
 
13
13
 
14
+ def ensure_config() -> None:
15
+ """Ensure the provider configuration directory and defaults exist."""
16
+ base_dir = Path.home() / ".golem" / "provider"
17
+ env_file = base_dir / ".env"
18
+ subdirs = ["keys", "ssh", "vms", "proxy"]
19
+ created = False
20
+
21
+ for sub in subdirs:
22
+ path = base_dir / sub
23
+ if not path.exists():
24
+ path.mkdir(parents=True, exist_ok=True)
25
+ created = True
26
+
27
+ if not env_file.exists():
28
+ env_file.write_text("GOLEM_PROVIDER_ENVIRONMENT=production\n")
29
+ created = True
30
+
31
+ from .security.ethereum import EthereumIdentity
32
+
33
+ identity = EthereumIdentity(str(base_dir / "keys"))
34
+ if not identity.key_file.exists():
35
+ identity.get_or_create_identity()
36
+ created = True
37
+
38
+ if created:
39
+ print("Using default settings – run with --help to customize")
40
+
41
+
42
+ ensure_config()
43
+
44
+
14
45
  class Settings(BaseSettings):
15
46
  """Provider configuration settings."""
16
47
 
provider/main.py CHANGED
@@ -1,4 +1,3 @@
1
- from .api import routes
2
1
  import asyncio
3
2
  import os
4
3
  import socket
@@ -6,14 +5,16 @@ from fastapi import FastAPI
6
5
  from fastapi.middleware.cors import CORSMiddleware
7
6
  from typing import Optional
8
7
 
9
- from .config import settings
10
- from .utils.logging import setup_logger, PROCESS, SUCCESS
8
+ from .config import settings, ensure_config
9
+ from .utils.logging import setup_logger
11
10
  from .utils.ascii_art import startup_animation
12
11
  from .discovery.resource_tracker import ResourceTracker
13
12
  from .discovery.advertiser import DiscoveryServerAdvertiser
14
13
  from .container import Container
15
14
  from .service import ProviderService
16
- from .utils.logging import setup_logger
15
+
16
+
17
+ logger = setup_logger(__name__)
17
18
 
18
19
  app = FastAPI(title="VM on Golem Provider")
19
20
  container = Container()
@@ -62,6 +63,7 @@ async def shutdown_event():
62
63
  await provider_service.cleanup()
63
64
 
64
65
  # Import routes after app creation to avoid circular imports
66
+ from .api import routes
65
67
  app.include_router(routes.router, prefix="/api/v1")
66
68
 
67
69
  # Export app for uvicorn
@@ -134,6 +136,7 @@ def print_version(ctx: typer.Context, value: bool):
134
136
  def main(
135
137
  version: bool = typer.Option(None, "--version", callback=print_version, is_eager=True, help="Show the version and exit.")
136
138
  ):
139
+ ensure_config()
137
140
  pass
138
141
 
139
142
  @cli.command()
@@ -152,8 +155,6 @@ def run_server(dev_mode: bool, no_verify_port: bool):
152
155
  from pathlib import Path
153
156
  from dotenv import load_dotenv
154
157
  import uvicorn
155
- from .utils.logging import setup_logger
156
-
157
158
  # Load appropriate .env file
158
159
  env_file = ".env.dev" if dev_mode else ".env"
159
160
  env_path = Path(__file__).parent.parent / env_file
provider/vm/service.py CHANGED
@@ -69,6 +69,13 @@ class VMService:
69
69
  finally:
70
70
  await self.name_mapper.remove_mapping(vm_id)
71
71
 
72
+ async def stop_vm(self, vm_id: str) -> VMInfo:
73
+ """Stop a VM and return its updated status."""
74
+ multipass_name = await self.name_mapper.get_multipass_name(vm_id)
75
+ if not multipass_name:
76
+ raise VMNotFoundError(f"VM {vm_id} not found")
77
+ return await self.provider.stop_vm(multipass_name)
78
+
72
79
  async def list_vms(self) -> List[VMInfo]:
73
80
  """List all VMs."""
74
81
  return await self.provider.list_vms()