request-vm-on-golem 0.1.54__py3-none-any.whl → 0.1.55__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.
- {request_vm_on_golem-0.1.54.dist-info → request_vm_on_golem-0.1.55.dist-info}/METADATA +1 -1
- {request_vm_on_golem-0.1.54.dist-info → request_vm_on_golem-0.1.55.dist-info}/RECORD +8 -8
- requestor/cli/commands.py +7 -3
- requestor/provider/client.py +19 -2
- requestor/services/provider_service.py +17 -4
- requestor/services/vm_service.py +39 -5
- {request_vm_on_golem-0.1.54.dist-info → request_vm_on_golem-0.1.55.dist-info}/WHEEL +0 -0
- {request_vm_on_golem-0.1.54.dist-info → request_vm_on_golem-0.1.55.dist-info}/entry_points.txt +0 -0
@@ -1,7 +1,7 @@
|
|
1
1
|
requestor/__init__.py,sha256=OqSUAh1uZBMx7GW0MoSMg967PVdmT8XdPJx3QYjwkak,116
|
2
2
|
requestor/api/main.py,sha256=CTnaM7KyBtDwVlyclYbNDy-nGi5_xt9GTcGusRasDVY,2493
|
3
3
|
requestor/cli/__init__.py,sha256=e3E4oEGxmGj-STPtFkQwg_qIWhR0JAiAQdw3G1hXciU,37
|
4
|
-
requestor/cli/commands.py,sha256=
|
4
|
+
requestor/cli/commands.py,sha256=Obr8Z1ZX3f6WThooIInlD7HqMl_pJmOqawzazLmhke0,51253
|
5
5
|
requestor/config.py,sha256=FMSRKdyo3nEdn62CRonnwrw4Hsy4VGcuvvfg60aORsI,12809
|
6
6
|
requestor/data/deployments/l2.json,sha256=XTNN2C5LkBfp4YbDKdUKfWMdp1fKnfv8D3TgcwVWxtQ,249
|
7
7
|
requestor/db/__init__.py,sha256=Gm5DfWls6uvCZZ3HGGnyRHswbUQdeA5OGN8yPwH0hc8,88
|
@@ -10,19 +10,19 @@ requestor/errors.py,sha256=wVpHBuYgQx5pTe_SamugfK-k768noikY1RxvPOjQGko,665
|
|
10
10
|
requestor/payments/blockchain_service.py,sha256=CACvZH2ZstutX7f0L_PXl8K_V5WlIkxNYIaeJuhP5I0,7500
|
11
11
|
requestor/payments/monitor.py,sha256=JtSnh2plFf-f8sJU-bkOpadhoK_R82_ULwkDRmBYSbc,6012
|
12
12
|
requestor/provider/__init__.py,sha256=fmW23aYUVciF8-gmBZkG-PLhn22upmcDzdPfAOLHG6g,103
|
13
|
-
requestor/provider/client.py,sha256=
|
13
|
+
requestor/provider/client.py,sha256=bWj4sNQ8w4F2sSRcMlHbWVjeBLAflDhHxy0BNMqzj8s,5021
|
14
14
|
requestor/run.py,sha256=sR9GgylQWbYPc60wRr3rUpemlNrWqIPNFIJ8WCz6YwE,2120
|
15
15
|
requestor/security/faucet.py,sha256=XF_13b66SKAaY0-40hNRcSgC8AZA4mD5gyXl3qaBLpQ,2320
|
16
16
|
requestor/services/__init__.py,sha256=1qSn_6RMn0KB0A7LCnY2IW6_tC3HBQsdfkFeV-h94eM,172
|
17
17
|
requestor/services/database_service.py,sha256=GlSrzzzd7PSYQJNup00sxkB-B2PMr1__04K8k5QSWvs,2996
|
18
|
-
requestor/services/provider_service.py,sha256=
|
18
|
+
requestor/services/provider_service.py,sha256=XMZtdkrpEKiGg0iFW3v_cf3zu7BZcYp1wjaphxo2SCU,16250
|
19
19
|
requestor/services/ssh_service.py,sha256=tcOCtk2SlB9Uuv-P2ghR22e7BJ9kigQh5b4zSGdPFns,4280
|
20
|
-
requestor/services/vm_service.py,sha256=
|
20
|
+
requestor/services/vm_service.py,sha256=e05OgMZwz3NcCiIwmz4EnB6joMK6S3G_RT3VajD92lw,9438
|
21
21
|
requestor/ssh/__init__.py,sha256=hNgSqJ5s1_AwwxVRyFjUqh_LTBpI4Hmzq0F-f_wXN9g,119
|
22
22
|
requestor/ssh/manager.py,sha256=3jQtbbK7CVC2yD1zCO88jGXh2fBcuv3CzWEqDLuaQVk,9758
|
23
23
|
requestor/utils/logging.py,sha256=lgAswzYvO9M0EOET0cFZvuAsGI4lInh_wln_6bI-fJk,4281
|
24
24
|
requestor/utils/spinner.py,sha256=X0jfPfs5ricglTS4_XmacrM2Z1DDHR7zGk2KqYZDpXg,2541
|
25
|
-
request_vm_on_golem-0.1.
|
26
|
-
request_vm_on_golem-0.1.
|
27
|
-
request_vm_on_golem-0.1.
|
28
|
-
request_vm_on_golem-0.1.
|
25
|
+
request_vm_on_golem-0.1.55.dist-info/METADATA,sha256=wepR8dMN4ehyEx4zmQjjTl3fuXs_OdGGiBCZPn3ZZ8I,15780
|
26
|
+
request_vm_on_golem-0.1.55.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
27
|
+
request_vm_on_golem-0.1.55.dist-info/entry_points.txt,sha256=Z-skRNpJ8aZcIl_En9mEm1ygkp9FKy0bzQoL3zO52-0,44
|
28
|
+
request_vm_on_golem-0.1.55.dist-info/RECORD,,
|
requestor/cli/commands.py
CHANGED
@@ -128,6 +128,7 @@ def vm():
|
|
128
128
|
@click.option('--memory', type=int, help='Minimum memory (GB) required')
|
129
129
|
@click.option('--storage', type=int, help='Minimum disk (GB) required')
|
130
130
|
@click.option('--country', help='Preferred provider country')
|
131
|
+
@click.option('--platform', help='Preferred platform/arch (e.g., x86_64, arm64)')
|
131
132
|
@click.option('--driver', type=click.Choice(['central', 'golem-base']), default=None, help='Discovery driver to use')
|
132
133
|
@click.option('--payments-network', type=str, default=None, help='Filter by payments network profile (default: current config)')
|
133
134
|
@click.option('--all-payments', is_flag=True, help='Do not filter by payments network (show all)')
|
@@ -135,7 +136,7 @@ def vm():
|
|
135
136
|
@click.option('--network', type=click.Choice(['testnet', 'mainnet']), default=None,
|
136
137
|
help='Override network filter for this command')
|
137
138
|
@async_command
|
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):
|
139
|
+
async def list_providers(cpu: Optional[int], memory: Optional[int], storage: Optional[int], country: Optional[str], platform: Optional[str], driver: Optional[str], payments_network: Optional[str] = None, all_payments: bool = False, as_json: bool = False, network: Optional[str] = None):
|
139
140
|
"""List available providers matching requirements."""
|
140
141
|
try:
|
141
142
|
if as_json:
|
@@ -143,7 +144,7 @@ async def list_providers(cpu: Optional[int], memory: Optional[int], storage: Opt
|
|
143
144
|
if network:
|
144
145
|
config.network = network
|
145
146
|
# Log search criteria if any
|
146
|
-
if any([cpu, memory, storage, country]):
|
147
|
+
if any([cpu, memory, storage, country, platform]):
|
147
148
|
logger.command("🔍 Searching for providers with criteria:")
|
148
149
|
if cpu:
|
149
150
|
logger.detail(f"CPU Cores: {cpu}+")
|
@@ -153,6 +154,8 @@ async def list_providers(cpu: Optional[int], memory: Optional[int], storage: Opt
|
|
153
154
|
logger.detail(f"Disk: {storage}GB+")
|
154
155
|
if country:
|
155
156
|
logger.detail(f"Country: {country}")
|
157
|
+
if platform:
|
158
|
+
logger.detail(f"Platform: {platform}")
|
156
159
|
|
157
160
|
# Determine the discovery driver being used
|
158
161
|
discovery_driver = driver or config.discovery_driver
|
@@ -171,6 +174,7 @@ async def list_providers(cpu: Optional[int], memory: Optional[int], storage: Opt
|
|
171
174
|
memory=memory,
|
172
175
|
storage=storage,
|
173
176
|
country=country,
|
177
|
+
platform=platform,
|
174
178
|
driver=driver,
|
175
179
|
payments_network=eff_pn,
|
176
180
|
include_all_payments=bool(all_payments),
|
@@ -178,7 +182,7 @@ async def list_providers(cpu: Optional[int], memory: Optional[int], storage: Opt
|
|
178
182
|
except TypeError:
|
179
183
|
# Backward compatibility with older/dummy service stubs in tests
|
180
184
|
providers = await provider_service.find_providers(
|
181
|
-
cpu=cpu, memory=memory, storage=storage, country=country, driver=driver
|
185
|
+
cpu=cpu, memory=memory, storage=storage, country=country, platform=platform, driver=driver
|
182
186
|
)
|
183
187
|
|
184
188
|
if not providers:
|
requestor/provider/client.py
CHANGED
@@ -24,7 +24,7 @@ class ProviderClient:
|
|
24
24
|
ssh_key: str,
|
25
25
|
stream_id: int | None = None,
|
26
26
|
) -> Dict:
|
27
|
-
"""Create a VM on the provider."""
|
27
|
+
"""Create a VM on the provider (async job semantics)."""
|
28
28
|
payload = {
|
29
29
|
"name": name,
|
30
30
|
"resources": {
|
@@ -37,12 +37,29 @@ class ProviderClient:
|
|
37
37
|
if stream_id is not None:
|
38
38
|
payload["stream_id"] = int(stream_id)
|
39
39
|
async with self.session.post(
|
40
|
-
f"{self.provider_url}/api/v1/vms",
|
40
|
+
f"{self.provider_url}/api/v1/vms?async=true",
|
41
41
|
json=payload
|
42
42
|
) as response:
|
43
43
|
if not response.ok:
|
44
44
|
error_text = await response.text()
|
45
45
|
raise Exception(f"Failed to create VM: {error_text}")
|
46
|
+
data = await response.json()
|
47
|
+
# Normalize: support both old (VMInfo) and new (job) responses
|
48
|
+
# New shape: { job_id, vm_id, status }
|
49
|
+
# Old shape: { id, ... }
|
50
|
+
if isinstance(data, dict) and "job_id" in data:
|
51
|
+
return data
|
52
|
+
# Fallback: synthesize a job-like envelope from immediate VM info
|
53
|
+
vm_id = data.get("id") or data.get("name") or name
|
54
|
+
return {"job_id": "", "vm_id": vm_id, "status": data.get("status", "ready"), "_vm": data}
|
55
|
+
|
56
|
+
async def get_vm_info(self, vm_id: str) -> Dict:
|
57
|
+
async with self.session.get(
|
58
|
+
f"{self.provider_url}/api/v1/vms/{vm_id}"
|
59
|
+
) as response:
|
60
|
+
if not response.ok:
|
61
|
+
error_text = await response.text()
|
62
|
+
raise Exception(f"Failed to get VM info: {error_text}")
|
46
63
|
return await response.json()
|
47
64
|
|
48
65
|
async def get_provider_info(self) -> Dict:
|
@@ -66,6 +66,7 @@ class ProviderService:
|
|
66
66
|
memory: Optional[int] = None,
|
67
67
|
storage: Optional[int] = None,
|
68
68
|
country: Optional[str] = None,
|
69
|
+
platform: Optional[str] = None,
|
69
70
|
driver: Optional[str] = None,
|
70
71
|
payments_network: Optional[str] = None,
|
71
72
|
include_all_payments: bool = False,
|
@@ -82,12 +83,12 @@ class ProviderService:
|
|
82
83
|
private_key=private_key_bytes,
|
83
84
|
)
|
84
85
|
return await self._find_providers_golem_base(
|
85
|
-
cpu, memory, storage, country,
|
86
|
+
cpu, memory, storage, country, platform,
|
86
87
|
payments_network=payments_network,
|
87
88
|
include_all_payments=include_all_payments,
|
88
89
|
)
|
89
90
|
else:
|
90
|
-
return await self._find_providers_central(cpu, memory, storage, country)
|
91
|
+
return await self._find_providers_central(cpu, memory, storage, country, platform)
|
91
92
|
|
92
93
|
async def _find_providers_golem_base(
|
93
94
|
self,
|
@@ -95,6 +96,7 @@ class ProviderService:
|
|
95
96
|
memory: Optional[int] = None,
|
96
97
|
storage: Optional[int] = None,
|
97
98
|
country: Optional[str] = None,
|
99
|
+
platform: Optional[str] = None,
|
98
100
|
payments_network: Optional[str] = None,
|
99
101
|
include_all_payments: bool = False,
|
100
102
|
) -> List[Dict]:
|
@@ -124,6 +126,8 @@ class ProviderService:
|
|
124
126
|
query += f' && golem_storage>={storage}'
|
125
127
|
if country:
|
126
128
|
query += f' && golem_country="{country}"'
|
129
|
+
if platform:
|
130
|
+
query += f' && golem_platform="{platform}"'
|
127
131
|
|
128
132
|
results = await self.golem_base_client.query_entities(query)
|
129
133
|
|
@@ -142,6 +146,7 @@ class ProviderService:
|
|
142
146
|
'provider_name': annotations.get('golem_provider_name'),
|
143
147
|
'ip_address': annotations.get('golem_ip_address'),
|
144
148
|
'country': annotations.get('golem_country'),
|
149
|
+
'platform': annotations.get('golem_platform') or None,
|
145
150
|
'payments_network': annotations.get('golem_payments_network'),
|
146
151
|
'resources': {
|
147
152
|
'cpu': int(annotations.get('golem_cpu', 0)),
|
@@ -171,7 +176,8 @@ class ProviderService:
|
|
171
176
|
cpu: Optional[int] = None,
|
172
177
|
memory: Optional[int] = None,
|
173
178
|
storage: Optional[int] = None,
|
174
|
-
country: Optional[str] = None
|
179
|
+
country: Optional[str] = None,
|
180
|
+
platform: Optional[str] = None
|
175
181
|
) -> List[Dict]:
|
176
182
|
"""Find providers using the central discovery service."""
|
177
183
|
try:
|
@@ -181,7 +187,8 @@ class ProviderService:
|
|
181
187
|
'cpu': cpu,
|
182
188
|
'memory': memory,
|
183
189
|
'storage': storage,
|
184
|
-
'country': country
|
190
|
+
'country': country,
|
191
|
+
'platform': platform,
|
185
192
|
}.items() if v is not None
|
186
193
|
}
|
187
194
|
|
@@ -328,6 +335,7 @@ class ProviderService:
|
|
328
335
|
usd_storage if usd_storage is not None else '—',
|
329
336
|
est_usd,
|
330
337
|
est_glm,
|
338
|
+
(provider.get('platform') or '—'),
|
331
339
|
updated_at_str
|
332
340
|
]
|
333
341
|
|
@@ -358,6 +366,10 @@ class ProviderService:
|
|
358
366
|
# Format location info
|
359
367
|
row[3] = style(f"🌍 {row[3]}", fg="green", bold=True)
|
360
368
|
|
369
|
+
# Platform column: dim label
|
370
|
+
if row[12] != '—':
|
371
|
+
row[12] = style(f"{row[12]}", fg="white")
|
372
|
+
|
361
373
|
return row
|
362
374
|
|
363
375
|
@property
|
@@ -376,5 +388,6 @@ class ProviderService:
|
|
376
388
|
"USD/GB Disk/mo",
|
377
389
|
"Est. $/mo",
|
378
390
|
"Est. GLM/mo",
|
391
|
+
"Platform",
|
379
392
|
"Updated"
|
380
393
|
]
|
requestor/services/vm_service.py
CHANGED
@@ -39,8 +39,8 @@ class VMService:
|
|
39
39
|
if existing_vm:
|
40
40
|
raise VMError(f"VM with name '{name}' already exists")
|
41
41
|
|
42
|
-
# Create VM on provider
|
43
|
-
|
42
|
+
# Create VM on provider (returns job envelope)
|
43
|
+
job = await self.provider_client.create_vm(
|
44
44
|
name=name,
|
45
45
|
cpu=cpu,
|
46
46
|
memory=memory,
|
@@ -49,8 +49,41 @@ class VMService:
|
|
49
49
|
stream_id=stream_id
|
50
50
|
)
|
51
51
|
|
52
|
-
|
53
|
-
|
52
|
+
vm_id = job.get('vm_id') or name
|
53
|
+
|
54
|
+
# Save initial record with 'creating' status (no port yet)
|
55
|
+
await self.db.save_vm(
|
56
|
+
name=name,
|
57
|
+
provider_ip=provider_ip,
|
58
|
+
vm_id=vm_id,
|
59
|
+
config={
|
60
|
+
'cpu': cpu,
|
61
|
+
'memory': memory,
|
62
|
+
'storage': storage,
|
63
|
+
**({"stream_id": stream_id} if stream_id is not None else {}),
|
64
|
+
},
|
65
|
+
status='creating'
|
66
|
+
)
|
67
|
+
|
68
|
+
# Poll provider until VM is ready, then fetch access info
|
69
|
+
import asyncio as _asyncio
|
70
|
+
deadline = _asyncio.get_event_loop().time() + 600.0 # 10 minutes max
|
71
|
+
last_status = 'creating'
|
72
|
+
while _asyncio.get_event_loop().time() < deadline:
|
73
|
+
try:
|
74
|
+
info = await self.provider_client.get_vm_info(vm_id)
|
75
|
+
last_status = (info.get('status') or '').lower() or last_status
|
76
|
+
if last_status == 'running':
|
77
|
+
break
|
78
|
+
except Exception:
|
79
|
+
# Best-effort: ignore transient errors during startup
|
80
|
+
pass
|
81
|
+
await _asyncio.sleep(2.0)
|
82
|
+
if last_status != 'running':
|
83
|
+
raise VMError(f"VM did not become ready in time (status={last_status})")
|
84
|
+
|
85
|
+
# Get VM access info (ssh port)
|
86
|
+
access_info = await self.provider_client.get_vm_access(vm_id)
|
54
87
|
|
55
88
|
# Preserve any provided stream_id; do not auto-create streams here
|
56
89
|
# Stream creation should be explicit via CLI `vm stream open` command.
|
@@ -67,7 +100,8 @@ class VMService:
|
|
67
100
|
name=name,
|
68
101
|
provider_ip=provider_ip,
|
69
102
|
vm_id=access_info['vm_id'],
|
70
|
-
config=config
|
103
|
+
config=config,
|
104
|
+
status='running'
|
71
105
|
)
|
72
106
|
|
73
107
|
return {
|
File without changes
|
{request_vm_on_golem-0.1.54.dist-info → request_vm_on_golem-0.1.55.dist-info}/entry_points.txt
RENAMED
File without changes
|