request-vm-on-golem 0.1.35__tar.gz → 0.1.36__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.35 → request_vm_on_golem-0.1.36}/PKG-INFO +1 -1
- {request_vm_on_golem-0.1.35 → request_vm_on_golem-0.1.36}/pyproject.toml +1 -1
- {request_vm_on_golem-0.1.35 → request_vm_on_golem-0.1.36}/requestor/cli/commands.py +103 -36
- {request_vm_on_golem-0.1.35 → request_vm_on_golem-0.1.36}/requestor/run.py +21 -13
- {request_vm_on_golem-0.1.35 → request_vm_on_golem-0.1.36}/README.md +0 -0
- {request_vm_on_golem-0.1.35 → request_vm_on_golem-0.1.36}/requestor/__init__.py +0 -0
- {request_vm_on_golem-0.1.35 → request_vm_on_golem-0.1.36}/requestor/api/main.py +0 -0
- {request_vm_on_golem-0.1.35 → request_vm_on_golem-0.1.36}/requestor/cli/__init__.py +0 -0
- {request_vm_on_golem-0.1.35 → request_vm_on_golem-0.1.36}/requestor/config.py +0 -0
- {request_vm_on_golem-0.1.35 → request_vm_on_golem-0.1.36}/requestor/db/__init__.py +0 -0
- {request_vm_on_golem-0.1.35 → request_vm_on_golem-0.1.36}/requestor/db/sqlite.py +0 -0
- {request_vm_on_golem-0.1.35 → request_vm_on_golem-0.1.36}/requestor/errors.py +0 -0
- {request_vm_on_golem-0.1.35 → request_vm_on_golem-0.1.36}/requestor/provider/__init__.py +0 -0
- {request_vm_on_golem-0.1.35 → request_vm_on_golem-0.1.36}/requestor/provider/client.py +0 -0
- {request_vm_on_golem-0.1.35 → request_vm_on_golem-0.1.36}/requestor/services/__init__.py +0 -0
- {request_vm_on_golem-0.1.35 → request_vm_on_golem-0.1.36}/requestor/services/database_service.py +0 -0
- {request_vm_on_golem-0.1.35 → request_vm_on_golem-0.1.36}/requestor/services/provider_service.py +0 -0
- {request_vm_on_golem-0.1.35 → request_vm_on_golem-0.1.36}/requestor/services/ssh_service.py +0 -0
- {request_vm_on_golem-0.1.35 → request_vm_on_golem-0.1.36}/requestor/services/vm_service.py +0 -0
- {request_vm_on_golem-0.1.35 → request_vm_on_golem-0.1.36}/requestor/ssh/__init__.py +0 -0
- {request_vm_on_golem-0.1.35 → request_vm_on_golem-0.1.36}/requestor/ssh/manager.py +0 -0
- {request_vm_on_golem-0.1.35 → request_vm_on_golem-0.1.36}/requestor/utils/logging.py +0 -0
- {request_vm_on_golem-0.1.35 → request_vm_on_golem-0.1.36}/requestor/utils/spinner.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
[tool.poetry]
|
2
2
|
name = "request-vm-on-golem"
|
3
|
-
version = "0.1.
|
3
|
+
version = "0.1.36"
|
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"
|
@@ -1,6 +1,7 @@
|
|
1
1
|
"""CLI interface for VM on Golem."""
|
2
2
|
import click
|
3
3
|
import asyncio
|
4
|
+
import json
|
4
5
|
from typing import Optional
|
5
6
|
from pathlib import Path
|
6
7
|
import subprocess
|
@@ -70,8 +71,9 @@ def vm():
|
|
70
71
|
@click.option('--storage', type=int, help='Minimum storage (GB) required')
|
71
72
|
@click.option('--country', help='Preferred provider country')
|
72
73
|
@click.option('--driver', type=click.Choice(['central', 'golem-base']), default=None, help='Discovery driver to use')
|
74
|
+
@click.option('--json', 'as_json', is_flag=True, help='Output in JSON format')
|
73
75
|
@async_command
|
74
|
-
async def list_providers(cpu: Optional[int], memory: Optional[int], storage: Optional[int], country: Optional[str], driver: Optional[str]):
|
76
|
+
async def list_providers(cpu: Optional[int], memory: Optional[int], storage: Optional[int], country: Optional[str], driver: Optional[str], as_json: bool):
|
75
77
|
"""List available providers matching requirements."""
|
76
78
|
try:
|
77
79
|
# Log search criteria if any
|
@@ -85,11 +87,11 @@ async def list_providers(cpu: Optional[int], memory: Optional[int], storage: Opt
|
|
85
87
|
logger.detail(f"Storage: {storage}GB+")
|
86
88
|
if country:
|
87
89
|
logger.detail(f"Country: {country}")
|
88
|
-
|
90
|
+
|
89
91
|
# Determine the discovery driver being used
|
90
92
|
discovery_driver = driver or config.discovery_driver
|
91
93
|
logger.process(f"Querying discovery service via {discovery_driver}")
|
92
|
-
|
94
|
+
|
93
95
|
# Initialize provider service
|
94
96
|
provider_service = ProviderService()
|
95
97
|
async with provider_service:
|
@@ -103,24 +105,31 @@ async def list_providers(cpu: Optional[int], memory: Optional[int], storage: Opt
|
|
103
105
|
|
104
106
|
if not providers:
|
105
107
|
logger.warning("No providers found matching criteria")
|
106
|
-
return
|
108
|
+
return {"providers": []}
|
107
109
|
|
108
|
-
|
109
|
-
headers = provider_service.provider_headers
|
110
|
-
rows = await asyncio.gather(*(provider_service.format_provider_row(p, colorize=True) for p in providers))
|
110
|
+
result = {"providers": providers}
|
111
111
|
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
112
|
+
if as_json:
|
113
|
+
click.echo(json.dumps(result, indent=2))
|
114
|
+
else:
|
115
|
+
# Format provider information using service with colors
|
116
|
+
headers = provider_service.provider_headers
|
117
|
+
rows = await asyncio.gather(*(provider_service.format_provider_row(p, colorize=True) for p in providers))
|
116
118
|
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
119
|
+
# Show fancy header
|
120
|
+
click.echo("\n" + "─" * 80)
|
121
|
+
click.echo(click.style(f" 🌍 Available Providers ({len(providers)} total)", fg="blue", bold=True))
|
122
|
+
click.echo("─" * 80)
|
123
|
+
|
124
|
+
# Show table with colored headers
|
125
|
+
click.echo("\n" + tabulate(
|
126
|
+
rows,
|
127
|
+
headers=[click.style(h, bold=True) for h in headers],
|
128
|
+
tablefmt="grid"
|
129
|
+
))
|
130
|
+
click.echo("\n" + "─" * 80)
|
131
|
+
|
132
|
+
return result
|
124
133
|
|
125
134
|
except Exception as e:
|
126
135
|
logger.error(f"Failed to list providers: {str(e)}")
|
@@ -274,6 +283,56 @@ async def ssh_vm(name: str):
|
|
274
283
|
raise click.Abort()
|
275
284
|
|
276
285
|
|
286
|
+
@vm.command(name='info')
|
287
|
+
@click.argument('name')
|
288
|
+
@click.option('--json', 'as_json', is_flag=True, help='Output in JSON format')
|
289
|
+
@async_command
|
290
|
+
async def info_vm(name: str, as_json: bool):
|
291
|
+
"""Show information about a VM."""
|
292
|
+
try:
|
293
|
+
logger.command(f"ℹ️ Getting info for VM '{name}'")
|
294
|
+
|
295
|
+
# Initialize VM service
|
296
|
+
ssh_service = SSHService(config.ssh_key_dir)
|
297
|
+
vm_service = VMService(db_service, ssh_service)
|
298
|
+
|
299
|
+
# Retrieve VM details
|
300
|
+
vm = await vm_service.get_vm(name)
|
301
|
+
if not vm:
|
302
|
+
raise click.BadParameter(f"VM '{name}' not found")
|
303
|
+
|
304
|
+
result = vm
|
305
|
+
|
306
|
+
if as_json:
|
307
|
+
click.echo(json.dumps(result, indent=2))
|
308
|
+
else:
|
309
|
+
headers = [
|
310
|
+
"Status",
|
311
|
+
"IP Address",
|
312
|
+
"SSH Port",
|
313
|
+
"CPU",
|
314
|
+
"Memory (GB)",
|
315
|
+
"Storage (GB)",
|
316
|
+
]
|
317
|
+
|
318
|
+
row = [
|
319
|
+
vm.get("status", "unknown"),
|
320
|
+
vm["provider_ip"],
|
321
|
+
vm["config"].get("ssh_port", "N/A"),
|
322
|
+
vm["config"]["cpu"],
|
323
|
+
vm["config"]["memory"],
|
324
|
+
vm["config"]["storage"],
|
325
|
+
]
|
326
|
+
|
327
|
+
click.echo("\n" + tabulate([row], headers=headers, tablefmt="grid"))
|
328
|
+
|
329
|
+
return result
|
330
|
+
|
331
|
+
except Exception as e:
|
332
|
+
logger.error(f"Failed to get VM info: {str(e)}")
|
333
|
+
raise click.Abort()
|
334
|
+
|
335
|
+
|
277
336
|
@vm.command(name='destroy')
|
278
337
|
@click.argument('name')
|
279
338
|
@async_command
|
@@ -520,37 +579,45 @@ def run_api_server(host: str, port: int, reload: bool):
|
|
520
579
|
|
521
580
|
|
522
581
|
@vm.command(name='list')
|
582
|
+
@click.option('--json', 'as_json', is_flag=True, help='Output in JSON format')
|
523
583
|
@async_command
|
524
|
-
async def list_vms():
|
584
|
+
async def list_vms(as_json: bool):
|
525
585
|
"""List all VMs."""
|
526
586
|
try:
|
527
587
|
logger.command("📋 Listing your VMs")
|
528
588
|
logger.process("Fetching VM details")
|
529
|
-
|
589
|
+
|
530
590
|
# Initialize VM service with temporary client (not needed for listing)
|
531
591
|
ssh_service = SSHService(config.ssh_key_dir)
|
532
592
|
vm_service = VMService(db_service, ssh_service, None)
|
533
593
|
vms = await vm_service.list_vms()
|
534
594
|
if not vms:
|
535
595
|
logger.warning("No VMs found")
|
536
|
-
return
|
596
|
+
return {"vms": []}
|
537
597
|
|
538
|
-
|
539
|
-
headers = vm_service.vm_headers
|
540
|
-
rows = [vm_service.format_vm_row(vm, colorize=True) for vm in vms]
|
598
|
+
result = {"vms": vms}
|
541
599
|
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
600
|
+
if as_json:
|
601
|
+
click.echo(json.dumps(result, indent=2))
|
602
|
+
else:
|
603
|
+
# Format VM information using service
|
604
|
+
headers = vm_service.vm_headers
|
605
|
+
rows = [vm_service.format_vm_row(vm, colorize=True) for vm in vms]
|
606
|
+
|
607
|
+
# Show fancy header
|
608
|
+
click.echo("\n" + "─" * 60)
|
609
|
+
click.echo(click.style(f" 📋 Your VMs ({len(vms)} total)", fg="blue", bold=True))
|
610
|
+
click.echo("─" * 60)
|
611
|
+
|
612
|
+
# Show table with colored status
|
613
|
+
click.echo("\n" + tabulate(
|
614
|
+
rows,
|
615
|
+
headers=[click.style(h, bold=True) for h in headers],
|
616
|
+
tablefmt="grid"
|
617
|
+
))
|
618
|
+
click.echo("\n" + "─" * 60)
|
619
|
+
|
620
|
+
return result
|
554
621
|
|
555
622
|
except Exception as e:
|
556
623
|
error_msg = str(e)
|
@@ -5,30 +5,36 @@ from pathlib import Path
|
|
5
5
|
from dotenv import load_dotenv
|
6
6
|
|
7
7
|
from requestor.utils.logging import setup_logger
|
8
|
-
from requestor.cli.commands import cli
|
9
8
|
|
10
9
|
# Configure logging with debug mode from environment variable
|
11
10
|
logger = setup_logger(__name__)
|
12
11
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
12
|
+
|
13
|
+
def get_ssh_key_dir() -> Path:
|
14
|
+
"""Return the path to the SSH key directory."""
|
15
|
+
return Path(
|
16
|
+
os.environ.get(
|
17
|
+
"GOLEM_REQUESTOR_SSH_KEY_DIR",
|
18
|
+
str(Path.home() / ".golem" / "requestor" / "ssh"),
|
19
|
+
)
|
19
20
|
)
|
20
|
-
|
21
|
+
|
22
|
+
|
23
|
+
def secure_directory(path: Path) -> bool:
|
24
|
+
"""Create the directory if needed and set strict permissions."""
|
21
25
|
try:
|
22
|
-
# Create and secure directories
|
23
|
-
path = Path(ssh_key_dir)
|
24
26
|
path.mkdir(parents=True, exist_ok=True)
|
25
|
-
path.chmod(0o700)
|
26
|
-
except Exception as e:
|
27
|
+
path.chmod(0o700)
|
28
|
+
except Exception as e: # pragma: no cover - OS-related failures
|
27
29
|
logger.error(f"Failed to create required directories: {e}")
|
28
30
|
return False
|
29
|
-
|
30
31
|
return True
|
31
32
|
|
33
|
+
|
34
|
+
def check_requirements() -> bool:
|
35
|
+
"""Check if all requirements are met."""
|
36
|
+
return secure_directory(get_ssh_key_dir())
|
37
|
+
|
32
38
|
def main():
|
33
39
|
"""Run the requestor CLI."""
|
34
40
|
try:
|
@@ -44,6 +50,8 @@ def main():
|
|
44
50
|
sys.exit(1)
|
45
51
|
|
46
52
|
# Run CLI
|
53
|
+
from requestor.cli.commands import cli
|
54
|
+
|
47
55
|
cli()
|
48
56
|
except Exception as e:
|
49
57
|
logger.error(f"Failed to start requestor CLI: {e}")
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{request_vm_on_golem-0.1.35 → request_vm_on_golem-0.1.36}/requestor/services/database_service.py
RENAMED
File without changes
|
{request_vm_on_golem-0.1.35 → request_vm_on_golem-0.1.36}/requestor/services/provider_service.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|