diff --git a/exasol/python_extension_common/deployment/language_container_deployer_cli.py b/exasol/python_extension_common/deployment/language_container_deployer_cli.py index 6a91c38..1b75f80 100644 --- a/exasol/python_extension_common/deployment/language_container_deployer_cli.py +++ b/exasol/python_extension_common/deployment/language_container_deployer_cli.py @@ -6,12 +6,6 @@ import click from exasol.python_extension_common.deployment.language_container_deployer import LanguageContainerDeployer -DB_PASSWORD_ENVIRONMENT_VARIABLE = "DB_PASSWORD" -BUCKETFS_PASSWORD_ENVIRONMENT_VARIABLE = "BUCKETFS_PASSWORD" -SAAS_ACCOUNT_ID_ENVIRONMENT_VARIABLE = "SAAS_ACCOUNT_ID" -SAAS_DATABASE_ID_ENVIRONMENT_VARIABLE = "SAAS_DATABASE_ID" -SAAS_TOKEN_ENVIRONMENT_VARIABLE = "SAAS_TOKEN" - class CustomizableParameters(Enum): """ @@ -82,23 +76,63 @@ def clear_formatters(self): slc_parameter_formatters = _ParameterFormatters() +# This text will be displayed instead of the actual value, if found in an environment +# variable, in a prompt. +SECRET_DISPLAY = '***' + + +class SecretParams(Enum): + """ + This enum serves as a definition of confidential parameters which values should not be + displayed in the console, unless the user types them in the command line. + + The enum name is also the name of the environment variable where the correspondent + secret value can be stored. + + The enum value is also the name of the cli parameter. + """ + DB_PASSWORD = 'db-pass' + BUCKETFS_PASSWORD = 'bucketfs-password' + SAAS_ACCOUNT_ID = 'saas-account-id' + SAAS_DATABASE_ID = 'saas-database-id' + SAAS_TOKEN = 'saas-token' + + +def secret_callback(ctx: click.Context, param: click.Option, value: Any): + """ + Here we try to get the secret parameter value from an environment variable. + The reason for doing this in the callback instead of using a callable default is + that we don't want the default to be displayed in the prompt. There seems to + be no way of altering this behaviour. + """ + if value == SECRET_DISPLAY: + secret_param = SecretParams(param.name) + return os.environ.get(secret_param.name) + return value + + @click.command(name="language-container") @click.option('--bucketfs-name', type=str) @click.option('--bucketfs-host', type=str) @click.option('--bucketfs-port', type=int) @click.option('--bucketfs-use-https', type=bool, default=False) @click.option('--bucketfs-user', type=str) -@click.option('--bucketfs-password', type=str, - default=lambda: os.environ.get(BUCKETFS_PASSWORD_ENVIRONMENT_VARIABLE)) +@click.option(f'--{SecretParams.BUCKETFS_PASSWORD.value}', type=str, + prompt='BucketFS password', prompt_required=False, + hide_input=True, default=SECRET_DISPLAY, callable=secret_callback) @click.option('--bucket', type=str) @click.option('--saas-url', type=str, default='https://cloud.exasol.com') -@click.option('--saas-account-id', type=str, - default=lambda: os.environ.get(SAAS_ACCOUNT_ID_ENVIRONMENT_VARIABLE)) -@click.option('--saas-database-id', type=str, - default=lambda: os.environ.get(SAAS_DATABASE_ID_ENVIRONMENT_VARIABLE)) -@click.option('--saas-token', type=str, - default=lambda: os.environ.get(SAAS_TOKEN_ENVIRONMENT_VARIABLE)) +@click.option(f'--{SecretParams.SAAS_ACCOUNT_ID.value}', type=str, + prompt='SaaS account id', prompt_required=False, + hide_input=True, default=SECRET_DISPLAY, callable=secret_callback) +@click.option(f'--{SecretParams.SAAS_DATABASE_ID.value}', type=str, + prompt='SaaS database id', prompt_required=False, + hide_input=True, default=SECRET_DISPLAY, callable=secret_callback) +@click.option('--saas-database-name', type=str) +@click.option(f'--{SecretParams.SAAS_TOKEN.value}', type=str, + prompt='SaaS token', prompt_required=False, + hide_input=True, default=SECRET_DISPLAY, callable=secret_callback) @click.option('--path-in-bucket', type=str) @click.option('--container-file', type=click.Path(exists=True, file_okay=True)) @@ -106,8 +140,9 @@ def clear_formatters(self): callback=slc_parameter_formatters) @click.option('--dsn', type=str) @click.option('--db-user', type=str) -@click.option('--db-pass', - default=lambda: os.environ.get(DB_PASSWORD_ENVIRONMENT_VARIABLE)) +@click.option(f'--{SecretParams.DB_PASSWORD.value}', type=str, + prompt='DB password', prompt_required=False, + hide_input=True, default=SECRET_DISPLAY, callable=secret_callback) @click.option('--language-alias', type=str, default="PYTHON3_EXT") @click.option('--ssl-cert-path', type=str, default="") @click.option('--ssl-client-cert-path', type=str, default="") @@ -127,6 +162,7 @@ def language_container_deployer_main( saas_url: str, saas_account_id: str, saas_database_id: str, + saas_database_name: str, saas_token: str, path_in_bucket: str, container_file: str, @@ -155,6 +191,7 @@ def language_container_deployer_main( saas_url=saas_url, saas_account_id=saas_account_id, saas_database_id=saas_database_id, + saas_database_name=saas_database_name, saas_token=saas_token, path_in_bucket=path_in_bucket, dsn=dsn, diff --git a/test/integration/test_language_container_deployer_saas_cli.py b/test/integration/test_language_container_deployer_saas_cli.py index 5b6d69c..4c36584 100644 --- a/test/integration/test_language_container_deployer_saas_cli.py +++ b/test/integration/test_language_container_deployer_saas_cli.py @@ -8,11 +8,7 @@ from click.testing import CliRunner import pyexasol -from exasol.python_extension_common.deployment.language_container_deployer_cli import ( - SAAS_ACCOUNT_ID_ENVIRONMENT_VARIABLE, - SAAS_DATABASE_ID_ENVIRONMENT_VARIABLE, - SAAS_TOKEN_ENVIRONMENT_VARIABLE, -) +from exasol.python_extension_common.deployment.language_container_deployer_cli import SecretParams from test.utils.revert_language_settings import revert_language_settings from test.utils.db_utils import (create_schema, assert_udf_running) @@ -33,9 +29,10 @@ def call_language_definition_deployer_cli(func, version: Optional[str] = None, use_ssl_cert_validation: bool = False): - os.environ[SAAS_ACCOUNT_ID_ENVIRONMENT_VARIABLE] = account_id - os.environ[SAAS_DATABASE_ID_ENVIRONMENT_VARIABLE] = database_id - os.environ[SAAS_TOKEN_ENVIRONMENT_VARIABLE] = token + os.environ[SecretParams.SAAS_ACCOUNT_ID.name] = account_id + os.environ[SecretParams.SAAS_TOKEN.name] = token + if database_id: + os.environ[SecretParams.SAAS_DATABASE_ID.name] = database_id args_list = [ "language-container", @@ -88,8 +85,7 @@ def test_language_container_deployer_cli_with_container_file( language_alias=TEST_LANGUAGE_ALIAS, url=saas_host, account_id=saas_account_id, - # database_name=saas_database_name, - database_id=operational_saas_database_id, + database_name=saas_database_name, token=saas_token) assert result.exit_code == 0 assert result.exception is None