Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
79 commits
Select commit Hold shift + click to select a range
b841a30
#220: Refactored class `SlctManager`
ckunki Aug 5, 2025
1272063
Updated tests, added tests, some refactoring
ckunki Aug 6, 2025
e214890
Some refactoring and cleanup
ckunki Aug 6, 2025
3834fc4
added test for flavor_path
ckunki Aug 6, 2025
3086626
Added more tests
ckunki Aug 6, 2025
6dbc202
Updated PTB incl. workflows
ckunki Aug 6, 2025
d6f62a1
Updated action versions in non-PTB GitHub workflows, too
ckunki Aug 6, 2025
0300400
project:fix
ckunki Aug 6, 2025
de30081
Updated SLC integration tests
ckunki Aug 6, 2025
26d3029
Fix lint errors
ckunki Aug 6, 2025
64998fb
project:fix
ckunki Aug 6, 2025
4e45cde
Merge branch 'main' into feature/#220-Refactored_class_SlctManager
ckunki Aug 6, 2025
c3060c6
Update exasol/nb_connector/slc/script_language_container.py
ckunki Aug 6, 2025
c4d7341
Updated based on discussion with tomuben
ckunki Aug 6, 2025
d221fac
Removed flag verify in constructor of SlcSession
ckunki Aug 6, 2025
3ae7aea
project:fix
ckunki Aug 6, 2025
39d3c7f
Updated integration tests
ckunki Aug 6, 2025
75f2e2e
Dixed mypy error
ckunki Aug 6, 2025
0201d0b
Fixed import in integration test
ckunki Aug 7, 2025
7a57943
Updated User guide
ckunki Aug 7, 2025
b0b7cae
project:fix
ckunki Aug 7, 2025
f2c2993
project:fix
ckunki Aug 7, 2025
393def2
project:fix
ckunki Aug 7, 2025
dd31d86
Fixed review findings
ckunki Aug 7, 2025
3653218
project:fix
ckunki Aug 7, 2025
78787b5
Removed figure from user guide
ckunki Aug 7, 2025
f7f38ec
Fixed integration tests
ckunki Aug 7, 2025
6e3258b
Fixed integration tests 2
ckunki Aug 7, 2025
a37e914
Fixed integration tests 3
ckunki Aug 7, 2025
a19a77b
Updated user guide
ckunki Aug 7, 2025
0604a1d
Fixed integration tests 4
ckunki Aug 7, 2025
e4a3439
Renamed SlcSessionError to SlcError
ckunki Aug 7, 2025
d249534
Fixed
ckunki Aug 7, 2025
ccece53
Fixed unit tests
ckunki Aug 7, 2025
beb8457
Removed parameter language_alias
ckunki Aug 7, 2025
e39b3d7
project:fix
ckunki Aug 7, 2025
a2fa252
Fixed mypy errors
ckunki Aug 7, 2025
a25a830
Some more cleanup and fixing deploy()
ckunki Aug 7, 2025
e5d98d7
Fixed parameter names of deploy
ckunki Aug 7, 2025
18944dc
Fixed parameter names of deploy 3
ckunki Aug 7, 2025
23c65c2
Changed ScriptLanguageContainer to convert name to upper case
ckunki Aug 7, 2025
fc2f297
Fixed itests
ckunki Aug 7, 2025
a80daf3
Fixed itests 6
ckunki Aug 7, 2025
5090bbc
Added comments about specific integration test cases
ckunki Aug 8, 2025
82400ec
Added more comments
ckunki Aug 8, 2025
616004e
Simplified test
ckunki Aug 8, 2025
51989cd
Replaced class SlcSession by SlcFlavor
ckunki Aug 8, 2025
fc1109f
project:fix
ckunki Aug 8, 2025
4f2cbb2
Removed dead code
ckunki Aug 8, 2025
6ce7d1d
Fixed mypy errors
ckunki Aug 8, 2025
594453d
Removed method flavor_path and renamed flavor_dir to flavor_path
ckunki Aug 8, 2025
1753329
Fixed integration tests
ckunki Aug 8, 2025
4b5e32c
Fixed integration tests 2
ckunki Aug 8, 2025
0796ffd
project:fix
ckunki Aug 8, 2025
d86e254
Fixed integration tests 3
ckunki Aug 8, 2025
dd2ff64
Refactored Workspace and fixed integration tests
ckunki Aug 9, 2025
11f2f23
Replaced manual rm by free-disk-space option "haskell"
ckunki Aug 9, 2025
e8bdc74
Used different flavor for other SLC
ckunki Aug 9, 2025
5fe09e9
Reverted renaming slow tests
ckunki Aug 9, 2025
a775d54
Fixed integration tests
ckunki Aug 9, 2025
eaa9c1b
Fixed integration tests 3
ckunki Aug 11, 2025
d24720d
Fixed code smell variable shadows a builtin
ckunki Aug 11, 2025
06f8080
Apply suggestions from code review
ckunki Aug 11, 2025
c200a67
Updated user guide
ckunki Aug 11, 2025
ea04890
Updated changelog and user guide
ckunki Aug 11, 2025
dd9dff8
Fixed review findings
ckunki Aug 11, 2025
07ea46a
project:fix
ckunki Aug 11, 2025
3e5c8b4
Simplified & fixed GitHub workflows
ckunki Aug 11, 2025
fc60725
restored merge-gate
ckunki Aug 11, 2025
8ee8771
Apply suggestions from code review
ckunki Aug 11, 2025
24cfd51
Fixed review findings
ckunki Aug 11, 2025
035811d
Changed release SLC tag from 9.6.0
ckunki Aug 11, 2025
5657165
Updated developer guide
ckunki Aug 11, 2025
e048c26
Moved R flavor in integration tests to separate constant
ckunki Aug 11, 2025
e2d27b3
Update SLCR release
ckunki Aug 11, 2025
6b22864
refactored fixture slc_factory
ckunki Aug 11, 2025
426f7f7
Added test for language_alias
ckunki Aug 11, 2025
b05572a
project:fix
ckunki Aug 11, 2025
d1f8d0a
Fixed review finding
ckunki Aug 11, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions .github/workflows/tests-ordinary-integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
file:
- test_itde_manager.py
- test_sagemaker_extension_wrapper.py
- test_slct_manager.py
- itest_slc.py
- test_transformers_extension_wrapper.py
- itde_mgr_in_container/test_itde_connect.py
- itde_mgr_in_container/test_itde_external.py
Expand All @@ -36,15 +36,14 @@ jobs:
with:
tool-cache: true
large-packages: false
haskell: true

