clan-core/pkgs/clan-cli/clan_cli/__init__.py
Johannes Kirschbauer b73246bdfd
All checks were successful
buildbot/nix-build .#checks.aarch64-darwin.nixos-test_install_machine Build done.
buildbot/nix-build .#checks.aarch64-darwin.nixos-flash-installer Build done.
buildbot/nix-build .#checks.aarch64-darwin.nixos-iso-installer Build done.
buildbot/nix-build .#checks.aarch64-linux.nixos-test_install_machine Build done.
buildbot/nix-build .#checks.x86_64-linux.clan-app-no-breakpoints Build done.
buildbot/nix-build .#checks.aarch64-linux.nixos-flash-installer Build done.
buildbot/nix-build .#checks.aarch64-linux.nixos-iso-installer Build done.
buildbot/nix-build .#checks.x86_64-linux.package-clan-ts-api Build done.
buildbot/nix-build .#checks.x86_64-linux.package-clan-cli-docs Build done.
buildbot/nix-build .#checks.x86_64-linux.package-gui-installer-apk Build done.
buildbot/nix-build .#checks.x86_64-linux.clan-dep-age Build done.
buildbot/nix-build .#checks.x86_64-linux.package-gui-installer-deb Build done.
buildbot/nix-build .#checks.x86_64-linux.package-gui-installer-archlinux Build done.
buildbot/nix-build .#checks.x86_64-linux.package-gui-installer-rpm Build done.
buildbot/nix-build .#checks.x86_64-linux.clan-dep-bash Build done.
buildbot/nix-build .#checks.x86_64-linux.clan-dep-e2fsprogs Build done.
buildbot/nix-build .#checks.x86_64-linux.package-module-docs Build done.
buildbot/nix-build .#checks.x86_64-linux.clan-dep-fakeroot Build done.
buildbot/nix-build .#checks.x86_64-linux.clan-dep-git Build done.
buildbot/nix-build .#checks.aarch64-linux.nixos-test-backup Build done.
buildbot/nix-build .#checks.aarch64-darwin.nixos-test-backup Build done.
buildbot/nix-build .#checks.x86_64-linux.renderClanOptions Build done.
buildbot/nix-build .#checks.x86_64-linux.clan-dep-nix Build done.
buildbot/nix-build .#checks.x86_64-linux.devShell-webview-ui Build done.
buildbot/nix-build .#checks.x86_64-linux.clan-dep-openssh Build done.
buildbot/nix-build .#checks.x86_64-linux.check-for-breakpoints Build done.
buildbot/nix-build .#checks.x86_64-linux.package-clan-cli Build done.
buildbot/nix-build .#checks.x86_64-linux.package-default Build done.
buildbot/nix-build .#checks.x86_64-linux."clan-dep-python3.11-mypy" Build done.
buildbot/nix-build .#checks.x86_64-linux.clan-dep-rsync Build done.
buildbot/nix-build .#checks.x86_64-linux.devShell-docs Build done.
buildbot/nix-build .#checks.x86_64-linux.clan-dep-sops Build done.
buildbot/nix-build .#checks.x86_64-linux.clan-dep-sshpass Build done.
buildbot/nix-build .#checks.x86_64-linux.clan-dep-tor Build done.
buildbot/nix-build .#checks.x86_64-linux.clan-dep-zbar Build done.
buildbot/nix-build .#checks.x86_64-linux."clan-dep-python3.11-qemu" Build done.
buildbot/nix-build .#checks.x86_64-linux.nixos-test-backup Build done.
buildbot/nix-build .#checks.x86_64-linux.devShell-clan-cli Build done.
buildbot/nix-build .#checks.x86_64-linux.lib-jsonschema-example-valid Build done.
buildbot/nix-build .#checks.x86_64-linux.container Build done.
buildbot/nix-build .#checks.x86_64-linux.devShell-default Build done.
buildbot/nix-build .#checks.x86_64-linux.borgbackup Build done.
buildbot/nix-build .#checks.x86_64-linux.deltachat Build done.
buildbot/nix-build .#checks.x86_64-linux.clan-app-pytest Build done.
buildbot/nix-build .#checks.x86_64-linux.matrix-synapse Build done.
buildbot/nix-build .#checks.x86_64-linux.package-editor Build done.
buildbot/nix-build .#checks.x86_64-linux.package-impure-checks Build done.
buildbot/nix-build .#checks.x86_64-linux.package-deploy-docs Build done.
buildbot/nix-build .#checks.x86_64-linux.module-schema Build done.
buildbot/nix-build .#checks.x86_64-linux.lib-jsonschema-nix-unit-tests Build done.
buildbot/nix-build .#checks.x86_64-linux.treefmt Build done.
buildbot/nix-build .#checks.x86_64-linux.package-moonlight-sunshine-accept Build done.
buildbot/nix-build .#checks.x86_64-linux.package-docs Build done.
buildbot/nix-build .#checks.x86_64-linux.package-pending-reviews Build done.
buildbot/nix-build .#checks.x86_64-linux.package-tea-create-pr Build done.
buildbot/nix-build .#checks.x86_64-linux.package-merge-after-ci Build done.
buildbot/nix-build .#checks.x86_64-linux.package-zerotier-members Build done.
buildbot/nix-build .#checks.x86_64-linux.package-zt-tcp-relay Build done.
buildbot/nix-build .#checks.x86_64-linux.package-zerotierone Build done.
buildbot/nix-build .#checks.x86_64-linux.nixos-test_install_machine Build done.
buildbot/nix-build .#checks.x86_64-linux.postgresql Build done.
buildbot/nix-build .#checks.x86_64-linux.nixos-flash-installer Build done.
buildbot/nix-build .#checks.x86_64-linux.package-module-schema Build done.
buildbot/nix-build .#checks.x86_64-linux.nixos-iso-installer Build done.
buildbot/nix-build .#checks.x86_64-linux.secrets Build done.
buildbot/nix-build .#checks.x86_64-linux.zt-tcp-relay Build done.
buildbot/nix-build .#checks.x86_64-linux.package-iso-installer Build done.
buildbot/nix-build .#checks.x86_64-linux.template-minimal Build done.
buildbot/nix-build .#checks.x86_64-linux.wayland-proxy-virtwl Build done.
buildbot/nix-build .#checks.x86_64-linux.package-function-schema Build done.
buildbot/nix-build .#checks.x86_64-linux.package-webview-ui Build done.
buildbot/nix-build .#checks.x86_64-linux.package-clan-app Build done.
buildbot/nix-build .#checks.x86_64-linux.clan-pytest-with-core Build done.
buildbot/nix-build .#checks.x86_64-linux.test-backups Build done.
buildbot/nix-build .#checks.x86_64-linux.syncthing Build done.
buildbot/nix-build .#checks.x86_64-linux.devShell-clan-app Build done.
buildbot/nix-build .#checks.x86_64-linux.clan-pytest-without-core Build done.
buildbot/nix-build .#checks.x86_64-linux.package-gui-install-test-ubuntu-22-04 Build done.
checks / checks-impure (pull_request) Successful in 2m15s
buildbot/nix-build .#checks.x86_64-linux.flash Build done.
buildbot/nix-build .#checks.x86_64-linux.test-installation Build done.
buildbot/nix-eval Build done.
API: init methods: hw_generate, dns discovery
2024-06-16 16:29:18 +02:00

