-
Notifications
You must be signed in to change notification settings - Fork 22
[CLI] New CLI tool for node operators #268
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
""" | ||
Global configuration object for the CLI. Use the `get_cli_config()` method | ||
to access and modify the configuration. | ||
""" | ||
|
||
from dataclasses import dataclass | ||
from pathlib import Path | ||
|
||
|
||
@dataclass | ||
class CliConfig: | ||
config_file_path: Path | ||
key_dir: Path | ||
verbose: bool | ||
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,46 @@ | ||||||||||||||||||||||||||||||||||||||||||
import typer | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
from aleph.ccn_cli.cli_config import CliConfig | ||||||||||||||||||||||||||||||||||||||||||
from typing import cast | ||||||||||||||||||||||||||||||||||||||||||
from aleph.ccn_cli.services.keys import generate_keypair, save_keys | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
keys_ns = typer.Typer() | ||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This naming does not seem clear to me. The habit in Typer is
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
@keys_ns.command() | ||||||||||||||||||||||||||||||||||||||||||
def generate(ctx: typer.Context): | ||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Replace
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||
""" | ||||||||||||||||||||||||||||||||||||||||||
Generates a new set of private/public keys for the Core Channel Node. | ||||||||||||||||||||||||||||||||||||||||||
The keys will be created in the key directory. You can modify the destination | ||||||||||||||||||||||||||||||||||||||||||
by using the --key-dir option. | ||||||||||||||||||||||||||||||||||||||||||
""" | ||||||||||||||||||||||||||||||||||||||||||
cli_config = cast(CliConfig, ctx.obj) | ||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This casting is not obvious. Would it be worth adding a comment to explain it ? |
||||||||||||||||||||||||||||||||||||||||||
print(cli_config) | ||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why this |
||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
typer.echo(f"Generating a key pair in {cli_config.key_dir.absolute()}...") | ||||||||||||||||||||||||||||||||||||||||||
key_pair = generate_keypair() | ||||||||||||||||||||||||||||||||||||||||||
save_keys(key_pair, str(cli_config.key_dir)) | ||||||||||||||||||||||||||||||||||||||||||
typer.echo("Done.") | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
@keys_ns.command() | ||||||||||||||||||||||||||||||||||||||||||
def show(ctx: typer.Context): | ||||||||||||||||||||||||||||||||||||||||||
""" | ||||||||||||||||||||||||||||||||||||||||||
Prints the private key of the node. | ||||||||||||||||||||||||||||||||||||||||||
""" | ||||||||||||||||||||||||||||||||||||||||||
cli_config = cast(CliConfig, ctx.obj) | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
key_path = cli_config.key_dir / "node-secret.key" | ||||||||||||||||||||||||||||||||||||||||||
if not key_path.exists(): | ||||||||||||||||||||||||||||||||||||||||||
typer.echo( | ||||||||||||||||||||||||||||||||||||||||||
f"'{key_path.absolute()}' does not exist. Did you run 'keys generate'?", | ||||||||||||||||||||||||||||||||||||||||||
err=True, | ||||||||||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||||||||||
raise typer.Exit(code=1) | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
if not key_path.is_file(): | ||||||||||||||||||||||||||||||||||||||||||
typer.echo(f"'{key_path}' is not a file.", err=True) | ||||||||||||||||||||||||||||||||||||||||||
raise typer.Exit(code=1) | ||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+34
to
+43
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
with key_path.open() as f: | ||||||||||||||||||||||||||||||||||||||||||
typer.echo(f.read()) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
import asyncio | ||
from pathlib import Path | ||
from traceback import format_exc | ||
from typing import Optional | ||
from typing import cast | ||
|
||
import typer | ||
|
||
from aleph.ccn_cli.cli_config import CliConfig | ||
from .migration_runner import run_migrations | ||
|
||
migrations_ns = typer.Typer() | ||
|
||
|
||
FILTER_SCRIPTS_HELP = ( | ||
"A filter for migration scripts. If specified, only the files " | ||
"matching the provided glob expression will be run." | ||
) | ||
|
||
KEY_FILE_HELP = ( | ||
"Path to the private key file, if any. " | ||
"Only used to upgrade the key to the latest format." | ||
) | ||
|
||
|
||
def run_migration_command( | ||
cli_config: CliConfig, | ||
command: str, | ||
filter_scripts: Optional[str], | ||
key_file: Optional[Path], | ||
): | ||
try: | ||
asyncio.run( | ||
run_migrations( | ||
cli_config=cli_config, | ||
command=command, | ||
filter_scripts=filter_scripts, | ||
key_file=key_file, | ||
) | ||
) | ||
except Exception as e: | ||
typer.echo(f"{command} failed: {e}.", err=True) | ||
if cli_config.verbose: | ||
typer.echo(format_exc()) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we really want to only display the exception in verbose mode ? I am wondering if it would not make it easier that any user can copy paste the traceback of an error without running the command again 🤔 |
||
raise typer.Exit(code=1) | ||
|
||
|
||
@migrations_ns.command() | ||
def upgrade( | ||
ctx: typer.Context, | ||
filter_scripts: Optional[str] = typer.Option( | ||
None, | ||
help=FILTER_SCRIPTS_HELP, | ||
), | ||
key_file: Optional[Path] = typer.Option( | ||
None, | ||
help=KEY_FILE_HELP, | ||
), | ||
): | ||
cli_config = cast(CliConfig, ctx.obj) | ||
run_migration_command( | ||
cli_config=cli_config, | ||
command="upgrade", | ||
filter_scripts=filter_scripts, | ||
key_file=key_file, | ||
) | ||
|
||
|
||
@migrations_ns.command() | ||
def downgrade( | ||
ctx: typer.Context, | ||
filter_scripts: Optional[str] = typer.Option( | ||
None, | ||
help=FILTER_SCRIPTS_HELP, | ||
), | ||
key_file: Optional[Path] = typer.Option( | ||
None, | ||
help=KEY_FILE_HELP, | ||
), | ||
): | ||
cli_config = cast(CliConfig, ctx.obj) | ||
run_migration_command( | ||
cli_config=cli_config, | ||
command="downgrade", | ||
filter_scripts=filter_scripts, | ||
key_file=key_file, | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No default ?