-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
#19 move slc notebook #122
Merged
Merged
Changes from all commits
Commits
Show all changes
19 commits
Select commit
Hold shift + click to select a range
2ca488e
Added slct_manager
tomuben fb9dd3f
1. Added dependencies
tomuben a0fe93a
Fixed output path for upload
tomuben 67d411b
Decreased exasol-script-languages-container-tool requiored version
tomuben 53cd102
Added AiLabConfig.slc_source
tomuben de132f7
Refactored slct_manager.
tomuben 164b2c4
Fixed MyPy findings
tomuben f709c7c
Fixed test_itde_manager_in_docker_container.py
tomuben 9270453
Fixes from review
tomuben 3a92c26
Fixed closing SQL connection at end of integration test
tomuben 6426d04
Allow custom definition of alias
tomuben bf50b73
Provide configuration of alias
tomuben fec53a6
Use language_alias also for export
tomuben 157a3e8
Added clean up functions
tomuben a061a6f
Added a function to get slc docker images
tomuben f9ecc6f
Ignore type
tomuben f4cf8b7
Updated lock-file
tomuben 190ad2c
Changed default-alias
tomuben 2be5218
Renamed default alias
tomuben File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,226 @@ | ||
import logging | ||
import os | ||
import re | ||
import contextlib | ||
import shutil | ||
from collections import namedtuple | ||
from typing import Optional, List | ||
|
||
from exasol_integration_test_docker_environment.lib.docker import ContextDockerClient # type: ignore | ||
from git import Repo | ||
from pathlib import Path | ||
from exasol_script_languages_container_tool.lib import api as exaslct_api # type: ignore | ||
from exasol.nb_connector.ai_lab_config import AILabConfig as CKey, AILabConfig | ||
from exasol.nb_connector.language_container_activation import ACTIVATION_KEY_PREFIX | ||
from exasol.nb_connector.secret_store import Secrets | ||
|
||
DEFAULT_ALIAS = "ai_lab_default" | ||
PATH_IN_BUCKET = "container" | ||
|
||
# Activation SQL for the Custom SLC will be saved in the secret | ||
# store with this key. | ||
SLC_ACTIVATION_KEY_PREFIX = ACTIVATION_KEY_PREFIX + "slc_" | ||
|
||
# This is the flavor customers are supposed to use for modifications. | ||
REQUIRED_FLAVOR = "template-Exasol-all-python-3.10" | ||
|
||
# Path to the used flavor within the script-languages-release repository | ||
FLAVOR_PATH_IN_SLC_REPO = Path("flavors") / REQUIRED_FLAVOR | ||
|
||
PipPackageDefinition = namedtuple('PipPackageDefinition', ['pkg', 'version']) | ||
|
||
|
||
class SlcDir: | ||
def __init__(self, secrets: Secrets): | ||
self._secrets = secrets | ||
|
||
@property | ||
def root_dir(self) -> Path: | ||
target_dir = self._secrets.get(AILabConfig.slc_target_dir) | ||
if not target_dir: | ||
raise RuntimeError("slc target dir is not defined in secrets.") | ||
return Path(target_dir) | ||
|
||
@property | ||
def flavor_dir(self) -> Path: | ||
return self.root_dir / FLAVOR_PATH_IN_SLC_REPO | ||
|
||
@property | ||
def custom_pip_file(self) -> Path: | ||
""" | ||
Returns the path to the custom pip file of the flavor | ||
""" | ||
return self.flavor_dir / "flavor_customization" / "packages" / "python3_pip_packages" | ||
|
||
@contextlib.contextmanager | ||
def enter(self): | ||
"""Changes working directory and returns to previous on exit.""" | ||
prev_cwd = Path.cwd() | ||
os.chdir(self.root_dir) | ||
try: | ||
yield | ||
finally: | ||
os.chdir(prev_cwd) | ||
|
||
def __str__(self): | ||
return str(self.root_dir) | ||
|
||
|
||
class WorkingDir: | ||
def __init__(self, p: Optional[Path]): | ||
if p is None: | ||
self.root_dir = Path.cwd() | ||
else: | ||
self.root_dir = p | ||
|
||
@property | ||
def export_path(self): | ||
""" | ||
Returns the export path for script-languages-container | ||
""" | ||
return self.root_dir / "container" | ||
|
||
@property | ||
def output_path(self): | ||
""" | ||
Returns the output path containing caches and logs. | ||
""" | ||
return self.root_dir / "output" | ||
|
||
def cleanup_output_path(self): | ||
""" | ||
Remove the output path recursively. | ||
""" | ||
shutil.rmtree(self.output_path) | ||
|
||
def cleanup_export_path(self): | ||
""" | ||
Remove the export path recursively | ||
""" | ||
shutil.rmtree(self.export_path) | ||
|
||
|
||
class SlctManager: | ||
def __init__(self, secrets: Secrets, working_path: Optional[Path] = None): | ||
self.working_path = WorkingDir(working_path) | ||
self.slc_dir = SlcDir(secrets) | ||
self._secrets = secrets | ||
|
||
def check_slc_repo_complete(self) -> bool: | ||
""" | ||
Checks if the target dir for the script-languages repository is present and correct. | ||
""" | ||
print(f"Script-languages repository path is '{self.slc_dir}'") | ||
if not self.slc_dir.flavor_dir.is_dir(): | ||
return False | ||
return True | ||
|
||
def clone_slc_repo(self): | ||
""" | ||
Clones the script-languages-release repository from Github into the target dir configured in the secret store. | ||
""" | ||
if not self.slc_dir.root_dir.is_dir(): | ||
logging.info(f"Cloning into {self.slc_dir}...") | ||
repo = Repo.clone_from("https://github.com/exasol/script-languages-release", self.slc_dir.root_dir) | ||
logging.info("Fetching submodules...") | ||
repo.submodule_update(recursive=True) | ||
else: | ||
logging.warning(f"Directory '{self.slc_dir}' already exists. Skipping cloning....") | ||
|
||
def export(self): | ||
""" | ||
Exports the current script-languages-container to the export directory. | ||
""" | ||
with self.slc_dir.enter(): | ||
exaslct_api.export(flavor_path=(str(FLAVOR_PATH_IN_SLC_REPO),), | ||
export_path=str(self.working_path.export_path), | ||
output_directory=str(self.working_path.output_path), | ||
release_name=self.language_alias,) | ||
|
||
def upload(self): | ||
""" | ||
Uploads the current script-languages-container to the database | ||
and stores the activation string in the secret store. | ||
""" | ||
bucketfs_name = self._secrets.get(CKey.bfs_service) | ||
bucket_name = self._secrets.get(CKey.bfs_bucket) | ||
database_host = self._secrets.get(CKey.bfs_host_name) | ||
bucketfs_port = self._secrets.get(CKey.bfs_port) | ||
bucketfs_username = self._secrets.get(CKey.bfs_user) | ||
bucketfs_password = self._secrets.get(CKey.bfs_password) | ||
|
||
with self.slc_dir.enter(): | ||
exaslct_api.upload(flavor_path=(str(FLAVOR_PATH_IN_SLC_REPO),), | ||
database_host=database_host, | ||
bucketfs_name=bucketfs_name, | ||
bucket_name=bucket_name, bucketfs_port=int(bucketfs_port), | ||
bucketfs_username=bucketfs_username, | ||
bucketfs_password=bucketfs_password, path_in_bucket=PATH_IN_BUCKET, | ||
release_name=self.language_alias, | ||
output_directory=str(self.working_path.output_path)) | ||
container_name = f"{REQUIRED_FLAVOR}-release-{self.language_alias}" | ||
result = exaslct_api.generate_language_activation(flavor_path=str(FLAVOR_PATH_IN_SLC_REPO), | ||
bucketfs_name=bucketfs_name, | ||
bucket_name=bucket_name, container_name=container_name, | ||
path_in_bucket=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) | ||
self._secrets.save(self._alias_key, f"{self.language_alias}={url}") | ||
|
||
@property | ||
def _alias_key(self): | ||
return 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. | ||
""" | ||
activation_key = self._secrets.get(self._alias_key) | ||
if not activation_key: | ||
raise RuntimeError("SLC activation key not defined in secrets.") | ||
return activation_key | ||
|
||
@property | ||
def language_alias(self) -> str: | ||
""" | ||
Returns the stored language alias. | ||
""" | ||
language_alias = self._secrets.get(AILabConfig.slc_alias, DEFAULT_ALIAS) | ||
if not language_alias: | ||
return DEFAULT_ALIAS | ||
return language_alias | ||
|
||
@language_alias.setter | ||
def language_alias(self, alias: str): | ||
""" | ||
Stores the language alias in the secret store. | ||
""" | ||
self._secrets.save(AILabConfig.slc_alias, alias) | ||
|
||
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 duplicated entries. | ||
""" | ||
with open(self.slc_dir.custom_pip_file, "a") as f: | ||
for p in pip_packages: | ||
print(f"{p.pkg}|{p.version}", file=f) | ||
|
||
@property | ||
def slc_docker_images(self): | ||
with ContextDockerClient() as docker_client: | ||
images = docker_client.images.list(name="exasol/script-language-container") | ||
image_tags = [img.tags[0] for img in images] | ||
return image_tags | ||
|
||
def clean_all_images(self): | ||
""" | ||
Deletes all local docker images. | ||
""" | ||
exaslct_api.clean_all_images(output_directory=str(self.working_path.output_path)) |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
with python
3.11
there is a ready to go context manager for changing the dir is available see (https://docs.python.org/3/library/contextlib.html#contextlib.chdir)There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good to know. Thx