diff --git a/exasol/ds/sandbox/runtime/ansible/roles/jupyter/files/notebook/utils/main_config_ui.ipynb b/exasol/ds/sandbox/runtime/ansible/roles/jupyter/files/notebook/utils/main_config_ui.ipynb index 48f42aa2..9a84fa34 100644 --- a/exasol/ds/sandbox/runtime/ansible/roles/jupyter/files/notebook/utils/main_config_ui.ipynb +++ b/exasol/ds/sandbox/runtime/ansible/roles/jupyter/files/notebook/utils/main_config_ui.ipynb @@ -24,7 +24,8 @@ "\n", "%run {upward_file_search('utils/ui_styles.ipynb')}\n", "%run {upward_file_search('utils/generic_config_ui.ipynb')}\n", - "%run {upward_file_search('utils/popup_message_ui.ipynb')}" + "%run {upward_file_search('utils/popup_message_ui.ipynb')}\n", + "%run {upward_file_search('utils/useful_urls.ipynb')}" ] }, { @@ -35,6 +36,7 @@ "outputs": [], "source": [ "from typing import List\n", + "import os\n", "from exasol.nb_connector.secret_store import Secrets\n", "from exasol.nb_connector.ai_lab_config import AILabConfig as CKey\n", "import ipywidgets as widgets\n", @@ -50,6 +52,7 @@ " running = 'Exasol Docker-DB is RUNNING'\n", " stopped = 'Exasol Docker-DB is STOPPED'\n", " missing = 'Exasol Docker-DB is NOT CREATED'\n", + " inaccessible = 'Exasol Docker-DB is INACCESSIBLE'\n", "\n", "\n", "def get_db_selection_ui(conf: Secrets) -> widgets.Widget:\n", @@ -208,6 +211,11 @@ " return [btn_start]\n", "\n", "\n", + "def _create_warning(warning_text: str) -> widgets.Widget:\n", + " return widgets.HTML(value='' \\\n", + " '
' + warning_text + '
')\n", + "\n", + "\n", "def get_start_docker_db_ui(conf: Secrets) -> widgets.Widget:\n", " \"\"\"\n", " A UI for starting or restarting the Exasol Docker-DB.\n", @@ -220,8 +228,14 @@ "\n", " ui_look = get_config_styles()\n", "\n", + " # Check if the docker-socket has been mounted\n", + " socket_mounted = os.path.exists('/var/run/docker.sock')\n", + "\n", " # Get the current status of the Exasol Docker-DB.\n", - " itde_exists, itde_running = is_itde_running(conf)\n", + " if socket_mounted:\n", + " itde_exists, itde_running = is_itde_running(conf)\n", + " else:\n", + " itde_exists, itde_running = False, False\n", "\n", " # Display the status.\n", " header_lbl = widgets.Label(style=ui_look.header_style, layout=ui_look.header_layout)\n", @@ -229,24 +243,33 @@ " header_lbl.value = ITDEStatus.running.value\n", " elif itde_exists:\n", " header_lbl.value = ITDEStatus.stopped.value\n", + " elif not socket_mounted:\n", + " header_lbl.value = ITDEStatus.inaccessible.value\n", " else:\n", " header_lbl.value = ITDEStatus.missing.value\n", " group_items = [header_lbl]\n", - " \n", - " # Add a warning message about recreating an existing Exasol Docker-DB.\n", - " if itde_exists:\n", - " warning_text = 'Please note that recreating the Exasol Docker-DB will result in the loss of all data stored in the ' \\\n", - " f'{\"running\" if itde_running else \"existing\"} instance of the database!'\n", - " warning_html = widgets.HTML(value= '' \\\n", - " '' + warning_text + '
')\n", + " \n", + " if socket_mounted:\n", + " # Add a warning message about recreating an existing Exasol Docker-DB.\n", + " if itde_exists:\n", + " warning_text = 'Please note that recreating the Exasol Docker-DB will result in the loss of all data stored in the ' \\\n", + " f'{\"running\" if itde_running else \"existing\"} instance of the database!'\n", + " warning_html = _create_warning(warning_text)\n", + " group_items.append(widgets.Box([warning_html], layout=ui_look.row_layout))\n", + " \n", + " # Create action buttons.\n", + " action_buttons = _get_docker_db_action_buttons(conf, itde_exists, itde_running, header_lbl)\n", + " for btn in action_buttons:\n", + " btn.style = ui_look.button_style\n", + " btn.layout = ui_look.button_layout\n", + " else:\n", + " warning_text = f'The docker socket is not mounted. Please consult the ' \\\n", + " f'documentation ' \\\n", + " 'on how to start the AI-Lab that will use the Integrated Exasol Docker-DB.'\n", + " warning_html = _create_warning(warning_text)\n", " group_items.append(widgets.Box([warning_html], layout=ui_look.row_layout))\n", - "\n", - " # Create action buttons.\n", - " action_buttons = _get_docker_db_action_buttons(conf, itde_exists, itde_running, header_lbl)\n", - " for btn in action_buttons:\n", - " btn.style = ui_look.button_style\n", - " btn.layout = ui_look.button_layout\n", - "\n", + " action_buttons = []\n", + " \n", " # Put all UI elements together.\n", " items = [widgets.Box(group_items, layout=ui_look.group_layout),\n", " widgets.Box(action_buttons, layout=ui_look.row_layout)]\n", diff --git a/exasol/ds/sandbox/runtime/ansible/roles/jupyter/files/notebook/utils/useful_urls.ipynb b/exasol/ds/sandbox/runtime/ansible/roles/jupyter/files/notebook/utils/useful_urls.ipynb new file mode 100644 index 00000000..2341880b --- /dev/null +++ b/exasol/ds/sandbox/runtime/ansible/roles/jupyter/files/notebook/utils/useful_urls.ipynb @@ -0,0 +1,48 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "51056cb1-6ee5-413e-a3b6-6ab2890ab887", + "metadata": {}, + "source": [ + "# List of URLs used in the code\n", + "\n", + "This notebook is not supposed to be used on its own." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d8fffc12-50f6-4f54-8911-75a387cc5245", + "metadata": {}, + "outputs": [], + "source": [ + "from enum import Enum\n", + "\n", + "class UsefulURLs(Enum):\n", + " user_manual_docker_db = 'https://github.com/exasol/ai-lab/blob/main/doc/user_guide/docker/docker-usage.md#ai-lab-with-integrated-exasol-docker-db'" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.10" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/test/notebooks/nbtest_useful_urls.py b/test/notebooks/nbtest_useful_urls.py new file mode 100644 index 00000000..5bdac41e --- /dev/null +++ b/test/notebooks/nbtest_useful_urls.py @@ -0,0 +1,29 @@ +import nbformat +from nbclient import NotebookClient + + +def test_urls() -> None: + + nb = nbformat.read('utils/useful_urls.ipynb', as_version=4) + + # Add the following code at the end of the notebook + test_code = ''' + def verify_all_urls(): + import requests + bad_urls = [] + for url in UsefulURLs: + try: + response = requests.head(url.value, allow_redirects=True) + if response.status_code >= 400: + bad_urls.append(url.value) + except requests.RequestException: + bad_urls.append(url.value) + if bad_urls: + raise RuntimeError(f"The following URL(s) are inaccessible {bad_urls}") + verify_all_urls() + ''' + nb.cells.append(nbformat.v4.new_code_cell(test_code)) + + # Execute the notebook object, expecting to get no exceptions. + nb_client = NotebookClient(nb, kernel_name='python3') + nb_client.execute()