355 lines
10 KiB
Python

import argparse
import logging
import sys
from pathlib import Path
from types import ModuleType
# These imports are unused, but necessary for @API.register to run once.
from clan_cli.api import directory, mdns_discovery
from clan_cli.arg_actions import AppendOptionAction
from clan_cli.clan import show
__all__ = ["directory", "mdns_discovery"]
from . import (
backups,
clan,
config,
facts,
flash,
flatpak,
history,
machines,
secrets,
vms,
)
from .custom_logger import setup_logging
from .dirs import get_clan_flake_toplevel_or_env
from .errors import ClanCmdError, ClanError
from .profiler import profile
from .ssh import cli as ssh_cli
log = logging.getLogger(__name__)
argcomplete: ModuleType | None = None
try:
import argcomplete # type: ignore[no-redef]
except ImportError:
pass
def flake_path(arg: str) -> str | Path:
flake_dir = Path(arg).resolve()
if flake_dir.exists() and flake_dir.is_dir():
return flake_dir
return arg
def add_common_flags(parser: argparse.ArgumentParser) -> None:
parser.add_argument(
"--debug",
help="Enable debug logging",
action="store_true",
default=False,
)
parser.add_argument(
"--option",
help="Nix option to set",
nargs=2,
metavar=("name", "value"),
action=AppendOptionAction,
default=[],
)
parser.add_argument(
"--flake",
help="path to the flake where the clan resides in, can be a remote flake or local, can be set through the [CLAN_DIR] environment variable",
default=get_clan_flake_toplevel_or_env(),
metavar="PATH",
type=flake_path,
)
def register_common_flags(parser: argparse.ArgumentParser) -> None:
has_subparsers = False
for action in parser._actions:
if isinstance(action, argparse._SubParsersAction):
for choice, child_parser in action.choices.items():
has_subparsers = True
register_common_flags(child_parser)
if not has_subparsers:
add_common_flags(parser)
def create_parser(prog: str | None = None) -> argparse.ArgumentParser:
parser = argparse.ArgumentParser(
prog=prog,
description="The clan cli tool.",
epilog=(
"""
Online reference for the clan cli tool: https://docs.clan.lol/reference/cli/
For more detailed information, visit: https://docs.clan.lol
"""
),
formatter_class=argparse.RawTextHelpFormatter,
)
subparsers = parser.add_subparsers()
# Commands directly under the root i.e. "clan show"
show_parser = subparsers.add_parser(
"show",
help="Show meta about the clan if present.",
description="Show meta about the clan if present.",
epilog=(
"""
This command prints the metadata of a clan.
Examples:
$ clan show --flake [PATH]
Name: My Empty Clan
Description: some nice description
Icon: A path to the png
Note: The meta results from clan/meta.json and manual flake arguments. It may not be present for clans not created via the clan-app.
"""
),
)
show_parser.set_defaults(func=show.show_command)
parser_backups = subparsers.add_parser(
"backups",
help="manage backups of clan machines",
description="manage backups of clan machines",
epilog=(
"""
This subcommand provides an interface to backups that clan machines expose.
Examples:
$ clan backups list [MACHINE]
List backups for the machine [MACHINE]
$ clan backups create [MACHINE]
Create a backup for the machine [MACHINE].
$ clan backups restore [MACHINE] [PROVIDER] [NAME]
The backup to restore for the machine [MACHINE] with the configured [PROVIDER]
with the name [NAME].
For more detailed information, visit: https://docs.clan.lol/getting-started/backups/
"""
),
formatter_class=argparse.RawTextHelpFormatter,
)
backups.register_parser(parser_backups)
parser_flake = subparsers.add_parser(
"flakes",
help="create a clan flake inside the current directory",
description="create a clan flake inside the current directory",
epilog=(
"""
Examples:
$ clan flakes create [DIR]
Will create a new clan flake in the specified directory and create it if it
doesn't exist yet. The flake will be created from a default template.
For more detailed information, visit: https://docs.clan.lol/getting-started
"""
),
formatter_class=argparse.RawTextHelpFormatter,
)
clan.register_parser(parser_flake)
parser_config = subparsers.add_parser(
"config",
help="read a nixos configuration option",
description="read a nixos configuration option",
epilog=(
"""
"""
),
formatter_class=argparse.RawTextHelpFormatter,
)
config.register_parser(parser_config)
parser_ssh = subparsers.add_parser(
"ssh",
help="ssh to a remote machine",
description="ssh to a remote machine",
epilog=(
"""
This subcommand allows seamless ssh access to the nixos-image builders.
Examples:
$ clan ssh [ssh_args ...] --json [JSON]
Will ssh in to the machine based on the deployment information contained in
the json string. [JSON] can either be a json formatted string itself, or point
towards a file containing the deployment information
For more detailed information, visit: https://docs.clan.lol/getting-started/deploy
"""
),
formatter_class=argparse.RawTextHelpFormatter,
)
ssh_cli.register_parser(parser_ssh)
parser_secrets = subparsers.add_parser(
"secrets",
help="manage secrets",
description="manage secrets",
epilog=(
"""
This subcommand provides an interface to secret facts.
Examples:
$ clan secrets list [regex]
Will list secrets for all managed machines.
It accepts an optional regex, allowing easy filtering of returned secrets.
$ clan secrets get [SECRET]
Will display the content of the specified secret.
For more detailed information, visit: https://docs.clan.lol/getting-started/secrets/
"""
),
formatter_class=argparse.RawTextHelpFormatter,
)
secrets.register_parser(parser_secrets)
parser_facts = subparsers.add_parser(
"facts",
help="manage facts",
description="manage facts",
epilog=(
"""
This subcommand provides an interface to facts of clan machines.
Facts are artifacts that a service can generate.
There are public and secret facts.
Public facts can be referenced by other machines directly.
Public facts can include: ip addresses, public keys.
Secret facts can include: passwords, private keys.
A service is an included clan-module that implements facts generation functionality.
For example the zerotier module will generate private and public facts.
In this case the public fact will be the resulting zerotier-ip of the machine.
The secret fact will be the zerotier-identity-secret, which is used by zerotier
to prove the machine has control of the zerotier-ip.
Examples:
$ clan facts generate
Will generate facts for all machines.
$ clan facts generate --service [SERVICE] --regenerate
Will regenerate facts, if they are already generated for a specific service.
This is especially useful for resetting certain passwords while leaving the rest
of the facts for a machine in place.
For more detailed information, visit: https://docs.clan.lol/getting-started/secrets/
"""
),
formatter_class=argparse.RawTextHelpFormatter,
)
facts.register_parser(parser_facts)
parser_machine = subparsers.add_parser(
"machines",
help="manage machines and their configuration",
description="manage machines and their configuration",
epilog=(
"""
This subcommand provides an interface to machines managed by clan.
Examples:
$ clan machines list
List all the machines managed by clan.
$ clan machines update [MACHINES]
Will update the specified machine [MACHINE], if [MACHINE] is omitted, the command
will attempt to update every configured machine.
$ clan machines install [MACHINES] [TARGET_HOST]
Will install the specified machine [MACHINE], to the specified [TARGET_HOST].
For more detailed information, visit: https://docs.clan.lol/getting-started/deploy
"""
),
formatter_class=argparse.RawTextHelpFormatter,
)
machines.register_parser(parser_machine)
parser_vms = subparsers.add_parser(
"vms", help="manage virtual machines", description="manage virtual machines"
)
vms.register_parser(parser_vms)
parser_history = subparsers.add_parser(
"history",
help="manage history",
description="manage history",
)
history.register_parser(parser_history)
parser_flash = subparsers.add_parser(
"flash",
help="flash machines to usb sticks or into isos",
description="flash machines to usb sticks or into isos",
)
flash.register_parser(parser_flash)
if argcomplete:
argcomplete.autocomplete(parser)
register_common_flags(parser)
return parser
# this will be the entrypoint under /bin/clan (see pyproject.toml config)
@profile
def main() -> None:
parser = create_parser()
args = parser.parse_args()
if len(sys.argv) == 1:
parser.print_help()
if getattr(args, "debug", False):
setup_logging(logging.DEBUG, root_log_name=__name__.split(".")[0])
log.debug("Debug log activated")
if flatpak.is_flatpak():
log.debug("Running inside a flatpak sandbox")
else:
setup_logging(logging.INFO, root_log_name=__name__.split(".")[0])
if not hasattr(args, "func"):
return
try:
args.func(args)
except ClanError as e:
if args.debug:
log.exception(e)
sys.exit(1)
if isinstance(e, ClanCmdError):
if e.cmd.msg:
log.error(e.cmd.msg)
sys.exit(1)
log.error(e)
sys.exit(1)
if __name__ == "__main__":
main()