This is an automated email from the ASF dual-hosted git repository. lahirujayathilake pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/airavata.git
commit 95b508db6dc53b56adc139aa058cd9866170da36 Author: Lahiru Jayathilake <[email protected]> AuthorDate: Tue Feb 25 15:34:42 2025 -0500 CyberFaCES docker file * initial docker config files for cyberfaces * docker dependencies --- .../deployments/cyberfaces/agent/Dockerfile | 25 ++ .../jupyter/deployments/cyberfaces/agent/README.md | 14 + .../cyberfaces/agent/build-container.sh | 6 + .../deployments/cyberfaces/agent/docker-agent.sh | 4 + .../jupyter/deployments/cyberfaces/agent/kernel.py | 145 ++++++++ .../deployments/cyberfaces/jupyterlab/Dockerfile | 14 + .../cyberfaces/jupyterlab/build-jupyter-image.sh | 1 + .../cyberfaces/jupyterlab/labconfig/__init__.py | 0 .../jupyterlab/labconfig/airavata_magics.py | 404 +++++++++++++++++++++ .../cyberfaces/jupyterlab/labconfig/bootstrap.sh | 2 + .../cyberfaces/jupyterlab/labconfig/device_auth.py | 58 +++ .../jupyterlab/labconfig/jupyter_lab_config.py | 25 ++ .../jupyterlab/run-jupyter-lab-container.sh | 1 + 13 files changed, 699 insertions(+) diff --git a/modules/agent-framework/airavata-agent/jupyter/deployments/cyberfaces/agent/Dockerfile b/modules/agent-framework/airavata-agent/jupyter/deployments/cyberfaces/agent/Dockerfile new file mode 100644 index 0000000000..3521c00a86 --- /dev/null +++ b/modules/agent-framework/airavata-agent/jupyter/deployments/cyberfaces/agent/Dockerfile @@ -0,0 +1,25 @@ +FROM python:3.8.13-slim + +USER root + +RUN pip install pandas +RUN pip install geopandas +RUN pip install pygeos +RUN pip install matplotlib +RUN pip install "numpy<2" +RUN apt update +RUN apt install -y gdal-bin +RUN pip install -U libpysal +RUN pip install -U esda +RUN pip3 install contextily + +RUN pip install flask jupyter jupyter-client wget jupyter_contrib_nbextensions \ + utm matplotlib_scalebar earthpy patool cdsapi gdown geojson pyarrow pooch zarr cython dask fsspec gcsfs \ + intake intake-esm cmaps cartopy regionmask cdo-api-py progressbar googledrivedownloader cartopy s3fs pywbt cfgrib \ + tensorflow seaborn earthengine-api folium scikit-learn netCDF4 xarray statsmodels pmdarima \ + pygridmet hydrofunctions pynhd missingno geemap numba==0.56.3 scipy \ + rasterio ipyleaflet bsddb3 scikit-learn +RUN mkdir -p /opt/jupyter +RUN python -m venv /opt/jupyter/venv +ADD airavata-agent-linux /opt/airavata-agent +ADD kernel.py /opt/jupyter/kernel.py \ No newline at end of file diff --git a/modules/agent-framework/airavata-agent/jupyter/deployments/cyberfaces/agent/README.md b/modules/agent-framework/airavata-agent/jupyter/deployments/cyberfaces/agent/README.md new file mode 100644 index 0000000000..bf95186cc5 --- /dev/null +++ b/modules/agent-framework/airavata-agent/jupyter/deployments/cyberfaces/agent/README.md @@ -0,0 +1,14 @@ +## Setting up Dev Environment + +### Agent +Build the Agent +```shell +./build-container.sh +``` + +Execute the following command to run an agent locally. +```shell +docker run --rm -v $(pwd):/workspace -w /workspace cybershuttle/remote-agent-cyberfaces bash -c "./docker-agent.sh" +``` + + diff --git a/modules/agent-framework/airavata-agent/jupyter/deployments/cyberfaces/agent/build-container.sh b/modules/agent-framework/airavata-agent/jupyter/deployments/cyberfaces/agent/build-container.sh new file mode 100755 index 0000000000..d821caca3a --- /dev/null +++ b/modules/agent-framework/airavata-agent/jupyter/deployments/cyberfaces/agent/build-container.sh @@ -0,0 +1,6 @@ +cd ../../../../ +env GOOS=linux GOARCH=amd64 go build +cp airavata-agent jupyter/deployments/cyberfaces/agent/airavata-agent-linux +cd jupyter/deployments/cyberfaces/agent +docker build --platform linux/x86_64 -t cybershuttle/remote-agent-cyberfaces . +docker push cybershuttle/remote-agent-cyberfaces \ No newline at end of file diff --git a/modules/agent-framework/airavata-agent/jupyter/deployments/cyberfaces/agent/docker-agent.sh b/modules/agent-framework/airavata-agent/jupyter/deployments/cyberfaces/agent/docker-agent.sh new file mode 100755 index 0000000000..9978af18b6 --- /dev/null +++ b/modules/agent-framework/airavata-agent/jupyter/deployments/cyberfaces/agent/docker-agent.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +/opt/airavata-agent api.gateway.cybershuttle.org:19900 agent2 + diff --git a/modules/agent-framework/airavata-agent/jupyter/deployments/cyberfaces/agent/kernel.py b/modules/agent-framework/airavata-agent/jupyter/deployments/cyberfaces/agent/kernel.py new file mode 100644 index 0000000000..c9bd281479 --- /dev/null +++ b/modules/agent-framework/airavata-agent/jupyter/deployments/cyberfaces/agent/kernel.py @@ -0,0 +1,145 @@ +import time +from jupyter_client import KernelManager +from flask import Flask, request, jsonify +import os +import json +import re + + +app = Flask(__name__) + +km = None +kc = None + +kernel_running = False + +ansi_escape = re.compile(r'\x1B\[[0-?]*[ -/]*[@-~]') + [email protected]('/start', methods=['GET']) +def start_kernel(): + + global km + global kc + global kernel_running + + if kernel_running: + return "Kernel already running" + # Create a new kernel manager + km = KernelManager(kernel_name='python3') + km.start_kernel() + + # Create a client to interact with the kernel + kc = km.client() + kc.start_channels() + + # Ensure the client is connected before executing code + kc.wait_for_ready() + kernel_running = True + return "Kernel started" + +def strip_ansi_codes(text): + return ansi_escape.sub('', text) + [email protected]('/execute', methods=['POST']) +def execute(): + + global km + global kc + + code = request.json.get('code', '') + if not code: + return jsonify({'error': 'No code provided'}), 400 + + kc.execute(code) + + outputs = [] + execution_noticed = False + + while True: + try: + msg = kc.get_iopub_msg(timeout=5) + + content = msg.get("content", {}) + msg_type = msg.get("msg_type", "") + + # When a message with the text stream comes and it's the result of our execution + if msg_type == "execute_input": + execution_noticed = True + + # Handle stdout streams + if msg_type == "stream" and content.get("name") == "stdout": + outputs.append({ + "output_type": "stream", + "name": "stdout", + "text": content.get("text", "") + }) + + # Handle stderr streams + if msg_type == "stream" and content.get("name") == "stderr": + outputs.append({ + "output_type": "stream", + "name": "stderr", + "text": content.get("text", "") + }) + + # Handle display data (e.g. plots) + if msg_type == "display_data": + outputs.append({ + "output_type": "display_data", + "data": content.get("data", {}), + "metadata": content.get("metadata", {}) + }) + + # Handle execution results (e.g. return values) + if msg_type == "execute_result": + outputs.append({ + "output_type": "execute_result", + "data": content.get("data", {}), + "metadata": content.get("metadata", {}), + "execution_count": content.get("execution_count", None) + }) + + # Handle errors + if msg_type == "error": + # Strip ANSI codes from traceback + clean_traceback = [strip_ansi_codes(line) for line in content.get("traceback", [])] + outputs.append({ + "output_type": "error", + "ename": content.get("ename", ""), + "evalue": content.get("evalue", ""), + "traceback": clean_traceback + }) + + # Check for end of execution + if msg_type == "status" and content.get("execution_state") == "idle" and execution_noticed: + break + + except KeyboardInterrupt: + return jsonify({'error': "Execution interrupted by user"}), 500 + except Exception as e: + print(f"Error while getting Jupyter message: {str(e)}") + + response = { + "outputs": outputs + } + + return jsonify(response), 200 + [email protected]('/stop', methods=['GET']) +def stop(): + + global km + global kc + global kernel_running + + if not kernel_running: + return "Kernel is not running to shut down" + + kc.stop_channels() + km.shutdown_kernel() + kernel_running = False + return 'Kernel shutting down...' + + +if __name__ == '__main__': + app.run(port=15000) diff --git a/modules/agent-framework/airavata-agent/jupyter/deployments/cyberfaces/jupyterlab/Dockerfile b/modules/agent-framework/airavata-agent/jupyter/deployments/cyberfaces/jupyterlab/Dockerfile new file mode 100644 index 0000000000..9dc84c72c7 --- /dev/null +++ b/modules/agent-framework/airavata-agent/jupyter/deployments/cyberfaces/jupyterlab/Dockerfile @@ -0,0 +1,14 @@ +FROM cybershuttle/base-cyberfaces + +USER root + +COPY labconfig/jupyter_lab_config.py /jupyter_lab_config.py +COPY labconfig/airavata_magics.py /airavata_magics.py +COPY labconfig/__init__.py /__init__.py +COPY labconfig/device_auth.py /device_auth.py +COPY labconfig/bootstrap.sh /bootstrap.sh +RUN chmod +x /bootstrap.sh + +USER ${NB_UID} + +CMD ["start-notebook.sh","--NotebookApp.iopub_data_rate_limit=1e10"] diff --git a/modules/agent-framework/airavata-agent/jupyter/deployments/cyberfaces/jupyterlab/build-jupyter-image.sh b/modules/agent-framework/airavata-agent/jupyter/deployments/cyberfaces/jupyterlab/build-jupyter-image.sh new file mode 100755 index 0000000000..234c95876a --- /dev/null +++ b/modules/agent-framework/airavata-agent/jupyter/deployments/cyberfaces/jupyterlab/build-jupyter-image.sh @@ -0,0 +1 @@ +docker build --platform linux/x86_64 -t cybershuttle/cyberfaces-jupyter-lab . \ No newline at end of file diff --git a/modules/agent-framework/airavata-agent/jupyter/deployments/cyberfaces/jupyterlab/labconfig/__init__.py b/modules/agent-framework/airavata-agent/jupyter/deployments/cyberfaces/jupyterlab/labconfig/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/modules/agent-framework/airavata-agent/jupyter/deployments/cyberfaces/jupyterlab/labconfig/airavata_magics.py b/modules/agent-framework/airavata-agent/jupyter/deployments/cyberfaces/jupyterlab/labconfig/airavata_magics.py new file mode 100644 index 0000000000..b6fd96db2a --- /dev/null +++ b/modules/agent-framework/airavata-agent/jupyter/deployments/cyberfaces/jupyterlab/labconfig/airavata_magics.py @@ -0,0 +1,404 @@ +import base64 +import binascii +import json +import time +from pathlib import Path +from typing import NamedTuple +import jwt +import os +import requests +from IPython.core.magic import register_cell_magic, register_line_magic +from IPython.display import HTML, Image, display +from device_auth import DeviceFlowAuthenticator + + +AgentInfo = NamedTuple('AgentInfo', [ + ('agentId', str), + ('experimentId', str), + ('processId', str), + ('cluster', str), + ('queue', str), + ('cpus', int), + ('memory', int), + ('walltime', int), + ('gateway_id', str), + ('group', str), +]) +api_base_url = "https://api.gateway.cybershuttle.org" +file_server_url = "http://3.142.234.94:8050" +current_agent : AgentInfo | None = None +MSG_NOT_INITIALIZED = r"Remote agent not initialized. Please run %init_remote cluster=<cluster> cpu=<cpu> memory=<memory mb> queue=<queue> walltime=<walltime minutes> group=<group>" + + +def get_access_token() -> str | None: + token_from_env = os.getenv('CS_ACCESS_TOKEN') + if token_from_env: + return token_from_env + EXPLICIT_TOKEN_FILE = Path("~").expanduser() / "csagent" / "token" / "keys.json" + if EXPLICIT_TOKEN_FILE.exists(): + with open(EXPLICIT_TOKEN_FILE, "r") as f: + return json.load(f).get("access_token") + + +def get_agent_status() -> dict | None: + if not current_agent: + return print(MSG_NOT_INITIALIZED) + url = f"{api_base_url}/api/v1/agent/{current_agent.agentId}" + response = requests.get(url) + if response.status_code == 202: + return response.json() + return print(f"Got [{response.status_code}] Response: {response.text}") + + +def get_process_id(experiment_id: str, headers) -> str: + """ + Get process id by experiment id + + """ + url = f"{api_base_url}/api/v1/exp/{experiment_id}/process" + process_id = "" + while not process_id: + response = requests.get(url, headers=headers) + if response.status_code == 200: + process_id = response.json().get("processId") + else: + time.sleep(5) + return process_id + + +def submit_agent_job(experiment_name, cluster, queue, cpus, memory, walltime, access_token, group, gateway_id='default'): + global current_agent + + # URL to which the POST request will be sent + url = api_base_url + '/api/v1/exp/launch' + + # Data to be sent in the POST request + data = { + 'experimentName': experiment_name, + 'remoteCluster': cluster, + 'cpuCount': cpus, + 'nodeCount': 1, + 'memory': memory, + 'wallTime': walltime, + 'queue': queue, + 'group': group, + } + + # Convert the data to JSON format + json_data = json.dumps(data) + + decode = jwt.decode(access_token, options={"verify_signature": False}) + user_id = decode['preferred_username'] + claimsMap = { + "userName": user_id, + "gatewayID": gateway_id + } + + # Headers + headers = { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer ' + access_token, + 'X-Claims': json.dumps(claimsMap) + } + + # Send the POST request + response = requests.post(url, headers=headers, data=json_data) + + # Check if the request was successful + if response.status_code == 200: + # Parse the JSON response + obj = response.json() + current_agent = AgentInfo( + agentId=obj['agentId'], + experimentId=obj['experimentId'], + processId=get_process_id(obj['experimentId'], headers=headers), + cluster=cluster, + queue=queue, + cpus=cpus, + memory=memory, + walltime=walltime, + gateway_id=gateway_id, + group=group, + ) + print('Agent Initialized:', current_agent) + else: + print('Failed to send POST request. Status code:', response.status_code) + print('Response:', response.text) + + +def terminate_agent(access_token, gateway_id='default'): + global current_agent + if not current_agent: + return print(MSG_NOT_INITIALIZED) + + expId = current_agent.experimentId + url = api_base_url + '/api/v1/exp/terminate/' + expId + + decode = jwt.decode(access_token, options={"verify_signature": False}) + user_id = decode['preferred_username'] + claimsMap = { + "userName": user_id, + "gatewayID": gateway_id + } + + # Headers + headers = { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer ' + access_token, + 'X-Claims': json.dumps(claimsMap) + } + + # Send the POST request + response = requests.get(url, headers=headers) + + if response.status_code == 200: + # Parse the JSON response + response_data = response.json() + print('Agent terminated:', response_data) + current_agent = None + else: + print('Failed to send termination request. Status code:', response.status_code) + print('Response:', response.text) + + +@register_cell_magic +def run_remote(line, cell): + global current_agent + if not current_agent: + return print(MSG_NOT_INITIALIZED) + + url = api_base_url + '/api/v1/agent/executejupyterrequest' + + data = { + "sessionId": "session1", + "keepAlive": True, + "code": cell, + "agentId": current_agent.agentId + } + + json_data = json.dumps(data) + response = requests.post(url, headers={'Content-Type': 'application/json'}, data=json_data) + execution_resp = response.json() + execution_id = execution_resp.get("executionId") + error = execution_resp.get("error") + if error: + print("Cell execution failed. Error: " + error) + if execution_id: + while True: + url = api_base_url + "/api/v1/agent/executejupyterresponse/" + execution_id + response = requests.get(url, headers={'Accept': 'application/json'}) + json_response = response.json() + if json_response.get('available'): + result_str = json_response.get('responseString') + try: + result = json.loads(result_str) + except json.JSONDecodeError as e: + print(f"Failed to decode JSON response: {e}") + break + + if 'outputs' in result: + for output in result['outputs']: + output_type = output.get('output_type') + if output_type == 'display_data': + data_obj = output.get('data', {}) + if 'image/png' in data_obj: + image_data = data_obj['image/png'] + try: + image_bytes = base64.b64decode(image_data) + display(Image(data=image_bytes, format='png')) + except binascii.Error as e: + print(f"Failed to decode image data: {e}") + # Ignoring any texts in the display data + # if 'text/plain' in data_obj: + # print(data_obj['text/plain']) + + elif output_type == 'stream': + stream_name = output.get('name', 'stdout') + stream_text = output.get('text', '') + if stream_name == 'stderr': + error_html = f""" + <div style=" + color: #a71d5d; + background-color: #fdd; + border: 1px solid #a71d5d; + padding: 5px; + border-radius: 5px; + font-family: Consolas, 'Courier New', monospace; + white-space: pre-wrap; + "> + {stream_text} + </div> + """ + display(HTML(error_html)) + else: + print(stream_text) + + elif output_type == 'error': + ename = output.get('ename', 'Error') + evalue = output.get('evalue', '') + traceback = output.get('traceback', []) + + error_html = f""" + <div style=" + color: #a71d5d; + background-color: #fdd; + border: 1px solid #a71d5d; + padding: 5px; + border-radius: 5px; + font-family: Consolas, 'Courier New', monospace; + "> + <pre><strong>{ename}: {evalue}</strong> + """ + for line in traceback: + error_html += f"{line}\n" + error_html += "</pre></div>" + display(HTML(error_html)) + + elif output_type == 'execute_result': + data_obj = output.get('data', {}) + if 'text/plain' in data_obj: + print(data_obj['text/plain']) + else: + if 'result' in result: + print(result['result']) + elif 'error' in result: + print(result['error']['ename']) + print(result['error']['evalue']) + print(result['error']['traceback']) + elif 'display' in result: + data_obj = result['display'].get('data', {}) + if 'image/png' in data_obj: + image_data = data_obj['image/png'] + try: + image_bytes = base64.b64decode(image_data) + display(Image(data=image_bytes, format='png')) + except binascii.Error as e: + print(f"Failed to decode image data: {e}") + break + time.sleep(1) + + +@register_line_magic +def cs_login(line): + try: + authenticator = DeviceFlowAuthenticator() + authenticator.login() + except ValueError as e: + print(f"Configuration error: {e}") + + +@register_line_magic +def init_remote(line): + if current_agent: + status = get_agent_status() + if status: + if status['agentUp']: + print("An agent is already running. Please terminate it first by running %terminate_remote") + return + else: + print("An agent was scheduled. Please terminate it first by running %terminate_remote") + return + + access_token = get_access_token() + pairs = line.split() + + # Initialize variable to store the cluster value + cluster_value = None + memory_value = None + cpu_value = None + queue_value = None + walltime_value = None + group_value = "" + + # Iterate through the pairs to find the cluster value + for pair in pairs: + if pair.startswith("cluster="): + cluster_value = pair.split("=")[1] + if pair.startswith("cpu="): + cpu_value = pair.split("=")[1] + if pair.startswith("memory="): + memory_value = pair.split("=")[1] + if pair.startswith("queue="): + queue_value = pair.split("=")[1] + if pair.startswith("walltime="): + walltime_value = pair.split("=")[1] + if pair.startswith("group="): + group_value = pair.split("=")[1] + + submit_agent_job('CS_Agent', cluster_value, queue_value, cpu_value, memory_value, walltime_value, access_token, group_value) + + +@register_line_magic +def status_remote(line): + status = get_agent_status() + if status: + if status['agentUp']: + print("Agent", status['agentId'], 'is running') + else: + print("Agent", status['agentId'], 'is still preparing. Please wait') + + +@register_line_magic +def terminate_remote(line): + global current_agent + access_token = get_access_token() + if current_agent: + terminate_agent(access_token) + + +@register_line_magic +def push_remote(line): + if not current_agent: + return print(MSG_NOT_INITIALIZED) + pairs = line.split() + remot_path = None + local_path = None + for pair in pairs: + if pair.startswith("source="): + local_path = pair.split("=")[1] + if pair.startswith("target="): + remot_path = pair.split("=")[1] + # validate paths + if not remot_path or not local_path: + return print("Please provide paths for both source and target") + # upload file + print(f"Pushing local:{local_path} to remote:{remot_path}") + url = f"{file_server_url}/upload/live/{current_agent.processId}/{remot_path}" + with open(local_path, "rb") as file: + files = {"file": file} + response = requests.post(url, files=files) + print(f"[{response.status_code}] Uploaded local:{local_path} to remote:{remot_path}") + + +@register_line_magic +def pull_remote(line): + if not current_agent: + return print(MSG_NOT_INITIALIZED) + pairs = line.split() + remot_path = None + local_path = None + for pair in pairs: + if pair.startswith("source="): + remot_path = pair.split("=")[1] + if pair.startswith("target="): + local_path = pair.split("=")[1] + # validate paths + if not remot_path or not local_path: + return print("Please provide paths for both source and target") + # download file + print(f"Pulling remote:{remot_path} to local:{local_path}") + url = f"{file_server_url}/download/live/{current_agent.processId}/{remot_path}" + response = requests.get(url) + with open(local_path, "wb") as file: + file.write(response.content) + print(f"[{response.status_code}] Downloaded remote:{remot_path} to local:{local_path}") + + +def load_ipython_extension(ipython): + ipython.register_magic_function(cs_login) + ipython.register_magic_function(init_remote) + ipython.register_magic_function(status_remote) + ipython.register_magic_function(terminate_remote) + ipython.register_magic_function(run_remote) + ipython.register_magic_function(push_remote) + ipython.register_magic_function(pull_remote) diff --git a/modules/agent-framework/airavata-agent/jupyter/deployments/cyberfaces/jupyterlab/labconfig/bootstrap.sh b/modules/agent-framework/airavata-agent/jupyter/deployments/cyberfaces/jupyterlab/labconfig/bootstrap.sh new file mode 100644 index 0000000000..754a6e8f52 --- /dev/null +++ b/modules/agent-framework/airavata-agent/jupyter/deployments/cyberfaces/jupyterlab/labconfig/bootstrap.sh @@ -0,0 +1,2 @@ +cd /home/jupyter-notebook-examples && git pull && cd - +jupyter lab --config=/jupyter_lab_config.py --ip=0.0.0.0 --port=8888 --no-browser --allow-root --NotebookApp.token='' \ No newline at end of file diff --git a/modules/agent-framework/airavata-agent/jupyter/deployments/cyberfaces/jupyterlab/labconfig/device_auth.py b/modules/agent-framework/airavata-agent/jupyter/deployments/cyberfaces/jupyterlab/labconfig/device_auth.py new file mode 100644 index 0000000000..269085ca69 --- /dev/null +++ b/modules/agent-framework/airavata-agent/jupyter/deployments/cyberfaces/jupyterlab/labconfig/device_auth.py @@ -0,0 +1,58 @@ +import requests +import time +import os +# Load environment variables from .env file + +class DeviceFlowAuthenticator: + def __init__(self): + self.client_id = "cybershuttle-agent" + self.realm = "default" + self.auth_server_url = "https://auth.cybershuttle.org" + + if not self.client_id or not self.realm or not self.auth_server_url: + raise ValueError("Missing required environment variables for client ID, realm, or auth server URL") + + self.device_code = None + self.interval = None + + def login(self): + # Step 1: Request device and user code + auth_device_url = f"{self.auth_server_url}/realms/{self.realm}/protocol/openid-connect/auth/device" + response = requests.post(auth_device_url, data={"client_id": self.client_id, "scope": "openid"}) + + if response.status_code != 200: + print(f"Error in device authorization request: {response.status_code} - {response.text}") + return + + data = response.json() + self.device_code = data.get("device_code") + self.interval = data.get("interval", 5) + + print(f"User code: {data.get('user_code')}") + print(f"Please authenticate by visiting: {data.get('verification_uri_complete')}") + + # Step 2: Poll for the token + self.poll_for_token() + + def poll_for_token(self): + token_url = f"{self.auth_server_url}/realms/{self.realm}/protocol/openid-connect/token" + while True: + response = requests.post(token_url, data={ + "client_id": self.client_id, + "grant_type": "urn:ietf:params:oauth:grant-type:device_code", + "device_code": self.device_code + }) + + if response.status_code == 200: + data = response.json() + access_token = data.get("access_token") + print(f"Received access token") + os.environ['CS_ACCESS_TOKEN'] = access_token + break + elif response.status_code == 400 and response.json().get("error") == "authorization_pending": + print("Authorization pending, retrying...") + else: + print(f"Error in token request: {response.status_code} - {response.text}") + break + + time.sleep(self.interval) diff --git a/modules/agent-framework/airavata-agent/jupyter/deployments/cyberfaces/jupyterlab/labconfig/jupyter_lab_config.py b/modules/agent-framework/airavata-agent/jupyter/deployments/cyberfaces/jupyterlab/labconfig/jupyter_lab_config.py new file mode 100644 index 0000000000..a160cd77cb --- /dev/null +++ b/modules/agent-framework/airavata-agent/jupyter/deployments/cyberfaces/jupyterlab/labconfig/jupyter_lab_config.py @@ -0,0 +1,25 @@ +import sys +sys.path.append('/') + +c = get_config() + +c.InteractiveShellApp.exec_lines = [ + "import sys" + "sys.path.append('/')" + "import airavata_magics", + "airavata_magics.load_ipython_extension(get_ipython())" +] + +# Set the IP address Jupyter Lab will listen on +c.ServerApp.ip = '0.0.0.0' + +# Set the port Jupyter Lab will listen on +c.ServerApp.port = 8888 + +# Don't open the browser by default +c.ServerApp.open_browser = False + +c.FileContentsManager.use_atomic_writing = False + +# Allow root access +c.ServerApp.allow_root = True \ No newline at end of file diff --git a/modules/agent-framework/airavata-agent/jupyter/deployments/cyberfaces/jupyterlab/run-jupyter-lab-container.sh b/modules/agent-framework/airavata-agent/jupyter/deployments/cyberfaces/jupyterlab/run-jupyter-lab-container.sh new file mode 100755 index 0000000000..81c92419c2 --- /dev/null +++ b/modules/agent-framework/airavata-agent/jupyter/deployments/cyberfaces/jupyterlab/run-jupyter-lab-container.sh @@ -0,0 +1 @@ +docker run -p 18888:8888 -it cybershuttle/cyberfaces-jupyter-lab \ No newline at end of file
