golem-vm-provider 0.1.55__tar.gz → 0.1.57__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.
- {golem_vm_provider-0.1.55 → golem_vm_provider-0.1.57}/PKG-INFO +74 -8
- {golem_vm_provider-0.1.55 → golem_vm_provider-0.1.57}/README.md +73 -7
- {golem_vm_provider-0.1.55 → golem_vm_provider-0.1.57}/provider/api/routes.py +14 -12
- {golem_vm_provider-0.1.55 → golem_vm_provider-0.1.57}/provider/config.py +2 -1
- {golem_vm_provider-0.1.55 → golem_vm_provider-0.1.57}/provider/container.py +2 -3
- {golem_vm_provider-0.1.55 → golem_vm_provider-0.1.57}/provider/main.py +646 -18
- {golem_vm_provider-0.1.55 → golem_vm_provider-0.1.57}/provider/network/port_verifier.py +32 -34
- {golem_vm_provider-0.1.55 → golem_vm_provider-0.1.57}/provider/utils/logging.py +18 -3
- {golem_vm_provider-0.1.55 → golem_vm_provider-0.1.57}/provider/utils/pricing.py +12 -1
- {golem_vm_provider-0.1.55 → golem_vm_provider-0.1.57}/pyproject.toml +1 -1
- {golem_vm_provider-0.1.55 → golem_vm_provider-0.1.57}/provider/__init__.py +0 -0
- {golem_vm_provider-0.1.55 → golem_vm_provider-0.1.57}/provider/api/__init__.py +0 -0
- {golem_vm_provider-0.1.55 → golem_vm_provider-0.1.57}/provider/api/models.py +0 -0
- {golem_vm_provider-0.1.55 → golem_vm_provider-0.1.57}/provider/data/deployments/l2.json +0 -0
- {golem_vm_provider-0.1.55 → golem_vm_provider-0.1.57}/provider/discovery/__init__.py +0 -0
- {golem_vm_provider-0.1.55 → golem_vm_provider-0.1.57}/provider/discovery/advertiser.py +0 -0
- {golem_vm_provider-0.1.55 → golem_vm_provider-0.1.57}/provider/discovery/golem_base_advertiser.py +0 -0
- {golem_vm_provider-0.1.55 → golem_vm_provider-0.1.57}/provider/discovery/golem_base_utils.py +0 -0
- {golem_vm_provider-0.1.55 → golem_vm_provider-0.1.57}/provider/discovery/multi_advertiser.py +0 -0
- {golem_vm_provider-0.1.55 → golem_vm_provider-0.1.57}/provider/discovery/resource_monitor.py +0 -0
- {golem_vm_provider-0.1.55 → golem_vm_provider-0.1.57}/provider/discovery/resource_tracker.py +0 -0
- {golem_vm_provider-0.1.55 → golem_vm_provider-0.1.57}/provider/discovery/service.py +0 -0
- {golem_vm_provider-0.1.55 → golem_vm_provider-0.1.57}/provider/payments/blockchain_service.py +0 -0
- {golem_vm_provider-0.1.55 → golem_vm_provider-0.1.57}/provider/payments/monitor.py +0 -0
- {golem_vm_provider-0.1.55 → golem_vm_provider-0.1.57}/provider/payments/stream_map.py +0 -0
- {golem_vm_provider-0.1.55 → golem_vm_provider-0.1.57}/provider/security/ethereum.py +0 -0
- {golem_vm_provider-0.1.55 → golem_vm_provider-0.1.57}/provider/security/faucet.py +0 -0
- {golem_vm_provider-0.1.55 → golem_vm_provider-0.1.57}/provider/security/l2_faucet.py +0 -0
- {golem_vm_provider-0.1.55 → golem_vm_provider-0.1.57}/provider/service.py +0 -0
- {golem_vm_provider-0.1.55 → golem_vm_provider-0.1.57}/provider/utils/__init__.py +0 -0
- {golem_vm_provider-0.1.55 → golem_vm_provider-0.1.57}/provider/utils/ascii_art.py +0 -0
- {golem_vm_provider-0.1.55 → golem_vm_provider-0.1.57}/provider/utils/port_display.py +0 -0
- {golem_vm_provider-0.1.55 → golem_vm_provider-0.1.57}/provider/utils/retry.py +0 -0
- {golem_vm_provider-0.1.55 → golem_vm_provider-0.1.57}/provider/utils/setup.py +0 -0
- {golem_vm_provider-0.1.55 → golem_vm_provider-0.1.57}/provider/vm/__init__.py +0 -0
- {golem_vm_provider-0.1.55 → golem_vm_provider-0.1.57}/provider/vm/cloud_init.py +0 -0
- {golem_vm_provider-0.1.55 → golem_vm_provider-0.1.57}/provider/vm/models.py +0 -0
- {golem_vm_provider-0.1.55 → golem_vm_provider-0.1.57}/provider/vm/multipass.py +0 -0
- {golem_vm_provider-0.1.55 → golem_vm_provider-0.1.57}/provider/vm/multipass_adapter.py +0 -0
- {golem_vm_provider-0.1.55 → golem_vm_provider-0.1.57}/provider/vm/name_mapper.py +0 -0
- {golem_vm_provider-0.1.55 → golem_vm_provider-0.1.57}/provider/vm/port_manager.py +0 -0
- {golem_vm_provider-0.1.55 → golem_vm_provider-0.1.57}/provider/vm/provider.py +0 -0
- {golem_vm_provider-0.1.55 → golem_vm_provider-0.1.57}/provider/vm/proxy_manager.py +0 -0
- {golem_vm_provider-0.1.55 → golem_vm_provider-0.1.57}/provider/vm/service.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: golem-vm-provider
|
3
|
-
Version: 0.1.
|
3
|
+
Version: 0.1.57
|
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
|
@@ -61,6 +61,69 @@ pip install golem-vm-provider
|
|
61
61
|
golem-provider start --network testnet
|
62
62
|
```
|
63
63
|
|
64
|
+
Verify your environment and connectivity anytime:
|
65
|
+
|
66
|
+
```bash
|
67
|
+
golem-provider status
|
68
|
+
```
|
69
|
+
This checks Multipass availability, local/external port reachability, and whether an update is available on PyPI.
|
70
|
+
|
71
|
+
### Status Command (TTY and JSON)
|
72
|
+
|
73
|
+
Use `golem-provider status` to quickly assess health.
|
74
|
+
|
75
|
+
TTY output highlights
|
76
|
+
|
77
|
+
```
|
78
|
+
Overall Error | Issues detected | Healthy
|
79
|
+
|
80
|
+
Multipass ✅ OK | ❌ Missing
|
81
|
+
|
82
|
+
Provider Port 0.0.0.0:7466
|
83
|
+
Local ✅ service is listening | ❌ port unavailable
|
84
|
+
External ✅ reachable | ❌ unreachable — <reason>
|
85
|
+
|
86
|
+
SSH Ports <start>-<end> — OK | limited — N issue(s) | blocked
|
87
|
+
Usable free <count> # free AND externally reachable
|
88
|
+
In use <count>
|
89
|
+
Issues e.g. "100 not reachable externally" or "3 unreachable, 1 not listening"
|
90
|
+
```
|
91
|
+
|
92
|
+
Severity rules
|
93
|
+
|
94
|
+
- Overall is Error when any critical prerequisite fails:
|
95
|
+
- Provider API port not externally reachable (or external check fails).
|
96
|
+
- No externally reachable SSH ports in the configured range.
|
97
|
+
- Multipass missing or provider local port not ready.
|
98
|
+
- Otherwise it shows Issues detected or Healthy.
|
99
|
+
|
100
|
+
Machine‑readable JSON
|
101
|
+
|
102
|
+
```bash
|
103
|
+
golem-provider status --json
|
104
|
+
```
|
105
|
+
|
106
|
+
Key fields:
|
107
|
+
|
108
|
+
- `overall.status`: "healthy" | "issues" | "error"
|
109
|
+
- `overall.issues`: list of concise issue strings
|
110
|
+
- `ports.provider`:
|
111
|
+
- `port`: int, `host`: string
|
112
|
+
- `status`: "reachable" | "unreachable" (external check failures are treated as "unreachable")
|
113
|
+
- `ports.ssh`:
|
114
|
+
- `range`: [start, end)
|
115
|
+
- `status`: "ok" | "limited" | "blocked"
|
116
|
+
- `usable_free`: integer — free AND externally reachable
|
117
|
+
- `in_use`: integer
|
118
|
+
- `issues`: `{ unreachable: int, not_listening: int }`
|
119
|
+
- `ports`: array of per‑port summaries:
|
120
|
+
- `{ port: int, status: "reachable" | "unreachable" | "unknown", listening: bool }`
|
121
|
+
|
122
|
+
Notes
|
123
|
+
|
124
|
+
- The concept of "free" in JSON is replaced by `usable_free` (free + externally reachable) to avoid misleading counts when ports are blocked.
|
125
|
+
- When the external checker is unavailable, per‑port `status` is `"unknown"` and `listening` still reflects local state.
|
126
|
+
|
64
127
|
3) Set pricing in USD (GLM rates auto‑compute):
|
65
128
|
|
66
129
|
```bash
|
@@ -592,13 +655,16 @@ The provider includes real-time port verification status:
|
|
592
655
|
|
593
656
|
Example status output:
|
594
657
|
|
595
|
-
```
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
658
|
+
```
|
659
|
+
Overall Healthy
|
660
|
+
|
661
|
+
Provider Port {host}:{provider_port}
|
662
|
+
Local ✅ service is listening
|
663
|
+
External ✅ reachable
|
664
|
+
|
665
|
+
SSH Ports {start_port}-{end_port_minus_one} — OK
|
666
|
+
Usable free {usable_free}
|
667
|
+
In use {in_use}
|
602
668
|
```
|
603
669
|
|
604
670
|
### Resource Allocation Issues
|
@@ -16,6 +16,69 @@ pip install golem-vm-provider
|
|
16
16
|
golem-provider start --network testnet
|
17
17
|
```
|
18
18
|
|
19
|
+
Verify your environment and connectivity anytime:
|
20
|
+
|
21
|
+
```bash
|
22
|
+
golem-provider status
|
23
|
+
```
|
24
|
+
This checks Multipass availability, local/external port reachability, and whether an update is available on PyPI.
|
25
|
+
|
26
|
+
### Status Command (TTY and JSON)
|
27
|
+
|
28
|
+
Use `golem-provider status` to quickly assess health.
|
29
|
+
|
30
|
+
TTY output highlights
|
31
|
+
|
32
|
+
```
|
33
|
+
Overall Error | Issues detected | Healthy
|
34
|
+
|
35
|
+
Multipass ✅ OK | ❌ Missing
|
36
|
+
|
37
|
+
Provider Port 0.0.0.0:7466
|
38
|
+
Local ✅ service is listening | ❌ port unavailable
|
39
|
+
External ✅ reachable | ❌ unreachable — <reason>
|
40
|
+
|
41
|
+
SSH Ports <start>-<end> — OK | limited — N issue(s) | blocked
|
42
|
+
Usable free <count> # free AND externally reachable
|
43
|
+
In use <count>
|
44
|
+
Issues e.g. "100 not reachable externally" or "3 unreachable, 1 not listening"
|
45
|
+
```
|
46
|
+
|
47
|
+
Severity rules
|
48
|
+
|
49
|
+
- Overall is Error when any critical prerequisite fails:
|
50
|
+
- Provider API port not externally reachable (or external check fails).
|
51
|
+
- No externally reachable SSH ports in the configured range.
|
52
|
+
- Multipass missing or provider local port not ready.
|
53
|
+
- Otherwise it shows Issues detected or Healthy.
|
54
|
+
|
55
|
+
Machine‑readable JSON
|
56
|
+
|
57
|
+
```bash
|
58
|
+
golem-provider status --json
|
59
|
+
```
|
60
|
+
|
61
|
+
Key fields:
|
62
|
+
|
63
|
+
- `overall.status`: "healthy" | "issues" | "error"
|
64
|
+
- `overall.issues`: list of concise issue strings
|
65
|
+
- `ports.provider`:
|
66
|
+
- `port`: int, `host`: string
|
67
|
+
- `status`: "reachable" | "unreachable" (external check failures are treated as "unreachable")
|
68
|
+
- `ports.ssh`:
|
69
|
+
- `range`: [start, end)
|
70
|
+
- `status`: "ok" | "limited" | "blocked"
|
71
|
+
- `usable_free`: integer — free AND externally reachable
|
72
|
+
- `in_use`: integer
|
73
|
+
- `issues`: `{ unreachable: int, not_listening: int }`
|
74
|
+
- `ports`: array of per‑port summaries:
|
75
|
+
- `{ port: int, status: "reachable" | "unreachable" | "unknown", listening: bool }`
|
76
|
+
|
77
|
+
Notes
|
78
|
+
|
79
|
+
- The concept of "free" in JSON is replaced by `usable_free` (free + externally reachable) to avoid misleading counts when ports are blocked.
|
80
|
+
- When the external checker is unavailable, per‑port `status` is `"unknown"` and `listening` still reflects local state.
|
81
|
+
|
19
82
|
3) Set pricing in USD (GLM rates auto‑compute):
|
20
83
|
|
21
84
|
```bash
|
@@ -547,13 +610,16 @@ The provider includes real-time port verification status:
|
|
547
610
|
|
548
611
|
Example status output:
|
549
612
|
|
550
|
-
```
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
613
|
+
```
|
614
|
+
Overall Healthy
|
615
|
+
|
616
|
+
Provider Port {host}:{provider_port}
|
617
|
+
Local ✅ service is listening
|
618
|
+
External ✅ reachable
|
619
|
+
|
620
|
+
SSH Ports {start_port}-{end_port_minus_one} — OK
|
621
|
+
Usable free {usable_free}
|
622
|
+
In use {in_use}
|
557
623
|
```
|
558
624
|
|
559
625
|
### Resource Allocation Issues
|
@@ -7,8 +7,7 @@ from fastapi import APIRouter, HTTPException, Request
|
|
7
7
|
from dependency_injector.wiring import inject, Provide
|
8
8
|
from fastapi import APIRouter, HTTPException, Depends
|
9
9
|
|
10
|
-
from
|
11
|
-
from ..config import Settings as _Cfg
|
10
|
+
from typing import TYPE_CHECKING, Any
|
12
11
|
from ..container import Container
|
13
12
|
from ..utils.logging import setup_logger
|
14
13
|
from ..utils.ascii_art import vm_creation_animation, vm_status_change
|
@@ -27,7 +26,7 @@ router = APIRouter()
|
|
27
26
|
async def create_vm(
|
28
27
|
request: CreateVMRequest,
|
29
28
|
vm_service: VMService = Depends(Provide[Container.vm_service]),
|
30
|
-
settings:
|
29
|
+
settings: Any = Depends(Provide[Container.config]),
|
31
30
|
stream_map = Depends(Provide[Container.stream_map]),
|
32
31
|
) -> VMInfo:
|
33
32
|
"""Create a new VM."""
|
@@ -39,11 +38,12 @@ async def create_vm(
|
|
39
38
|
# If payments are enabled, require a valid stream before starting
|
40
39
|
# Determine if we should enforce gating
|
41
40
|
enforce = False
|
42
|
-
spa = settings
|
41
|
+
spa = (settings.get("STREAM_PAYMENT_ADDRESS") if isinstance(settings, dict) else getattr(settings, "STREAM_PAYMENT_ADDRESS", None))
|
43
42
|
if spa and spa != "0x0000000000000000000000000000000000000000":
|
44
43
|
if os.environ.get("PYTEST_CURRENT_TEST"):
|
45
44
|
# In pytest, skip gating only when using default deployment address
|
46
45
|
try:
|
46
|
+
from ..config import Settings as _Cfg # type: ignore
|
47
47
|
default_spa, _ = _Cfg._load_l2_deployment() # type: ignore[attr-defined]
|
48
48
|
except Exception:
|
49
49
|
default_spa = None
|
@@ -54,8 +54,10 @@ async def create_vm(
|
|
54
54
|
if enforce:
|
55
55
|
if request.stream_id is None:
|
56
56
|
raise HTTPException(status_code=400, detail="stream_id required when payments are enabled")
|
57
|
-
|
58
|
-
|
57
|
+
rpc_url = settings.get("POLYGON_RPC_URL") if isinstance(settings, dict) else getattr(settings, "POLYGON_RPC_URL", None)
|
58
|
+
reader = StreamPaymentReader(rpc_url, spa)
|
59
|
+
expected_recipient = settings.get("PROVIDER_ID") if isinstance(settings, dict) else getattr(settings, "PROVIDER_ID", None)
|
60
|
+
ok, reason = reader.verify_stream(int(request.stream_id), expected_recipient)
|
59
61
|
try:
|
60
62
|
s = reader.get_stream(int(request.stream_id))
|
61
63
|
now = int(reader.web3.eth.get_block("latest")["timestamp"]) # type: ignore[attr-defined]
|
@@ -73,7 +75,7 @@ async def create_vm(
|
|
73
75
|
# Create VM config
|
74
76
|
config = VMConfig(
|
75
77
|
name=request.name,
|
76
|
-
image=request.image or settings
|
78
|
+
image=request.image or (settings.get("DEFAULT_VM_IMAGE") if isinstance(settings, dict) else getattr(settings, "DEFAULT_VM_IMAGE", "")),
|
77
79
|
resources=resources,
|
78
80
|
ssh_key=request.ssh_key
|
79
81
|
)
|
@@ -143,7 +145,7 @@ async def get_vm_status(
|
|
143
145
|
async def get_vm_access(
|
144
146
|
requestor_name: str,
|
145
147
|
vm_service: VMService = Depends(Provide[Container.vm_service]),
|
146
|
-
settings:
|
148
|
+
settings: Any = Depends(Provide[Container.config]),
|
147
149
|
) -> VMAccessInfo:
|
148
150
|
"""Get VM access information."""
|
149
151
|
try:
|
@@ -156,7 +158,7 @@ async def get_vm_access(
|
|
156
158
|
raise HTTPException(404, "VM mapping not found")
|
157
159
|
|
158
160
|
return VMAccessInfo(
|
159
|
-
ssh_host=settings
|
161
|
+
ssh_host=((settings.get("PUBLIC_IP") if isinstance(settings, dict) else getattr(settings, "PUBLIC_IP", None)) or "localhost"),
|
160
162
|
ssh_port=vm.ssh_port,
|
161
163
|
vm_id=requestor_name,
|
162
164
|
multipass_name=multipass_name
|
@@ -222,7 +224,7 @@ async def delete_vm(
|
|
222
224
|
raise HTTPException(status_code=500, detail="An unexpected error occurred")
|
223
225
|
@router.get("/provider/info", response_model=ProviderInfoResponse)
|
224
226
|
@inject
|
225
|
-
async def provider_info(settings:
|
227
|
+
async def provider_info(settings: Any = Depends(Provide[Container.config])) -> ProviderInfoResponse:
|
226
228
|
return ProviderInfoResponse(
|
227
229
|
provider_id=settings["PROVIDER_ID"],
|
228
230
|
stream_payment_address=settings["STREAM_PAYMENT_ADDRESS"],
|
@@ -234,7 +236,7 @@ async def provider_info(settings: Settings = Depends(Provide[Container.config]))
|
|
234
236
|
@inject
|
235
237
|
async def get_vm_stream_status(
|
236
238
|
requestor_name: str,
|
237
|
-
settings:
|
239
|
+
settings: Any = Depends(Provide[Container.config]),
|
238
240
|
stream_map = Depends(Provide[Container.stream_map]),
|
239
241
|
) -> StreamStatus:
|
240
242
|
"""Return on-chain stream status for a VM (if mapped)."""
|
@@ -266,7 +268,7 @@ async def get_vm_stream_status(
|
|
266
268
|
@router.get("/payments/streams", response_model=List[StreamStatus])
|
267
269
|
@inject
|
268
270
|
async def list_stream_statuses(
|
269
|
-
settings:
|
271
|
+
settings: Any = Depends(Provide[Container.config]),
|
270
272
|
stream_map = Depends(Provide[Container.stream_map]),
|
271
273
|
) -> List[StreamStatus]:
|
272
274
|
"""List stream status for all mapped VMs."""
|
@@ -38,7 +38,8 @@ def ensure_config() -> None:
|
|
38
38
|
created = True
|
39
39
|
|
40
40
|
if created:
|
41
|
-
|
41
|
+
# Inform the user, but write to stderr so JSON outputs on stdout remain clean
|
42
|
+
logger.info("Using default settings – run with --help to customize")
|
42
43
|
|
43
44
|
|
44
45
|
if not os.environ.get("GOLEM_PROVIDER_SKIP_BOOTSTRAP") and not os.environ.get("PYTEST_CURRENT_TEST"):
|
@@ -2,7 +2,6 @@ import os
|
|
2
2
|
from dependency_injector import containers, providers
|
3
3
|
from pathlib import Path
|
4
4
|
|
5
|
-
from .config import settings
|
6
5
|
from .discovery.resource_tracker import ResourceTracker
|
7
6
|
from .discovery.golem_base_advertiser import GolemBaseAdvertiser
|
8
7
|
from .discovery.advertiser import DiscoveryServerAdvertiser
|
@@ -49,12 +48,12 @@ class Container(containers.DeclarativeContainer):
|
|
49
48
|
|
50
49
|
vm_name_mapper = providers.Singleton(
|
51
50
|
VMNameMapper,
|
52
|
-
db_path=Path(
|
51
|
+
db_path=providers.Callable(lambda base: Path(base) / "vm_names.json", config.VM_DATA_DIR),
|
53
52
|
)
|
54
53
|
|
55
54
|
stream_map = providers.Singleton(
|
56
55
|
StreamMap,
|
57
|
-
storage_path=Path(
|
56
|
+
storage_path=providers.Callable(lambda base: Path(base) / "streams.json", config.VM_DATA_DIR),
|
58
57
|
)
|
59
58
|
|
60
59
|
port_manager = providers.Singleton(
|