- name: Free disk space by removing large directories
run: |
sudo rm -rf /usr/local/graalvm/
sudo rm -rf /usr/local/.ghcup/
sudo rm -rf /usr/local/share/powershell
sudo rm -rf /usr/local/share/chromium
sudo rm -rf /usr/local/lib/node_modules
sudo rm -rf /opt/ghc

- name: Setup Python & Poetry Environment
uses: exasol/python-toolbox/.github/actions/python-environment@1.7.4
Expand Down
24 changes: 23 additions & 1 deletion doc/changes/unreleased.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,32 @@
# Unreleased

## Summary

This release of the Notebook Connector evolves the prior `SlctManager` interface to
* Support building SLCs with GPU support, requiring a special flavor, e.g. [template-Exasol-8-python-3.10-cuda-conda](https://github.com/exasol/script-languages/tree/master/flavors/template-Exasol-8-python-3.10-cuda-conda)
* Incl. isolating various SLC sessions regarding flavors, Git clones and working directories.

The release comes with breaking changes:
* Class `SlctManager` has been renamed to `ScriptLanguageContainer`.
* Some public methods or and attributes have been
* renamed
* `flavor_name` to `flavor`
* `flavor_dir` to `flavor_path`
* `upload()` to `deploy()`
* `slc_docker_images()` to `docker_image_tags()`
* `clean_all_images()` to `clean_docker_images()`
* removed
* `check_slc_repo_complete()`
* `clone_slc_repo()`
* The handling of Secure Configuration Storage has been changed to support using multiple SLC flavors.

See the NC [User Guide](../user_guide/user-guide.md) for details.

## Features

* #213: Added Support to specify the SLC flavor via a session parameter
* #205: Added GPU support to ITDE manager
* #220: Replaced implementation on using SLCs by Gen.2

## Documentation

Expand All @@ -16,4 +39,3 @@
* #208: Widened version constraints for:
* exasol-saas-api from ">=0.9.0,<1.0.0" to ">=0.9.0,<3"
* exasol-bucketfs from "^1.0.0" to ">=1,<3"

6 changes: 6 additions & 0 deletions doc/developer_guide/developer-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,9 @@ Check if the referred version of SLCR is also compatible with the version of SLC
1. Go to [SLCR releases](https://github.com/exasol/script-languages-release/releases)
2. Search for the SLCR version referenced in NC's file `exasol/nb_connector/slct_manager.py`
3. Check if in the SLCR release, file `pyproject.toml`, dependency `script-languages-container-tools` has the same major version

### Impact on NC Tests

Some of the tests of the Notebook Connector, especially the integration tests, may depend on particular properties of a particular SLCR release, e.g. a particular flavor to be present.

In consequence updating the SLCR version potentially may require to update the NC tests, e.g. the name of the flavor used in the tests.
Binary file removed doc/user_guide/slct-manager-parameters.drawio.png
Binary file not shown.
24 changes: 18 additions & 6 deletions doc/user_guide/user-guide.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,25 @@
# Notebook Connector User Guide

## SlctManager
## Managing Script Language Containers (SLCs)

Class `SlctManager` in the Notebook Connector (NC) supports building different flavors of [Exasol Script Language Containers](https://github.com/exasol/script-languages-release) (SLCs). SlctManager uses [script-languages-container-tool](https://github.com/exasol/script-languages-container-tool) internally.
The Notebook Connector (NC) supports building different flavors of [Exasol Script Language Containers](https://github.com/exasol/script-languages-release) (SLCs) using the [script-languages-container-tool](https://github.com/exasol/script-languages-container-tool).

* The name of the SLC flavor must be provided in the Secure Configuration Storage (SCS) passed as parameter `secrets` to the constructor of SlctManager.
* Additionally the caller must specify the *key* in the SCS for finding the flavor name.
The specific options for building an SLC are stored in the Secure Configuration Storage (SCS). Each SLC is identified by an arbitrary unique name used as index into the SCS for finding the related options.

The constructor therefore supports the additional optional parameter `session`:
You can set the SLC options using the class method `ScriptLanguageContainer.create()`, with parameters
Copy link
Collaborator

Choose a reason for hiding this comment

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

We should change the documentation sphinx and rst, then then it would also generate the api doc already.

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 was about thinking in the same direction 👍
I propose to address this in a separate PR

* `secrets`: The SCS
* `name`: The name of the SLC instance
* will be converted to upper-case and must be unique
* `flavor`: The name of a template as provided by the [Exasol Script Language Containers](https://github.com/exasol/script-languages-release).

![](slct-manager-parameters.drawio.png)
Method `create()` will then
* Select a Language Alias for executing UDF scripts inside the SLC
* See section _Define your own script aliases_ on [docs.exasol.com](https://docs.exasol.com/db/latest/database_concepts/udf_scripts/adding_new_packages_script_languages.htm).
* The Language Alias will use prefix `custom_slc_` followed by the specified name
* Consecutive call to method `deploy()` will overwrite the SLC using the same Language Alias.
* Save the `flavor` to the SCS indexed by the SLC's name.
* Raise an error if the name has already been used.
* Clone the SLC Git repository to the local file system.

The constructor of class `ScriptLanguageContainer` verifies the SCS to contain the flavor and the SLC repository to be cloned to the local file system.

5 changes: 5 additions & 0 deletions exasol/nb_connector/slc/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from exasol.nb_connector.slc.script_language_container import (
PipPackageDefinition,
ScriptLanguageContainer,
)
from exasol.nb_connector.slc.slc_flavor import SlcError
25 changes: 25 additions & 0 deletions exasol/nb_connector/slc/constants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
from pathlib import Path

from exasol.nb_connector.language_container_activation import ACTIVATION_KEY_PREFIX

DEFAULT_ALIAS = "ai_lab_default" # To be used in the Jupyter notebooks of the AI Lab
PATH_IN_BUCKET = "container"

SLC_DOCKER_IMG_NAME = "exasol/script-language-container"

SLC_ACTIVATION_KEY_PREFIX = ACTIVATION_KEY_PREFIX + "slc_"
"""
Activation SQL for the Custom SLC will be saved in the Secure
Configuration Storage with this key.
"""

FLAVORS_PATH_IN_SLC_REPO = Path("flavors")
"""Path to flavors within the script-languages-release repository"""

SLC_RELEASE_TAG = "9.7.0"
"""
Using the SLC_RELEASE 9.7.0 because we are limited to slc-tool 3.*. (see pyproject.toml)
Check the developer guide (./doc/developer-guide.md) for more information.
"""

WORKSPACE_DIR = ".workspace"
212 changes: 212 additions & 0 deletions exasol/nb_connector/slc/script_language_container.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
from __future__ import annotations

import re
from collections import namedtuple
from pathlib import (
Path,
)

from exasol.slc import api as exaslct_api
from exasol_integration_test_docker_environment.lib.docker import (
ContextDockerClient,
)

from exasol.nb_connector.ai_lab_config import AILabConfig as CKey
from exasol.nb_connector.language_container_activation import ACTIVATION_KEY_PREFIX
from exasol.nb_connector.secret_store import Secrets
from exasol.nb_connector.slc import constants
from exasol.nb_connector.slc.slc_flavor import (
SlcError,
SlcFlavor,
)
from exasol.nb_connector.slc.workspace import (
Workspace,
current_directory,
)

PipPackageDefinition = namedtuple("PipPackageDefinition", ["pkg", "version"])


class ScriptLanguageContainer:
"""
Support building different flavors of Exasol Script Language
Containers (SLCs) using the SLCT.

Parameter ``name`` serves as base of the language alias and a key for the related flavor stored in the
Secure Configuration Storage (SCS / secrets / conf). The flavor is used
as a template for building the SLC.

If the flavor is missing in the SCS or the SLC Git repository has not been
checked out (i.e. cloned) into the checkout_dir, then the constructor will
raise an SlcError.

Additionally, the caller needs to ensure, that a flavor with this name is
contained in the SLC release specified in variable
constants.SLC_RELEASE_TAG.
"""

def __init__(
self,
secrets: Secrets,
name: str,
):
self.secrets = secrets
self.name = name
self.flavor = SlcFlavor(name).verify(secrets)
self.workspace = Workspace.for_slc(name)
if not self.flavor_path.is_dir():
raise SlcError(
f"SLC Git repository not checked out to {self.checkout_dir}."
)

@classmethod
def create(
cls,
secrets: Secrets,
name: str,
flavor: str,
) -> ScriptLanguageContainer:
slc_flavor = SlcFlavor(name)
if slc_flavor.exists(secrets):
raise SlcError(
"Secure Configuration Storage already contains a"
f" flavor for SLC name {name}."
)
slc_flavor.save(secrets, flavor)
workspace = Workspace.for_slc(name)
workspace.clone_slc_repo()
return cls(secrets=secrets, name=name)

@property
def language_alias(self) -> str:
"""
Is case-insensitive.
"""
return f"custom_slc_{self.name}"

@property
def checkout_dir(self) -> Path:
return self.workspace.git_clone_path

@property
def _flavor_path_rel(self) -> str:
return str(self.flavor_path.relative_to(self.checkout_dir))

@property
def flavor_path(self) -> Path:
return self.checkout_dir / constants.FLAVORS_PATH_IN_SLC_REPO / self.flavor

@property
def custom_pip_file(self) -> Path:
"""
Returns the path to the custom pip file of the flavor
"""
return (
self.flavor_path
/ "flavor_customization"
/ "packages"
/ "python3_pip_packages"
)

def export(self):
"""
Exports the current SLC to the export directory.
"""
with current_directory(self.checkout_dir):
exaslct_api.export(
flavor_path=(str(self._flavor_path_rel),),
export_path=str(self.workspace.export_path),
output_directory=str(self.workspace.output_path),
release_name=self.language_alias,
)

def deploy(self):
"""
Deploys the current script-languages-container to the database and
stores the activation string in the Secure Configuration Storage.
"""
bfs_params = {
k: self.secrets.get(v)
for k, v in [
("bucketfs_host", CKey.bfs_host_name),
("bucketfs_port", CKey.bfs_port),
("bucketfs_user", CKey.bfs_user),
("bucketfs_password", CKey.bfs_password),
("bucketfs_name", CKey.bfs_service),
("bucket", CKey.bfs_bucket),
]
}

with current_directory(self.checkout_dir):
exaslct_api.deploy(
Copy link
Collaborator

@tkilias tkilias Aug 11, 2025

Choose a reason for hiding this comment

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

Suggested change
exaslct_api.deploy(
deploy_result = exaslct_api.deploy(

Copy link
Collaborator

Choose a reason for hiding this comment

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

deploy_result[flavor_name]["release"]

Copy link
Contributor Author

Choose a reason for hiding this comment

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

flavor_path=(str(self._flavor_path_rel),),
**bfs_params,
path_in_bucket=constants.PATH_IN_BUCKET,
release_name=self.language_alias,
output_directory=str(self.workspace.output_path),
)
container_name = f"{self.flavor}-release-{self.language_alias}"
result = exaslct_api.generate_language_activation(
flavor_path=str(self._flavor_path_rel),
bucketfs_name=bfs_params["bucketfs_name"],
bucket_name=bfs_params["bucket"],
container_name=container_name,
path_in_bucket=constants.PATH_IN_BUCKET,
)
alter_session_cmd = result[0]
re_res = re.search(
r"ALTER SESSION SET SCRIPT_LANGUAGES='(.*)'", alter_session_cmd
)
activation_key = re_res.groups()[0]
_, url = activation_key.split("=", maxsplit=1)
Comment on lines +149 to +161
Copy link
Collaborator

Choose a reason for hiding this comment

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

please use LanguageDefinitionsBuilder from the DeployResult which exaslct_api.deploy returns

Copy link
Contributor Author

Choose a reason for hiding this comment

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

self.secrets.save(self._alias_key, f"{self.language_alias}={url}")

@property
def _alias_key(self):
return constants.SLC_ACTIVATION_KEY_PREFIX + self.language_alias

@property
def activation_key(self) -> str:
"""
Returns the language activation string for the uploaded script-language-container.
Can be used in `ALTER SESSION` or `ALTER_SYSTEM` SQL commands to activate
the language of the uploaded script-language-container.
"""
try:
return self.secrets[self._alias_key]
except AttributeError as ex:
raise SlcError(
"Secure Configuration Storage does not contains an activation key."
) from ex

def append_custom_packages(self, pip_packages: list[PipPackageDefinition]):
"""
Appends packages to the custom pip file.

Note: This method is not idempotent: Multiple calls with the same
package definitions will result in duplicate entries.
"""
with open(self.custom_pip_file, "a") as f:
for p in pip_packages:
print(f"{p.pkg}|{p.version}", file=f)

@property
def docker_image_tags(self) -> list[str]:
"""
Return list of Docker image tags related to the current SLC.
"""
image_name = constants.SLC_DOCKER_IMG_NAME
prefix = f"{image_name}:{self.flavor}"
with ContextDockerClient() as docker_client:
images = docker_client.images.list(name=image_name)
return [tag for img in images if (tag := img.tags[0]).startswith(prefix)]

def clean_docker_images(self):
"""
Deletes local docker images related to the current SLC.
"""
with current_directory(self.checkout_dir):
exaslct_api.clean_flavor_images(
flavor_path=(str(self._flavor_path_rel),),
output_directory=str(self.workspace.output_path),
)
Loading