Skip to content
Merged
1 change: 1 addition & 0 deletions doc/changes/unreleased.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Additionally the release includes a CLI for populating the Secure Configuration
* #263: Added functions for handling a set of options for SCS CLI
* #267: Implemented modify operations for the SCS
* #269: Implemented showing SCS content
* #271: Implemented checking SCS content

## Refactorings

Expand Down
4 changes: 3 additions & 1 deletion exasol/nb_connector/cli/commands/check.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
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()
Expand All @@ -24,4 +25,5 @@ def check(scs_file: Path, connect: bool):
Optionally also verify if a connection to the configured Exasol database
instance is successful.
"""
pass
result = processing.check_scs(scs_file, connect)
sys.exit(result)
32 changes: 32 additions & 0 deletions exasol/nb_connector/cli/processing/processing.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@
get_option_set,
get_scs,
)
from exasol.nb_connector.connections import open_pyexasol_connection
from exasol.nb_connector.itde_manager import bring_itde_up
from exasol.nb_connector.secret_store import Secrets

LOG = logging.getLogger(__name__)

Expand Down Expand Up @@ -63,6 +66,35 @@ def save(
return 0


def verify_connection(scs: Secrets) -> int:
if BackendSelector(scs).use_itde:
# Question: Is it OK, to let bring_itde_up modify the SCS content, here?
Copy link
Contributor Author

@ckunki ckunki Oct 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it OK, to let bring_itde_up() modify the SCS content, here?

Copy link
Contributor Author

@ckunki ckunki Oct 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Additional question:

  • Should the command line really launch the IDTE only for verifying the connection parameters?
  • As actually the ITDE does not require actual connection parameters but only offers optional(!) configuration of disk and mem size.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See my comment above.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, we need to bring the ITDE up and take it down, in a try .. finally manner.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I updated the docstring.
But the question regarding the ITDE is still pending.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. We had the initial discussion, that actually the CLI does not interact too much with the ITDE.

  2. Additionally, launching the ITDE takes quite some time and hence I am not sure whether a user really wants to verify launching and connecting to a Docker DB controlled by ITDE without any significant parameters needing to be configured and hence no significant parameters needing to be verified either.

  3. Binging the ITDE up and take it down, in a try ... finally manner still requires some additional logic compared to the other DB instance variants and hence, I assume, we will need a test, which will again increase the size of this PR.

All in all, I want to ask for confirmation if the benefits of this feature justify the additional effort.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my opinion, it doesn't really makes sense to test the connection to the ITDE. If we want to make sure the parameters are correct, we should make sure their format is checked while setting them.

False and bring_itde_up(scs)
report.warning(f"Bring up ITDE currently disabled")
return 1
try:
open_pyexasol_connection(scs).execute("SELECT 1 FROM DUAL").fetchone()
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should verify_connection() (CLI command scs check --connect) verify the bucketfs, too?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Is it sufficient to list the BFS contents in the test?
  • What is the expectation?
  • Are there any default files we expect to be contained in the BFS?
  • Or is it acceptable to modify the BFS contents for the sake of testing the connection?
  • Should the test also do a cleanup after having verified the connection?

Copy link
Contributor Author

@ckunki ckunki Oct 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will add verification for bucket FS parameters:

  • list contents
  • choose unique file name
  • upload and download sample file
  • verify identical content
  • remove the file

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I moved the BucketFS verification to a separate ticket/PR:

except Exception as ex:
report.error(f"Failed to connect to the configured database {ex}")
return 1
report.success("Connection to the configured database instance was successful.")
return 0


def check_scs(scs_file: Path, connect: bool) -> int:
"""
Check the SCS content for completeness. Infer the required keys from
backend and use_itde if these are contained in the SCS already.

If parameter `connect` is True then also verify if a connection to the
configured Exasol database instance is successful.
"""
options = get_option_set(scs_file)
if not options or not options.check():
return 1
return 0 if not connect else verify_connection(options.scs)


def show_scs_content(scs_file: Path) -> int:
"""
If the SCS contains a proper backend selection, then show the SCS
Expand Down
27 changes: 27 additions & 0 deletions test/unit/cli/test_cli.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import getpass
import itertools
from typing import Iterator
import os
from inspect import cleandoc
from pathlib import Path
from test.utils.integration_test_utils import sample_db_file
from unittest.mock import Mock

import click
import pytest
Expand All @@ -16,9 +21,15 @@ def assert_error(result: click.testing.Result, message: str):
assert message in result.output


def assert_success(result: click.testing.Result, message: str):
assert result.exit_code == 0
assert message in result.output


@pytest.mark.parametrize(
"args",
[
(commands.check, []),
(commands.configure, ["onprem"]),
(commands.configure, ["saas"]),
(commands.configure, ["docker-db"]),
Expand All @@ -30,6 +41,20 @@ def test_missing_scs_file(args):
assert_error(result, "Error: Missing argument 'SCS_FILE'")


@pytest.fixture
def scs_file() -> Iterator[Path]:
with sample_db_file() as scs_file:
yield scs_file


def test_check_ask_for_master_password(monkeypatch, scs_file):
mock = Mock(return_value="interactive password")
monkeypatch.setattr(getpass, "getpass", mock)
result = CliRunner().invoke(commands.check, [str(scs_file)])
assert mock.called
assert_error(result, f"{scs_file} does not contain any backend")


@pytest.fixture
def scs_with_env(secrets, monkeypatch) -> Secrets:
"""
Expand Down Expand Up @@ -137,5 +162,7 @@ def cmd_args():
monkeypatch.setitem(os.environ, env_var, f"secret {i+1}")
result = CliRunner().invoke(commands.configure, cmd_args())
assert result.exit_code == 0
result = CliRunner().invoke(commands.check, [scs_file])
assert_success(result, f"Configuration is complete")
result = CliRunner().invoke(commands.show, [scs_file])
assert cleandoc(expected_show) in result.output
Loading