request-vm-on-golem 0.1.51__tar.gz → 0.1.53__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.
- {request_vm_on_golem-0.1.51 → request_vm_on_golem-0.1.53}/PKG-INFO +65 -36
- {request_vm_on_golem-0.1.51 → request_vm_on_golem-0.1.53}/README.md +64 -35
- {request_vm_on_golem-0.1.51 → request_vm_on_golem-0.1.53}/pyproject.toml +1 -1
- {request_vm_on_golem-0.1.51 → request_vm_on_golem-0.1.53}/requestor/cli/commands.py +52 -9
- {request_vm_on_golem-0.1.51 → request_vm_on_golem-0.1.53}/requestor/config.py +112 -16
- {request_vm_on_golem-0.1.51 → request_vm_on_golem-0.1.53}/requestor/security/faucet.py +5 -2
- {request_vm_on_golem-0.1.51 → request_vm_on_golem-0.1.53}/requestor/services/provider_service.py +16 -3
- {request_vm_on_golem-0.1.51 → request_vm_on_golem-0.1.53}/requestor/__init__.py +0 -0
- {request_vm_on_golem-0.1.51 → request_vm_on_golem-0.1.53}/requestor/api/main.py +0 -0
- {request_vm_on_golem-0.1.51 → request_vm_on_golem-0.1.53}/requestor/cli/__init__.py +0 -0
- {request_vm_on_golem-0.1.51 → request_vm_on_golem-0.1.53}/requestor/data/deployments/l2.json +0 -0
- {request_vm_on_golem-0.1.51 → request_vm_on_golem-0.1.53}/requestor/db/__init__.py +0 -0
- {request_vm_on_golem-0.1.51 → request_vm_on_golem-0.1.53}/requestor/db/sqlite.py +0 -0
- {request_vm_on_golem-0.1.51 → request_vm_on_golem-0.1.53}/requestor/errors.py +0 -0
- {request_vm_on_golem-0.1.51 → request_vm_on_golem-0.1.53}/requestor/payments/blockchain_service.py +0 -0
- {request_vm_on_golem-0.1.51 → request_vm_on_golem-0.1.53}/requestor/payments/monitor.py +0 -0
- {request_vm_on_golem-0.1.51 → request_vm_on_golem-0.1.53}/requestor/provider/__init__.py +0 -0
- {request_vm_on_golem-0.1.51 → request_vm_on_golem-0.1.53}/requestor/provider/client.py +0 -0
- {request_vm_on_golem-0.1.51 → request_vm_on_golem-0.1.53}/requestor/run.py +0 -0
- {request_vm_on_golem-0.1.51 → request_vm_on_golem-0.1.53}/requestor/services/__init__.py +0 -0
- {request_vm_on_golem-0.1.51 → request_vm_on_golem-0.1.53}/requestor/services/database_service.py +0 -0
- {request_vm_on_golem-0.1.51 → request_vm_on_golem-0.1.53}/requestor/services/ssh_service.py +0 -0
- {request_vm_on_golem-0.1.51 → request_vm_on_golem-0.1.53}/requestor/services/vm_service.py +0 -0
- {request_vm_on_golem-0.1.51 → request_vm_on_golem-0.1.53}/requestor/ssh/__init__.py +0 -0
- {request_vm_on_golem-0.1.51 → request_vm_on_golem-0.1.53}/requestor/ssh/manager.py +0 -0
- {request_vm_on_golem-0.1.51 → request_vm_on_golem-0.1.53}/requestor/utils/logging.py +0 -0
- {request_vm_on_golem-0.1.51 → request_vm_on_golem-0.1.53}/requestor/utils/spinner.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: request-vm-on-golem
|
3
|
-
Version: 0.1.
|
3
|
+
Version: 0.1.53
|
4
4
|
Summary: VM on Golem Requestor CLI - Create and manage virtual machines on the Golem Network
|
5
5
|
Keywords: golem,vm,cloud,decentralized,cli
|
6
6
|
Author: Phillip Jensen
|
@@ -41,7 +41,46 @@ Description-Content-Type: text/markdown
|
|
41
41
|
|
42
42
|
# VM on Golem Requestor
|
43
43
|
|
44
|
-
|
44
|
+
Rent compute on demand — like Airbnb for servers. The `golem` CLI helps you discover providers, fund pay‑as‑you‑go streams, launch VMs, and connect via SSH.
|
45
|
+
|
46
|
+
## Quick Start (Rent a VM)
|
47
|
+
|
48
|
+
1) Install:
|
49
|
+
|
50
|
+
```bash
|
51
|
+
pip install request-vm-on-golem
|
52
|
+
```
|
53
|
+
|
54
|
+
2) Find providers (testnet by default):
|
55
|
+
|
56
|
+
```bash
|
57
|
+
golem vm providers
|
58
|
+
```
|
59
|
+
|
60
|
+
3) Create a VM (auto‑opens a payment stream if needed):
|
61
|
+
|
62
|
+
```bash
|
63
|
+
golem vm create my-vm --provider-id 0xProvider --cpu 2 --memory 4 --storage 20
|
64
|
+
```
|
65
|
+
|
66
|
+
4) SSH in:
|
67
|
+
|
68
|
+
```bash
|
69
|
+
golem vm ssh my-vm
|
70
|
+
```
|
71
|
+
|
72
|
+
Check your installed version and whether an update is available:
|
73
|
+
|
74
|
+
```bash
|
75
|
+
golem version
|
76
|
+
```
|
77
|
+
|
78
|
+
5) Stop or destroy when done:
|
79
|
+
|
80
|
+
```bash
|
81
|
+
golem vm stop my-vm
|
82
|
+
golem vm destroy my-vm
|
83
|
+
```
|
45
84
|
|
46
85
|
## Architecture Overview
|
47
86
|
|
@@ -141,7 +180,7 @@ CLI helpers
|
|
141
180
|
- Open a stream for a planned VM (computes rate from provider pricing):
|
142
181
|
|
143
182
|
```bash
|
144
|
-
|
183
|
+
golem vm stream open \
|
145
184
|
--provider-id 0xProvider \
|
146
185
|
--cpu 2 --memory 4 --storage 20 \
|
147
186
|
--hours 1
|
@@ -152,39 +191,39 @@ poetry run golem vm stream open \
|
|
152
191
|
|
153
192
|
```bash
|
154
193
|
# Add 3 hours at prior rate
|
155
|
-
|
194
|
+
golem vm stream topup --stream-id 123 --hours 3
|
156
195
|
|
157
196
|
# Or specify exact GLM amount
|
158
|
-
|
197
|
+
golem vm stream topup --stream-id 123 --glm 25.0
|
159
198
|
```
|
160
199
|
|
161
200
|
- Check stream status via provider (by VM name recorded in your DB):
|
162
201
|
|
163
202
|
```bash
|
164
|
-
|
203
|
+
golem vm stream status my-vm
|
165
204
|
# add --json for machine-readable output
|
166
205
|
```
|
167
206
|
|
168
207
|
- Inspect a stream directly on-chain:
|
169
208
|
|
170
209
|
```bash
|
171
|
-
|
210
|
+
golem vm stream inspect --stream-id 123
|
172
211
|
```
|
173
212
|
|
174
213
|
- Stopping or destroying a VM ends the stream:
|
175
214
|
|
176
215
|
```bash
|
177
216
|
# Stop VM and terminate payment stream (best-effort)
|
178
|
-
|
217
|
+
golem vm stop my-vm
|
179
218
|
|
180
219
|
# Destroy VM and terminate stream
|
181
|
-
|
220
|
+
golem vm destroy my-vm
|
182
221
|
```
|
183
222
|
|
184
223
|
- Create a VM and attach an existing stream (no auto-streams are created by the requestor):
|
185
224
|
|
186
225
|
```bash
|
187
|
-
|
226
|
+
golem vm create my-vm \
|
188
227
|
--provider-id 0xProvider \
|
189
228
|
--cpu 2 --memory 4 --storage 20 \
|
190
229
|
--stream-id 123
|
@@ -192,7 +231,8 @@ poetry run golem vm create my-vm \
|
|
192
231
|
|
193
232
|
Environment (env prefix `GOLEM_REQUESTOR_`):
|
194
233
|
|
195
|
-
- `
|
234
|
+
- `payments_network` — Payments network profile (defaults to `l2.holesky`). Profiles provide RPC + faucet defaults.
|
235
|
+
- `polygon_rpc_url` — EVM RPC URL (defaults from `payments_network` profile; can be overridden)
|
196
236
|
- `stream_payment_address` — StreamPayment address (defaults from `contracts/deployments/l2.json`; overridden by provider info)
|
197
237
|
- `glm_token_address` — Token address (defaults from `contracts/deployments/l2.json`; zero address means native ETH)
|
198
238
|
- Optional override of deployments directory: set `GOLEM_DEPLOYMENTS_DIR` to a folder containing `l2.json`.
|
@@ -210,16 +250,16 @@ Monitoring and auto top-up:
|
|
210
250
|
- The requestor API runs a background monitor that keeps each running VM’s stream funded with at least 1 hour runway (configurable). It checks every 30s and tops up to the target runway.
|
211
251
|
- Configure via env (prefix `GOLEM_REQUESTOR_`): `stream_monitor_enabled` (default true), `stream_monitor_interval_seconds` (default 30), `stream_min_remaining_seconds` (default 3600), `stream_topup_target_seconds` (default 3600).
|
212
252
|
|
213
|
-
## Faucet (
|
253
|
+
## Faucet (Testnet only)
|
214
254
|
|
215
255
|
- Request L2 test ETH to cover stream transactions:
|
216
256
|
|
217
257
|
```bash
|
218
|
-
|
258
|
+
golem wallet faucet
|
219
259
|
```
|
220
260
|
|
221
261
|
- Defaults:
|
222
|
-
- Faucet
|
262
|
+
- Faucet URL and enablement come from the active `payments_network` profile. On `mainnet` (or other profiles without faucet) the command is disabled.
|
223
263
|
- CAPTCHA: `https://cap.gobas.me/05381a2cef5e`
|
224
264
|
- Override with env: `GOLEM_REQUESTOR_l2_faucet_url`, `GOLEM_REQUESTOR_captcha_url`, `GOLEM_REQUESTOR_captcha_api_key`.
|
225
265
|
|
@@ -227,7 +267,7 @@ poetry run golem wallet faucet
|
|
227
267
|
|
228
268
|
```bash
|
229
269
|
# Install using pip
|
230
|
-
pip install
|
270
|
+
pip install request-vm-on-golem
|
231
271
|
|
232
272
|
# Or install from source
|
233
273
|
git clone https://github.com/golem/vm-on-golem.git
|
@@ -249,11 +289,7 @@ First, source the development environment variables:
|
|
249
289
|
source .env.dev
|
250
290
|
```
|
251
291
|
|
252
|
-
Then, run any `golem` command. For example:
|
253
|
-
|
254
|
-
```bash
|
255
|
-
poetry run golem vm providers
|
256
|
-
```
|
292
|
+
Then, run any `golem` command. For example: `golem vm providers`
|
257
293
|
|
258
294
|
### Prepending variables
|
259
295
|
|
@@ -270,19 +306,15 @@ GOLEM_REQUESTOR_ENVIRONMENT="development" GOLEM_REQUESTOR_FORCE_LOCALHOST="true"
|
|
270
306
|
- Does not determine chain selection.
|
271
307
|
|
272
308
|
- Network Selection (`--network` or `GOLEM_REQUESTOR_NETWORK`)
|
273
|
-
- Filters
|
274
|
-
|
275
|
-
|
309
|
+
- Filters results by `testnet|mainnet`. Defaults are sensible; most users don’t need to change anything.
|
310
|
+
|
311
|
+
- Payments Network (`GOLEM_REQUESTOR_PAYMENTS_NETWORK`)
|
312
|
+
- Selects the payments chain profile (e.g., `l2.holesky`, `mainnet`) used for streaming payments; sets default RPC and faucet behavior.
|
313
|
+
- Provider discovery filters by this payments network via `vm providers` unless `--all-payments` is supplied. Override payments filter with `--payments-network <name>`.
|
276
314
|
|
277
315
|
Examples:
|
278
|
-
- List providers on mainnet without changing env:
|
279
|
-
|
280
|
-
poetry run golem vm providers --network mainnet
|
281
|
-
```
|
282
|
-
- Create a VM while targeting testnet:
|
283
|
-
```bash
|
284
|
-
poetry run golem vm create my-vm --provider-id 0xProvider --cpu 2 --memory 4 --storage 20 --network testnet
|
285
|
-
```
|
316
|
+
- List providers on mainnet without changing env: `golem vm providers --network mainnet`
|
317
|
+
- Create a VM while targeting testnet: `golem vm create my-vm --provider-id 0xProvider --cpu 2 --memory 4 --storage 20 --network testnet`
|
286
318
|
|
287
319
|
## Usage
|
288
320
|
|
@@ -388,9 +420,6 @@ The requestor uses a hierarchical configuration system:
|
|
388
420
|
1. Environment Variables:
|
389
421
|
|
390
422
|
```bash
|
391
|
-
# Discovery Service
|
392
|
-
export GOLEM_REQUESTOR_DISCOVERY_URL="http://discovery.golem.network:9001"
|
393
|
-
|
394
423
|
# Base Directory (default: ~/.golem)
|
395
424
|
export GOLEM_REQUESTOR_BASE_DIR="/path/to/golem/dir"
|
396
425
|
|
@@ -401,7 +430,7 @@ export GOLEM_REQUESTOR_DB_PATH="/path/to/database.db"
|
|
401
430
|
# Environment Mode (defaults to "production")
|
402
431
|
export GOLEM_REQUESTOR_ENVIRONMENT="development" # Optional: Switch to development mode
|
403
432
|
export GOLEM_REQUESTOR_FORCE_LOCALHOST="true" # Optional: Force localhost in development mode
|
404
|
-
export GOLEM_REQUESTOR_NETWORK="testnet" # Or "mainnet";
|
433
|
+
export GOLEM_REQUESTOR_NETWORK="testnet" # Or "mainnet"; optional filter for listing/creation
|
405
434
|
```
|
406
435
|
|
407
436
|
2. Directory Structure:
|
@@ -438,7 +467,7 @@ Local state is maintained in SQLite:
|
|
438
467
|
|
439
468
|
The requestor communicates with providers through:
|
440
469
|
|
441
|
-
1.
|
470
|
+
1. Network discovery (uses sane defaults; no setup required for most users)
|
442
471
|
2. Direct API calls for VM management
|
443
472
|
3. SSH proxy system for secure access
|
444
473
|
4. Resource tracking for capacity management
|
@@ -1,6 +1,45 @@
|
|
1
1
|
# VM on Golem Requestor
|
2
2
|
|
3
|
-
|
3
|
+
Rent compute on demand — like Airbnb for servers. The `golem` CLI helps you discover providers, fund pay‑as‑you‑go streams, launch VMs, and connect via SSH.
|
4
|
+
|
5
|
+
## Quick Start (Rent a VM)
|
6
|
+
|
7
|
+
1) Install:
|
8
|
+
|
9
|
+
```bash
|
10
|
+
pip install request-vm-on-golem
|
11
|
+
```
|
12
|
+
|
13
|
+
2) Find providers (testnet by default):
|
14
|
+
|
15
|
+
```bash
|
16
|
+
golem vm providers
|
17
|
+
```
|
18
|
+
|
19
|
+
3) Create a VM (auto‑opens a payment stream if needed):
|
20
|
+
|
21
|
+
```bash
|
22
|
+
golem vm create my-vm --provider-id 0xProvider --cpu 2 --memory 4 --storage 20
|
23
|
+
```
|
24
|
+
|
25
|
+
4) SSH in:
|
26
|
+
|
27
|
+
```bash
|
28
|
+
golem vm ssh my-vm
|
29
|
+
```
|
30
|
+
|
31
|
+
Check your installed version and whether an update is available:
|
32
|
+
|
33
|
+
```bash
|
34
|
+
golem version
|
35
|
+
```
|
36
|
+
|
37
|
+
5) Stop or destroy when done:
|
38
|
+
|
39
|
+
```bash
|
40
|
+
golem vm stop my-vm
|
41
|
+
golem vm destroy my-vm
|
42
|
+
```
|
4
43
|
|
5
44
|
## Architecture Overview
|
6
45
|
|
@@ -100,7 +139,7 @@ CLI helpers
|
|
100
139
|
- Open a stream for a planned VM (computes rate from provider pricing):
|
101
140
|
|
102
141
|
```bash
|
103
|
-
|
142
|
+
golem vm stream open \
|
104
143
|
--provider-id 0xProvider \
|
105
144
|
--cpu 2 --memory 4 --storage 20 \
|
106
145
|
--hours 1
|
@@ -111,39 +150,39 @@ poetry run golem vm stream open \
|
|
111
150
|
|
112
151
|
```bash
|
113
152
|
# Add 3 hours at prior rate
|
114
|
-
|
153
|
+
golem vm stream topup --stream-id 123 --hours 3
|
115
154
|
|
116
155
|
# Or specify exact GLM amount
|
117
|
-
|
156
|
+
golem vm stream topup --stream-id 123 --glm 25.0
|
118
157
|
```
|
119
158
|
|
120
159
|
- Check stream status via provider (by VM name recorded in your DB):
|
121
160
|
|
122
161
|
```bash
|
123
|
-
|
162
|
+
golem vm stream status my-vm
|
124
163
|
# add --json for machine-readable output
|
125
164
|
```
|
126
165
|
|
127
166
|
- Inspect a stream directly on-chain:
|
128
167
|
|
129
168
|
```bash
|
130
|
-
|
169
|
+
golem vm stream inspect --stream-id 123
|
131
170
|
```
|
132
171
|
|
133
172
|
- Stopping or destroying a VM ends the stream:
|
134
173
|
|
135
174
|
```bash
|
136
175
|
# Stop VM and terminate payment stream (best-effort)
|
137
|
-
|
176
|
+
golem vm stop my-vm
|
138
177
|
|
139
178
|
# Destroy VM and terminate stream
|
140
|
-
|
179
|
+
golem vm destroy my-vm
|
141
180
|
```
|
142
181
|
|
143
182
|
- Create a VM and attach an existing stream (no auto-streams are created by the requestor):
|
144
183
|
|
145
184
|
```bash
|
146
|
-
|
185
|
+
golem vm create my-vm \
|
147
186
|
--provider-id 0xProvider \
|
148
187
|
--cpu 2 --memory 4 --storage 20 \
|
149
188
|
--stream-id 123
|
@@ -151,7 +190,8 @@ poetry run golem vm create my-vm \
|
|
151
190
|
|
152
191
|
Environment (env prefix `GOLEM_REQUESTOR_`):
|
153
192
|
|
154
|
-
- `
|
193
|
+
- `payments_network` — Payments network profile (defaults to `l2.holesky`). Profiles provide RPC + faucet defaults.
|
194
|
+
- `polygon_rpc_url` — EVM RPC URL (defaults from `payments_network` profile; can be overridden)
|
155
195
|
- `stream_payment_address` — StreamPayment address (defaults from `contracts/deployments/l2.json`; overridden by provider info)
|
156
196
|
- `glm_token_address` — Token address (defaults from `contracts/deployments/l2.json`; zero address means native ETH)
|
157
197
|
- Optional override of deployments directory: set `GOLEM_DEPLOYMENTS_DIR` to a folder containing `l2.json`.
|
@@ -169,16 +209,16 @@ Monitoring and auto top-up:
|
|
169
209
|
- The requestor API runs a background monitor that keeps each running VM’s stream funded with at least 1 hour runway (configurable). It checks every 30s and tops up to the target runway.
|
170
210
|
- Configure via env (prefix `GOLEM_REQUESTOR_`): `stream_monitor_enabled` (default true), `stream_monitor_interval_seconds` (default 30), `stream_min_remaining_seconds` (default 3600), `stream_topup_target_seconds` (default 3600).
|
171
211
|
|
172
|
-
## Faucet (
|
212
|
+
## Faucet (Testnet only)
|
173
213
|
|
174
214
|
- Request L2 test ETH to cover stream transactions:
|
175
215
|
|
176
216
|
```bash
|
177
|
-
|
217
|
+
golem wallet faucet
|
178
218
|
```
|
179
219
|
|
180
220
|
- Defaults:
|
181
|
-
- Faucet
|
221
|
+
- Faucet URL and enablement come from the active `payments_network` profile. On `mainnet` (or other profiles without faucet) the command is disabled.
|
182
222
|
- CAPTCHA: `https://cap.gobas.me/05381a2cef5e`
|
183
223
|
- Override with env: `GOLEM_REQUESTOR_l2_faucet_url`, `GOLEM_REQUESTOR_captcha_url`, `GOLEM_REQUESTOR_captcha_api_key`.
|
184
224
|
|
@@ -186,7 +226,7 @@ poetry run golem wallet faucet
|
|
186
226
|
|
187
227
|
```bash
|
188
228
|
# Install using pip
|
189
|
-
pip install
|
229
|
+
pip install request-vm-on-golem
|
190
230
|
|
191
231
|
# Or install from source
|
192
232
|
git clone https://github.com/golem/vm-on-golem.git
|
@@ -208,11 +248,7 @@ First, source the development environment variables:
|
|
208
248
|
source .env.dev
|
209
249
|
```
|
210
250
|
|
211
|
-
Then, run any `golem` command. For example:
|
212
|
-
|
213
|
-
```bash
|
214
|
-
poetry run golem vm providers
|
215
|
-
```
|
251
|
+
Then, run any `golem` command. For example: `golem vm providers`
|
216
252
|
|
217
253
|
### Prepending variables
|
218
254
|
|
@@ -229,19 +265,15 @@ GOLEM_REQUESTOR_ENVIRONMENT="development" GOLEM_REQUESTOR_FORCE_LOCALHOST="true"
|
|
229
265
|
- Does not determine chain selection.
|
230
266
|
|
231
267
|
- Network Selection (`--network` or `GOLEM_REQUESTOR_NETWORK`)
|
232
|
-
- Filters
|
233
|
-
|
234
|
-
|
268
|
+
- Filters results by `testnet|mainnet`. Defaults are sensible; most users don’t need to change anything.
|
269
|
+
|
270
|
+
- Payments Network (`GOLEM_REQUESTOR_PAYMENTS_NETWORK`)
|
271
|
+
- Selects the payments chain profile (e.g., `l2.holesky`, `mainnet`) used for streaming payments; sets default RPC and faucet behavior.
|
272
|
+
- Provider discovery filters by this payments network via `vm providers` unless `--all-payments` is supplied. Override payments filter with `--payments-network <name>`.
|
235
273
|
|
236
274
|
Examples:
|
237
|
-
- List providers on mainnet without changing env:
|
238
|
-
|
239
|
-
poetry run golem vm providers --network mainnet
|
240
|
-
```
|
241
|
-
- Create a VM while targeting testnet:
|
242
|
-
```bash
|
243
|
-
poetry run golem vm create my-vm --provider-id 0xProvider --cpu 2 --memory 4 --storage 20 --network testnet
|
244
|
-
```
|
275
|
+
- List providers on mainnet without changing env: `golem vm providers --network mainnet`
|
276
|
+
- Create a VM while targeting testnet: `golem vm create my-vm --provider-id 0xProvider --cpu 2 --memory 4 --storage 20 --network testnet`
|
245
277
|
|
246
278
|
## Usage
|
247
279
|
|
@@ -347,9 +379,6 @@ The requestor uses a hierarchical configuration system:
|
|
347
379
|
1. Environment Variables:
|
348
380
|
|
349
381
|
```bash
|
350
|
-
# Discovery Service
|
351
|
-
export GOLEM_REQUESTOR_DISCOVERY_URL="http://discovery.golem.network:9001"
|
352
|
-
|
353
382
|
# Base Directory (default: ~/.golem)
|
354
383
|
export GOLEM_REQUESTOR_BASE_DIR="/path/to/golem/dir"
|
355
384
|
|
@@ -360,7 +389,7 @@ export GOLEM_REQUESTOR_DB_PATH="/path/to/database.db"
|
|
360
389
|
# Environment Mode (defaults to "production")
|
361
390
|
export GOLEM_REQUESTOR_ENVIRONMENT="development" # Optional: Switch to development mode
|
362
391
|
export GOLEM_REQUESTOR_FORCE_LOCALHOST="true" # Optional: Force localhost in development mode
|
363
|
-
export GOLEM_REQUESTOR_NETWORK="testnet" # Or "mainnet";
|
392
|
+
export GOLEM_REQUESTOR_NETWORK="testnet" # Or "mainnet"; optional filter for listing/creation
|
364
393
|
```
|
365
394
|
|
366
395
|
2. Directory Structure:
|
@@ -397,7 +426,7 @@ Local state is maintained in SQLite:
|
|
397
426
|
|
398
427
|
The requestor communicates with providers through:
|
399
428
|
|
400
|
-
1.
|
429
|
+
1. Network discovery (uses sane defaults; no setup required for most users)
|
401
430
|
2. Direct API calls for VM management
|
402
431
|
3. SSH proxy system for secure access
|
403
432
|
4. Resource tracking for capacity management
|
@@ -1,6 +1,6 @@
|
|
1
1
|
[tool.poetry]
|
2
2
|
name = "request-vm-on-golem"
|
3
|
-
version = "0.1.
|
3
|
+
version = "0.1.53"
|
4
4
|
description = "VM on Golem Requestor CLI - Create and manage virtual machines on the Golem Network"
|
5
5
|
authors = ["Phillip Jensen <phillip+vm-on-golem@golemgrid.com>"]
|
6
6
|
readme = "README.md"
|
@@ -5,6 +5,7 @@ import json
|
|
5
5
|
from typing import Optional
|
6
6
|
from pathlib import Path
|
7
7
|
import subprocess
|
8
|
+
import os
|
8
9
|
import aiohttp
|
9
10
|
from tabulate import tabulate
|
10
11
|
import uvicorn
|
@@ -89,6 +90,33 @@ def cli(network: str | None):
|
|
89
90
|
pass
|
90
91
|
|
91
92
|
|
93
|
+
@cli.command(name="version")
|
94
|
+
def version_cmd():
|
95
|
+
"""Show installed and latest versions from PyPI."""
|
96
|
+
pkg = "request-vm-on-golem"
|
97
|
+
try:
|
98
|
+
current = metadata.version(pkg)
|
99
|
+
except Exception:
|
100
|
+
current = "unknown"
|
101
|
+
latest = None
|
102
|
+
# Avoid network during pytest
|
103
|
+
if not os.environ.get("PYTEST_CURRENT_TEST"):
|
104
|
+
try:
|
105
|
+
import json as _json
|
106
|
+
from urllib.request import urlopen
|
107
|
+
with urlopen(f"https://pypi.org/pypi/{pkg}/json", timeout=5) as resp:
|
108
|
+
data = _json.loads(resp.read().decode("utf-8"))
|
109
|
+
latest = data.get("info", {}).get("version")
|
110
|
+
except Exception:
|
111
|
+
latest = None
|
112
|
+
|
113
|
+
if latest and latest != current:
|
114
|
+
click.echo(f"Requestor CLI: {current} (update available: {latest})")
|
115
|
+
click.echo("Update: pip install -U request-vm-on-golem")
|
116
|
+
else:
|
117
|
+
click.echo(f"Requestor CLI: {current} (up-to-date)" if latest else f"Requestor CLI: {current}")
|
118
|
+
|
119
|
+
|
92
120
|
@cli.group()
|
93
121
|
def vm():
|
94
122
|
"""VM management commands"""
|
@@ -101,11 +129,13 @@ def vm():
|
|
101
129
|
@click.option('--storage', type=int, help='Minimum disk (GB) required')
|
102
130
|
@click.option('--country', help='Preferred provider country')
|
103
131
|
@click.option('--driver', type=click.Choice(['central', 'golem-base']), default=None, help='Discovery driver to use')
|
132
|
+
@click.option('--payments-network', type=str, default=None, help='Filter by payments network profile (default: current config)')
|
133
|
+
@click.option('--all-payments', is_flag=True, help='Do not filter by payments network (show all)')
|
104
134
|
@click.option('--json', 'as_json', is_flag=True, help='Output in JSON format')
|
105
135
|
@click.option('--network', type=click.Choice(['testnet', 'mainnet']), default=None,
|
106
136
|
help='Override network filter for this command')
|
107
137
|
@async_command
|
108
|
-
async def list_providers(cpu: Optional[int], memory: Optional[int], storage: Optional[int], country: Optional[str], driver: Optional[str], as_json: bool, network: Optional[str] = None):
|
138
|
+
async def list_providers(cpu: Optional[int], memory: Optional[int], storage: Optional[int], country: Optional[str], driver: Optional[str], payments_network: Optional[str] = None, all_payments: bool = False, as_json: bool = False, network: Optional[str] = None):
|
109
139
|
"""List available providers matching requirements."""
|
110
140
|
try:
|
111
141
|
if network:
|
@@ -124,7 +154,8 @@ async def list_providers(cpu: Optional[int], memory: Optional[int], storage: Opt
|
|
124
154
|
|
125
155
|
# Determine the discovery driver being used
|
126
156
|
discovery_driver = driver or config.discovery_driver
|
127
|
-
|
157
|
+
eff_pn = payments_network if payments_network is not None else getattr(config, 'payments_network', None)
|
158
|
+
logger.process(f"Querying discovery via {discovery_driver} (network={config.network}, payments={eff_pn if not all_payments else 'ALL'})")
|
128
159
|
|
129
160
|
# Initialize provider service
|
130
161
|
provider_service = ProviderService()
|
@@ -132,13 +163,21 @@ async def list_providers(cpu: Optional[int], memory: Optional[int], storage: Opt
|
|
132
163
|
# If a full spec is provided, enable per-provider estimate display
|
133
164
|
if cpu and memory and storage:
|
134
165
|
provider_service.estimate_spec = (cpu, memory, storage)
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
166
|
+
try:
|
167
|
+
providers = await provider_service.find_providers(
|
168
|
+
cpu=cpu,
|
169
|
+
memory=memory,
|
170
|
+
storage=storage,
|
171
|
+
country=country,
|
172
|
+
driver=driver,
|
173
|
+
payments_network=eff_pn,
|
174
|
+
include_all_payments=bool(all_payments),
|
175
|
+
)
|
176
|
+
except TypeError:
|
177
|
+
# Backward compatibility with older/dummy service stubs in tests
|
178
|
+
providers = await provider_service.find_providers(
|
179
|
+
cpu=cpu, memory=memory, storage=storage, country=country, driver=driver
|
180
|
+
)
|
142
181
|
|
143
182
|
if not providers:
|
144
183
|
logger.warning("No providers found matching criteria")
|
@@ -606,6 +645,10 @@ def wallet():
|
|
606
645
|
async def wallet_faucet():
|
607
646
|
"""Request L2 faucet funds for the requestor's payment address."""
|
608
647
|
try:
|
648
|
+
if not getattr(config, 'faucet_enabled', False):
|
649
|
+
logger.warning("Faucet is disabled for the current payments network.")
|
650
|
+
click.echo(json.dumps({"error": "faucet_disabled", "network": getattr(config, 'payments_network', None)}, indent=2))
|
651
|
+
return
|
609
652
|
from ..security.faucet import L2FaucetService
|
610
653
|
from eth_account import Account
|
611
654
|
acct = Account.from_key(config.ethereum_private_key)
|
@@ -54,6 +54,13 @@ class RequestorConfig(BaseSettings):
|
|
54
54
|
description="Target network: 'testnet' or 'mainnet'"
|
55
55
|
)
|
56
56
|
|
57
|
+
# Payments chain selection (modular network profiles)
|
58
|
+
# Keep current standard as l2.holesky
|
59
|
+
payments_network: str = Field(
|
60
|
+
default="l2.holesky",
|
61
|
+
description="Payments network profile (e.g., 'l2.holesky', 'kaolin.holesky', 'mainnet')"
|
62
|
+
)
|
63
|
+
|
57
64
|
# Development Settings
|
58
65
|
force_localhost: bool = Field(
|
59
66
|
default=False,
|
@@ -102,8 +109,8 @@ class RequestorConfig(BaseSettings):
|
|
102
109
|
|
103
110
|
# Payments (EVM RPC)
|
104
111
|
polygon_rpc_url: str = Field(
|
105
|
-
default="
|
106
|
-
description="EVM RPC URL for streaming payments
|
112
|
+
default="",
|
113
|
+
description="EVM RPC URL for streaming payments; defaults from payments_network profile"
|
107
114
|
)
|
108
115
|
stream_payment_address: str = Field(
|
109
116
|
default="",
|
@@ -130,10 +137,10 @@ class RequestorConfig(BaseSettings):
|
|
130
137
|
default=3600,
|
131
138
|
description="Target runway after top-up (seconds)"
|
132
139
|
)
|
133
|
-
# Faucet settings (
|
140
|
+
# Faucet settings (payments)
|
134
141
|
l2_faucet_url: str = Field(
|
135
|
-
default="
|
136
|
-
description="
|
142
|
+
default="",
|
143
|
+
description="Faucet base URL (no trailing /api). Only used on testnets. Defaults from payments_network profile"
|
137
144
|
)
|
138
145
|
captcha_url: str = Field(
|
139
146
|
default="https://cap.gobas.me",
|
@@ -150,8 +157,8 @@ class RequestorConfig(BaseSettings):
|
|
150
157
|
|
151
158
|
@field_validator("polygon_rpc_url", mode='before')
|
152
159
|
@classmethod
|
153
|
-
def prefer_alt_env(cls, v: str) -> str:
|
154
|
-
# Accept alt aliases
|
160
|
+
def prefer_alt_env(cls, v: str, info: ValidationInfo) -> str:
|
161
|
+
# Accept alt aliases overriding the profile
|
155
162
|
for key in (
|
156
163
|
"GOLEM_REQUESTOR_l2_rpc_url",
|
157
164
|
"GOLEM_REQUESTOR_L2_RPC_URL",
|
@@ -160,22 +167,45 @@ class RequestorConfig(BaseSettings):
|
|
160
167
|
):
|
161
168
|
if os.environ.get(key):
|
162
169
|
return os.environ[key]
|
163
|
-
|
170
|
+
if v:
|
171
|
+
return v
|
172
|
+
# Default from payments profile
|
173
|
+
pn = info.data.get("payments_network") or "l2.holesky"
|
174
|
+
return RequestorConfig._profile_defaults(pn)["rpc_url"]
|
175
|
+
|
176
|
+
@field_validator("l2_faucet_url", mode='before')
|
177
|
+
@classmethod
|
178
|
+
def default_faucet_env(cls, v: str, info: ValidationInfo) -> str:
|
179
|
+
for key in (
|
180
|
+
"GOLEM_REQUESTOR_l2_faucet_url",
|
181
|
+
"GOLEM_REQUESTOR_L2_FAUCET_URL",
|
182
|
+
):
|
183
|
+
if os.environ.get(key):
|
184
|
+
return os.environ[key]
|
185
|
+
if v:
|
186
|
+
return v
|
187
|
+
pn = info.data.get("payments_network") or "l2.holesky"
|
188
|
+
return RequestorConfig._profile_defaults(pn).get("faucet_url", "")
|
164
189
|
|
165
190
|
@staticmethod
|
166
|
-
def
|
191
|
+
def _load_deployment(network: str) -> tuple[str | None, str | None]:
|
167
192
|
try:
|
168
193
|
base = os.environ.get("GOLEM_DEPLOYMENTS_DIR")
|
169
194
|
if base:
|
170
|
-
path = Path(base) / "
|
195
|
+
path = Path(base) / f"{RequestorConfig._deployment_basename(network)}.json"
|
171
196
|
else:
|
172
197
|
# repo root assumption: ../../ relative to this file
|
173
|
-
path =
|
198
|
+
path = (
|
199
|
+
Path(__file__).resolve().parents[2]
|
200
|
+
/ "contracts" / "deployments" / f"{RequestorConfig._deployment_basename(network)}.json"
|
201
|
+
)
|
174
202
|
if not path.exists():
|
175
203
|
# Try package resource fallback
|
176
204
|
try:
|
177
205
|
import importlib.resources as ir
|
178
|
-
with ir.files("requestor.data.deployments").joinpath(
|
206
|
+
with ir.files("requestor.data.deployments").joinpath(
|
207
|
+
f"{RequestorConfig._deployment_basename(network)}.json"
|
208
|
+
).open("r") as fh: # type: ignore[attr-defined]
|
179
209
|
import json as _json
|
180
210
|
data = _json.load(fh)
|
181
211
|
except Exception:
|
@@ -192,22 +222,83 @@ class RequestorConfig(BaseSettings):
|
|
192
222
|
pass
|
193
223
|
return None, None
|
194
224
|
|
225
|
+
@staticmethod
|
226
|
+
def _deployment_basename(network: str) -> str:
|
227
|
+
# Map well-known network aliases to deployment file base names
|
228
|
+
n = (network or "").lower()
|
229
|
+
if n in ("l2", "l2.holesky"): # current standard
|
230
|
+
return "l2"
|
231
|
+
if "." in n:
|
232
|
+
return n.split(".")[0]
|
233
|
+
return n or "l2"
|
234
|
+
|
235
|
+
@staticmethod
|
236
|
+
def _profile_defaults(network: str) -> Dict[str, str]:
|
237
|
+
n = (network or "l2.holesky").lower()
|
238
|
+
# Built-in profiles; extend easily in future
|
239
|
+
profiles = {
|
240
|
+
"l2.holesky": {
|
241
|
+
"rpc_url": "https://l2.holesky.golemdb.io/rpc",
|
242
|
+
"faucet_url": "https://l2.holesky.golemdb.io/faucet",
|
243
|
+
"faucet_enabled": True,
|
244
|
+
"token_symbol": "GLM",
|
245
|
+
"gas_symbol": "ETH",
|
246
|
+
},
|
247
|
+
# Example: mainnet has no faucet by default
|
248
|
+
"mainnet": {
|
249
|
+
"rpc_url": "",
|
250
|
+
"faucet_url": "",
|
251
|
+
"faucet_enabled": False,
|
252
|
+
"token_symbol": "GLM",
|
253
|
+
"gas_symbol": "ETH",
|
254
|
+
},
|
255
|
+
}
|
256
|
+
return profiles.get(n, profiles["l2.holesky"]) # default to current standard
|
257
|
+
|
195
258
|
@field_validator("stream_payment_address", mode='before')
|
196
259
|
@classmethod
|
197
|
-
def default_stream_addr(cls, v: str) -> str:
|
260
|
+
def default_stream_addr(cls, v: str, info: ValidationInfo) -> str:
|
198
261
|
if v:
|
199
262
|
return v
|
200
|
-
|
263
|
+
network = info.data.get("payments_network") or "l2.holesky"
|
264
|
+
addr, _ = RequestorConfig._load_deployment(network)
|
201
265
|
return addr or "0x0000000000000000000000000000000000000000"
|
202
266
|
|
203
267
|
@field_validator("glm_token_address", mode='before')
|
204
268
|
@classmethod
|
205
|
-
def default_token_addr(cls, v: str) -> str:
|
269
|
+
def default_token_addr(cls, v: str, info: ValidationInfo) -> str:
|
206
270
|
if v:
|
207
271
|
return v
|
208
|
-
|
272
|
+
network = info.data.get("payments_network") or "l2.holesky"
|
273
|
+
_, token = RequestorConfig._load_deployment(network)
|
209
274
|
return token or "0x0000000000000000000000000000000000000000"
|
210
275
|
|
276
|
+
# Optional convenience: expose token and gas symbols based on profile
|
277
|
+
token_symbol: str = Field(
|
278
|
+
default="",
|
279
|
+
description="Human-friendly symbol of payment token (e.g., GLM)"
|
280
|
+
)
|
281
|
+
gas_token_symbol: str = Field(
|
282
|
+
default="",
|
283
|
+
description="Symbol of gas token for the chain (e.g., ETH)"
|
284
|
+
)
|
285
|
+
|
286
|
+
@field_validator("token_symbol", mode="before")
|
287
|
+
@classmethod
|
288
|
+
def default_token_symbol(cls, v: str, info: ValidationInfo) -> str:
|
289
|
+
if v:
|
290
|
+
return v
|
291
|
+
pn = info.data.get("payments_network") or "l2.holesky"
|
292
|
+
return RequestorConfig._profile_defaults(pn).get("token_symbol", "")
|
293
|
+
|
294
|
+
@field_validator("gas_token_symbol", mode="before")
|
295
|
+
@classmethod
|
296
|
+
def default_gas_symbol(cls, v: str, info: ValidationInfo) -> str:
|
297
|
+
if v:
|
298
|
+
return v
|
299
|
+
pn = info.data.get("payments_network") or "l2.holesky"
|
300
|
+
return RequestorConfig._profile_defaults(pn).get("gas_symbol", "")
|
301
|
+
|
211
302
|
# Base Directory
|
212
303
|
base_dir: Path = Field(
|
213
304
|
default_factory=lambda: Path.home() / ".golem" / "requestor",
|
@@ -240,6 +331,11 @@ class RequestorConfig(BaseSettings):
|
|
240
331
|
kwargs['db_path'] = base_dir / "vms.db"
|
241
332
|
super().__init__(**kwargs)
|
242
333
|
|
334
|
+
@property
|
335
|
+
def faucet_enabled(self) -> bool:
|
336
|
+
"""Whether requesting funds from faucet is allowed for current payments network."""
|
337
|
+
return bool(self._profile_defaults(self.payments_network).get("faucet_enabled", False))
|
338
|
+
|
243
339
|
def get_provider_url(self, ip_address: str) -> str:
|
244
340
|
"""Get provider API URL.
|
245
341
|
|
@@ -15,7 +15,7 @@ class L2FaucetService:
|
|
15
15
|
self.cfg = config
|
16
16
|
self.web3 = Web3(Web3.HTTPProvider(config.polygon_rpc_url))
|
17
17
|
self.client = PowFaucetClient(
|
18
|
-
faucet_url=getattr(config, 'l2_faucet_url', 'https://l2.holesky.golemdb.io/faucet'
|
18
|
+
faucet_url=getattr(config, 'l2_faucet_url', '') or 'https://l2.holesky.golemdb.io/faucet',
|
19
19
|
captcha_base_url=getattr(config, 'captcha_url', 'https://cap.gobas.me'),
|
20
20
|
captcha_api_key=getattr(config, 'captcha_api_key', '05381a2cef5e'),
|
21
21
|
)
|
@@ -29,6 +29,10 @@ class L2FaucetService:
|
|
29
29
|
return 0.0
|
30
30
|
|
31
31
|
async def request_funds(self, address: str) -> Optional[str]:
|
32
|
+
# Disallow faucet if explicitly disabled by profile
|
33
|
+
if hasattr(self.cfg, 'faucet_enabled') and not getattr(self.cfg, 'faucet_enabled'):
|
34
|
+
logger.info("Faucet disabled for current payments network; skipping.")
|
35
|
+
return None
|
32
36
|
bal = self._balance_eth(address)
|
33
37
|
if bal > 0.01:
|
34
38
|
logger.info(f"Sufficient L2 funds ({bal} ETH), skipping faucet.")
|
@@ -51,4 +55,3 @@ class L2FaucetService:
|
|
51
55
|
if tx:
|
52
56
|
logger.success(f"L2 faucet sent tx: {tx}")
|
53
57
|
return tx
|
54
|
-
|
{request_vm_on_golem-0.1.51 → request_vm_on_golem-0.1.53}/requestor/services/provider_service.py
RENAMED
@@ -66,7 +66,9 @@ class ProviderService:
|
|
66
66
|
memory: Optional[int] = None,
|
67
67
|
storage: Optional[int] = None,
|
68
68
|
country: Optional[str] = None,
|
69
|
-
driver: Optional[str] = None
|
69
|
+
driver: Optional[str] = None,
|
70
|
+
payments_network: Optional[str] = None,
|
71
|
+
include_all_payments: bool = False,
|
70
72
|
) -> List[Dict]:
|
71
73
|
"""Find providers matching requirements."""
|
72
74
|
discovery_driver = driver or config.discovery_driver
|
@@ -79,7 +81,11 @@ class ProviderService:
|
|
79
81
|
ws_url=config.golem_base_ws_url,
|
80
82
|
private_key=private_key_bytes,
|
81
83
|
)
|
82
|
-
return await self._find_providers_golem_base(
|
84
|
+
return await self._find_providers_golem_base(
|
85
|
+
cpu, memory, storage, country,
|
86
|
+
payments_network=payments_network,
|
87
|
+
include_all_payments=include_all_payments,
|
88
|
+
)
|
83
89
|
else:
|
84
90
|
return await self._find_providers_central(cpu, memory, storage, country)
|
85
91
|
|
@@ -88,7 +94,9 @@ class ProviderService:
|
|
88
94
|
cpu: Optional[int] = None,
|
89
95
|
memory: Optional[int] = None,
|
90
96
|
storage: Optional[int] = None,
|
91
|
-
country: Optional[str] = None
|
97
|
+
country: Optional[str] = None,
|
98
|
+
payments_network: Optional[str] = None,
|
99
|
+
include_all_payments: bool = False,
|
92
100
|
) -> List[Dict]:
|
93
101
|
"""Find providers using Golem Base."""
|
94
102
|
try:
|
@@ -104,6 +112,10 @@ class ProviderService:
|
|
104
112
|
# Filter by advertised network to avoid cross-network results
|
105
113
|
if config.network:
|
106
114
|
query += f' && golem_network="{config.network}"'
|
115
|
+
# Filter by payments network unless explicitly disabled
|
116
|
+
pn = payments_network if payments_network is not None else getattr(config, 'payments_network', None)
|
117
|
+
if pn and not include_all_payments:
|
118
|
+
query += f' && golem_payments_network="{pn}"'
|
107
119
|
if cpu:
|
108
120
|
query += f' && golem_cpu>={cpu}'
|
109
121
|
if memory:
|
@@ -130,6 +142,7 @@ class ProviderService:
|
|
130
142
|
'provider_name': annotations.get('golem_provider_name'),
|
131
143
|
'ip_address': annotations.get('golem_ip_address'),
|
132
144
|
'country': annotations.get('golem_country'),
|
145
|
+
'payments_network': annotations.get('golem_payments_network'),
|
133
146
|
'resources': {
|
134
147
|
'cpu': int(annotations.get('golem_cpu', 0)),
|
135
148
|
'memory': int(annotations.get('golem_memory', 0)),
|
File without changes
|
File without changes
|
File without changes
|
{request_vm_on_golem-0.1.51 → request_vm_on_golem-0.1.53}/requestor/data/deployments/l2.json
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{request_vm_on_golem-0.1.51 → request_vm_on_golem-0.1.53}/requestor/payments/blockchain_service.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{request_vm_on_golem-0.1.51 → request_vm_on_golem-0.1.53}/requestor/services/database_service.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|