Skip to content

Commit 3aa896c

Browse files
committed
Add runtime-checker to program cmds
1 parent 775cc27 commit 3aa896c

File tree

3 files changed

+125
-10
lines changed

3 files changed

+125
-10
lines changed

src/aleph_client/commands/program.py

Lines changed: 89 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@
22

33
import json
44
import logging
5+
import re
56
from base64 import b16decode, b32encode
67
from collections.abc import Mapping
78
from pathlib import Path
89
from typing import List, Optional, cast
910
from zipfile import BadZipFile
1011

12+
import aiohttp
1113
import typer
1214
from aleph.sdk import AlephHttpClient, AuthenticatedAlephHttpClient
1315
from aleph.sdk.account import _load_account
@@ -171,14 +173,14 @@ async def upload(
171173
hash_base32 = b32encode(b16decode(item_hash.upper())).strip(b"=").lower().decode()
172174

173175
if verbose:
174-
typer.echo(
175-
f"Your program has been uploaded on aleph.im\n\n"
176-
"Available on:\n"
177-
f" {settings.VM_URL_PATH.format(hash=item_hash)}\n"
178-
f" {settings.VM_URL_HOST.format(hash_base32=hash_base32)}\n"
179-
"Visualise on:\n https://explorer.aleph.im/address/"
180-
f"{message.chain.value}/{message.sender}/message/PROGRAM/{item_hash}\n"
181-
)
176+
typer.echo(
177+
f"Your program has been uploaded on aleph.im\n\n"
178+
"Available on:\n"
179+
f" {settings.VM_URL_PATH.format(hash=item_hash)}\n"
180+
f" {settings.VM_URL_HOST.format(hash_base32=hash_base32)}\n"
181+
"Visualise on:\n https://explorer.aleph.im/address/"
182+
f"{message.chain.value}/{message.sender}/message/PROGRAM/{item_hash}\n"
183+
)
182184
return item_hash
183185

184186

@@ -286,11 +288,11 @@ async def delete(
286288
hashes=[ItemHash(code_volume.item_hash)], reason=f"Deletion of program {item_hash}"
287289
)
288290
if verbose:
289-
typer.echo(f"Code volume {code_volume.item_hash} has been deleted.")
291+
typer.echo(f"Code volume {code_volume.item_hash} has been deleted.")
290292
if print_message:
291293
typer.echo(f"{message.json(indent=4)}")
292294
if verbose:
293-
typer.echo(f"Program {item_hash} has been deleted.")
295+
typer.echo(f"Program {item_hash} has been deleted.")
294296

295297

296298
@app.command(name="list")
@@ -469,3 +471,80 @@ async def logs(
469471
log_entries = await response.json()
470472
for log in log_entries:
471473
echo(f'{log["__REALTIME_TIMESTAMP"]}> {log["MESSAGE"]}')
474+
475+
476+
@app.command()
477+
async def runtime_checker(
478+
item_hash: str = typer.Argument(..., help="Item hash of the runtime to check"),
479+
private_key: Optional[str] = settings.PRIVATE_KEY_STRING,
480+
private_key_file: Optional[Path] = settings.PRIVATE_KEY_FILE,
481+
verbose: bool = False,
482+
debug: bool = False,
483+
):
484+
"""Check versions used by a runtime (distribution, python, nodejs, etc)"""
485+
486+
setup_logging(debug)
487+
488+
echo("Deploy runtime checker program...")
489+
try:
490+
program_hash = await upload(
491+
path=Path(__file__).resolve().parent / "program_utils/runtime_checker.squashfs",
492+
entrypoint="main:app",
493+
channel=settings.DEFAULT_CHANNEL,
494+
memory=settings.DEFAULT_VM_MEMORY,
495+
vcpus=settings.DEFAULT_VM_VCPUS,
496+
timeout_seconds=settings.DEFAULT_VM_TIMEOUT,
497+
name="runtime_checker",
498+
runtime=item_hash,
499+
beta=False,
500+
persistent=False,
501+
skip_volume=True,
502+
private_key=private_key,
503+
private_key_file=private_key_file,
504+
print_messages=False,
505+
print_code_message=False,
506+
print_program_message=False,
507+
verbose=verbose,
508+
debug=debug,
509+
)
510+
except Exception as e:
511+
echo(f"Failed to deploy the runtime checker program: {e}")
512+
raise typer.Exit(code=1)
513+
514+
program_url = settings.VM_URL_PATH.format(hash=program_hash)
515+
versions: dict
516+
echo("Query runtime checker to retrieve versions...")
517+
try:
518+
timeout = aiohttp.ClientTimeout(total=settings.HTTP_REQUEST_TIMEOUT)
519+
async with aiohttp.ClientSession(timeout=timeout) as session:
520+
async with session.get(program_url) as resp:
521+
resp.raise_for_status()
522+
versions = await resp.json()
523+
except Exception as e:
524+
logger.debug(f"Unexpected error when calling {program_url}: {e}")
525+
raise typer.Exit(code=1)
526+
527+
echo("Delete runtime checker...")
528+
try:
529+
await delete(
530+
item_hash=program_hash,
531+
reason="Automatic deletion of the runtime checker program",
532+
delete_code=True,
533+
private_key=private_key,
534+
private_key_file=private_key_file,
535+
print_message=False,
536+
verbose=verbose,
537+
debug=debug,
538+
)
539+
except Exception as e:
540+
echo(f"Failed to delete the runtime checker program: {e}")
541+
raise typer.Exit(code=1)
542+
543+
console = Console()
544+
infos = [Text.from_markup(f"[bold]Ref:[/bold] [bright_cyan]{item_hash}[/bright_cyan]")]
545+
for label, version in versions.items():
546+
color = "green" if bool(re.search(r"\d", version)) else "red"
547+
infos.append(Text.from_markup(f"\n[bold]{label}:[/bold] [{color}]{version}[/{color}]"))
548+
console.print(
549+
Panel(Text.assemble(*infos), title="Runtime Infos", border_style="violet", expand=False, title_align="left")
550+
)
Binary file not shown.
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import platform
2+
import subprocess
3+
from typing import Dict
4+
5+
from fastapi import FastAPI
6+
7+
app = FastAPI()
8+
9+
extra_checks = dict(
10+
Nodejs="node --version",
11+
Rust="rustc --version",
12+
Go="go version",
13+
)
14+
15+
16+
@app.get("/")
17+
async def versions() -> Dict[str, str]:
18+
results = dict()
19+
20+
# Distribution
21+
try:
22+
results["Distribution"] = platform.freedesktop_os_release()["PRETTY_NAME"] # type: ignore
23+
except Exception:
24+
results["Distribution"] = "Not available"
25+
26+
# Python
27+
results["Python"] = platform.python_version()
28+
29+
# Others
30+
for label, command in extra_checks.items():
31+
try:
32+
results[label] = subprocess.check_output(command.split(" ")).decode("utf-8").strip()
33+
except Exception:
34+
results[label] = "Not installed"
35+
36+
return results

0 commit comments

Comments
 (0)