文件预览

cli.py

查看 Alibabacloud Emr Starrocks Assistant 技能包中的文件内容。

文件内容

scripts/sr_connect/cli.py

"""click CLI entry points: sr-login / sr-logout / sr-whoami / srsql."""

from __future__ import annotations

import os
import sys

import click

from . import doctor as doctor_mod
from . import login as login_mod
from . import logout as logout_mod
from . import query as query_mod
from . import whoami as whoami_mod
from .errors import SRConnectError


def _read_password_interactive(prompt: str) -> str:
    if not sys.stdin.isatty():
        _fail(
            "sr-login needs a password but stdin is not a TTY. "
            "Set SR_PASSWORD in the environment for non-interactive login, "
            "or run sr-login from an interactive terminal."
        )
    return click.prompt(prompt, hide_input=True, err=True)


def _fail(msg: str, code: int = 1) -> None:
    click.echo(f"ERROR: {msg}", err=True)
    sys.exit(code)


@click.command(name="sr-login")
@click.option("--host", default=None, help="StarRocks FE host (required unless --from-env)")
@click.option("--port", default=9030, show_default=True, type=int)
@click.option("--user", default=None, help="StarRocks user account (required unless --from-env)")
@click.option(
    "--password", default=None, envvar="SR_PASSWORD",
    help="Password. Prefer interactive prompt; SR_PASSWORD env var supported."
)
@click.option(
    "--profile", default="default", show_default=True,
    help="Local profile name; supports multi-cluster (use SR_PROFILE to select at runtime)."
)
@click.option("--ssl", is_flag=True, help="Enable TLS (rarely needed; EMR Serverless uses plain TCP)")
@click.option(
    "--from-env", "from_env", is_flag=True,
    help=(
        "Non-interactive login for CI / sandbox setup scripts. "
        "Reads required SR_HOST / SR_USER / SR_PASSWORD and optional SR_PORT (default 9030) "
        "from the environment. Exits 2 if any required variable is missing."
    ),
)
def login_cmd(host, port, user, password, profile, ssl, from_env):
    """Log into a StarRocks cluster (registers credentials locally; overwrites if exists)."""
    if from_env:
        host = host or os.environ.get("SR_HOST")
        user = user or os.environ.get("SR_USER")
        sr_port = os.environ.get("SR_PORT")
        if sr_port:
            try:
                port = int(sr_port)
            except ValueError:
                _fail(f"SR_PORT must be an integer, got: {sr_port!r}")
        missing = [
            name for name, value in (
                ("SR_HOST", host),
                ("SR_USER", user),
                ("SR_PASSWORD", password),
            ) if not value
        ]
        if missing:
            _fail(
                "--from-env requires these environment variables to be set: "
                + ", ".join(missing),
                code=2,
            )
    else:
        if not host:
            _fail("Missing --host")
        if not user:
            _fail("Missing --user")
        if password is None:
            password = _read_password_interactive(f"Password for {user}@{host}")
    try:
        login_mod.run_login(
            host=host, port=port, user=user, password=password,
            profile=profile, ssl=ssl,
        )
    except SRConnectError as e:
        _fail(str(e))


@click.command(name="sr-logout")
@click.option(
    "--profile",
    default=lambda: os.environ.get("SR_PROFILE", "default"),
    show_default="default or $SR_PROFILE",
)
def logout_cmd(profile):
    """Remove local profile for a cluster."""
    try:
        logout_mod.run_logout(profile=profile)
    except SRConnectError as e:
        _fail(str(e))


@click.command(name="sr-whoami")
@click.option(
    "--profile",
    default=lambda: os.environ.get("SR_PROFILE", "default"),
    show_default="default or $SR_PROFILE",
)
def whoami_cmd(profile):
    """Print current profile state and captured grants."""
    try:
        whoami_mod.run_whoami(profile=profile)
    except SRConnectError as e:
        _fail(str(e))


@click.command(name="sr-doctor")
@click.option(
    "--host",
    default=lambda: os.environ.get("SR_HOST"),
    help="StarRocks FE host to diagnose (defaults to SR_HOST env var)",
)
@click.option(
    "--port",
    default=lambda: int(os.environ.get("SR_PORT", "9030")),
    show_default="9030 or $SR_PORT",
    type=int,
)
def doctor_cmd(host, port):
    """Diagnose connection failures and print actionable next steps."""
    if not host:
        _fail("Missing --host (or set SR_HOST in the environment)")
    sys.exit(doctor_mod.run_doctor(host, port))


@click.command(name="srsql")
@click.option("-e", "--execute", "sql", required=True, help="SQL to execute")
@click.option(
    "--profile",
    default=lambda: os.environ.get("SR_PROFILE", "default"),
    show_default="default or $SR_PROFILE",
)
@click.option(
    "-f", "--format", "fmt",
    default=lambda: os.environ.get("SR_FORMAT", "tsv"),
    type=click.Choice(query_mod.SUPPORTED_FORMATS),
    help="Output format",
)
@click.option("--yes", is_flag=True, help="Confirm execution of non-READ statements")
@click.option(
    "--dry-run", is_flag=True,
    help="Classify SQL and print verdict; do not execute"
)
def srsql_cmd(sql, profile, fmt, yes, dry_run):
    """Execute SQL against a logged-in cluster. Non-READ statements require --yes."""
    try:
        rc = query_mod.run_query(
            profile=profile, sql=sql, fmt=fmt,
            confirm=yes, dry_run=dry_run,
        )
        sys.exit(rc)
    except SRConnectError as e:
        _fail(str(e))