From 6e807c0e8dcebae0549ea0860e04037de2d1ef8b Mon Sep 17 00:00:00 2001 From: ckunki Date: Thu, 18 Sep 2025 13:25:49 +0200 Subject: [PATCH 01/25] #258: Added initial SCS CLI --- doc/changes/unreleased.md | 4 ++ exasol/nb_connector/cli/_decorators.py | 7 ++ exasol/nb_connector/cli/cfg_commands.py | 75 ++++++++++++++++++++ exasol/nb_connector/cli/check_commands.py | 28 ++++++++ exasol/nb_connector/cli/groups.py | 5 ++ exasol/nb_connector/cli/main.py | 11 +++ exasol/nb_connector/cli/options/__init__.py | 6 ++ exasol/nb_connector/cli/options/all.py | 11 +++ exasol/nb_connector/cli/options/bucketfs.py | 74 +++++++++++++++++++ exasol/nb_connector/cli/options/docker_db.py | 30 ++++++++ exasol/nb_connector/cli/options/onprem.py | 44 ++++++++++++ exasol/nb_connector/cli/options/saas.py | 38 ++++++++++ exasol/nb_connector/cli/options/ssl.py | 17 +++++ pyproject.toml | 5 +- 14 files changed, 354 insertions(+), 1 deletion(-) create mode 100644 exasol/nb_connector/cli/_decorators.py create mode 100644 exasol/nb_connector/cli/cfg_commands.py create mode 100644 exasol/nb_connector/cli/check_commands.py create mode 100644 exasol/nb_connector/cli/groups.py create mode 100644 exasol/nb_connector/cli/main.py create mode 100644 exasol/nb_connector/cli/options/__init__.py create mode 100644 exasol/nb_connector/cli/options/all.py create mode 100644 exasol/nb_connector/cli/options/bucketfs.py create mode 100644 exasol/nb_connector/cli/options/docker_db.py create mode 100644 exasol/nb_connector/cli/options/onprem.py create mode 100644 exasol/nb_connector/cli/options/saas.py create mode 100644 exasol/nb_connector/cli/options/ssl.py diff --git a/doc/changes/unreleased.md b/doc/changes/unreleased.md index 7495835c..4af6a4ec 100644 --- a/doc/changes/unreleased.md +++ b/doc/changes/unreleased.md @@ -4,6 +4,10 @@ This release marks most of the NC's dependencies in file `pyproject.toml` as _optional_. Please see updated installation instructions in the NC User Guide. +## Features + +* #258: Added initial SCS CLI + ## Refactorings * #253: Made dependencies optional in file `pyproject.toml` diff --git a/exasol/nb_connector/cli/_decorators.py b/exasol/nb_connector/cli/_decorators.py new file mode 100644 index 00000000..abbef7c2 --- /dev/null +++ b/exasol/nb_connector/cli/_decorators.py @@ -0,0 +1,7 @@ +def add_options(options): + def _add_options(func): + for option in reversed(options): + func = option(func) + return func + + return _add_options diff --git a/exasol/nb_connector/cli/cfg_commands.py b/exasol/nb_connector/cli/cfg_commands.py new file mode 100644 index 00000000..3254a681 --- /dev/null +++ b/exasol/nb_connector/cli/cfg_commands.py @@ -0,0 +1,75 @@ +import click +from exasol.nb_connector.ai_lab_config import Accelerator + +from exasol.ai.mcp.server.cli._decorators import add_options +from exasol.ai.mcp.server.cli.groups import cli +from exasol.ai.mcp.server.cli.options import ( + BUCKETFS_OPTIONS, + COMMON_OPTIONS, + DOCKER_DB_OPTIONS, + ONPREM_OPTIONS, + SAAS_OPTIONS, + SSL_OPTIONS, +) + + +@cli.group() +def configure(): + pass + + +@configure.command("onprem") +@add_options(ONPREM_OPTIONS) +@add_options(BUCKETFS_OPTIONS) +@add_options(SSL_OPTIONS) +@add_options(COMMON_OPTIONS) +def configure_onprem( + db_host_name: str, + db_port: int, + db_username: str, + db_password: str, + db_use_encryption: bool, + bucketfs_host: str, + bucketfs_host_internal: str, + bucketfs_port: int, + bucketfs_port_internal: int, + bucketfs_username: str, + bucketfs_password: str, + bucketfs_service_name: str, + bucketfs_bucket_name: str, + bucketfs_use_encryption: bool, + ssl_use_cert_validation: bool, + ssl_cert_path: str, + db_schema: str, +): + print(f'Password is {db_password}') + + +@configure.command("saas") +@add_options(SAAS_OPTIONS) +@add_options(SSL_OPTIONS) +@add_options(COMMON_OPTIONS) +def configure_saas( + saas_url: str, + saas_account_id: str, + saas_database_id: str, + saas_database_name: str, + saas_token: str, + ssl_use_cert_validation: bool, + ssl_cert_path: str, + db_schema: str, +): + pass + + +@configure.command("docker-db") +@add_options(DOCKER_DB_OPTIONS) +@add_options(COMMON_OPTIONS) +def configure_docker_db( + docker_db_mem_size: int, + docker_db_disk_size: int, + docker_db_accelerator: Accelerator, + db_schema: str, +): + pass + diff --git a/exasol/nb_connector/cli/check_commands.py b/exasol/nb_connector/cli/check_commands.py new file mode 100644 index 00000000..8b8990c8 --- /dev/null +++ b/exasol/nb_connector/cli/check_commands.py @@ -0,0 +1,28 @@ +import click +from exasol.ai.mcp.server.cli.groups import cli +from enum import Enum + + +class Backend(Enum): + ONPREM = "onprem" + SAAS = "saas" + DOCKER_DB = "docker-db" + + @classmethod + def help(cls): + return [x.value for x in cls] + + +@cli.command() +@click.option( + "--backend", + metavar="BACKEND", + required=True, + # show_choices=True, + # show_default=True, + type=click.Choice(Backend.help(), case_sensitive=False), + help=f"Exasol backend for which to check the parameters, one of {Backend.help()}", +) +def check(backend: str): + b = Backend(backend) + print(f'{b}') diff --git a/exasol/nb_connector/cli/groups.py b/exasol/nb_connector/cli/groups.py new file mode 100644 index 00000000..a7929b63 --- /dev/null +++ b/exasol/nb_connector/cli/groups.py @@ -0,0 +1,5 @@ +import click + +@click.group() +def cli(): + pass diff --git a/exasol/nb_connector/cli/main.py b/exasol/nb_connector/cli/main.py new file mode 100644 index 00000000..894a3696 --- /dev/null +++ b/exasol/nb_connector/cli/main.py @@ -0,0 +1,11 @@ +from exasol.ai.mcp.server.cli.groups import cli +import exasol.ai.mcp.server.cli.check_commands +import exasol.ai.mcp.server.cli.cfg_commands + + +def main(): + cli() + + +if __name__ == "__main__": + main() diff --git a/exasol/nb_connector/cli/options/__init__.py b/exasol/nb_connector/cli/options/__init__.py new file mode 100644 index 00000000..aa23fe65 --- /dev/null +++ b/exasol/nb_connector/cli/options/__init__.py @@ -0,0 +1,6 @@ +from exasol.ai.mcp.server.cli.options.all import COMMON_OPTIONS +from exasol.ai.mcp.server.cli.options.bucketfs import BUCKETFS_OPTIONS +from exasol.ai.mcp.server.cli.options.docker_db import DOCKER_DB_OPTIONS +from exasol.ai.mcp.server.cli.options.onprem import ONPREM_OPTIONS +from exasol.ai.mcp.server.cli.options.saas import SAAS_OPTIONS +from exasol.ai.mcp.server.cli.options.ssl import SSL_OPTIONS diff --git a/exasol/nb_connector/cli/options/all.py b/exasol/nb_connector/cli/options/all.py new file mode 100644 index 00000000..3674eb14 --- /dev/null +++ b/exasol/nb_connector/cli/options/all.py @@ -0,0 +1,11 @@ +import click + + +COMMON_OPTIONS = [ + click.option( + "--db-schema", + metavar="DB_SCHEMA", + type=str, + help="Database schema for installing UDFs of Exasol extensions", + ) +] diff --git a/exasol/nb_connector/cli/options/bucketfs.py b/exasol/nb_connector/cli/options/bucketfs.py new file mode 100644 index 00000000..a9ed019b --- /dev/null +++ b/exasol/nb_connector/cli/options/bucketfs.py @@ -0,0 +1,74 @@ +import click + + +BUCKETFS_OPTIONS = [ + click.option( + "--bucketfs-host", + metavar="HOST", + type=str, + default="localhost", + show_default=True, + help="BucketFS host name", + ), + click.option( + "--bucketfs-host-internal", + metavar="HOST", + type=str, + default="localhost", + show_default=True, + help="BucketFS Internal Host Name"), + click.option( + "--bucketfs-port", + metavar="PORT", + type=int, + default=2580, + show_default=True, + help="BucketFS port", + ), + click.option( + "--bucketfs-port-internal", + metavar="PORT", + type=int, + default=2580, + show_default=True, + help="BucketFS internal port", + ), + click.option( + "--bucketfs-username", + metavar="USERNAME", + type=str, + help="BucketFS user name", + ), + click.option( + "--bucketfs-password", + metavar="PASSWORD", + type=str, + prompt=True, + prompt_required=False, + hide_input=True, + help="BucketFS password", + ), + click.option( + "--bucketfs-name", + metavar="BFS_SERVICE", + type=str, + default="bfsdefault", + show_default=True, + help="BucketFS service name", + ), + click.option( + "--bucket", + metavar="BUCKET", + type=str, + default="default", + show_default=True, + help="BucketFS bucket name", + ), + click.option( + "--bucketfs-use-encryption/--no-bucketfs-use-encryption", + type=bool, + default=True, + show_default=True, + help="Whether to encrypt communication with the BucketFS or not", + ), +] diff --git a/exasol/nb_connector/cli/options/docker_db.py b/exasol/nb_connector/cli/options/docker_db.py new file mode 100644 index 00000000..60953af8 --- /dev/null +++ b/exasol/nb_connector/cli/options/docker_db.py @@ -0,0 +1,30 @@ +import click +from exasol.nb_connector.ai_lab_config import Accelerator + + +DOCKER_DB_OPTIONS = [ + click.option( + "--db-mem-size", + type=int, + metavar="GiB", + default=2, + show_default=True, + help="Database memory size (GiB)", + ), + click.option( + "--db-disk-size", + metavar="GiB", + type=int, + default=2, + show_default=True, + help="Database disk size (GiB)", + ), + click.option( + "--accelerator", + type=click.Choice(Accelerator, case_sensitive=False), + default="none", + show_default=True, + help="Hardware acceleration", + ), +] + diff --git a/exasol/nb_connector/cli/options/onprem.py b/exasol/nb_connector/cli/options/onprem.py new file mode 100644 index 00000000..98d79650 --- /dev/null +++ b/exasol/nb_connector/cli/options/onprem.py @@ -0,0 +1,44 @@ +import click + + +ONPREM_OPTIONS = [ + click.option( + "--db-host-name", + metavar="HOST", + type=str, + default="localhost", + show_default=True, + help="Database connection host name", + ), + click.option( + "--db-port", + metavar="PORT", + type=int, + default=8563, + show_default=True, + help="Database connection port", + ), + click.option( + "--db-username", + metavar="USERNAME", + type=str, + help="Database user name", + ), + click.option( + "--db-password", + metavar="PASSWORD", + type=str, + prompt=True, + prompt_required=False, + # show_envvar=True, + hide_input=True, + help="Database password", + ), + click.option( + "--db-use-encryption/--no-db-use-encryption", + type=bool, + default=True, + show_default=True, + help="Whether to encrypt communication with the database or not", + ), +] diff --git a/exasol/nb_connector/cli/options/saas.py b/exasol/nb_connector/cli/options/saas.py new file mode 100644 index 00000000..2c87e916 --- /dev/null +++ b/exasol/nb_connector/cli/options/saas.py @@ -0,0 +1,38 @@ +import click + +SAAS_OPTIONS = [ + click.option( + "--saas-url", + metavar="URL", + type=str, + default="https://cloud.exasol.com", + show_default=True, + help="SaaS service URL", + ), + click.option( + "--saas-account-id", + metavar="ACCOUNT_ID", + type=str, + help="SaaS account ID", + ), + click.option( + "--saas-database-id", + metavar="ID", + type=str, + help="SaaS database ID", + ), + click.option( + "--saas-database-name", + metavar="NAME", + type=str, + help="SaaS database name", + ), + click.option( + "--saas-token", + metavar="PAT", + type=str, + prompt=True, + hide_input=True, + help="SaaS personal access token", + ), +] diff --git a/exasol/nb_connector/cli/options/ssl.py b/exasol/nb_connector/cli/options/ssl.py new file mode 100644 index 00000000..0206d1bb --- /dev/null +++ b/exasol/nb_connector/cli/options/ssl.py @@ -0,0 +1,17 @@ +import click + +SSL_OPTIONS = [ + click.option( + "--ssl-use-cert-validation/--no-ssl-use-cert-validation", + type=bool, + default=True, + show_default=True, + help="Whether to validate SSL certificates or not", + ), + click.option( + "--ssl-cert-path", + metavar="FILE/DIR", + type=str, + help="SSL trusted CA file/dir", + ), + ] diff --git a/pyproject.toml b/pyproject.toml index df9dfc99..1ed5eec9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -145,4 +145,7 @@ max-module-lines = 800 [tool.sonar] projectKey = "com.exasol:notebook-connector" hostUrl = "https://sonarcloud.io" -organization = "exasol" \ No newline at end of file +organization = "exasol" + +[tool.poetry.plugins."console_scripts"] +scs = 'exasol.nb_connector.cli.main:main' From 2a94249e8bf02ae054d6ae31c2b394e029098e0d Mon Sep 17 00:00:00 2001 From: ckunki Date: Thu, 18 Sep 2025 13:30:32 +0200 Subject: [PATCH 02/25] Fixed imports --- exasol/nb_connector/cli/cfg_commands.py | 6 +++--- exasol/nb_connector/cli/check_commands.py | 2 +- exasol/nb_connector/cli/main.py | 6 +++--- exasol/nb_connector/cli/options/__init__.py | 12 ++++++------ 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/exasol/nb_connector/cli/cfg_commands.py b/exasol/nb_connector/cli/cfg_commands.py index 3254a681..09d6a0f7 100644 --- a/exasol/nb_connector/cli/cfg_commands.py +++ b/exasol/nb_connector/cli/cfg_commands.py @@ -1,9 +1,9 @@ import click from exasol.nb_connector.ai_lab_config import Accelerator -from exasol.ai.mcp.server.cli._decorators import add_options -from exasol.ai.mcp.server.cli.groups import cli -from exasol.ai.mcp.server.cli.options import ( +from exasol.nb_connector.cli._decorators import add_options +from exasol.nb_connector.cli.groups import cli +from exasol.nb_connector.cli.options import ( BUCKETFS_OPTIONS, COMMON_OPTIONS, DOCKER_DB_OPTIONS, diff --git a/exasol/nb_connector/cli/check_commands.py b/exasol/nb_connector/cli/check_commands.py index 8b8990c8..6f3b5886 100644 --- a/exasol/nb_connector/cli/check_commands.py +++ b/exasol/nb_connector/cli/check_commands.py @@ -1,5 +1,5 @@ import click -from exasol.ai.mcp.server.cli.groups import cli +from exasol.nb_connector.cli.groups import cli from enum import Enum diff --git a/exasol/nb_connector/cli/main.py b/exasol/nb_connector/cli/main.py index 894a3696..9f60ed1e 100644 --- a/exasol/nb_connector/cli/main.py +++ b/exasol/nb_connector/cli/main.py @@ -1,6 +1,6 @@ -from exasol.ai.mcp.server.cli.groups import cli -import exasol.ai.mcp.server.cli.check_commands -import exasol.ai.mcp.server.cli.cfg_commands +from exasol.nb_connector.cli.groups import cli +import exasol.nb_connector.cli.check_commands +import exasol.nb_connector.cli.cfg_commands def main(): diff --git a/exasol/nb_connector/cli/options/__init__.py b/exasol/nb_connector/cli/options/__init__.py index aa23fe65..38ddb0c7 100644 --- a/exasol/nb_connector/cli/options/__init__.py +++ b/exasol/nb_connector/cli/options/__init__.py @@ -1,6 +1,6 @@ -from exasol.ai.mcp.server.cli.options.all import COMMON_OPTIONS -from exasol.ai.mcp.server.cli.options.bucketfs import BUCKETFS_OPTIONS -from exasol.ai.mcp.server.cli.options.docker_db import DOCKER_DB_OPTIONS -from exasol.ai.mcp.server.cli.options.onprem import ONPREM_OPTIONS -from exasol.ai.mcp.server.cli.options.saas import SAAS_OPTIONS -from exasol.ai.mcp.server.cli.options.ssl import SSL_OPTIONS +from exasol.nb_connector.cli.options.all import COMMON_OPTIONS +from exasol.nb_connector.cli.options.bucketfs import BUCKETFS_OPTIONS +from exasol.nb_connector.cli.options.docker_db import DOCKER_DB_OPTIONS +from exasol.nb_connector.cli.options.onprem import ONPREM_OPTIONS +from exasol.nb_connector.cli.options.saas import SAAS_OPTIONS +from exasol.nb_connector.cli.options.ssl import SSL_OPTIONS From d6c986bebb2b19e98f218b19b3228a7c56029a08 Mon Sep 17 00:00:00 2001 From: ckunki Date: Thu, 18 Sep 2025 14:52:25 +0200 Subject: [PATCH 03/25] Updated CLI configuration Also added environment variables for passwords. --- exasol/nb_connector/cli/_decorators.py | 7 --- exasol/nb_connector/cli/check_commands.py | 28 --------- exasol/nb_connector/cli/commands/check.py | 33 +++++++++++ .../configure.py} | 57 +++++++++++++------ exasol/nb_connector/cli/commands/show.py | 17 ++++++ exasol/nb_connector/cli/groups.py | 6 +- exasol/nb_connector/cli/main.py | 5 +- exasol/nb_connector/cli/options/__init__.py | 3 +- exasol/nb_connector/cli/options/all.py | 26 ++++++++- exasol/nb_connector/cli/options/bucketfs.py | 2 + exasol/nb_connector/cli/options/onprem.py | 3 +- exasol/nb_connector/cli/options/saas.py | 2 + exasol/nb_connector/cli/util.py | 19 +++++++ 13 files changed, 151 insertions(+), 57 deletions(-) delete mode 100644 exasol/nb_connector/cli/_decorators.py delete mode 100644 exasol/nb_connector/cli/check_commands.py create mode 100644 exasol/nb_connector/cli/commands/check.py rename exasol/nb_connector/cli/{cfg_commands.py => commands/configure.py} (50%) create mode 100644 exasol/nb_connector/cli/commands/show.py create mode 100644 exasol/nb_connector/cli/util.py diff --git a/exasol/nb_connector/cli/_decorators.py b/exasol/nb_connector/cli/_decorators.py deleted file mode 100644 index abbef7c2..00000000 --- a/exasol/nb_connector/cli/_decorators.py +++ /dev/null @@ -1,7 +0,0 @@ -def add_options(options): - def _add_options(func): - for option in reversed(options): - func = option(func) - return func - - return _add_options diff --git a/exasol/nb_connector/cli/check_commands.py b/exasol/nb_connector/cli/check_commands.py deleted file mode 100644 index 6f3b5886..00000000 --- a/exasol/nb_connector/cli/check_commands.py +++ /dev/null @@ -1,28 +0,0 @@ -import click -from exasol.nb_connector.cli.groups import cli -from enum import Enum - - -class Backend(Enum): - ONPREM = "onprem" - SAAS = "saas" - DOCKER_DB = "docker-db" - - @classmethod - def help(cls): - return [x.value for x in cls] - - -@cli.command() -@click.option( - "--backend", - metavar="BACKEND", - required=True, - # show_choices=True, - # show_default=True, - type=click.Choice(Backend.help(), case_sensitive=False), - help=f"Exasol backend for which to check the parameters, one of {Backend.help()}", -) -def check(backend: str): - b = Backend(backend) - print(f'{b}') diff --git a/exasol/nb_connector/cli/commands/check.py b/exasol/nb_connector/cli/commands/check.py new file mode 100644 index 00000000..0432ca87 --- /dev/null +++ b/exasol/nb_connector/cli/commands/check.py @@ -0,0 +1,33 @@ +from pathlib import Path + +from exasol.nb_connector.cli.groups import cli +from exasol.nb_connector.cli.options import SCS_OPTIONS +from exasol.nb_connector.cli.util import add_options + + +@cli.group( + help="""Check the configuration current contained in the Secure + Configuration Storage.""" +) +def check(): + pass + + +@check.command( + help="""Verify if all required parameters are saved in the SCS.""" +) +@add_options(SCS_OPTIONS) +def configuration(scs_file: Path, scs_password: str): + # conf = None + # b = get_backend(conf) + pass + + +@check.command( + help="""Verify successful connection to the configured Exasol database + instance.""" +) +@add_options(SCS_OPTIONS) +def connection(scs_file: Path, scs_password: str): + print(f'scs_file: {scs_file}') + print(f'scs_password: {scs_password}') diff --git a/exasol/nb_connector/cli/cfg_commands.py b/exasol/nb_connector/cli/commands/configure.py similarity index 50% rename from exasol/nb_connector/cli/cfg_commands.py rename to exasol/nb_connector/cli/commands/configure.py index 09d6a0f7..f0be77ce 100644 --- a/exasol/nb_connector/cli/cfg_commands.py +++ b/exasol/nb_connector/cli/commands/configure.py @@ -1,29 +1,39 @@ import click -from exasol.nb_connector.ai_lab_config import Accelerator +from pathlib import Path +from exasol.nb_connector.ai_lab_config import Accelerator, StorageBackend -from exasol.nb_connector.cli._decorators import add_options +from exasol.nb_connector.cli.util import add_options from exasol.nb_connector.cli.groups import cli from exasol.nb_connector.cli.options import ( BUCKETFS_OPTIONS, - COMMON_OPTIONS, + COMMON_CONFIGURE_OPTIONS, DOCKER_DB_OPTIONS, ONPREM_OPTIONS, SAAS_OPTIONS, + SCS_OPTIONS, SSL_OPTIONS, ) -@cli.group() +@cli.group( + help="Add configuration options to the Secure Configuration Storage." +) def configure(): pass -@configure.command("onprem") +@configure.command( + "onprem", + help="Configure connection to an Exasol on-premise instance." +) +@add_options(SCS_OPTIONS) @add_options(ONPREM_OPTIONS) @add_options(BUCKETFS_OPTIONS) @add_options(SSL_OPTIONS) -@add_options(COMMON_OPTIONS) +@add_options(COMMON_CONFIGURE_OPTIONS) def configure_onprem( + scs_file: Path, + scs_password: str, db_host_name: str, db_port: int, db_username: str, @@ -35,21 +45,29 @@ def configure_onprem( bucketfs_port_internal: int, bucketfs_username: str, bucketfs_password: str, - bucketfs_service_name: str, - bucketfs_bucket_name: str, + bucketfs_name: str, + bucket: str, bucketfs_use_encryption: bool, ssl_use_cert_validation: bool, ssl_cert_path: str, db_schema: str, ): - print(f'Password is {db_password}') + backend = StorageBackend.onprem + print(f'SCS Master Password: {scs_password}') + print(f'DB Password: {db_password}') -@configure.command("saas") +@configure.command( + "saas", + help="Configure connection to an Exasol SaaS instance." +) +@add_options(SCS_OPTIONS) @add_options(SAAS_OPTIONS) @add_options(SSL_OPTIONS) -@add_options(COMMON_OPTIONS) +@add_options(COMMON_CONFIGURE_OPTIONS) def configure_saas( + scs_file: Path, + scs_password: str, saas_url: str, saas_account_id: str, saas_database_id: str, @@ -59,17 +77,24 @@ def configure_saas( ssl_cert_path: str, db_schema: str, ): - pass + backend = StorageBackend.saas -@configure.command("docker-db") +@configure.command( + "docker-db", + help="Configure connection to an Exasol Docker instance." +) +@add_options(SCS_OPTIONS) @add_options(DOCKER_DB_OPTIONS) -@add_options(COMMON_OPTIONS) +@add_options(COMMON_CONFIGURE_OPTIONS) def configure_docker_db( + scs_file: Path, + scs_password: str, docker_db_mem_size: int, docker_db_disk_size: int, docker_db_accelerator: Accelerator, db_schema: str, ): - pass - + # CKey.use_itde + # CKey.storage_backend + backend = StorageBackend.onprem diff --git a/exasol/nb_connector/cli/commands/show.py b/exasol/nb_connector/cli/commands/show.py new file mode 100644 index 00000000..b3bd24c3 --- /dev/null +++ b/exasol/nb_connector/cli/commands/show.py @@ -0,0 +1,17 @@ +from pathlib import Path + +from exasol.nb_connector.cli.groups import cli +from exasol.nb_connector.cli.options import SCS_OPTIONS +from exasol.nb_connector.cli.util import add_options + + +@cli.command( + help="""Show the configuration currently saved to the Secure Configuration + Storage.""" +) +@add_options(SCS_OPTIONS) +def show( + scs_file: Path, + scs_password: str, +): + pass diff --git a/exasol/nb_connector/cli/groups.py b/exasol/nb_connector/cli/groups.py index a7929b63..12edfa29 100644 --- a/exasol/nb_connector/cli/groups.py +++ b/exasol/nb_connector/cli/groups.py @@ -1,5 +1,9 @@ import click -@click.group() + +@click.group( + help="""Manage Application configuration data in the Secure Configuration + Storage (SCS).""" +) def cli(): pass diff --git a/exasol/nb_connector/cli/main.py b/exasol/nb_connector/cli/main.py index 9f60ed1e..efae3c56 100644 --- a/exasol/nb_connector/cli/main.py +++ b/exasol/nb_connector/cli/main.py @@ -1,6 +1,7 @@ from exasol.nb_connector.cli.groups import cli -import exasol.nb_connector.cli.check_commands -import exasol.nb_connector.cli.cfg_commands +import exasol.nb_connector.cli.commands.configure +import exasol.nb_connector.cli.commands.check +import exasol.nb_connector.cli.commands.show def main(): diff --git a/exasol/nb_connector/cli/options/__init__.py b/exasol/nb_connector/cli/options/__init__.py index 38ddb0c7..2052c35f 100644 --- a/exasol/nb_connector/cli/options/__init__.py +++ b/exasol/nb_connector/cli/options/__init__.py @@ -1,4 +1,5 @@ -from exasol.nb_connector.cli.options.all import COMMON_OPTIONS +from exasol.nb_connector.cli.options.all import SCS_OPTIONS +from exasol.nb_connector.cli.options.all import COMMON_CONFIGURE_OPTIONS from exasol.nb_connector.cli.options.bucketfs import BUCKETFS_OPTIONS from exasol.nb_connector.cli.options.docker_db import DOCKER_DB_OPTIONS from exasol.nb_connector.cli.options.onprem import ONPREM_OPTIONS diff --git a/exasol/nb_connector/cli/options/all.py b/exasol/nb_connector/cli/options/all.py index 3674eb14..961117e3 100644 --- a/exasol/nb_connector/cli/options/all.py +++ b/exasol/nb_connector/cli/options/all.py @@ -1,7 +1,31 @@ import click +from pathlib import Path -COMMON_OPTIONS = [ +SCS_OPTIONS = [ + click.option( + "--scs-file", + metavar="PATH", + type=Path, + help="File containing the Secure Configuration Storage (SCS)", + ), + click.option( + "--scs-master-password", + "scs_password", + metavar="PASSWORD", + type=str, + prompt=True, + prompt_required=False, + # show_envvar=True, + hide_input=True, + envvar="SCS_MASTER_PASSWORD", + show_envvar=True, + help="Master password for the SCS", + ), +] + + +COMMON_CONFIGURE_OPTIONS = [ click.option( "--db-schema", metavar="DB_SCHEMA", diff --git a/exasol/nb_connector/cli/options/bucketfs.py b/exasol/nb_connector/cli/options/bucketfs.py index a9ed019b..1cf994df 100644 --- a/exasol/nb_connector/cli/options/bucketfs.py +++ b/exasol/nb_connector/cli/options/bucketfs.py @@ -46,6 +46,8 @@ prompt=True, prompt_required=False, hide_input=True, + envvar="EXASOL_BUCKETFS_PASSWORD", + show_envvar=True, help="BucketFS password", ), click.option( diff --git a/exasol/nb_connector/cli/options/onprem.py b/exasol/nb_connector/cli/options/onprem.py index 98d79650..c69fd940 100644 --- a/exasol/nb_connector/cli/options/onprem.py +++ b/exasol/nb_connector/cli/options/onprem.py @@ -30,8 +30,9 @@ type=str, prompt=True, prompt_required=False, - # show_envvar=True, hide_input=True, + envvar="EXASOL_DB_PASSWORD", + show_envvar=True, help="Database password", ), click.option( diff --git a/exasol/nb_connector/cli/options/saas.py b/exasol/nb_connector/cli/options/saas.py index 2c87e916..1a9146fa 100644 --- a/exasol/nb_connector/cli/options/saas.py +++ b/exasol/nb_connector/cli/options/saas.py @@ -33,6 +33,8 @@ type=str, prompt=True, hide_input=True, + envvar="EXASOL_SAAS_TOKEN", + show_envvar=True, help="SaaS personal access token", ), ] diff --git a/exasol/nb_connector/cli/util.py b/exasol/nb_connector/cli/util.py new file mode 100644 index 00000000..2b839262 --- /dev/null +++ b/exasol/nb_connector/cli/util.py @@ -0,0 +1,19 @@ +# from enum import Enum + +def add_options(options): + def _add_options(func): + for option in reversed(options): + func = option(func) + return func + + return _add_options + + +# class Backend(Enum): +# ONPREM = "onprem" +# SAAS = "saas" +# DOCKER_DB = "docker-db" +# +# @classmethod +# def help(cls): +# return [x.value for x in cls] From 1ac901c1eb2187ba83508a5fbcbed30e665ff74b Mon Sep 17 00:00:00 2001 From: ckunki Date: Thu, 18 Sep 2025 15:10:00 +0200 Subject: [PATCH 04/25] Used type=Path --- exasol/nb_connector/cli/commands/configure.py | 4 ++-- exasol/nb_connector/cli/options/all.py | 2 +- exasol/nb_connector/cli/options/bucketfs.py | 2 +- exasol/nb_connector/cli/options/ssl.py | 4 +++- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/exasol/nb_connector/cli/commands/configure.py b/exasol/nb_connector/cli/commands/configure.py index f0be77ce..2cbecca8 100644 --- a/exasol/nb_connector/cli/commands/configure.py +++ b/exasol/nb_connector/cli/commands/configure.py @@ -49,7 +49,7 @@ def configure_onprem( bucket: str, bucketfs_use_encryption: bool, ssl_use_cert_validation: bool, - ssl_cert_path: str, + ssl_cert_path: Path, db_schema: str, ): backend = StorageBackend.onprem @@ -74,7 +74,7 @@ def configure_saas( saas_database_name: str, saas_token: str, ssl_use_cert_validation: bool, - ssl_cert_path: str, + ssl_cert_path: Path, db_schema: str, ): backend = StorageBackend.saas diff --git a/exasol/nb_connector/cli/options/all.py b/exasol/nb_connector/cli/options/all.py index 961117e3..ec3d27d1 100644 --- a/exasol/nb_connector/cli/options/all.py +++ b/exasol/nb_connector/cli/options/all.py @@ -5,7 +5,7 @@ SCS_OPTIONS = [ click.option( "--scs-file", - metavar="PATH", + metavar="FILE", type=Path, help="File containing the Secure Configuration Storage (SCS)", ), diff --git a/exasol/nb_connector/cli/options/bucketfs.py b/exasol/nb_connector/cli/options/bucketfs.py index 1cf994df..1f3ae357 100644 --- a/exasol/nb_connector/cli/options/bucketfs.py +++ b/exasol/nb_connector/cli/options/bucketfs.py @@ -34,7 +34,7 @@ help="BucketFS internal port", ), click.option( - "--bucketfs-username", + "--bucketfs-user", metavar="USERNAME", type=str, help="BucketFS user name", diff --git a/exasol/nb_connector/cli/options/ssl.py b/exasol/nb_connector/cli/options/ssl.py index 0206d1bb..b9fa715b 100644 --- a/exasol/nb_connector/cli/options/ssl.py +++ b/exasol/nb_connector/cli/options/ssl.py @@ -1,3 +1,5 @@ +from pathlib import Path + import click SSL_OPTIONS = [ @@ -11,7 +13,7 @@ click.option( "--ssl-cert-path", metavar="FILE/DIR", - type=str, + type=Path, help="SSL trusted CA file/dir", ), ] From 2bc8e55e0522dace1e216fb4125f9b434b061776 Mon Sep 17 00:00:00 2001 From: ckunki Date: Fri, 19 Sep 2025 17:47:11 +0200 Subject: [PATCH 05/25] Initial implementation of options only --- exasol/nb_connector/cli/commands/check.py | 16 ++-- exasol/nb_connector/cli/commands/configure.py | 94 +++---------------- exasol/nb_connector/cli/commands/show.py | 4 +- exasol/nb_connector/cli/main.py | 4 +- exasol/nb_connector/cli/options/__init__.py | 24 ++++- exasol/nb_connector/cli/options/all.py | 12 ++- exasol/nb_connector/cli/options/bucketfs.py | 32 +++++-- exasol/nb_connector/cli/options/docker_db.py | 16 ++-- exasol/nb_connector/cli/options/onprem.py | 19 ++-- exasol/nb_connector/cli/options/saas.py | 23 +++-- exasol/nb_connector/cli/options/ssl.py | 12 ++- exasol/nb_connector/cli/scs_options.py | 79 ++++++++++++++++ exasol/nb_connector/cli/util.py | 19 ---- 13 files changed, 201 insertions(+), 153 deletions(-) create mode 100644 exasol/nb_connector/cli/scs_options.py delete mode 100644 exasol/nb_connector/cli/util.py diff --git a/exasol/nb_connector/cli/commands/check.py b/exasol/nb_connector/cli/commands/check.py index 0432ca87..8a2d5d42 100644 --- a/exasol/nb_connector/cli/commands/check.py +++ b/exasol/nb_connector/cli/commands/check.py @@ -2,7 +2,7 @@ from exasol.nb_connector.cli.groups import cli from exasol.nb_connector.cli.options import SCS_OPTIONS -from exasol.nb_connector.cli.util import add_options +from exasol.nb_connector.cli.scs_options import click_options @cli.group( @@ -13,13 +13,9 @@ def check(): pass -@check.command( - help="""Verify if all required parameters are saved in the SCS.""" -) -@add_options(SCS_OPTIONS) +@check.command(help="Verify if all required parameters are saved in the SCS.") +@click_options(SCS_OPTIONS) def configuration(scs_file: Path, scs_password: str): - # conf = None - # b = get_backend(conf) pass @@ -27,7 +23,7 @@ def configuration(scs_file: Path, scs_password: str): help="""Verify successful connection to the configured Exasol database instance.""" ) -@add_options(SCS_OPTIONS) +@click_options(SCS_OPTIONS) def connection(scs_file: Path, scs_password: str): - print(f'scs_file: {scs_file}') - print(f'scs_password: {scs_password}') + print(f"scs_file: {scs_file}") + print(f"scs_password: {scs_password}") diff --git a/exasol/nb_connector/cli/commands/configure.py b/exasol/nb_connector/cli/commands/configure.py index 2cbecca8..334a9263 100644 --- a/exasol/nb_connector/cli/commands/configure.py +++ b/exasol/nb_connector/cli/commands/configure.py @@ -1,100 +1,34 @@ -import click -from pathlib import Path -from exasol.nb_connector.ai_lab_config import Accelerator, StorageBackend - -from exasol.nb_connector.cli.util import add_options from exasol.nb_connector.cli.groups import cli from exasol.nb_connector.cli.options import ( - BUCKETFS_OPTIONS, - COMMON_CONFIGURE_OPTIONS, DOCKER_DB_OPTIONS, ONPREM_OPTIONS, SAAS_OPTIONS, - SCS_OPTIONS, - SSL_OPTIONS, ) +from exasol.nb_connector.cli.scs_options import click_options -@cli.group( - help="Add configuration options to the Secure Configuration Storage." -) +@cli.group(help="Add configuration options to the Secure Configuration Storage.") def configure(): pass @configure.command( - "onprem", - help="Configure connection to an Exasol on-premise instance." + "onprem", help="Configure connection to an Exasol on-premise instance." ) -@add_options(SCS_OPTIONS) -@add_options(ONPREM_OPTIONS) -@add_options(BUCKETFS_OPTIONS) -@add_options(SSL_OPTIONS) -@add_options(COMMON_CONFIGURE_OPTIONS) -def configure_onprem( - scs_file: Path, - scs_password: str, - db_host_name: str, - db_port: int, - db_username: str, - db_password: str, - db_use_encryption: bool, - bucketfs_host: str, - bucketfs_host_internal: str, - bucketfs_port: int, - bucketfs_port_internal: int, - bucketfs_username: str, - bucketfs_password: str, - bucketfs_name: str, - bucket: str, - bucketfs_use_encryption: bool, - ssl_use_cert_validation: bool, - ssl_cert_path: Path, - db_schema: str, -): - backend = StorageBackend.onprem - print(f'SCS Master Password: {scs_password}') - print(f'DB Password: {db_password}') +@click_options(ONPREM_OPTIONS) +def configure_onprem(**kwargs): + pass -@configure.command( - "saas", - help="Configure connection to an Exasol SaaS instance." -) -@add_options(SCS_OPTIONS) -@add_options(SAAS_OPTIONS) -@add_options(SSL_OPTIONS) -@add_options(COMMON_CONFIGURE_OPTIONS) -def configure_saas( - scs_file: Path, - scs_password: str, - saas_url: str, - saas_account_id: str, - saas_database_id: str, - saas_database_name: str, - saas_token: str, - ssl_use_cert_validation: bool, - ssl_cert_path: Path, - db_schema: str, -): - backend = StorageBackend.saas +@configure.command("saas", help="Configure connection to an Exasol SaaS instance.") +@click_options(SAAS_OPTIONS) +def configure_saas(**kwargs): + pass @configure.command( - "docker-db", - help="Configure connection to an Exasol Docker instance." + "docker-db", help="Configure connection to an Exasol Docker instance." ) -@add_options(SCS_OPTIONS) -@add_options(DOCKER_DB_OPTIONS) -@add_options(COMMON_CONFIGURE_OPTIONS) -def configure_docker_db( - scs_file: Path, - scs_password: str, - docker_db_mem_size: int, - docker_db_disk_size: int, - docker_db_accelerator: Accelerator, - db_schema: str, -): - # CKey.use_itde - # CKey.storage_backend - backend = StorageBackend.onprem +@click_options(DOCKER_DB_OPTIONS) +def configure_docker_db(**kwargs): + pass diff --git a/exasol/nb_connector/cli/commands/show.py b/exasol/nb_connector/cli/commands/show.py index b3bd24c3..a1606b18 100644 --- a/exasol/nb_connector/cli/commands/show.py +++ b/exasol/nb_connector/cli/commands/show.py @@ -2,14 +2,14 @@ from exasol.nb_connector.cli.groups import cli from exasol.nb_connector.cli.options import SCS_OPTIONS -from exasol.nb_connector.cli.util import add_options +from exasol.nb_connector.cli.scs_options import click_options @cli.command( help="""Show the configuration currently saved to the Secure Configuration Storage.""" ) -@add_options(SCS_OPTIONS) +@click_options(SCS_OPTIONS) def show( scs_file: Path, scs_password: str, diff --git a/exasol/nb_connector/cli/main.py b/exasol/nb_connector/cli/main.py index efae3c56..0520942d 100644 --- a/exasol/nb_connector/cli/main.py +++ b/exasol/nb_connector/cli/main.py @@ -1,7 +1,7 @@ -from exasol.nb_connector.cli.groups import cli -import exasol.nb_connector.cli.commands.configure import exasol.nb_connector.cli.commands.check +import exasol.nb_connector.cli.commands.configure import exasol.nb_connector.cli.commands.show +from exasol.nb_connector.cli.groups import cli def main(): diff --git a/exasol/nb_connector/cli/options/__init__.py b/exasol/nb_connector/cli/options/__init__.py index 2052c35f..d95c0b14 100644 --- a/exasol/nb_connector/cli/options/__init__.py +++ b/exasol/nb_connector/cli/options/__init__.py @@ -1,7 +1,21 @@ -from exasol.nb_connector.cli.options.all import SCS_OPTIONS -from exasol.nb_connector.cli.options.all import COMMON_CONFIGURE_OPTIONS +from exasol.nb_connector.cli.options.all import ( + COMMON_CONFIGURE_OPTIONS, + SCS_OPTIONS, +) from exasol.nb_connector.cli.options.bucketfs import BUCKETFS_OPTIONS -from exasol.nb_connector.cli.options.docker_db import DOCKER_DB_OPTIONS -from exasol.nb_connector.cli.options.onprem import ONPREM_OPTIONS -from exasol.nb_connector.cli.options.saas import SAAS_OPTIONS +from exasol.nb_connector.cli.options.docker_db import EXTRA_DOCKER_DB_OPTIONS +from exasol.nb_connector.cli.options.onprem import ONPREM_DB_OPTIONS +from exasol.nb_connector.cli.options.saas import EXTRA_SAAS_OPTIONS from exasol.nb_connector.cli.options.ssl import SSL_OPTIONS + +DOCKER_DB_OPTIONS = SCS_OPTIONS + EXTRA_DOCKER_DB_OPTIONS + COMMON_CONFIGURE_OPTIONS + +SAAS_OPTIONS = SCS_OPTIONS + EXTRA_SAAS_OPTIONS + SSL_OPTIONS + COMMON_CONFIGURE_OPTIONS + +ONPREM_OPTIONS = ( + SCS_OPTIONS + + ONPREM_DB_OPTIONS + + BUCKETFS_OPTIONS + + SSL_OPTIONS + + COMMON_CONFIGURE_OPTIONS +) diff --git a/exasol/nb_connector/cli/options/all.py b/exasol/nb_connector/cli/options/all.py index ec3d27d1..2dda9c04 100644 --- a/exasol/nb_connector/cli/options/all.py +++ b/exasol/nb_connector/cli/options/all.py @@ -1,19 +1,23 @@ -import click from pathlib import Path +from exasol.nb_connector.cli.scs_options import ScsOption SCS_OPTIONS = [ - click.option( + ScsOption( "--scs-file", metavar="FILE", type=Path, + required=True, + envvar="SCS_FILE", + show_envvar=True, help="File containing the Secure Configuration Storage (SCS)", ), - click.option( + ScsOption( "--scs-master-password", "scs_password", metavar="PASSWORD", type=str, + required=True, prompt=True, prompt_required=False, # show_envvar=True, @@ -26,7 +30,7 @@ COMMON_CONFIGURE_OPTIONS = [ - click.option( + ScsOption( "--db-schema", metavar="DB_SCHEMA", type=str, diff --git a/exasol/nb_connector/cli/options/bucketfs.py b/exasol/nb_connector/cli/options/bucketfs.py index 1f3ae357..b345b132 100644 --- a/exasol/nb_connector/cli/options/bucketfs.py +++ b/exasol/nb_connector/cli/options/bucketfs.py @@ -1,45 +1,53 @@ import click +from exasol.nb_connector.ai_lab_config import AILabConfig as CKey +from exasol.nb_connector.cli.scs_options import ScsOption BUCKETFS_OPTIONS = [ - click.option( + ScsOption( "--bucketfs-host", metavar="HOST", type=str, default="localhost", show_default=True, help="BucketFS host name", + scs_key=CKey.bfs_host_name, ), - click.option( + ScsOption( "--bucketfs-host-internal", metavar="HOST", type=str, default="localhost", show_default=True, - help="BucketFS Internal Host Name"), - click.option( + help="BucketFS Internal Host Name", + scs_key=CKey.bfs_internal_host_name, + ), + ScsOption( "--bucketfs-port", metavar="PORT", type=int, default=2580, show_default=True, help="BucketFS port", + scs_key="bucketfs_port", ), - click.option( + ScsOption( "--bucketfs-port-internal", metavar="PORT", type=int, default=2580, show_default=True, help="BucketFS internal port", + scs_key=CKey.bfs_internal_port, ), - click.option( + ScsOption( "--bucketfs-user", metavar="USERNAME", type=str, help="BucketFS user name", + scs_key=CKey.bfs_user, ), - click.option( + ScsOption( "--bucketfs-password", metavar="PASSWORD", type=str, @@ -49,28 +57,32 @@ envvar="EXASOL_BUCKETFS_PASSWORD", show_envvar=True, help="BucketFS password", + scs_key=CKey.bfs_password, ), - click.option( + ScsOption( "--bucketfs-name", metavar="BFS_SERVICE", type=str, default="bfsdefault", show_default=True, help="BucketFS service name", + scs_key="bucketfs_name", ), - click.option( + ScsOption( "--bucket", metavar="BUCKET", type=str, default="default", show_default=True, help="BucketFS bucket name", + scs_key=CKey.bfs_bucket, ), - click.option( + ScsOption( "--bucketfs-use-encryption/--no-bucketfs-use-encryption", type=bool, default=True, show_default=True, help="Whether to encrypt communication with the BucketFS or not", + scs_key=CKey.bfs_encryption, ), ] diff --git a/exasol/nb_connector/cli/options/docker_db.py b/exasol/nb_connector/cli/options/docker_db.py index 60953af8..2f206c8c 100644 --- a/exasol/nb_connector/cli/options/docker_db.py +++ b/exasol/nb_connector/cli/options/docker_db.py @@ -1,30 +1,34 @@ import click -from exasol.nb_connector.ai_lab_config import Accelerator +from exasol.nb_connector.ai_lab_config import Accelerator +from exasol.nb_connector.ai_lab_config import AILabConfig as CKey +from exasol.nb_connector.cli.scs_options import ScsOption -DOCKER_DB_OPTIONS = [ - click.option( +EXTRA_DOCKER_DB_OPTIONS = [ + ScsOption( "--db-mem-size", type=int, metavar="GiB", default=2, show_default=True, help="Database memory size (GiB)", + scs_key=CKey.mem_size, ), - click.option( + ScsOption( "--db-disk-size", metavar="GiB", type=int, default=2, show_default=True, help="Database disk size (GiB)", + scs_key=CKey.disk_size, ), - click.option( + ScsOption( "--accelerator", type=click.Choice(Accelerator, case_sensitive=False), default="none", show_default=True, help="Hardware acceleration", + scs_key=CKey.accelerator, ), ] - diff --git a/exasol/nb_connector/cli/options/onprem.py b/exasol/nb_connector/cli/options/onprem.py index c69fd940..73a533eb 100644 --- a/exasol/nb_connector/cli/options/onprem.py +++ b/exasol/nb_connector/cli/options/onprem.py @@ -1,30 +1,35 @@ import click +from exasol.nb_connector.ai_lab_config import AILabConfig as CKey +from exasol.nb_connector.cli.scs_options import ScsOption -ONPREM_OPTIONS = [ - click.option( +ONPREM_DB_OPTIONS = [ + ScsOption( "--db-host-name", metavar="HOST", type=str, default="localhost", show_default=True, help="Database connection host name", + scs_key=CKey.db_host_name, ), - click.option( + ScsOption( "--db-port", metavar="PORT", type=int, default=8563, show_default=True, help="Database connection port", + scs_key=CKey.db_port, ), - click.option( + ScsOption( "--db-username", metavar="USERNAME", type=str, help="Database user name", + scs_key=CKey.db_user, ), - click.option( + ScsOption( "--db-password", metavar="PASSWORD", type=str, @@ -34,12 +39,14 @@ envvar="EXASOL_DB_PASSWORD", show_envvar=True, help="Database password", + scs_key=CKey.db_password, ), - click.option( + ScsOption( "--db-use-encryption/--no-db-use-encryption", type=bool, default=True, show_default=True, help="Whether to encrypt communication with the database or not", + scs_key=CKey.db_encryption, ), ] diff --git a/exasol/nb_connector/cli/options/saas.py b/exasol/nb_connector/cli/options/saas.py index 1a9146fa..25f3cfe3 100644 --- a/exasol/nb_connector/cli/options/saas.py +++ b/exasol/nb_connector/cli/options/saas.py @@ -1,40 +1,51 @@ import click -SAAS_OPTIONS = [ - click.option( +from exasol.nb_connector.ai_lab_config import AILabConfig as CKey +from exasol.nb_connector.cli.scs_options import ScsOption + +EXTRA_SAAS_OPTIONS = [ + ScsOption( "--saas-url", metavar="URL", type=str, default="https://cloud.exasol.com", show_default=True, help="SaaS service URL", + scs_key=CKey.saas_url, ), - click.option( + ScsOption( "--saas-account-id", metavar="ACCOUNT_ID", type=str, help="SaaS account ID", + scs_key=CKey.saas_account_id, ), - click.option( + ScsOption( "--saas-database-id", metavar="ID", type=str, help="SaaS database ID", + scs_key=CKey.saas_database_id, + scs_alternative_key=CKey.saas_database_name, ), - click.option( + ScsOption( "--saas-database-name", metavar="NAME", type=str, help="SaaS database name", + scs_key=CKey.saas_database_name, + scs_alternative_key=CKey.saas_database_id, ), - click.option( + ScsOption( "--saas-token", metavar="PAT", type=str, prompt=True, + prompt_required=False, hide_input=True, envvar="EXASOL_SAAS_TOKEN", show_envvar=True, help="SaaS personal access token", + scs_key=CKey.saas_token, ), ] diff --git a/exasol/nb_connector/cli/options/ssl.py b/exasol/nb_connector/cli/options/ssl.py index b9fa715b..906d4494 100644 --- a/exasol/nb_connector/cli/options/ssl.py +++ b/exasol/nb_connector/cli/options/ssl.py @@ -2,18 +2,24 @@ import click +from exasol.nb_connector.ai_lab_config import AILabConfig as CKey +from exasol.nb_connector.cli.scs_options import ScsOption + SSL_OPTIONS = [ - click.option( + ScsOption( "--ssl-use-cert-validation/--no-ssl-use-cert-validation", type=bool, default=True, show_default=True, help="Whether to validate SSL certificates or not", + scs_key=CKey.cert_vld, ), - click.option( + ScsOption( "--ssl-cert-path", metavar="FILE/DIR", type=Path, help="SSL trusted CA file/dir", + scs_key=CKey.trusted_ca, + scs_required=False, ), - ] +] diff --git a/exasol/nb_connector/cli/scs_options.py b/exasol/nb_connector/cli/scs_options.py new file mode 100644 index 00000000..a0b6eca0 --- /dev/null +++ b/exasol/nb_connector/cli/scs_options.py @@ -0,0 +1,79 @@ +import re + +import click + +from exasol.nb_connector.secret_store import Secrets + + +class ScsOption: + """ + CLI option for saving and checking values to the Secure Configuration + Storage (SCS). + + In addition to the arguments supported by click.option() this class + supports the following additional + + Parameters: + scs_key: + The related key in SCS or None if the option is not be be stored + in the SCS. + + scs_alternative_key: + An alternative key for options that can are optional in case another + option is provided. + + scs_required: + Whether this option is required to be stored in the SCS or only + optional. + """ + + def __init__( + self, + *args, + scs_key: str | None = None, + scs_alternative_key: str | None = None, + scs_required: bool = True, + **kwargs, + ): + self._args = args + self._kwargs = dict(kwargs) + self.scs_key = scs_key + self.scs_alternative_key = scs_alternative_key + self.scs_required = scs_required + + @property + def cli_option(self) -> str: + return self._args[0] + + @property + def param_name(self) -> str: + for arg in self._args: + if not arg.startswith("--"): + return arg + return re.sub(r"/--.*$", "", self.cli_option)[2:].replace("-", "_") + + def click_option(self, func): + decorate = click.option(*self._args, **self._kwargs) + return decorate(func) + + def needs_entry(self, scs: Secrets) -> bool: + def has_value(): + alt = self.scs_alternative_key + return scs.get(self.scs_key) is not None or ( + alt and scs.get(alt) is not None + ) + + return self.scs_key and self.scs_required and not has_value() + + def __repr__(self) -> str: + cls_name = type(self).__name__ + return f"{cls_name}<{self.cli_option}>" + + +def click_options(scs_options: list[ScsOption]): + def decorated(func): + for o in reversed(scs_options): + func = o.click_option(func) + return func + + return decorated diff --git a/exasol/nb_connector/cli/util.py b/exasol/nb_connector/cli/util.py deleted file mode 100644 index 2b839262..00000000 --- a/exasol/nb_connector/cli/util.py +++ /dev/null @@ -1,19 +0,0 @@ -# from enum import Enum - -def add_options(options): - def _add_options(func): - for option in reversed(options): - func = option(func) - return func - - return _add_options - - -# class Backend(Enum): -# ONPREM = "onprem" -# SAAS = "saas" -# DOCKER_DB = "docker-db" -# -# @classmethod -# def help(cls): -# return [x.value for x in cls] From b82a6bfec1ad24d310bf364a46cf7b6d23a0e205 Mon Sep 17 00:00:00 2001 From: ckunki Date: Sat, 20 Sep 2025 13:27:34 +0200 Subject: [PATCH 06/25] Used custom classes for secret-related CLI options --- exasol/nb_connector/cli/commands/check.py | 28 ++--- exasol/nb_connector/cli/commands/configure.py | 27 +++-- exasol/nb_connector/cli/commands/show.py | 14 ++- exasol/nb_connector/cli/groups.py | 16 ++- exasol/nb_connector/cli/options/all.py | 29 ++--- exasol/nb_connector/cli/options/bucketfs.py | 19 ++-- exasol/nb_connector/cli/options/onprem.py | 19 ++-- exasol/nb_connector/cli/options/saas.py | 23 ++-- exasol/nb_connector/cli/options/ssl.py | 2 - exasol/nb_connector/cli/scs_options.py | 101 +++++++++++------- 10 files changed, 150 insertions(+), 128 deletions(-) diff --git a/exasol/nb_connector/cli/commands/check.py b/exasol/nb_connector/cli/commands/check.py index 8a2d5d42..491d60ae 100644 --- a/exasol/nb_connector/cli/commands/check.py +++ b/exasol/nb_connector/cli/commands/check.py @@ -5,25 +5,29 @@ from exasol.nb_connector.cli.scs_options import click_options -@cli.group( - help="""Check the configuration current contained in the Secure - Configuration Storage.""" -) +@cli.group() def check(): + """ + Check the configuration current contained in the Secure Configuration + Storage. + """ pass -@check.command(help="Verify if all required parameters are saved in the SCS.") +@check.command() @click_options(SCS_OPTIONS) -def configuration(scs_file: Path, scs_password: str): +def configuration(scs_file: Path): + """ + Verify if all required parameters are saved in the SCS. + """ pass -@check.command( - help="""Verify successful connection to the configured Exasol database - instance.""" -) +@check.command() @click_options(SCS_OPTIONS) -def connection(scs_file: Path, scs_password: str): +def connection(scs_file: Path): + """ + Verify successful connection to the configured Exasol database + instance. + """ print(f"scs_file: {scs_file}") - print(f"scs_password: {scs_password}") diff --git a/exasol/nb_connector/cli/commands/configure.py b/exasol/nb_connector/cli/commands/configure.py index 334a9263..9bea96ee 100644 --- a/exasol/nb_connector/cli/commands/configure.py +++ b/exasol/nb_connector/cli/commands/configure.py @@ -7,28 +7,39 @@ from exasol.nb_connector.cli.scs_options import click_options -@cli.group(help="Add configuration options to the Secure Configuration Storage.") +@cli.group() def configure(): + """ + Add configuration options to the Secure Configuration Storage. + """ pass -@configure.command( - "onprem", help="Configure connection to an Exasol on-premise instance." -) +@configure.command("onprem") @click_options(ONPREM_OPTIONS) def configure_onprem(**kwargs): + """ + Configure connection to an Exasol on-premise instance. + """ pass -@configure.command("saas", help="Configure connection to an Exasol SaaS instance.") +@configure.command("saas") @click_options(SAAS_OPTIONS) def configure_saas(**kwargs): + """ + Configure connection to an Exasol SaaS instance. + + Configuring one of the parameters --saas-database-id and + --saas-database-name is sufficient. + """ pass -@configure.command( - "docker-db", help="Configure connection to an Exasol Docker instance." -) +@configure.command("docker-db") @click_options(DOCKER_DB_OPTIONS) def configure_docker_db(**kwargs): + """ + Configure connection to an Exasol Docker instance. + """ pass diff --git a/exasol/nb_connector/cli/commands/show.py b/exasol/nb_connector/cli/commands/show.py index a1606b18..c7c0d635 100644 --- a/exasol/nb_connector/cli/commands/show.py +++ b/exasol/nb_connector/cli/commands/show.py @@ -5,13 +5,11 @@ from exasol.nb_connector.cli.scs_options import click_options -@cli.command( - help="""Show the configuration currently saved to the Secure Configuration - Storage.""" -) +@cli.command() @click_options(SCS_OPTIONS) -def show( - scs_file: Path, - scs_password: str, -): +def show(scs_file: Path): + """ + Show the configuration currently saved to the Secure Configuration + Storage. + """ pass diff --git a/exasol/nb_connector/cli/groups.py b/exasol/nb_connector/cli/groups.py index 12edfa29..ef54ab22 100644 --- a/exasol/nb_connector/cli/groups.py +++ b/exasol/nb_connector/cli/groups.py @@ -1,9 +1,17 @@ import click -@click.group( - help="""Manage Application configuration data in the Secure Configuration - Storage (SCS).""" -) +@click.group() def cli(): + """ + Manage Application configuration data in the Secure Configuration + Storage (SCS). + + You can set environment variables SCS_FILE and SCS_MASTER_PASSWORD + specifying the file containing the SCS and the master password for + accessing and encrypting the file, respectively. + + Otherwise the scs commands will require the SCS file to be passed as + positional argument and the master password to be typed interactively. + """ pass diff --git a/exasol/nb_connector/cli/options/all.py b/exasol/nb_connector/cli/options/all.py index 2dda9c04..5f74979f 100644 --- a/exasol/nb_connector/cli/options/all.py +++ b/exasol/nb_connector/cli/options/all.py @@ -1,30 +1,19 @@ from pathlib import Path -from exasol.nb_connector.cli.scs_options import ScsOption +import click + +from exasol.nb_connector.cli.scs_options import ( + ScsArgument, + ScsOption, +) SCS_OPTIONS = [ - ScsOption( - "--scs-file", - metavar="FILE", + ScsArgument( + "scs_file", + metavar="SCS_FILE", type=Path, required=True, envvar="SCS_FILE", - show_envvar=True, - help="File containing the Secure Configuration Storage (SCS)", - ), - ScsOption( - "--scs-master-password", - "scs_password", - metavar="PASSWORD", - type=str, - required=True, - prompt=True, - prompt_required=False, - # show_envvar=True, - hide_input=True, - envvar="SCS_MASTER_PASSWORD", - show_envvar=True, - help="Master password for the SCS", ), ] diff --git a/exasol/nb_connector/cli/options/bucketfs.py b/exasol/nb_connector/cli/options/bucketfs.py index b345b132..705cbb41 100644 --- a/exasol/nb_connector/cli/options/bucketfs.py +++ b/exasol/nb_connector/cli/options/bucketfs.py @@ -1,7 +1,8 @@ -import click - from exasol.nb_connector.ai_lab_config import AILabConfig as CKey -from exasol.nb_connector.cli.scs_options import ScsOption +from exasol.nb_connector.cli.scs_options import ( + ScsOption, + ScsSecretOption, +) BUCKETFS_OPTIONS = [ ScsOption( @@ -47,16 +48,10 @@ help="BucketFS user name", scs_key=CKey.bfs_user, ), - ScsOption( + ScsSecretOption( "--bucketfs-password", - metavar="PASSWORD", - type=str, - prompt=True, - prompt_required=False, - hide_input=True, - envvar="EXASOL_BUCKETFS_PASSWORD", - show_envvar=True, - help="BucketFS password", + envvar="SCS_BUCKETFS_PASSWORD", + prompt="BucketFS write password", scs_key=CKey.bfs_password, ), ScsOption( diff --git a/exasol/nb_connector/cli/options/onprem.py b/exasol/nb_connector/cli/options/onprem.py index 73a533eb..8c105789 100644 --- a/exasol/nb_connector/cli/options/onprem.py +++ b/exasol/nb_connector/cli/options/onprem.py @@ -1,7 +1,8 @@ -import click - from exasol.nb_connector.ai_lab_config import AILabConfig as CKey -from exasol.nb_connector.cli.scs_options import ScsOption +from exasol.nb_connector.cli.scs_options import ( + ScsOption, + ScsSecretOption, +) ONPREM_DB_OPTIONS = [ ScsOption( @@ -29,16 +30,10 @@ help="Database user name", scs_key=CKey.db_user, ), - ScsOption( + ScsSecretOption( "--db-password", - metavar="PASSWORD", - type=str, - prompt=True, - prompt_required=False, - hide_input=True, - envvar="EXASOL_DB_PASSWORD", - show_envvar=True, - help="Database password", + envvar="SCS_EXASOL_DB_PASSWORD", + prompt="Exasol database password", scs_key=CKey.db_password, ), ScsOption( diff --git a/exasol/nb_connector/cli/options/saas.py b/exasol/nb_connector/cli/options/saas.py index 25f3cfe3..997a94a4 100644 --- a/exasol/nb_connector/cli/options/saas.py +++ b/exasol/nb_connector/cli/options/saas.py @@ -1,7 +1,8 @@ -import click - from exasol.nb_connector.ai_lab_config import AILabConfig as CKey -from exasol.nb_connector.cli.scs_options import ScsOption +from exasol.nb_connector.cli.scs_options import ( + ScsOption, + ScsSecretOption, +) EXTRA_SAAS_OPTIONS = [ ScsOption( @@ -20,6 +21,9 @@ help="SaaS account ID", scs_key=CKey.saas_account_id, ), + # CKey.saas_database_id and CKey.saas_database_name can be used + # alternatively, see + # https://github.com/exasol/saas-api-python/blob/main/exasol/saas/client/api_access.py#L134 ScsOption( "--saas-database-id", metavar="ID", @@ -36,16 +40,11 @@ scs_key=CKey.saas_database_name, scs_alternative_key=CKey.saas_database_id, ), - ScsOption( + ScsSecretOption( "--saas-token", - metavar="PAT", - type=str, - prompt=True, - prompt_required=False, - hide_input=True, - envvar="EXASOL_SAAS_TOKEN", - show_envvar=True, - help="SaaS personal access token", + envvar="SCS_EXASOL_SAAS_TOKEN", + prompt="Exasol SaaS personal access token (PAT)", scs_key=CKey.saas_token, + metavar="PAT", ), ] diff --git a/exasol/nb_connector/cli/options/ssl.py b/exasol/nb_connector/cli/options/ssl.py index 906d4494..ac090c5d 100644 --- a/exasol/nb_connector/cli/options/ssl.py +++ b/exasol/nb_connector/cli/options/ssl.py @@ -1,7 +1,5 @@ from pathlib import Path -import click - from exasol.nb_connector.ai_lab_config import AILabConfig as CKey from exasol.nb_connector.cli.scs_options import ScsOption diff --git a/exasol/nb_connector/cli/scs_options.py b/exasol/nb_connector/cli/scs_options.py index a0b6eca0..dbf92e96 100644 --- a/exasol/nb_connector/cli/scs_options.py +++ b/exasol/nb_connector/cli/scs_options.py @@ -1,11 +1,25 @@ -import re - import click -from exasol.nb_connector.secret_store import Secrets +from exasol.nb_connector.ai_lab_config import AILabConfig as CKey -class ScsOption: +class ScsArgument: + """ + Represents a CLI argument for the SCS command which should not be + stored into the SCS. + """ + + def __init__(self, *args, scs_key: CKey | None = None, **kwargs): + self._args = args + self.scs_key = scs_key + self._kwargs = dict(kwargs) + + def decorate(self, func): + decorator = click.argument(*self._args, **self._kwargs) + return decorator(func) + + +class ScsOption(ScsArgument): """ CLI option for saving and checking values to the Secure Configuration Storage (SCS). @@ -30,50 +44,61 @@ class ScsOption: def __init__( self, *args, - scs_key: str | None = None, - scs_alternative_key: str | None = None, + scs_key: CKey | None = None, + scs_alternative_key: CKey | None = None, scs_required: bool = True, **kwargs, ): - self._args = args - self._kwargs = dict(kwargs) + super().__init__(*args, scs_key=scs_key, **kwargs) self.scs_key = scs_key self.scs_alternative_key = scs_alternative_key self.scs_required = scs_required - @property - def cli_option(self) -> str: - return self._args[0] - - @property - def param_name(self) -> str: - for arg in self._args: - if not arg.startswith("--"): - return arg - return re.sub(r"/--.*$", "", self.cli_option)[2:].replace("-", "_") - - def click_option(self, func): - decorate = click.option(*self._args, **self._kwargs) - return decorate(func) - - def needs_entry(self, scs: Secrets) -> bool: - def has_value(): - alt = self.scs_alternative_key - return scs.get(self.scs_key) is not None or ( - alt and scs.get(alt) is not None - ) - - return self.scs_key and self.scs_required and not has_value() - - def __repr__(self) -> str: - cls_name = type(self).__name__ - return f"{cls_name}<{self.cli_option}>" +# @property +# def cli_option(self) -> str: +# return self._args[0] +# +# @property +# def param_name(self) -> str: +# for arg in self._args: +# if not arg.startswith("--"): +# return arg +# return re.sub(r"/--.*$", "", self.cli_option)[2:].replace("-", "_") +# + def decorate(self, func): + decorator = click.option(*self._args, **self._kwargs) + return decorator(func) + + +class ScsSecretOption(ScsOption): + """ + Represents a CLI option to be stored into SCS. + """ + def __init__( + self, + name: str, + envvar: str, + prompt: str, + scs_key: CKey, + metavar: str = "PASSWORD", + ): + super().__init__( + name, + metavar=metavar, + type=bool, + is_flag=True, + help=f"{prompt} [env var: {envvar}]", + scs_key=scs_key, + ) + self.envvar = envvar + self.prompt = prompt + self.name = name def click_options(scs_options: list[ScsOption]): - def decorated(func): + def multi_decorator(func): for o in reversed(scs_options): - func = o.click_option(func) + func = o.decorate(func) return func - return decorated + return multi_decorator From c85c79602e9084f9ee57678c46ea5ba854598bfe Mon Sep 17 00:00:00 2001 From: ckunki Date: Sat, 20 Sep 2025 13:30:41 +0200 Subject: [PATCH 07/25] Removed dead code --- exasol/nb_connector/cli/scs_options.py | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/exasol/nb_connector/cli/scs_options.py b/exasol/nb_connector/cli/scs_options.py index dbf92e96..cb984342 100644 --- a/exasol/nb_connector/cli/scs_options.py +++ b/exasol/nb_connector/cli/scs_options.py @@ -54,17 +54,6 @@ def __init__( self.scs_alternative_key = scs_alternative_key self.scs_required = scs_required -# @property -# def cli_option(self) -> str: -# return self._args[0] -# -# @property -# def param_name(self) -> str: -# for arg in self._args: -# if not arg.startswith("--"): -# return arg -# return re.sub(r"/--.*$", "", self.cli_option)[2:].replace("-", "_") -# def decorate(self, func): decorator = click.option(*self._args, **self._kwargs) return decorator(func) From b910cb8fb35b4d32f09cec2e2d2e4eb80aa4f4c2 Mon Sep 17 00:00:00 2001 From: ckunki Date: Sat, 20 Sep 2025 13:33:58 +0200 Subject: [PATCH 08/25] Added show_default=True by default --- exasol/nb_connector/cli/options/bucketfs.py | 7 ------- exasol/nb_connector/cli/options/docker_db.py | 3 --- exasol/nb_connector/cli/options/onprem.py | 3 --- exasol/nb_connector/cli/options/saas.py | 1 - exasol/nb_connector/cli/options/ssl.py | 1 - exasol/nb_connector/cli/scs_options.py | 6 +++++- 6 files changed, 5 insertions(+), 16 deletions(-) diff --git a/exasol/nb_connector/cli/options/bucketfs.py b/exasol/nb_connector/cli/options/bucketfs.py index 705cbb41..cf46a36f 100644 --- a/exasol/nb_connector/cli/options/bucketfs.py +++ b/exasol/nb_connector/cli/options/bucketfs.py @@ -10,7 +10,6 @@ metavar="HOST", type=str, default="localhost", - show_default=True, help="BucketFS host name", scs_key=CKey.bfs_host_name, ), @@ -19,7 +18,6 @@ metavar="HOST", type=str, default="localhost", - show_default=True, help="BucketFS Internal Host Name", scs_key=CKey.bfs_internal_host_name, ), @@ -28,7 +26,6 @@ metavar="PORT", type=int, default=2580, - show_default=True, help="BucketFS port", scs_key="bucketfs_port", ), @@ -37,7 +34,6 @@ metavar="PORT", type=int, default=2580, - show_default=True, help="BucketFS internal port", scs_key=CKey.bfs_internal_port, ), @@ -59,7 +55,6 @@ metavar="BFS_SERVICE", type=str, default="bfsdefault", - show_default=True, help="BucketFS service name", scs_key="bucketfs_name", ), @@ -68,7 +63,6 @@ metavar="BUCKET", type=str, default="default", - show_default=True, help="BucketFS bucket name", scs_key=CKey.bfs_bucket, ), @@ -76,7 +70,6 @@ "--bucketfs-use-encryption/--no-bucketfs-use-encryption", type=bool, default=True, - show_default=True, help="Whether to encrypt communication with the BucketFS or not", scs_key=CKey.bfs_encryption, ), diff --git a/exasol/nb_connector/cli/options/docker_db.py b/exasol/nb_connector/cli/options/docker_db.py index 2f206c8c..12f8c749 100644 --- a/exasol/nb_connector/cli/options/docker_db.py +++ b/exasol/nb_connector/cli/options/docker_db.py @@ -10,7 +10,6 @@ type=int, metavar="GiB", default=2, - show_default=True, help="Database memory size (GiB)", scs_key=CKey.mem_size, ), @@ -19,7 +18,6 @@ metavar="GiB", type=int, default=2, - show_default=True, help="Database disk size (GiB)", scs_key=CKey.disk_size, ), @@ -27,7 +25,6 @@ "--accelerator", type=click.Choice(Accelerator, case_sensitive=False), default="none", - show_default=True, help="Hardware acceleration", scs_key=CKey.accelerator, ), diff --git a/exasol/nb_connector/cli/options/onprem.py b/exasol/nb_connector/cli/options/onprem.py index 8c105789..bef1d99f 100644 --- a/exasol/nb_connector/cli/options/onprem.py +++ b/exasol/nb_connector/cli/options/onprem.py @@ -10,7 +10,6 @@ metavar="HOST", type=str, default="localhost", - show_default=True, help="Database connection host name", scs_key=CKey.db_host_name, ), @@ -19,7 +18,6 @@ metavar="PORT", type=int, default=8563, - show_default=True, help="Database connection port", scs_key=CKey.db_port, ), @@ -40,7 +38,6 @@ "--db-use-encryption/--no-db-use-encryption", type=bool, default=True, - show_default=True, help="Whether to encrypt communication with the database or not", scs_key=CKey.db_encryption, ), diff --git a/exasol/nb_connector/cli/options/saas.py b/exasol/nb_connector/cli/options/saas.py index 997a94a4..98b6dda8 100644 --- a/exasol/nb_connector/cli/options/saas.py +++ b/exasol/nb_connector/cli/options/saas.py @@ -10,7 +10,6 @@ metavar="URL", type=str, default="https://cloud.exasol.com", - show_default=True, help="SaaS service URL", scs_key=CKey.saas_url, ), diff --git a/exasol/nb_connector/cli/options/ssl.py b/exasol/nb_connector/cli/options/ssl.py index ac090c5d..4770315d 100644 --- a/exasol/nb_connector/cli/options/ssl.py +++ b/exasol/nb_connector/cli/options/ssl.py @@ -8,7 +8,6 @@ "--ssl-use-cert-validation/--no-ssl-use-cert-validation", type=bool, default=True, - show_default=True, help="Whether to validate SSL certificates or not", scs_key=CKey.cert_vld, ), diff --git a/exasol/nb_connector/cli/scs_options.py b/exasol/nb_connector/cli/scs_options.py index cb984342..bf51e294 100644 --- a/exasol/nb_connector/cli/scs_options.py +++ b/exasol/nb_connector/cli/scs_options.py @@ -55,7 +55,11 @@ def __init__( self.scs_required = scs_required def decorate(self, func): - decorator = click.option(*self._args, **self._kwargs) + decorator = click.option( + *self._args, + **self._kwargs, + show_default=True, + ) return decorator(func) From fed2a5e4d670561e38cc8c610dcb425222e3cdca Mon Sep 17 00:00:00 2001 From: ckunki Date: Sun, 21 Sep 2025 09:05:52 +0200 Subject: [PATCH 09/25] Renamed files and functions file scs_options.py to param_wrappers.py click_options to add_params --- exasol/nb_connector/cli/commands/check.py | 11 ++++++----- exasol/nb_connector/cli/commands/configure.py | 16 +++++++++------- exasol/nb_connector/cli/commands/show.py | 4 ++-- exasol/nb_connector/cli/options/__init__.py | 8 ++++---- exasol/nb_connector/cli/options/all.py | 4 ++-- exasol/nb_connector/cli/options/bucketfs.py | 2 +- exasol/nb_connector/cli/options/docker_db.py | 2 +- exasol/nb_connector/cli/options/onprem.py | 2 +- exasol/nb_connector/cli/options/saas.py | 2 +- exasol/nb_connector/cli/options/ssl.py | 2 +- .../cli/{scs_options.py => param_wrappers.py} | 8 ++++++-- 11 files changed, 34 insertions(+), 27 deletions(-) rename exasol/nb_connector/cli/{scs_options.py => param_wrappers.py} (95%) diff --git a/exasol/nb_connector/cli/commands/check.py b/exasol/nb_connector/cli/commands/check.py index 491d60ae..e470552d 100644 --- a/exasol/nb_connector/cli/commands/check.py +++ b/exasol/nb_connector/cli/commands/check.py @@ -2,7 +2,7 @@ from exasol.nb_connector.cli.groups import cli from exasol.nb_connector.cli.options import SCS_OPTIONS -from exasol.nb_connector.cli.scs_options import click_options +from exasol.nb_connector.cli.param_wrappers import add_params @cli.group() @@ -15,19 +15,20 @@ def check(): @check.command() -@click_options(SCS_OPTIONS) +@add_params(SCS_OPTIONS) def configuration(scs_file: Path): """ Verify if all required parameters are saved in the SCS. """ - pass + result = processing.check_scs_content(scs_file) + sys.exit(result) @check.command() -@click_options(SCS_OPTIONS) +@add_params(SCS_OPTIONS) def connection(scs_file: Path): """ Verify successful connection to the configured Exasol database instance. """ - print(f"scs_file: {scs_file}") + pass diff --git a/exasol/nb_connector/cli/commands/configure.py b/exasol/nb_connector/cli/commands/configure.py index 9bea96ee..2c6d76e1 100644 --- a/exasol/nb_connector/cli/commands/configure.py +++ b/exasol/nb_connector/cli/commands/configure.py @@ -1,10 +1,12 @@ +from pathlib import Path + from exasol.nb_connector.cli.groups import cli from exasol.nb_connector.cli.options import ( DOCKER_DB_OPTIONS, ONPREM_OPTIONS, SAAS_OPTIONS, ) -from exasol.nb_connector.cli.scs_options import click_options +from exasol.nb_connector.cli.param_wrappers import add_params @cli.group() @@ -16,8 +18,8 @@ def configure(): @configure.command("onprem") -@click_options(ONPREM_OPTIONS) -def configure_onprem(**kwargs): +@add_params(ONPREM_OPTIONS) +def configure_onprem(scs_file: Path, **kwargs): """ Configure connection to an Exasol on-premise instance. """ @@ -25,8 +27,8 @@ def configure_onprem(**kwargs): @configure.command("saas") -@click_options(SAAS_OPTIONS) -def configure_saas(**kwargs): +@add_params(SAAS_OPTIONS) +def configure_saas(scs_file: Path, **kwargs): """ Configure connection to an Exasol SaaS instance. @@ -37,8 +39,8 @@ def configure_saas(**kwargs): @configure.command("docker-db") -@click_options(DOCKER_DB_OPTIONS) -def configure_docker_db(**kwargs): +@add_params(DOCKER_DB_OPTIONS) +def configure_docker_db(scs_file: Path, **kwargs): """ Configure connection to an Exasol Docker instance. """ diff --git a/exasol/nb_connector/cli/commands/show.py b/exasol/nb_connector/cli/commands/show.py index c7c0d635..07e85203 100644 --- a/exasol/nb_connector/cli/commands/show.py +++ b/exasol/nb_connector/cli/commands/show.py @@ -2,11 +2,11 @@ from exasol.nb_connector.cli.groups import cli from exasol.nb_connector.cli.options import SCS_OPTIONS -from exasol.nb_connector.cli.scs_options import click_options +from exasol.nb_connector.cli.param_wrappers import add_params @cli.command() -@click_options(SCS_OPTIONS) +@add_params(SCS_OPTIONS) def show(scs_file: Path): """ Show the configuration currently saved to the Secure Configuration diff --git a/exasol/nb_connector/cli/options/__init__.py b/exasol/nb_connector/cli/options/__init__.py index d95c0b14..b318953d 100644 --- a/exasol/nb_connector/cli/options/__init__.py +++ b/exasol/nb_connector/cli/options/__init__.py @@ -1,5 +1,5 @@ from exasol.nb_connector.cli.options.all import ( - COMMON_CONFIGURE_OPTIONS, + COMMON_OPTIONS, SCS_OPTIONS, ) from exasol.nb_connector.cli.options.bucketfs import BUCKETFS_OPTIONS @@ -8,14 +8,14 @@ from exasol.nb_connector.cli.options.saas import EXTRA_SAAS_OPTIONS from exasol.nb_connector.cli.options.ssl import SSL_OPTIONS -DOCKER_DB_OPTIONS = SCS_OPTIONS + EXTRA_DOCKER_DB_OPTIONS + COMMON_CONFIGURE_OPTIONS +DOCKER_DB_OPTIONS = SCS_OPTIONS + EXTRA_DOCKER_DB_OPTIONS + COMMON_OPTIONS -SAAS_OPTIONS = SCS_OPTIONS + EXTRA_SAAS_OPTIONS + SSL_OPTIONS + COMMON_CONFIGURE_OPTIONS +SAAS_OPTIONS = SCS_OPTIONS + EXTRA_SAAS_OPTIONS + SSL_OPTIONS + COMMON_OPTIONS ONPREM_OPTIONS = ( SCS_OPTIONS + ONPREM_DB_OPTIONS + BUCKETFS_OPTIONS + SSL_OPTIONS - + COMMON_CONFIGURE_OPTIONS + + COMMON_OPTIONS ) diff --git a/exasol/nb_connector/cli/options/all.py b/exasol/nb_connector/cli/options/all.py index 5f74979f..98a18a49 100644 --- a/exasol/nb_connector/cli/options/all.py +++ b/exasol/nb_connector/cli/options/all.py @@ -2,7 +2,7 @@ import click -from exasol.nb_connector.cli.scs_options import ( +from exasol.nb_connector.cli.param_wrappers import ( ScsArgument, ScsOption, ) @@ -18,7 +18,7 @@ ] -COMMON_CONFIGURE_OPTIONS = [ +COMMON_OPTIONS = [ ScsOption( "--db-schema", metavar="DB_SCHEMA", diff --git a/exasol/nb_connector/cli/options/bucketfs.py b/exasol/nb_connector/cli/options/bucketfs.py index cf46a36f..5dbdc5cd 100644 --- a/exasol/nb_connector/cli/options/bucketfs.py +++ b/exasol/nb_connector/cli/options/bucketfs.py @@ -1,5 +1,5 @@ from exasol.nb_connector.ai_lab_config import AILabConfig as CKey -from exasol.nb_connector.cli.scs_options import ( +from exasol.nb_connector.cli.param_wrappers import ( ScsOption, ScsSecretOption, ) diff --git a/exasol/nb_connector/cli/options/docker_db.py b/exasol/nb_connector/cli/options/docker_db.py index 12f8c749..238777f2 100644 --- a/exasol/nb_connector/cli/options/docker_db.py +++ b/exasol/nb_connector/cli/options/docker_db.py @@ -2,7 +2,7 @@ from exasol.nb_connector.ai_lab_config import Accelerator from exasol.nb_connector.ai_lab_config import AILabConfig as CKey -from exasol.nb_connector.cli.scs_options import ScsOption +from exasol.nb_connector.cli.param_wrappers import ScsOption EXTRA_DOCKER_DB_OPTIONS = [ ScsOption( diff --git a/exasol/nb_connector/cli/options/onprem.py b/exasol/nb_connector/cli/options/onprem.py index bef1d99f..368057a4 100644 --- a/exasol/nb_connector/cli/options/onprem.py +++ b/exasol/nb_connector/cli/options/onprem.py @@ -1,5 +1,5 @@ from exasol.nb_connector.ai_lab_config import AILabConfig as CKey -from exasol.nb_connector.cli.scs_options import ( +from exasol.nb_connector.cli.param_wrappers import ( ScsOption, ScsSecretOption, ) diff --git a/exasol/nb_connector/cli/options/saas.py b/exasol/nb_connector/cli/options/saas.py index 98b6dda8..6c1717fb 100644 --- a/exasol/nb_connector/cli/options/saas.py +++ b/exasol/nb_connector/cli/options/saas.py @@ -1,5 +1,5 @@ from exasol.nb_connector.ai_lab_config import AILabConfig as CKey -from exasol.nb_connector.cli.scs_options import ( +from exasol.nb_connector.cli.param_wrappers import ( ScsOption, ScsSecretOption, ) diff --git a/exasol/nb_connector/cli/options/ssl.py b/exasol/nb_connector/cli/options/ssl.py index 4770315d..2c763bbc 100644 --- a/exasol/nb_connector/cli/options/ssl.py +++ b/exasol/nb_connector/cli/options/ssl.py @@ -1,7 +1,7 @@ from pathlib import Path from exasol.nb_connector.ai_lab_config import AILabConfig as CKey -from exasol.nb_connector.cli.scs_options import ScsOption +from exasol.nb_connector.cli.param_wrappers import ScsOption SSL_OPTIONS = [ ScsOption( diff --git a/exasol/nb_connector/cli/scs_options.py b/exasol/nb_connector/cli/param_wrappers.py similarity index 95% rename from exasol/nb_connector/cli/scs_options.py rename to exasol/nb_connector/cli/param_wrappers.py index bf51e294..631540f5 100644 --- a/exasol/nb_connector/cli/scs_options.py +++ b/exasol/nb_connector/cli/param_wrappers.py @@ -1,3 +1,7 @@ +""" +Wrappers for adding custom properties to click parameters, e.g. SCS key. +""" + import click from exasol.nb_connector.ai_lab_config import AILabConfig as CKey @@ -67,6 +71,7 @@ class ScsSecretOption(ScsOption): """ Represents a CLI option to be stored into SCS. """ + def __init__( self, name: str, @@ -87,8 +92,7 @@ def __init__( self.prompt = prompt self.name = name - -def click_options(scs_options: list[ScsOption]): +def add_params(scs_options: list[ScsOption]): def multi_decorator(func): for o in reversed(scs_options): func = o.decorate(func) From 59df5a03aaa7b05234cda99254032ac8ea4169c1 Mon Sep 17 00:00:00 2001 From: ckunki Date: Sun, 21 Sep 2025 10:31:12 +0200 Subject: [PATCH 10/25] Added get_default_from For CLI options getting their default value from other CLI options. --- exasol/nb_connector/cli/options/__init__.py | 6 +----- exasol/nb_connector/cli/options/bucketfs.py | 9 +++++---- exasol/nb_connector/cli/param_wrappers.py | 2 ++ 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/exasol/nb_connector/cli/options/__init__.py b/exasol/nb_connector/cli/options/__init__.py index b318953d..97716f94 100644 --- a/exasol/nb_connector/cli/options/__init__.py +++ b/exasol/nb_connector/cli/options/__init__.py @@ -13,9 +13,5 @@ SAAS_OPTIONS = SCS_OPTIONS + EXTRA_SAAS_OPTIONS + SSL_OPTIONS + COMMON_OPTIONS ONPREM_OPTIONS = ( - SCS_OPTIONS - + ONPREM_DB_OPTIONS - + BUCKETFS_OPTIONS - + SSL_OPTIONS - + COMMON_OPTIONS + SCS_OPTIONS + ONPREM_DB_OPTIONS + BUCKETFS_OPTIONS + SSL_OPTIONS + COMMON_OPTIONS ) diff --git a/exasol/nb_connector/cli/options/bucketfs.py b/exasol/nb_connector/cli/options/bucketfs.py index 5dbdc5cd..92ea1ea5 100644 --- a/exasol/nb_connector/cli/options/bucketfs.py +++ b/exasol/nb_connector/cli/options/bucketfs.py @@ -17,9 +17,9 @@ "--bucketfs-host-internal", metavar="HOST", type=str, - default="localhost", - help="BucketFS Internal Host Name", + help="BucketFS Internal Host Name [defaults to --bucketfs-host]", scs_key=CKey.bfs_internal_host_name, + get_default_from="bucketfs_host" ), ScsOption( "--bucketfs-port", @@ -33,14 +33,15 @@ "--bucketfs-port-internal", metavar="PORT", type=int, - default=2580, - help="BucketFS internal port", + help="BucketFS internal port [defaults to --bucketfs-port]", scs_key=CKey.bfs_internal_port, + get_default_from="bucketfs_port" ), ScsOption( "--bucketfs-user", metavar="USERNAME", type=str, + # should we add "w" as default here? help="BucketFS user name", scs_key=CKey.bfs_user, ), diff --git a/exasol/nb_connector/cli/param_wrappers.py b/exasol/nb_connector/cli/param_wrappers.py index 631540f5..7098d999 100644 --- a/exasol/nb_connector/cli/param_wrappers.py +++ b/exasol/nb_connector/cli/param_wrappers.py @@ -51,12 +51,14 @@ def __init__( scs_key: CKey | None = None, scs_alternative_key: CKey | None = None, scs_required: bool = True, + get_default_from: str|None = None, **kwargs, ): super().__init__(*args, scs_key=scs_key, **kwargs) self.scs_key = scs_key self.scs_alternative_key = scs_alternative_key self.scs_required = scs_required + self.get_default_from = get_default_from def decorate(self, func): decorator = click.option( From ae258c85542e7d330c8a3aa8aad3b4e8e1b6fb73 Mon Sep 17 00:00:00 2001 From: ckunki Date: Sun, 21 Sep 2025 11:01:35 +0200 Subject: [PATCH 11/25] Updated help strings for bucketfs internal host and port --- exasol/nb_connector/cli/options/bucketfs.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/exasol/nb_connector/cli/options/bucketfs.py b/exasol/nb_connector/cli/options/bucketfs.py index 92ea1ea5..83e62e9f 100644 --- a/exasol/nb_connector/cli/options/bucketfs.py +++ b/exasol/nb_connector/cli/options/bucketfs.py @@ -17,7 +17,7 @@ "--bucketfs-host-internal", metavar="HOST", type=str, - help="BucketFS Internal Host Name [defaults to --bucketfs-host]", + help="BucketFS Internal Host Name [reads default from --bucketfs-host]", scs_key=CKey.bfs_internal_host_name, get_default_from="bucketfs_host" ), @@ -33,7 +33,7 @@ "--bucketfs-port-internal", metavar="PORT", type=int, - help="BucketFS internal port [defaults to --bucketfs-port]", + help="BucketFS internal port [reads default from --bucketfs-port]", scs_key=CKey.bfs_internal_port, get_default_from="bucketfs_port" ), From e11f377b410642b579ab87f93332794f7f9dd236 Mon Sep 17 00:00:00 2001 From: ckunki Date: Sun, 21 Sep 2025 15:10:04 +0200 Subject: [PATCH 12/25] Fixed formatting and removed redundant att --- exasol/nb_connector/cli/options/bucketfs.py | 4 ++-- exasol/nb_connector/cli/param_wrappers.py | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/exasol/nb_connector/cli/options/bucketfs.py b/exasol/nb_connector/cli/options/bucketfs.py index 83e62e9f..d7f9d9fe 100644 --- a/exasol/nb_connector/cli/options/bucketfs.py +++ b/exasol/nb_connector/cli/options/bucketfs.py @@ -19,7 +19,7 @@ type=str, help="BucketFS Internal Host Name [reads default from --bucketfs-host]", scs_key=CKey.bfs_internal_host_name, - get_default_from="bucketfs_host" + get_default_from="bucketfs_host", ), ScsOption( "--bucketfs-port", @@ -35,7 +35,7 @@ type=int, help="BucketFS internal port [reads default from --bucketfs-port]", scs_key=CKey.bfs_internal_port, - get_default_from="bucketfs_port" + get_default_from="bucketfs_port", ), ScsOption( "--bucketfs-user", diff --git a/exasol/nb_connector/cli/param_wrappers.py b/exasol/nb_connector/cli/param_wrappers.py index 7098d999..2e1e194b 100644 --- a/exasol/nb_connector/cli/param_wrappers.py +++ b/exasol/nb_connector/cli/param_wrappers.py @@ -51,11 +51,10 @@ def __init__( scs_key: CKey | None = None, scs_alternative_key: CKey | None = None, scs_required: bool = True, - get_default_from: str|None = None, + get_default_from: str | None = None, **kwargs, ): super().__init__(*args, scs_key=scs_key, **kwargs) - self.scs_key = scs_key self.scs_alternative_key = scs_alternative_key self.scs_required = scs_required self.get_default_from = get_default_from From dee5ba29c99df5072acd3acf0bb8cc74853b2d82 Mon Sep 17 00:00:00 2001 From: ckunki Date: Mon, 22 Sep 2025 08:29:30 +0200 Subject: [PATCH 13/25] Removed processing from check command --- exasol/nb_connector/cli/commands/check.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/exasol/nb_connector/cli/commands/check.py b/exasol/nb_connector/cli/commands/check.py index e470552d..7c38e7e3 100644 --- a/exasol/nb_connector/cli/commands/check.py +++ b/exasol/nb_connector/cli/commands/check.py @@ -20,8 +20,7 @@ def configuration(scs_file: Path): """ Verify if all required parameters are saved in the SCS. """ - result = processing.check_scs_content(scs_file) - sys.exit(result) + pass @check.command() From d78e21063e05d830f55c79ee1c12a7413fa01271 Mon Sep 17 00:00:00 2001 From: ckunki Date: Mon, 22 Sep 2025 08:30:49 +0200 Subject: [PATCH 14/25] Simplified check command by adding option --connect --- exasol/nb_connector/cli/commands/check.py | 37 ++++++++++------------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/exasol/nb_connector/cli/commands/check.py b/exasol/nb_connector/cli/commands/check.py index 7c38e7e3..9e1a1ae0 100644 --- a/exasol/nb_connector/cli/commands/check.py +++ b/exasol/nb_connector/cli/commands/check.py @@ -1,33 +1,28 @@ +import sys from pathlib import Path +import click + from exasol.nb_connector.cli.groups import cli from exasol.nb_connector.cli.options import SCS_OPTIONS from exasol.nb_connector.cli.param_wrappers import add_params +from exasol.nb_connector.cli.processing import processing -@cli.group() -def check(): - """ - Check the configuration current contained in the Secure Configuration - Storage. - """ - pass - - -@check.command() +@cli.command() @add_params(SCS_OPTIONS) -def configuration(scs_file: Path): +@click.option( + "--connect", + is_flag=True, + help="""Verify if connecting to the configured Exasol database instance + succeeds.""", +) +def check(scs_file: Path, connect: bool): """ - Verify if all required parameters are saved in the SCS. - """ - pass - + Check the configuration current contained in the Secure Configuration + Storage and verify if it contains all required parameters. -@check.command() -@add_params(SCS_OPTIONS) -def connection(scs_file: Path): - """ - Verify successful connection to the configured Exasol database - instance. + Optionally also verify if a connection to the configured Exasol database + instance is successful. """ pass From 296ab144c101f46ce923e318f0b8bd19fd0b4ce7 Mon Sep 17 00:00:00 2001 From: ckunki Date: Mon, 22 Sep 2025 08:31:38 +0200 Subject: [PATCH 15/25] Removed processing import --- exasol/nb_connector/cli/commands/check.py | 1 - 1 file changed, 1 deletion(-) diff --git a/exasol/nb_connector/cli/commands/check.py b/exasol/nb_connector/cli/commands/check.py index 9e1a1ae0..f3633a54 100644 --- a/exasol/nb_connector/cli/commands/check.py +++ b/exasol/nb_connector/cli/commands/check.py @@ -6,7 +6,6 @@ from exasol.nb_connector.cli.groups import cli from exasol.nb_connector.cli.options import SCS_OPTIONS from exasol.nb_connector.cli.param_wrappers import add_params -from exasol.nb_connector.cli.processing import processing @cli.command() From 254bbfadc5ef93712904ba7153c19fd629673652 Mon Sep 17 00:00:00 2001 From: ckunki Date: Mon, 22 Sep 2025 08:41:43 +0200 Subject: [PATCH 16/25] Updated docstrings --- exasol/nb_connector/cli/param_wrappers.py | 29 ++++++++++++++++------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/exasol/nb_connector/cli/param_wrappers.py b/exasol/nb_connector/cli/param_wrappers.py index 2e1e194b..1965e710 100644 --- a/exasol/nb_connector/cli/param_wrappers.py +++ b/exasol/nb_connector/cli/param_wrappers.py @@ -9,8 +9,7 @@ class ScsArgument: """ - Represents a CLI argument for the SCS command which should not be - stored into the SCS. + Represents a CLI argument for the SCS command. """ def __init__(self, *args, scs_key: CKey | None = None, **kwargs): @@ -19,6 +18,11 @@ def __init__(self, *args, scs_key: CKey | None = None, **kwargs): self._kwargs = dict(kwargs) def decorate(self, func): + """ + This method is to be called when decorating the functions in the + actual CLI declaration. Hence, ScsArgument calls click.argument() + under the hood. + """ decorator = click.argument(*self._args, **self._kwargs) return decorator(func) @@ -28,21 +32,23 @@ class ScsOption(ScsArgument): CLI option for saving and checking values to the Secure Configuration Storage (SCS). - In addition to the arguments supported by click.option() this class - supports the following additional + In addition to the args supported by click.option() this class supports + the following additional Parameters: scs_key: - The related key in SCS or None if the option is not be be stored - in the SCS. + The related key in SCS or None if the option is not be stored in + the SCS. ScsArgument For exaemple, ScsArgument scs_file is not to + be stored in the SCS. scs_alternative_key: - An alternative key for options that can are optional in case another - option is provided. + An alternative key for ScsOptions that are optional in case + another option is provided. For example, for --saas-database-id + you can specify --saas-database-name instead and vice-versa. scs_required: Whether this option is required to be stored in the SCS or only - optional. + optional. This applies to --ssl-cert-path, for example. """ def __init__( @@ -60,6 +66,10 @@ def __init__( self.get_default_from = get_default_from def decorate(self, func): + """ + This method is to be called when decorating the functions in the + actual CLI declaration. ScsOption calls click.option(). + """ decorator = click.option( *self._args, **self._kwargs, @@ -93,6 +103,7 @@ def __init__( self.prompt = prompt self.name = name + def add_params(scs_options: list[ScsOption]): def multi_decorator(func): for o in reversed(scs_options): From 44f9e3e6726340df11dd1e38e3d577b41ee2d997 Mon Sep 17 00:00:00 2001 From: ckunki Date: Mon, 22 Sep 2025 08:47:58 +0200 Subject: [PATCH 17/25] Updated command help strings --- exasol/nb_connector/cli/commands/check.py | 4 ++-- exasol/nb_connector/cli/groups.py | 2 +- exasol/nb_connector/cli/options/bucketfs.py | 2 +- exasol/nb_connector/cli/options/saas.py | 8 ++++---- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/exasol/nb_connector/cli/commands/check.py b/exasol/nb_connector/cli/commands/check.py index f3633a54..dba0f845 100644 --- a/exasol/nb_connector/cli/commands/check.py +++ b/exasol/nb_connector/cli/commands/check.py @@ -11,14 +11,14 @@ @cli.command() @add_params(SCS_OPTIONS) @click.option( - "--connect", + "--connect/--no-connect", is_flag=True, help="""Verify if connecting to the configured Exasol database instance succeeds.""", ) def check(scs_file: Path, connect: bool): """ - Check the configuration current contained in the Secure Configuration + Check the configuration current saved to the Secure Configuration Storage and verify if it contains all required parameters. Optionally also verify if a connection to the configured Exasol database diff --git a/exasol/nb_connector/cli/groups.py b/exasol/nb_connector/cli/groups.py index ef54ab22..43b03a61 100644 --- a/exasol/nb_connector/cli/groups.py +++ b/exasol/nb_connector/cli/groups.py @@ -4,7 +4,7 @@ @click.group() def cli(): """ - Manage Application configuration data in the Secure Configuration + Manage application configuration data in the Secure Configuration Storage (SCS). You can set environment variables SCS_FILE and SCS_MASTER_PASSWORD diff --git a/exasol/nb_connector/cli/options/bucketfs.py b/exasol/nb_connector/cli/options/bucketfs.py index d7f9d9fe..e4af9c7c 100644 --- a/exasol/nb_connector/cli/options/bucketfs.py +++ b/exasol/nb_connector/cli/options/bucketfs.py @@ -17,7 +17,7 @@ "--bucketfs-host-internal", metavar="HOST", type=str, - help="BucketFS Internal Host Name [reads default from --bucketfs-host]", + help="BucketFS internal host name [reads default from --bucketfs-host]", scs_key=CKey.bfs_internal_host_name, get_default_from="bucketfs_host", ), diff --git a/exasol/nb_connector/cli/options/saas.py b/exasol/nb_connector/cli/options/saas.py index 6c1717fb..3a11eefd 100644 --- a/exasol/nb_connector/cli/options/saas.py +++ b/exasol/nb_connector/cli/options/saas.py @@ -10,14 +10,14 @@ metavar="URL", type=str, default="https://cloud.exasol.com", - help="SaaS service URL", + help="Exasol SaaS service URL", scs_key=CKey.saas_url, ), ScsOption( "--saas-account-id", metavar="ACCOUNT_ID", type=str, - help="SaaS account ID", + help="Exasol SaaS account ID", scs_key=CKey.saas_account_id, ), # CKey.saas_database_id and CKey.saas_database_name can be used @@ -27,7 +27,7 @@ "--saas-database-id", metavar="ID", type=str, - help="SaaS database ID", + help="Exasol SaaS database ID", scs_key=CKey.saas_database_id, scs_alternative_key=CKey.saas_database_name, ), @@ -35,7 +35,7 @@ "--saas-database-name", metavar="NAME", type=str, - help="SaaS database name", + help="Exasol SaaS database name", scs_key=CKey.saas_database_name, scs_alternative_key=CKey.saas_database_id, ), From 8a2163e28e8a9b638940d4c6f72e959301b7a024 Mon Sep 17 00:00:00 2001 From: ckunki Date: Mon, 22 Sep 2025 08:56:47 +0200 Subject: [PATCH 18/25] typo --- exasol/nb_connector/cli/commands/check.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exasol/nb_connector/cli/commands/check.py b/exasol/nb_connector/cli/commands/check.py index dba0f845..c874d6ec 100644 --- a/exasol/nb_connector/cli/commands/check.py +++ b/exasol/nb_connector/cli/commands/check.py @@ -18,7 +18,7 @@ ) def check(scs_file: Path, connect: bool): """ - Check the configuration current saved to the Secure Configuration + Check the configuration currently saved to the Secure Configuration Storage and verify if it contains all required parameters. Optionally also verify if a connection to the configured Exasol database From 65b1bce71b86f563f4fd937a0dd39722e6269cd5 Mon Sep 17 00:00:00 2001 From: ckunki Date: Mon, 22 Sep 2025 11:21:10 +0200 Subject: [PATCH 19/25] Fixed type errors --- exasol/nb_connector/cli/options/bucketfs.py | 4 ++-- exasol/nb_connector/cli/param_wrappers.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/exasol/nb_connector/cli/options/bucketfs.py b/exasol/nb_connector/cli/options/bucketfs.py index e4af9c7c..5ba83983 100644 --- a/exasol/nb_connector/cli/options/bucketfs.py +++ b/exasol/nb_connector/cli/options/bucketfs.py @@ -27,7 +27,7 @@ type=int, default=2580, help="BucketFS port", - scs_key="bucketfs_port", + scs_key=CKey.bfs_port, ), ScsOption( "--bucketfs-port-internal", @@ -57,7 +57,7 @@ type=str, default="bfsdefault", help="BucketFS service name", - scs_key="bucketfs_name", + scs_key=CKey.bfs_service, ), ScsOption( "--bucket", diff --git a/exasol/nb_connector/cli/param_wrappers.py b/exasol/nb_connector/cli/param_wrappers.py index 1965e710..42fe73af 100644 --- a/exasol/nb_connector/cli/param_wrappers.py +++ b/exasol/nb_connector/cli/param_wrappers.py @@ -104,7 +104,7 @@ def __init__( self.name = name -def add_params(scs_options: list[ScsOption]): +def add_params(scs_options: list[ScsArgument]): def multi_decorator(func): for o in reversed(scs_options): func = o.decorate(func) From d9b48c24aa0880d4c900c6b5b94d3154080550b1 Mon Sep 17 00:00:00 2001 From: ckunki Date: Mon, 22 Sep 2025 12:15:54 +0200 Subject: [PATCH 20/25] Added exasol.ai.text to pylint ignored modules Module exasol.ai.text is compiled via Cython, released as binary. So probably pylint cannot verify types there. --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index 1ed5eec9..668752b1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -116,6 +116,7 @@ force_grid_wrap = 2 [tool.pylint.master] +ignored-modules = [ "exasol.ai.text" ] fail-under = 8.0 [tool.mypy] From 2ddaf513cdab56c235fb5dc763fe92777268ed4c Mon Sep 17 00:00:00 2001 From: ckunki Date: Mon, 22 Sep 2025 14:01:17 +0200 Subject: [PATCH 21/25] Renamed all.py to common.py --- exasol/nb_connector/cli/options/__init__.py | 2 +- exasol/nb_connector/cli/options/{all.py => common.py} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename exasol/nb_connector/cli/options/{all.py => common.py} (100%) diff --git a/exasol/nb_connector/cli/options/__init__.py b/exasol/nb_connector/cli/options/__init__.py index 97716f94..b501cbd1 100644 --- a/exasol/nb_connector/cli/options/__init__.py +++ b/exasol/nb_connector/cli/options/__init__.py @@ -1,4 +1,4 @@ -from exasol.nb_connector.cli.options.all import ( +from exasol.nb_connector.cli.options.common import ( COMMON_OPTIONS, SCS_OPTIONS, ) diff --git a/exasol/nb_connector/cli/options/all.py b/exasol/nb_connector/cli/options/common.py similarity index 100% rename from exasol/nb_connector/cli/options/all.py rename to exasol/nb_connector/cli/options/common.py From e37410baad79e5949049f26708083b18def8ad33 Mon Sep 17 00:00:00 2001 From: ckunki Date: Mon, 22 Sep 2025 14:06:21 +0200 Subject: [PATCH 22/25] Updated import --- exasol/nb_connector/cli/options/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exasol/nb_connector/cli/options/__init__.py b/exasol/nb_connector/cli/options/__init__.py index b501cbd1..f8104c21 100644 --- a/exasol/nb_connector/cli/options/__init__.py +++ b/exasol/nb_connector/cli/options/__init__.py @@ -1,8 +1,8 @@ +from exasol.nb_connector.cli.options.bucketfs import BUCKETFS_OPTIONS from exasol.nb_connector.cli.options.common import ( COMMON_OPTIONS, SCS_OPTIONS, ) -from exasol.nb_connector.cli.options.bucketfs import BUCKETFS_OPTIONS from exasol.nb_connector.cli.options.docker_db import EXTRA_DOCKER_DB_OPTIONS from exasol.nb_connector.cli.options.onprem import ONPREM_DB_OPTIONS from exasol.nb_connector.cli.options.saas import EXTRA_SAAS_OPTIONS From 6476fef454c4cf365e0b53fd399bb2b17a551626 Mon Sep 17 00:00:00 2001 From: ckunki Date: Mon, 22 Sep 2025 14:11:59 +0200 Subject: [PATCH 23/25] Added SAVE_OPTIONS --- exasol/nb_connector/cli/options/__init__.py | 14 +++++++++----- exasol/nb_connector/cli/options/common.py | 7 +++++++ 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/exasol/nb_connector/cli/options/__init__.py b/exasol/nb_connector/cli/options/__init__.py index f8104c21..1c514604 100644 --- a/exasol/nb_connector/cli/options/__init__.py +++ b/exasol/nb_connector/cli/options/__init__.py @@ -1,6 +1,7 @@ from exasol.nb_connector.cli.options.bucketfs import BUCKETFS_OPTIONS from exasol.nb_connector.cli.options.common import ( COMMON_OPTIONS, + SAVE_OPTIONS, SCS_OPTIONS, ) from exasol.nb_connector.cli.options.docker_db import EXTRA_DOCKER_DB_OPTIONS @@ -8,10 +9,13 @@ from exasol.nb_connector.cli.options.saas import EXTRA_SAAS_OPTIONS from exasol.nb_connector.cli.options.ssl import SSL_OPTIONS -DOCKER_DB_OPTIONS = SCS_OPTIONS + EXTRA_DOCKER_DB_OPTIONS + COMMON_OPTIONS -SAAS_OPTIONS = SCS_OPTIONS + EXTRA_SAAS_OPTIONS + SSL_OPTIONS + COMMON_OPTIONS +def _wrap(options): + return SCS_OPTIONS + SAVE_OPTIONS + options + COMMON_OPTIONS -ONPREM_OPTIONS = ( - SCS_OPTIONS + ONPREM_DB_OPTIONS + BUCKETFS_OPTIONS + SSL_OPTIONS + COMMON_OPTIONS -) + +DOCKER_DB_OPTIONS = _wrap(EXTRA_DOCKER_DB_OPTIONS) + +SAAS_OPTIONS = _wrap(EXTRA_SAAS_OPTIONS + SSL_OPTIONS) + +ONPREM_OPTIONS = _wrap(ONPREM_DB_OPTIONS + BUCKETFS_OPTIONS + SSL_OPTIONS) diff --git a/exasol/nb_connector/cli/options/common.py b/exasol/nb_connector/cli/options/common.py index 98a18a49..7511392c 100644 --- a/exasol/nb_connector/cli/options/common.py +++ b/exasol/nb_connector/cli/options/common.py @@ -17,6 +17,13 @@ ), ] +SAVE_OPTIONS = [ + ScsOption( + "--overwrite-backend/--no-overwrite-backend", + is_flag=True, + help="Whether to overwrite a different backend in the SCS.", + ) +] COMMON_OPTIONS = [ ScsOption( From 6671a2b09df954d88ef485d67260e1efa80ec491 Mon Sep 17 00:00:00 2001 From: ckunki Date: Mon, 22 Sep 2025 16:19:21 +0200 Subject: [PATCH 24/25] Removed copying the kwargs --- exasol/nb_connector/cli/param_wrappers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exasol/nb_connector/cli/param_wrappers.py b/exasol/nb_connector/cli/param_wrappers.py index 42fe73af..877f5add 100644 --- a/exasol/nb_connector/cli/param_wrappers.py +++ b/exasol/nb_connector/cli/param_wrappers.py @@ -15,7 +15,7 @@ class ScsArgument: def __init__(self, *args, scs_key: CKey | None = None, **kwargs): self._args = args self.scs_key = scs_key - self._kwargs = dict(kwargs) + self._kwargs = kwargs def decorate(self, func): """ From ff79532fca086ef2cd3edfffa898db879af3582d Mon Sep 17 00:00:00 2001 From: ckunki Date: Tue, 23 Sep 2025 13:41:25 +0200 Subject: [PATCH 25/25] Added variadic args to ScsSecretOption --- exasol/nb_connector/cli/param_wrappers.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/exasol/nb_connector/cli/param_wrappers.py b/exasol/nb_connector/cli/param_wrappers.py index 877f5add..6ee8c34a 100644 --- a/exasol/nb_connector/cli/param_wrappers.py +++ b/exasol/nb_connector/cli/param_wrappers.py @@ -89,15 +89,19 @@ def __init__( envvar: str, prompt: str, scs_key: CKey, + *args, metavar: str = "PASSWORD", + **kwargs, ): super().__init__( name, + *args, metavar=metavar, type=bool, is_flag=True, help=f"{prompt} [env var: {envvar}]", scs_key=scs_key, + **kwargs, ) self.envvar = envvar self.prompt = prompt