From c888d97434c4105f770a90519e0f65d2231b6c20 Mon Sep 17 00:00:00 2001 From: Bhavana Rajan Date: Tue, 6 Oct 2026 16:31:59 -0700 Subject: [PATCH] Sync unified skills to 4.6 template --- template/v4/v4.6/Dockerfile | 282 ++++++++++ .../code_editor_machine_settings.json | 4 + .../code_editor_user_settings.json | 3 + .../code-editor/extensions-sagemaker-ui.txt | 4 + .../v4.6/dirs/etc/code-editor/extensions.txt | 4 + template/v4/v4.6/dirs/etc/conda/.condarc | 6 + .../dirs/etc/jupyter/jupyter_server_config.py | 31 ++ .../v4/v4.6/dirs/etc/patches/apply_patches.sh | 114 ++++ .../smus-code-editor/0001-sparkmagic.patch | 11 + .../0002-sparkmagic-override-info-table.patch | 17 + .../0003-fix-ipython-display.patch | 7 + .../0004-fix-boto3-endpoints.patch | 12 + .../smus-script/replace-job-with-schedule.sh | 43 ++ .../etc/patches/smus/0001-sparkmagic.patch | 10 + .../0002-sparkmagic-override-info-table.patch | 17 + .../etc/patches/smus/0005-fix-logger.patch | 68 +++ .../sagemaker-inference-server/__init__.py | 3 + .../dirs/etc/sagemaker-inference-server/serve | 2 + .../etc/sagemaker-inference-server/serve.py | 25 + .../tornado_server/__init__.py | 12 + .../tornado_server/async_handler.py | 76 +++ .../tornado_server/server.py | 127 +++++ .../tornado_server/stream_handler.py | 59 ++ .../tornado_server/sync_handler.py | 77 +++ .../utils/__init__.py | 1 + .../utils/environment.py | 59 ++ .../utils/exception.py | 21 + .../utils/logger.py | 43 ++ .../etc/sagemaker-ui/fetch_feature_flags.py | 100 ++++ .../v4.6/dirs/etc/sagemaker-ui/git_clone.sh | 62 +++ .../v4.6/dirs/etc/sagemaker-ui/git_config.sh | 9 + .../jupyter/lab/settings/overrides.json | 5 + .../jupyter/lab/settings/page_config.json | 15 + .../zzz_sagemaker_ui_overrides.json | 8 + .../jupyter/server/jupyter_server_config.py | 43 ++ .../python3_kernel_launcher.sh | 51 ++ .../sagemaker-ui/kernels/python3/kernel.json | 14 + .../etc/sagemaker-ui/libmgmt/install-lib.sh | 18 + .../etc/sagemaker-ui/network_validation.sh | 220 ++++++++ .../sagemaker-ui/project-storage/README.md | 24 + .../project-storage/create-storage-readme.sh | 10 + .../sagemaker-ui/sagemaker-mcp/default.json | 41 ++ .../etc/sagemaker-ui/sagemaker-mcp/mcp.json | 29 + .../sagemaker-ui/sagemaker-mcp/smus-mcp.py | 180 +++++++ .../sagemaker-ui/sagemaker_ui_post_startup.sh | 509 ++++++++++++++++++ .../etc/sagemaker-ui/set_code_editor_theme.sh | 23 + .../etc/sagemaker-ui/steering/smus-rules.md | 169 ++++++ .../workflows/create-workflows-resources.sh | 95 ++++ ...akerWorkflowsOperator-1.0-py3-none-any.whl | Bin 0 -> 23090 bytes ...n_sagemaker_studio-1.0.27-py3-none-any.whl | Bin 0 -> 308037 bytes .../workflows/requirements/requirements.txt | 5 + .../etc/sagemaker-ui/workflows/sample_dag.py | 18 + .../workflows/sm-spark-cli-install.sh | 18 + .../sagemaker-ui/workflows/sm_init_script.sh | 24 + .../sagemaker-ui/workflows/startup/startup.sh | 1 + .../sagemaker-ui/workflows/workflow_client.py | 77 +++ .../jupyter/lab/settings/overrides.json | 14 + .../zzz_disable_rtc.json | 7 + .../private/labconfig/page_config.json | 6 + .../zzz_sagemaker_overrides.json | 10 + .../zzz_disable_jai.json | 16 + .../jupyter/shared/labconfig/page_config.json | 14 + .../sagemaker/sagemaker-default-agent.json | 23 + .../dirs/etc/sagemaker/skills/clone_skills.sh | 18 + .../etc/sagemaker/skills/skills-manifest.json | 6 + .../dirs/etc/sagemaker/skills/sync_skills.sh | 174 ++++++ .../etc/sagemaker/sm_pysdk_default_config.py | 113 ++++ .../v4/v4.6/dirs/etc/sagemaker/sync_agent.sh | 23 + .../conf.d/supervisord-code-editor.conf | 12 + .../supervisor/conf.d/supervisord-common.conf | 18 + .../conf.d/supervisord-jupyter-lab.conf | 11 + .../supervisord-sagemaker-ui-code-editor.conf | 28 + .../supervisord-sagemaker-ui-default.conf | 27 + .../conf.d/supervisord-sagemaker-ui.conf | 27 + .../etc/supervisor/conf.d/supervisord.conf | 27 + .../dirs/usr/local/bin/entrypoint-code-editor | 16 + .../usr/local/bin/entrypoint-jupyter-server | 25 + .../bin/entrypoint-sagemaker-ui-code-editor | 19 + .../entrypoint-sagemaker-ui-jupyter-server | 26 + .../dirs/usr/local/bin/merge-settings-util.py | 22 + .../dirs/usr/local/bin/restart-jupyter-server | 6 + .../bin/restart-sagemaker-ui-jupyter-server | 6 + .../v4.6/dirs/usr/local/bin/start-code-editor | 109 ++++ .../dirs/usr/local/bin/start-jupyter-server | 87 +++ .../local/bin/start-sagemaker-ui-code-editor | 110 ++++ .../bin/start-sagemaker-ui-jupyter-server | 90 ++++ 86 files changed, 3996 insertions(+) create mode 100644 template/v4/v4.6/Dockerfile create mode 100644 template/v4/v4.6/dirs/etc/code-editor/code_editor_machine_settings.json create mode 100644 template/v4/v4.6/dirs/etc/code-editor/code_editor_user_settings.json create mode 100644 template/v4/v4.6/dirs/etc/code-editor/extensions-sagemaker-ui.txt create mode 100644 template/v4/v4.6/dirs/etc/code-editor/extensions.txt create mode 100644 template/v4/v4.6/dirs/etc/conda/.condarc create mode 100644 template/v4/v4.6/dirs/etc/jupyter/jupyter_server_config.py create mode 100755 template/v4/v4.6/dirs/etc/patches/apply_patches.sh create mode 100644 template/v4/v4.6/dirs/etc/patches/smus-code-editor/0001-sparkmagic.patch create mode 100644 template/v4/v4.6/dirs/etc/patches/smus-code-editor/0002-sparkmagic-override-info-table.patch create mode 100644 template/v4/v4.6/dirs/etc/patches/smus-code-editor/0003-fix-ipython-display.patch create mode 100644 template/v4/v4.6/dirs/etc/patches/smus-code-editor/0004-fix-boto3-endpoints.patch create mode 100755 template/v4/v4.6/dirs/etc/patches/smus-script/replace-job-with-schedule.sh create mode 100644 template/v4/v4.6/dirs/etc/patches/smus/0001-sparkmagic.patch create mode 100644 template/v4/v4.6/dirs/etc/patches/smus/0002-sparkmagic-override-info-table.patch create mode 100644 template/v4/v4.6/dirs/etc/patches/smus/0005-fix-logger.patch create mode 100644 template/v4/v4.6/dirs/etc/sagemaker-inference-server/__init__.py create mode 100755 template/v4/v4.6/dirs/etc/sagemaker-inference-server/serve create mode 100644 template/v4/v4.6/dirs/etc/sagemaker-inference-server/serve.py create mode 100644 template/v4/v4.6/dirs/etc/sagemaker-inference-server/tornado_server/__init__.py create mode 100644 template/v4/v4.6/dirs/etc/sagemaker-inference-server/tornado_server/async_handler.py create mode 100644 template/v4/v4.6/dirs/etc/sagemaker-inference-server/tornado_server/server.py create mode 100644 template/v4/v4.6/dirs/etc/sagemaker-inference-server/tornado_server/stream_handler.py create mode 100644 template/v4/v4.6/dirs/etc/sagemaker-inference-server/tornado_server/sync_handler.py create mode 100644 template/v4/v4.6/dirs/etc/sagemaker-inference-server/utils/__init__.py create mode 100644 template/v4/v4.6/dirs/etc/sagemaker-inference-server/utils/environment.py create mode 100644 template/v4/v4.6/dirs/etc/sagemaker-inference-server/utils/exception.py create mode 100644 template/v4/v4.6/dirs/etc/sagemaker-inference-server/utils/logger.py create mode 100644 template/v4/v4.6/dirs/etc/sagemaker-ui/fetch_feature_flags.py create mode 100755 template/v4/v4.6/dirs/etc/sagemaker-ui/git_clone.sh create mode 100644 template/v4/v4.6/dirs/etc/sagemaker-ui/git_config.sh create mode 100644 template/v4/v4.6/dirs/etc/sagemaker-ui/jupyter/lab/settings/overrides.json create mode 100644 template/v4/v4.6/dirs/etc/sagemaker-ui/jupyter/lab/settings/page_config.json create mode 100644 template/v4/v4.6/dirs/etc/sagemaker-ui/jupyter/server/jupyter_server_config.d/zzz_sagemaker_ui_overrides.json create mode 100644 template/v4/v4.6/dirs/etc/sagemaker-ui/jupyter/server/jupyter_server_config.py create mode 100755 template/v4/v4.6/dirs/etc/sagemaker-ui/kernels/kernel_launchers/python3_kernel_launcher.sh create mode 100644 template/v4/v4.6/dirs/etc/sagemaker-ui/kernels/python3/kernel.json create mode 100755 template/v4/v4.6/dirs/etc/sagemaker-ui/libmgmt/install-lib.sh create mode 100644 template/v4/v4.6/dirs/etc/sagemaker-ui/network_validation.sh create mode 100644 template/v4/v4.6/dirs/etc/sagemaker-ui/project-storage/README.md create mode 100644 template/v4/v4.6/dirs/etc/sagemaker-ui/project-storage/create-storage-readme.sh create mode 100644 template/v4/v4.6/dirs/etc/sagemaker-ui/sagemaker-mcp/default.json create mode 100644 template/v4/v4.6/dirs/etc/sagemaker-ui/sagemaker-mcp/mcp.json create mode 100644 template/v4/v4.6/dirs/etc/sagemaker-ui/sagemaker-mcp/smus-mcp.py create mode 100755 template/v4/v4.6/dirs/etc/sagemaker-ui/sagemaker_ui_post_startup.sh create mode 100755 template/v4/v4.6/dirs/etc/sagemaker-ui/set_code_editor_theme.sh create mode 100644 template/v4/v4.6/dirs/etc/sagemaker-ui/steering/smus-rules.md create mode 100644 template/v4/v4.6/dirs/etc/sagemaker-ui/workflows/create-workflows-resources.sh create mode 100644 template/v4/v4.6/dirs/etc/sagemaker-ui/workflows/plugins/amzn_SagemakerWorkflowsOperator-1.0-py3-none-any.whl create mode 100644 template/v4/v4.6/dirs/etc/sagemaker-ui/workflows/plugins/amzn_sagemaker_studio-1.0.27-py3-none-any.whl create mode 100644 template/v4/v4.6/dirs/etc/sagemaker-ui/workflows/requirements/requirements.txt create mode 100644 template/v4/v4.6/dirs/etc/sagemaker-ui/workflows/sample_dag.py create mode 100755 template/v4/v4.6/dirs/etc/sagemaker-ui/workflows/sm-spark-cli-install.sh create mode 100755 template/v4/v4.6/dirs/etc/sagemaker-ui/workflows/sm_init_script.sh create mode 100755 template/v4/v4.6/dirs/etc/sagemaker-ui/workflows/startup/startup.sh create mode 100644 template/v4/v4.6/dirs/etc/sagemaker-ui/workflows/workflow_client.py create mode 100644 template/v4/v4.6/dirs/etc/sagemaker/jupyter/lab/settings/overrides.json create mode 100644 template/v4/v4.6/dirs/etc/sagemaker/jupyter/private/jupyter_server_config.d/zzz_disable_rtc.json create mode 100644 template/v4/v4.6/dirs/etc/sagemaker/jupyter/private/labconfig/page_config.json create mode 100644 template/v4/v4.6/dirs/etc/sagemaker/jupyter/server/jupyter_server_config.d/zzz_sagemaker_overrides.json create mode 100644 template/v4/v4.6/dirs/etc/sagemaker/jupyter/shared/jupyter_server_config.d/zzz_disable_jai.json create mode 100644 template/v4/v4.6/dirs/etc/sagemaker/jupyter/shared/labconfig/page_config.json create mode 100644 template/v4/v4.6/dirs/etc/sagemaker/sagemaker-default-agent.json create mode 100755 template/v4/v4.6/dirs/etc/sagemaker/skills/clone_skills.sh create mode 100644 template/v4/v4.6/dirs/etc/sagemaker/skills/skills-manifest.json create mode 100755 template/v4/v4.6/dirs/etc/sagemaker/skills/sync_skills.sh create mode 100644 template/v4/v4.6/dirs/etc/sagemaker/sm_pysdk_default_config.py create mode 100755 template/v4/v4.6/dirs/etc/sagemaker/sync_agent.sh create mode 100644 template/v4/v4.6/dirs/etc/supervisor/conf.d/supervisord-code-editor.conf create mode 100644 template/v4/v4.6/dirs/etc/supervisor/conf.d/supervisord-common.conf create mode 100644 template/v4/v4.6/dirs/etc/supervisor/conf.d/supervisord-jupyter-lab.conf create mode 100644 template/v4/v4.6/dirs/etc/supervisor/conf.d/supervisord-sagemaker-ui-code-editor.conf create mode 100644 template/v4/v4.6/dirs/etc/supervisor/conf.d/supervisord-sagemaker-ui-default.conf create mode 100644 template/v4/v4.6/dirs/etc/supervisor/conf.d/supervisord-sagemaker-ui.conf create mode 100644 template/v4/v4.6/dirs/etc/supervisor/conf.d/supervisord.conf create mode 100755 template/v4/v4.6/dirs/usr/local/bin/entrypoint-code-editor create mode 100755 template/v4/v4.6/dirs/usr/local/bin/entrypoint-jupyter-server create mode 100755 template/v4/v4.6/dirs/usr/local/bin/entrypoint-sagemaker-ui-code-editor create mode 100755 template/v4/v4.6/dirs/usr/local/bin/entrypoint-sagemaker-ui-jupyter-server create mode 100644 template/v4/v4.6/dirs/usr/local/bin/merge-settings-util.py create mode 100755 template/v4/v4.6/dirs/usr/local/bin/restart-jupyter-server create mode 100755 template/v4/v4.6/dirs/usr/local/bin/restart-sagemaker-ui-jupyter-server create mode 100755 template/v4/v4.6/dirs/usr/local/bin/start-code-editor create mode 100755 template/v4/v4.6/dirs/usr/local/bin/start-jupyter-server create mode 100755 template/v4/v4.6/dirs/usr/local/bin/start-sagemaker-ui-code-editor create mode 100755 template/v4/v4.6/dirs/usr/local/bin/start-sagemaker-ui-jupyter-server diff --git a/template/v4/v4.6/Dockerfile b/template/v4/v4.6/Dockerfile new file mode 100644 index 000000000..eb005fa3e --- /dev/null +++ b/template/v4/v4.6/Dockerfile @@ -0,0 +1,282 @@ +ARG TAG_FOR_BASE_MICROMAMBA_IMAGE +FROM mambaorg/micromamba:$TAG_FOR_BASE_MICROMAMBA_IMAGE + +ARG CUDA_MAJOR_MINOR_VERSION='' +ARG ENV_IN_FILENAME +ARG PINNED_ENV_IN_FILENAME +ARG ARG_BASED_ENV_IN_FILENAME +ARG IMAGE_VERSION +ARG EXTERNAL_LIB_CACHE_S3_BUCKET='' + +# Amazon Q Agentic Chat version - update this default value when needed +ARG FLARE_SERVER_VERSION_JL=1.67.0 +# IDE type for Amazon Q integration +ARG AMAZON_Q_IDE_TYPE=jupyterlab + +LABEL "org.amazon.sagemaker-distribution.image.version"=$IMAGE_VERSION + +ARG AMZN_BASE="/opt/amazon/sagemaker" +ARG DB_ROOT_DIR="/opt/db" +ARG DIRECTORY_TREE_STAGE_DIR="${AMZN_BASE}/dir-staging" + +ARG NB_USER="sagemaker-user" +ARG NB_UID=1000 +ARG NB_GID=100 + +# https://www.openssl.org/source/ +ARG FIPS_VALIDATED_SSL=3.0.8 +ARG MIN_REQUIRED_MICROMAMBA_VERSION=1.5.11 + +ENV SAGEMAKER_LOGGING_DIR="/var/log/sagemaker/" +ENV STUDIO_LOGGING_DIR="/var/log/studio/" +ENV EDITOR="nano" +ENV IMAGE_VERSION=$IMAGE_VERSION +ENV PINNED_MICROMAMBA_MINOR_VERSION="1.5.*" +ENV SAGEMAKER_RECOVERY_MODE_HOME=/tmp/sagemaker-recovery-mode-home + +USER root +# Upgrade micromamba to the latest patch version in the pinned minor version range, if applicable +RUN CURRENT_MICROMAMBA_VERSION=$(micromamba --version) && \ + echo "Current micromamba version: $CURRENT_MICROMAMBA_VERSION" && \ + if [[ "$CURRENT_MICROMAMBA_VERSION" == $PINNED_MICROMAMBA_MINOR_VERSION ]]; then \ + echo "Upgrading micromamba to the latest $PINNED_MICROMAMBA_MINOR_VERSION version..." && \ + micromamba self-update -c conda-forge --version "$MIN_REQUIRED_MICROMAMBA_VERSION" && \ + micromamba clean --all --yes --force-pkgs-dirs; \ + else \ + echo "Micromamba is already at version $CURRENT_MICROMAMBA_VERSION (outside $PINNED_MICROMAMBA_MINOR_VERSION). No upgrade performed."; \ + fi + +RUN EXISTING_USER=$(getent passwd 1000 | cut -d: -f1) && \ + userdel -r "$EXISTING_USER" && \ + usermod "--login=${NB_USER}" "--home=/home/${NB_USER}" --move-home "-u ${NB_UID}" "${MAMBA_USER}" && \ + groupmod "--new-name=${NB_USER}" --non-unique "-g ${NB_GID}" "${MAMBA_USER}" && \ + # Update the expected value of MAMBA_USER for the + # _entrypoint.sh consistency check. + echo "${NB_USER}" > "/etc/arg_mamba_user" && \ + : +ENV MAMBA_USER=$NB_USER +ENV USER=$NB_USER + +COPY aws-cli-public-key.asc /tmp/ +COPY extract_amazon_q_agentic_chat_urls.py /tmp/ +COPY download_amazon_q_agentic_chat_artifacts.sh /tmp/ + +RUN apt-get update && apt-get upgrade -y && \ + apt-get install -y --no-install-recommends sudo gettext-base wget curl unzip git rsync build-essential openssh-client nano cron less mandoc jq ca-certificates gnupg && \ + # We just install tzdata below but leave default time zone as UTC. This helps packages like Pandas to function correctly. + DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends tzdata krb5-user libkrb5-dev libsasl2-dev libsasl2-modules && \ + chmod g+w /etc/passwd && \ + echo "ALL ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers && \ + touch /etc/krb5.conf.lock && chown ${NB_USER}:${MAMBA_USER} /etc/krb5.conf* && \ + # Note that we do NOT run `rm -rf /var/lib/apt/lists/*` here. If we did, anyone building on top of our images will + # not be able to run any `apt-get install` commands and that would hamper customizability of the images. + curl -O "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" && \ + curl -O "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip.sig" && \ + gpg --import /tmp/aws-cli-public-key.asc && \ + gpg --trust-model always --verify awscli-exe-linux-x86_64.zip.sig awscli-exe-linux-x86_64.zip || \ + (echo "GPG verification failed" && exit 1) && \ + unzip awscli-exe-linux-x86_64.zip && \ + sudo ./aws/install && \ + rm -rf aws awscli-exe-linux-x86_64.zip awscli-exe-linux-x86_64.zip.sig aws-cli-public-key.asc && \ + : && \ + # Install Q CLI + curl --proto '=https' --tlsv1.2 -sSf "https://desktop-release.q.us-east-1.amazonaws.com/latest/q-x86_64-linux.zip" -o "q.zip" && \ + unzip q.zip && \ + Q_INSTALL_GLOBAL=true ./q/install.sh --no-confirm && \ + rm -rf q q.zip && \ + echo "source /usr/local/bin/_activate_current_env.sh" | tee --append /etc/profile && \ + : && \ + # Install Kiro CLI + curl -o /tmp/kirocli.zip 'https://desktop-release.q.us-east-1.amazonaws.com/latest/kirocli-x86_64-linux.zip' && \ + unzip /tmp/kirocli.zip -d /tmp && \ + Q_INSTALL_GLOBAL=1 KIRO_CLI_SKIP_SETUP=1 /tmp/kirocli/install.sh && \ + rm -rf /tmp/kirocli.zip /tmp/kirocli && \ +# CodeEditor - create server, user data dirs + mkdir -p /opt/amazon/sagemaker/sagemaker-code-editor-server-data /opt/amazon/sagemaker/sagemaker-ui-code-editor-server-data /opt/amazon/sagemaker/sagemaker-code-editor-user-data \ + && chown $MAMBA_USER:$MAMBA_USER /opt/amazon/sagemaker/sagemaker-code-editor-server-data /opt/amazon/sagemaker/sagemaker-ui-code-editor-server-data /opt/amazon/sagemaker/sagemaker-code-editor-user-data && \ +# create dir to store user data files + mkdir -p /opt/amazon/sagemaker/user-data \ + && chown $MAMBA_USER:$MAMBA_USER /opt/amazon/sagemaker/user-data && \ +# Merge in OS directory tree contents. + mkdir -p ${DIRECTORY_TREE_STAGE_DIR} +COPY dirs/ ${DIRECTORY_TREE_STAGE_DIR}/ +RUN rsync -a ${DIRECTORY_TREE_STAGE_DIR}/ / && \ + rm -rf ${DIRECTORY_TREE_STAGE_DIR} && \ + # Clone skills from manifest config (must run after COPY dirs/ + rsync which provides skills-manifest.json) + bash /etc/sagemaker/skills/clone_skills.sh && \ + # Clone SMUS-specific skills (data analytics) + mkdir -p /etc/sagemaker-ui/skills && \ + git clone --depth 1 https://github.com/awslabs/agent-plugins.git /tmp/smus-skill-repo-1 && \ + cp -r /tmp/smus-skill-repo-1/plugins/sagemaker-ai/skills/* /etc/sagemaker-ui/skills/ && \ + rm -rf /tmp/smus-skill-repo-1 && \ + git clone --depth 1 https://github.com/aws/agent-toolkit-for-aws.git /tmp/smus-skill-repo-2 && \ + cp -r /tmp/smus-skill-repo-2/plugins/aws-data-analytics/skills/* /etc/sagemaker-ui/skills/ && \ + rm -rf /tmp/smus-skill-repo-2 && \ +# CodeEditor - download the extensions + mkdir -p /etc/code-editor/extensions /etc/code-editor/extensions-sagemaker-ui && \ + while IFS= read -r url || [ -n "$url" ]; do \ + echo "Downloading extension from ${url}..." && \ + wget --no-check-certificate -P /etc/code-editor/extensions "${url}"; \ + done < /etc/code-editor/extensions.txt && \ + while IFS= read -r url || [ -n "$url" ]; do \ + echo "Downloading sagemaker-ui extension from ${url}..." && \ + wget --no-check-certificate -P /etc/code-editor/extensions-sagemaker-ui "${url}"; \ + done < /etc/code-editor/extensions-sagemaker-ui.txt + +USER $MAMBA_USER +COPY --chown=$MAMBA_USER:$MAMBA_USER $ENV_IN_FILENAME *.in /tmp/ +COPY --chown=$MAMBA_USER:$MAMBA_USER $PINNED_ENV_IN_FILENAME *.in /tmp/ + +ARG MAMBA_DOCKERFILE_ACTIVATE=1 +ARG CONDA_OVERRIDE_CUDA=$CUDA_MAJOR_MINOR_VERSION + +# Make sure that $ENV_IN_FILENAME and $PINNED_ENV_IN_FILENAME has a newline at the end before the `tee` command runs. +# Otherwise, nasty things will happen. +RUN if [[ -z $ARG_BASED_ENV_IN_FILENAME ]] ; \ + then echo 'No ARG_BASED_ENV_IN_FILENAME passed' ; \ + else envsubst < /tmp/$ARG_BASED_ENV_IN_FILENAME | tee --append /tmp/$ENV_IN_FILENAME ; \ + fi && \ + # Enforce dependencies are all installed from conda-forge + micromamba install -y --name base --file /tmp/$ENV_IN_FILENAME --file /tmp/$PINNED_ENV_IN_FILENAME && \ + mkdir -p $SAGEMAKER_RECOVERY_MODE_HOME && \ + chown $MAMBA_USER:$MAMBA_USER $SAGEMAKER_RECOVERY_MODE_HOME && \ + SUPERVISOR_VERSION=$(grep "^conda-forge::supervisor\[" /tmp/$ENV_IN_FILENAME) && \ + JUPYTERLAB_VERSION=$(grep "^conda-forge::jupyterlab\[" /tmp/$ENV_IN_FILENAME) && \ + SAGEMAKER_JUPYTERLAB_VERSION=$(grep "^conda-forge::sagemaker-jupyterlab-extension" /tmp/$ENV_IN_FILENAME) && \ + PYTHON_VERSION=$(grep "^conda-forge::python\[" /tmp/$ENV_IN_FILENAME) && \ + echo "Installing in sagemaker-recovery-mode micromamba environment: $PYTHON_VERSION $JUPYTERLAB_VERSION $SAGEMAKER_JUPYTERLAB_VERSION" && \ + micromamba create --prefix /opt/conda/envs/sagemaker-recovery-mode && \ + micromamba install --prefix /opt/conda/envs/sagemaker-recovery-mode -y $PYTHON_VERSION $JUPYTERLAB_VERSION $SAGEMAKER_JUPYTERLAB_VERSION $SUPERVISOR_VERSION && \ + micromamba clean --all --yes --force-pkgs-dirs && \ + sudo ln -s $(which python3) /usr/bin/python && \ + # Download shared web client libraries + sudo mkdir -p /etc/web-client/libs && \ + (sudo curl -L --retry 3 --retry-delay 5 --fail "https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.min.js" -o "/etc/web-client/libs/jszip.min.js" || \ + sudo aws s3 cp $EXTERNAL_LIB_CACHE_S3_BUCKET/libs/jszip.min.js /etc/web-client/libs/jszip.min.js || \ + (echo "Failed to download JSZip library from both CDN and S3" && exit 1)) && \ + # Download Amazon Q artifacts for JupyterLab extension + bash /tmp/download_amazon_q_agentic_chat_artifacts.sh $FLARE_SERVER_VERSION_JL /etc/amazon-q-agentic-chat/artifacts/$AMAZON_Q_IDE_TYPE $AMAZON_Q_IDE_TYPE && \ + # Fix ownership for JupyterLab access + sudo chown -R $MAMBA_USER:$MAMBA_USER /etc/amazon-q-agentic-chat/ /etc/web-client/ && \ + # Update npm version + npm i -g npm && \ + # Enforce to use `conda-forge` as only channel, by removing `defaults` + conda config --remove channels defaults && \ + micromamba config append channels conda-forge --env && \ + # Configure CodeEditor - Install extensions and set preferences + extensionloc=/opt/amazon/sagemaker/sagemaker-code-editor-server-data/extensions && mkdir -p "${extensionloc}" \ + # Loop through all vsix files in /etc/code-editor/extensions and install them + && for ext in /etc/code-editor/extensions/*.vsix; do \ + echo "Installing extension ${ext}..."; \ + sagemaker-code-editor --install-extension "${ext}" --extensions-dir "${extensionloc}" --server-data-dir /opt/amazon/sagemaker/sagemaker-code-editor-server-data --user-data-dir /opt/amazon/sagemaker/sagemaker-code-editor-user-data; \ + done \ + # Install sagemaker-ui extensions + && extensionloc_ui=/opt/amazon/sagemaker/sagemaker-ui-code-editor-server-data/extensions && mkdir -p "${extensionloc_ui}" \ + && for ext in /etc/code-editor/extensions-sagemaker-ui/*.vsix; do \ + echo "Installing sagemaker-ui extension ${ext}..."; \ + sagemaker-code-editor --install-extension "${ext}" --extensions-dir "${extensionloc_ui}" --server-data-dir /opt/amazon/sagemaker/sagemaker-ui-code-editor-server-data --user-data-dir /opt/amazon/sagemaker/sagemaker-code-editor-user-data; \ + done \ + # Copy the settings + && cp /etc/code-editor/code_editor_machine_settings.json /opt/amazon/sagemaker/sagemaker-code-editor-server-data/data/Machine/settings.json && \ + cp /etc/code-editor/code_editor_user_settings.json /opt/amazon/sagemaker/sagemaker-code-editor-server-data/data/User/settings.json && \ + cp /etc/code-editor/code_editor_machine_settings.json /opt/amazon/sagemaker/sagemaker-ui-code-editor-server-data/data/Machine/settings.json && \ + cp /etc/code-editor/code_editor_user_settings.json /opt/amazon/sagemaker/sagemaker-ui-code-editor-server-data/data/User/settings.json && \ + # Install glue kernels, and move to shared directory + # Also patching base kernel so Studio background code doesn't start session silently + install-glue-kernels && \ + SITE_PACKAGES=$(pip show aws-glue-sessions | grep Location | awk '{print $2}') && \ + jupyter-kernelspec install $SITE_PACKAGES/aws_glue_interactive_sessions_kernel/glue_pyspark --user && \ + jupyter-kernelspec install $SITE_PACKAGES/aws_glue_interactive_sessions_kernel/glue_spark --user && \ + mv /home/sagemaker-user/.local/share/jupyter/kernels/glue_pyspark /opt/conda/share/jupyter/kernels && \ + mv /home/sagemaker-user/.local/share/jupyter/kernels/glue_spark /opt/conda/share/jupyter/kernels && \ + sed -i '/if not store_history and (/i\ if "sm_analytics_runtime_check" in code:\n return await self._complete_cell()\n' \ + "$SITE_PACKAGES/aws_glue_interactive_sessions_kernel/glue_kernel_base/BaseKernel.py" && \ + # Install FIPS Provider for OpenSSL, on top of existing OpenSSL installation + # v3.0.8 is latest FIPS validated provider, so this is the one we install + # But we need to run tests against the installed version. + # see https://github.com/openssl/openssl/blob/master/README-FIPS.md https://www.openssl.org/source/ + INSTALLED_SSL=$(micromamba list | grep openssl | tr -s ' ' | cut -d ' ' -f 3 | head -n 1) && \ + # download source code for installed, and FIPS validated openssl versions + curl -L https://github.com/openssl/openssl/releases/download/openssl-$FIPS_VALIDATED_SSL/openssl-$FIPS_VALIDATED_SSL.tar.gz > openssl-$FIPS_VALIDATED_SSL.tar.gz && \ + curl -L https://github.com/openssl/openssl/releases/download/openssl-$INSTALLED_SSL/openssl-$INSTALLED_SSL.tar.gz > openssl-$INSTALLED_SSL.tar.gz && \ + tar -xf openssl-$FIPS_VALIDATED_SSL.tar.gz && tar -xf openssl-$INSTALLED_SSL.tar.gz && cd openssl-$FIPS_VALIDATED_SSL && \ + # Configure both versions to enable FIPS and build + ./Configure enable-fips --prefix=/opt/conda --openssldir=/opt/conda/ssl && make && \ + cd ../openssl-$INSTALLED_SSL && \ + ./Configure enable-fips --prefix=/opt/conda --openssldir=/opt/conda/ssl && make && \ + # Copy validated provider to installed version for testing + cp ../openssl-$FIPS_VALIDATED_SSL/providers/fips.so providers/. && \ + cp ../openssl-$FIPS_VALIDATED_SSL/providers/fipsmodule.cnf providers/. && \ + make tests && cd ../openssl-$FIPS_VALIDATED_SSL && \ + # After tests pass, install FIPS provider and remove source code + make install_fips && cd .. && rm -rf ./openssl-* && \ +# Create new config file with fips-enabled. Then user can override OPENSSL_CONF to enable FIPS +# e.g. export OPENSSL_CONF=/opt/conda/ssl/openssl-fips.cnf + cp /opt/conda/ssl/openssl.cnf /opt/conda/ssl/openssl-fips.cnf && \ + sed -i "s:# .include fipsmodule.cnf:.include /opt/conda/ssl/fipsmodule.cnf:" /opt/conda/ssl/openssl-fips.cnf && \ + sed -i 's:# fips = fips_sect:fips = fips_sect:' /opt/conda/ssl/openssl-fips.cnf && \ +# Install Kerberos. +# Make sure no dependency is added/updated + pip install "krb5>=0.5.1,<0.6" && \ + pip show krb5 | grep Require | xargs -i sh -c '[ $(echo {} | cut -d: -f2 | wc -w) -eq 0 ] ' && \ +# https://stackoverflow.com/questions/122327 + SYSTEM_PYTHON_PATH=$(python3 -c "from __future__ import print_function;import sysconfig; print(sysconfig.get_paths().get('purelib'))") && \ + # Remove SparkRKernel as it's not supported \ + jupyter-kernelspec remove -f -y sparkrkernel && \ + # Patch Sparkmagic lib to support Custom Certificates \ + # https://github.com/jupyter-incubator/sparkmagic/pull/435/files \ + cp -a ${SYSTEM_PYTHON_PATH}/sagemaker_studio_analytics_extension/patches/configuration.py ${SYSTEM_PYTHON_PATH}/sparkmagic/utils/ && \ + cp -a ${SYSTEM_PYTHON_PATH}/sagemaker_studio_analytics_extension/patches/reliablehttpclient.py ${SYSTEM_PYTHON_PATH}/sparkmagic/livyclientlib/reliablehttpclient.py && \ + sed -i 's= "python"= "/opt/conda/bin/python"=g' /opt/conda/share/jupyter/kernels/pysparkkernel/kernel.json /opt/conda/share/jupyter/kernels/sparkkernel/kernel.json && \ + sed -i 's="Spark"="SparkMagic Spark"=g' /opt/conda/share/jupyter/kernels/sparkkernel/kernel.json && \ + sed -i 's="PySpark"="SparkMagic PySpark"=g' /opt/conda/share/jupyter/kernels/pysparkkernel/kernel.json + + +# Patch glue kernels to use kernel wrapper +COPY patch_glue_pyspark.json /opt/conda/share/jupyter/kernels/glue_pyspark/kernel.json +COPY patch_glue_spark.json /opt/conda/share/jupyter/kernels/glue_spark/kernel.json + +USER root + +# Create logging directories for supervisor +RUN mkdir -p $SAGEMAKER_LOGGING_DIR && \ + chmod a+rw $SAGEMAKER_LOGGING_DIR && \ + mkdir -p ${STUDIO_LOGGING_DIR} && \ + chown ${NB_USER}:${MAMBA_USER} ${STUDIO_LOGGING_DIR} && \ + # Create sagemaker pysdk admin default config directory + mkdir -p /etc/xdg/sagemaker && \ + chmod a+rw /etc/xdg/sagemaker && \ + # Clean up CodeEditor artifacts + rm -rf /etc/code-editor && \ + # Create supervisord runtime directory + mkdir -p /var/run/supervisord && \ + chmod a+rw /var/run/supervisord && \ + # Create root directory for DB + # Create logging directories for supervisor + mkdir -p $DB_ROOT_DIR && \ + chmod a+rw $DB_ROOT_DIR && \ + HOME_DIR="/home/${NB_USER}/licenses" \ + && mkdir -p ${HOME_DIR} \ + && curl -o ${HOME_DIR}/oss_compliance.zip https://aws-dlinfra-utilities.s3.amazonaws.com/oss_compliance.zip \ + && unzip ${HOME_DIR}/oss_compliance.zip -d ${HOME_DIR}/ \ + && cp ${HOME_DIR}/oss_compliance/test/testOSSCompliance /usr/local/bin/testOSSCompliance \ + && chmod +x /usr/local/bin/testOSSCompliance \ + && chmod +x ${HOME_DIR}/oss_compliance/generate_oss_compliance.sh \ + && ${HOME_DIR}/oss_compliance/generate_oss_compliance.sh ${HOME_DIR} python \ + && rm -rf ${HOME_DIR}/oss_compliance* \ + # Remove all temp data generated during image build process + # This process must be done at the end of image build + && rm -rf /opt/conda/etc/conda/test-files/ \ + && find /opt/conda -name "yarn.lock" -type f -delete \ + && find /opt/conda/include/ -name "requirements.txt" -delete \ + && rm -rf /tmp/*.in \ + # Restore /home to world-writable (systemd's tmpfiles.d on Ubuntu 24.04 sets it to 755) + && chmod 777 /home + +# Explicitly disable BuildKit for SM Studio Docker functionality +ENV DOCKER_BUILDKIT=0 +ENV PATH="/etc/sagemaker-inference-server:/opt/conda/bin:/opt/conda/condabin:$PATH:/home/${NB_USER}/.local/bin" +WORKDIR "/home/${NB_USER}" +ENV SHELL=/bin/bash +ENV OPENSSL_MODULES=/opt/conda/lib64/ossl-modules/ +USER $MAMBA_USER diff --git a/template/v4/v4.6/dirs/etc/code-editor/code_editor_machine_settings.json b/template/v4/v4.6/dirs/etc/code-editor/code_editor_machine_settings.json new file mode 100644 index 000000000..44fb8ef7f --- /dev/null +++ b/template/v4/v4.6/dirs/etc/code-editor/code_editor_machine_settings.json @@ -0,0 +1,4 @@ +{ + "python.terminal.activateEnvironment": false, + "python.defaultInterpreterPath": "/opt/conda/bin/python" +} diff --git a/template/v4/v4.6/dirs/etc/code-editor/code_editor_user_settings.json b/template/v4/v4.6/dirs/etc/code-editor/code_editor_user_settings.json new file mode 100644 index 000000000..ed3ef56a4 --- /dev/null +++ b/template/v4/v4.6/dirs/etc/code-editor/code_editor_user_settings.json @@ -0,0 +1,3 @@ +{ + "extensions.autoUpdate": false +} diff --git a/template/v4/v4.6/dirs/etc/code-editor/extensions-sagemaker-ui.txt b/template/v4/v4.6/dirs/etc/code-editor/extensions-sagemaker-ui.txt new file mode 100644 index 000000000..4ca196fbe --- /dev/null +++ b/template/v4/v4.6/dirs/etc/code-editor/extensions-sagemaker-ui.txt @@ -0,0 +1,4 @@ +https://open-vsx.org/api/ms-toolsai/jupyter/2024.5.0/file/ms-toolsai.jupyter-2024.5.0.vsix +https://open-vsx.org/api/ms-python/python/2026.2.0/file/ms-python.python-2026.2.0.vsix +https://open-vsx.org/api/amazonwebservices/aws-toolkit-vscode/3.101.0/file/amazonwebservices.aws-toolkit-vscode-3.101.0.vsix +https://open-vsx.org/api/amazonwebservices/amazon-q-vscode/2.0.0/file/amazonwebservices.amazon-q-vscode-2.0.0.vsix diff --git a/template/v4/v4.6/dirs/etc/code-editor/extensions.txt b/template/v4/v4.6/dirs/etc/code-editor/extensions.txt new file mode 100644 index 000000000..cf3424ac6 --- /dev/null +++ b/template/v4/v4.6/dirs/etc/code-editor/extensions.txt @@ -0,0 +1,4 @@ +https://open-vsx.org/api/ms-toolsai/jupyter/2024.5.0/file/ms-toolsai.jupyter-2024.5.0.vsix +https://open-vsx.org/api/ms-python/python/2023.20.0/file/ms-python.python-2023.20.0.vsix +https://open-vsx.org/api/amazonwebservices/aws-toolkit-vscode/3.101.0/file/amazonwebservices.aws-toolkit-vscode-3.101.0.vsix +https://open-vsx.org/api/amazonwebservices/amazon-q-vscode/2.0.0/file/amazonwebservices.amazon-q-vscode-2.0.0.vsix diff --git a/template/v4/v4.6/dirs/etc/conda/.condarc b/template/v4/v4.6/dirs/etc/conda/.condarc new file mode 100644 index 000000000..c3616df50 --- /dev/null +++ b/template/v4/v4.6/dirs/etc/conda/.condarc @@ -0,0 +1,6 @@ +envs_dirs: + - ~/.conda/envs + - /opt/conda/envs +pkgs_dirs: + - ~/.conda/pkgs + - /opt/conda/pkgs diff --git a/template/v4/v4.6/dirs/etc/jupyter/jupyter_server_config.py b/template/v4/v4.6/dirs/etc/jupyter/jupyter_server_config.py new file mode 100644 index 000000000..012152e6f --- /dev/null +++ b/template/v4/v4.6/dirs/etc/jupyter/jupyter_server_config.py @@ -0,0 +1,31 @@ +# Default Jupyter server config +# Note: those config can be overridden by user-level configs. + +c.ServerApp.terminado_settings = {"shell_command": ["/bin/bash"]} +c.ServerApp.tornado_settings = {"compress_response": True} + +# Do not delete files to trash. Instead, permanently delete files. +c.FileContentsManager.delete_to_trash = False + +# Allow deleting non-empty directory via file browser. Related documentation: +# https://github.com/jupyter-server/jupyter_server/blob/main/jupyter_server/services/contents/filemanager.py#L125-L129 +c.FileContentsManager.always_delete_dir = True + +# Enable `allow_hidden` by default, so hidden files are accessible via Jupyter server +# Related documentation: https://jupyterlab.readthedocs.io/en/stable/user/files.html#displaying-hidden-files +c.ContentsManager.allow_hidden = True + +# This will set the LanguageServerManager.extra_node_roots setting if amazon_sagemaker_sql_editor exists in the +# environment. Ignore otherwise, don't fail the JL server start +# Related documentation: https://jupyterlab-lsp.readthedocs.io/en/v3.4.0/Configuring.html +try: + import os + + module = __import__("amazon_sagemaker_sql_editor") + module_location = os.path.dirname(module.__file__) + c.LanguageServerManager.extra_node_roots = [f"{module_location}/sql-language-server"] +except: + pass + +# Set Kiro as the default AI persona +c.PersonaManager.default_persona_id = "jupyter-ai-personas::jupyter_ai_acp_client::KiroAcpPersona" diff --git a/template/v4/v4.6/dirs/etc/patches/apply_patches.sh b/template/v4/v4.6/dirs/etc/patches/apply_patches.sh new file mode 100755 index 000000000..4d40e6024 --- /dev/null +++ b/template/v4/v4.6/dirs/etc/patches/apply_patches.sh @@ -0,0 +1,114 @@ +#!/bin/bash + +set -eux + +# Function to compare version numbers +# Returns 0 if version1 >= version2, 1 otherwise +version_gte() { + local version1="$1" + local version2="$2" + + # Handle empty versions + [ -z "$version1" ] && return 1 + [ -z "$version2" ] && return 0 + + # If versions are identical, return true + [ "$version1" = "$version2" ] && return 0 + + # Use sort -V (version sort) to compare versions + # Check if version1 comes after version2 in version sort + local sorted=$(printf '%s\n%s\n' "$version1" "$version2" | sort -V) + local first_line=$(echo "$sorted" | head -n1) + + # If version2 comes first in sort, then version1 >= version2 + [ "$first_line" = "$version2" ] +} + +get_package_version() { + local package_name="$1" + + # Try to get version using pip show + local pkg_version=$(pip show "$package_name" 2>/dev/null | grep "Version:" | cut -d' ' -f2) + + if [ -z "$pkg_version" ]; then + # Try using conda list as fallback + pkg_version=$(conda list "$package_name" 2>/dev/null | grep "^$package_name " | awk '{print $2}' | head -n1) + fi + + echo "$pkg_version" +} + +# NOTE: Consider removing these patches entirely if all non-deprecating SMD versions +# have package versions larger than the specified thresholds, as the patches would +# no longer be needed. +should_skip_patch() { + local patch_file="$1" + local patch_basename=$(basename "$patch_file") + + # Check if patch filename contains "fix-ipython-display" + if [[ "$patch_basename" == *"fix-ipython-display"* ]]; then + # Skip this patch if hdijupyterutils >= 0.23.0 + local hdijupyterutils_version=$(get_package_version "hdijupyterutils") + if [ -n "$hdijupyterutils_version" ]; then + if version_gte "$hdijupyterutils_version" "0.23.0"; then + echo "Skipping $patch_basename: hdijupyterutils version $hdijupyterutils_version >= 0.23" + return 0 + fi + fi + fi + + # Check if patch filename contains "fix-boto3-endpoints" + if [[ "$patch_basename" == *"fix-boto3-endpoints"* ]]; then + # Skip this patch if botocore >= 1.37.17 + local botocore_version=$(get_package_version "botocore") + if [ -n "$botocore_version" ]; then + if version_gte "$botocore_version" "1.37.17"; then + echo "Skipping $patch_basename: botocore version $botocore_version >= 1.37.17" + return 0 + fi + fi + fi + + return 1 +} + +# Check if parameter is provided +if [ $# -ne 1 ]; then + echo "Usage: $0 [smus|smus-code-editor]" + exit 1 +fi + +# Validate parameter +case "$1" in + "smus") + bash "/etc/patches/smus-script/replace-job-with-schedule.sh" + PATCH_DIR="/etc/patches/smus" + ;; + "smus-code-editor") + PATCH_DIR="/etc/patches/smus-code-editor" + ;; + *) + echo "Error: Parameter must be either 'smus' or 'smus-code-editor'" + exit 1 + ;; +esac + +# Check if patch directory exists +if [ ! -d "$PATCH_DIR" ]; then + echo "Error: Patch directory $PATCH_DIR does not exist" + exit 1 +fi + +# Patch files can be generated via "diff -u /path/to/original_file /path/to/new_file > XXX_bad_package.patch" +# See https://www.thegeekstuff.com/2014/12/patch-command-examples/ +for PATCHFILE in "$PATCH_DIR"/*.patch; do + [ -f "$PATCHFILE" ] || continue + + # Check if this patch should be skipped due to version constraints + if should_skip_patch "$PATCHFILE"; then + continue + fi + + echo "Applying $PATCHFILE" + (cd "/opt/conda" && patch --strip=3 < "$PATCHFILE") +done diff --git a/template/v4/v4.6/dirs/etc/patches/smus-code-editor/0001-sparkmagic.patch b/template/v4/v4.6/dirs/etc/patches/smus-code-editor/0001-sparkmagic.patch new file mode 100644 index 000000000..f7edf9f27 --- /dev/null +++ b/template/v4/v4.6/dirs/etc/patches/smus-code-editor/0001-sparkmagic.patch @@ -0,0 +1,11 @@ +--- /opt/conda/lib/python3.12/site-packages/sparkmagic/livyclientlib/command.py ++++ /opt/conda/lib/python3.12/site-packages/sparkmagic/livyclientlib/command.py +@@ -54,6 +54,7 @@ + try: + session.wait_for_idle() + data = {"code": self.code} ++ data["kind"] = session.kind + response = session.http_client.post_statement(session.id, data) + statement_id = response["id"] + output = self._get_statement_output(session, statement_id) + diff --git a/template/v4/v4.6/dirs/etc/patches/smus-code-editor/0002-sparkmagic-override-info-table.patch b/template/v4/v4.6/dirs/etc/patches/smus-code-editor/0002-sparkmagic-override-info-table.patch new file mode 100644 index 000000000..82fd0c94b --- /dev/null +++ b/template/v4/v4.6/dirs/etc/patches/smus-code-editor/0002-sparkmagic-override-info-table.patch @@ -0,0 +1,17 @@ +--- /opt/conda/lib/python3.12/site-packages/sparkmagic/utils/utils.py ++++ /opt/conda/lib/python3.12/site-packages/sparkmagic/utils/utils.py +@@ -94,15 +94,7 @@ + + + def get_sessions_info_html(info_sessions, current_session_id): +- html = ( +- """ +-""" +- + "".join( +- [session.get_row_html(current_session_id) for session in info_sessions] +- ) +- + "
IDYARN Application IDKindStateSpark UIDriver logUserCurrent session?
" +- ) +- ++ html = "" + return html diff --git a/template/v4/v4.6/dirs/etc/patches/smus-code-editor/0003-fix-ipython-display.patch b/template/v4/v4.6/dirs/etc/patches/smus-code-editor/0003-fix-ipython-display.patch new file mode 100644 index 000000000..f4b2389a8 --- /dev/null +++ b/template/v4/v4.6/dirs/etc/patches/smus-code-editor/0003-fix-ipython-display.patch @@ -0,0 +1,7 @@ +--- /opt/conda/lib/python3.12/site-packages/hdijupyterutils/ipythondisplay.py ++++ /opt/conda/lib/python3.12/site-packages/hdijupyterutils/ipythondisplay.py +@@ -1,4 +1,4 @@ +-from IPython.core.display import display, HTML ++from IPython.display import display, HTML + from IPython import get_ipython + import sys diff --git a/template/v4/v4.6/dirs/etc/patches/smus-code-editor/0004-fix-boto3-endpoints.patch b/template/v4/v4.6/dirs/etc/patches/smus-code-editor/0004-fix-boto3-endpoints.patch new file mode 100644 index 000000000..cadcc70b3 --- /dev/null +++ b/template/v4/v4.6/dirs/etc/patches/smus-code-editor/0004-fix-boto3-endpoints.patch @@ -0,0 +1,12 @@ +--- /opt/conda/lib/python3.12/site-packages/botocore/data/endpoints.json ++++ /opt/conda/lib/python3.12/site-packages/botocore/data/endpoints.json +@@ -5404,6 +5404,9 @@ + "ap-northeast-3" : { + "hostname" : "datazone.ap-northeast-3.api.aws" + }, ++ "ap-south-1" : { ++ "hostname" : "datazone.ap-south-1.api.aws" ++ }, + "ap-south-2" : { + "hostname" : "datazone.ap-south-2.api.aws" + }, diff --git a/template/v4/v4.6/dirs/etc/patches/smus-script/replace-job-with-schedule.sh b/template/v4/v4.6/dirs/etc/patches/smus-script/replace-job-with-schedule.sh new file mode 100755 index 000000000..737eaed58 --- /dev/null +++ b/template/v4/v4.6/dirs/etc/patches/smus-script/replace-job-with-schedule.sh @@ -0,0 +1,43 @@ +#!/bin/bash +# this is to replace sagemaker unfied studio jupyter scheduler label from "Job" to "Scheudule" to align with overall experience +set -ex + +BASE_PATH="/opt/conda/share/jupyter/labextensions/@jupyterlab/scheduler/static" + +# Function to perform replacement +replace_string() { + local search="$1" + local replace="$2" + echo "Replacing '$search' with '$replace'..." + grep -l -i -r "$search" "$BASE_PATH" | xargs sed -i "s/$search/$replace/g" +} + +# List of replacements +replace_string "\"Schedule\"" "\" \"" +replace_string "Create Job\"" "Create Schedule\"" +replace_string "Job name\"" "Schedule name\"" +replace_string "Run job with input folder\"" "Run schedule with input folder\"" +replace_string "\"The scheduled job will have access to all files under" "\"The schedule will have access to all files under" +replace_string "Jobs\"" "Schedules\"" +replace_string "Job Definitions\"" "Schedule Definitions\"" +replace_string "Job definitions" "Schedule definitions" +replace_string "Job definition" "Schedule definition" +replace_string "job definitions" "schedule definitions" +replace_string "Create Job" "Create Schedule" +replace_string "Job Detail\"" "Schedule Detail\"" +replace_string "Job ID\"" "Schedule ID\"" +replace_string "Your job" "Your schedule" +replace_string "Job Definition\"" "Schedule Definition\"" +replace_string "job definition" "schedule definition" +replace_string "Run Job\"" "Run Schedule\"" +replace_string "Creating job" "Creating schedule" +replace_string "Reload Job\"" "Reload Schedule\"" +replace_string "Delete Job\"" "Delete Schedule\"" +replace_string "Download Job Files\"" "Download Schedule Files\"" +replace_string "No jobs associated with this schedule definition" "No schedules associated with this schedule definition" +replace_string "There are no jobs. Jobs run" "There are no schedules. Schedules run" +replace_string "Create a job" "Create a schedule" +replace_string "create a job" "create a schedule" +replace_string "Stop Job\"" "Stop Schedule\"" + +echo "All replacements completed!" diff --git a/template/v4/v4.6/dirs/etc/patches/smus/0001-sparkmagic.patch b/template/v4/v4.6/dirs/etc/patches/smus/0001-sparkmagic.patch new file mode 100644 index 000000000..25d380b9d --- /dev/null +++ b/template/v4/v4.6/dirs/etc/patches/smus/0001-sparkmagic.patch @@ -0,0 +1,10 @@ +--- /opt/conda/lib/python3.12/site-packages/sparkmagic/livyclientlib/command.py ++++ /opt/conda/lib/python3.12/site-packages/sparkmagic/livyclientlib/command.py +@@ -54,6 +54,7 @@ + try: + session.wait_for_idle() + data = {"code": self.code} ++ data["kind"] = session.kind + response = session.http_client.post_statement(session.id, data) + statement_id = response["id"] + output = self._get_statement_output(session, statement_id) diff --git a/template/v4/v4.6/dirs/etc/patches/smus/0002-sparkmagic-override-info-table.patch b/template/v4/v4.6/dirs/etc/patches/smus/0002-sparkmagic-override-info-table.patch new file mode 100644 index 000000000..82fd0c94b --- /dev/null +++ b/template/v4/v4.6/dirs/etc/patches/smus/0002-sparkmagic-override-info-table.patch @@ -0,0 +1,17 @@ +--- /opt/conda/lib/python3.12/site-packages/sparkmagic/utils/utils.py ++++ /opt/conda/lib/python3.12/site-packages/sparkmagic/utils/utils.py +@@ -94,15 +94,7 @@ + + + def get_sessions_info_html(info_sessions, current_session_id): +- html = ( +- """ +-""" +- + "".join( +- [session.get_row_html(current_session_id) for session in info_sessions] +- ) +- + "
IDYARN Application IDKindStateSpark UIDriver logUserCurrent session?
" +- ) +- ++ html = "" + return html diff --git a/template/v4/v4.6/dirs/etc/patches/smus/0005-fix-logger.patch b/template/v4/v4.6/dirs/etc/patches/smus/0005-fix-logger.patch new file mode 100644 index 000000000..55be5db83 --- /dev/null +++ b/template/v4/v4.6/dirs/etc/patches/smus/0005-fix-logger.patch @@ -0,0 +1,68 @@ +--- /opt/conda/lib/python3.12/site-packages/hdijupyterutils/log.py ++++ /opt/conda/lib/python3.12/site-packages/hdijupyterutils/log.py +@@ -2,7 +2,7 @@ + + from __future__ import print_function + import logging +-import logging.config ++import importlib + + from .constants import LOGGING_CONFIG_CLASS_NAME + +@@ -11,13 +11,56 @@ + """Logger for magics. A small wrapper class around the configured logger described in the configuration file""" + + def __init__(self, logger_name, logging_config, caller_name): +- logging.config.dictConfig(logging_config) ++ self._setup_logger(logger_name, logging_config) + + assert caller_name is not None + self._caller_name = caller_name + self.logger_name = logger_name + self._getLogger() + ++ def _setup_logger(self, logger_name, logging_config): ++ """Set up logger manually using handlers and formatters from logging_config""" ++ config = logging_config ++ ++ # Create logger ++ logger = logging.getLogger(logger_name) ++ ++ # Set up formatters ++ formatters = {} ++ for formatter_name, formatter_config in config["formatters"].items(): ++ formatters[formatter_name] = logging.Formatter( ++ fmt=formatter_config["format"], ++ datefmt=formatter_config["datefmt"] ++ ) ++ ++ # Check which handlers are needed but not already present ++ existing_handler_types = {type(handler).__name__ for handler in logger.handlers} ++ ++ # Set up handlers only if they don't already exist ++ for handler_name in config["handlers"]: ++ handler_config = config["handlers"][handler_name] ++ ++ # Get handler class ++ handler_class_name = handler_config["class"] ++ module_name, class_name = handler_class_name.rsplit(".", 1) ++ module = importlib.import_module(module_name) ++ handler_class = getattr(module, class_name) ++ ++ # Check if this type of handler already exists ++ if handler_class.__name__ not in existing_handler_types: ++ # Create handler with config (excluding class and formatter) ++ handler_kwargs = {k: v for k, v in handler_config.items() ++ if k not in ["class", "formatter"]} ++ handler = handler_class(**handler_kwargs) ++ ++ # Set formatter if specified ++ if "formatter" in handler_config: ++ formatter_name = handler_config["formatter"] ++ handler.setFormatter(formatters[formatter_name]) ++ ++ # Add handler to logger ++ logger.addHandler(handler) ++ + def debug(self, message): + self.logger.debug(self._transform_log_message(message)) \ No newline at end of file diff --git a/template/v4/v4.6/dirs/etc/sagemaker-inference-server/__init__.py b/template/v4/v4.6/dirs/etc/sagemaker-inference-server/__init__.py new file mode 100644 index 000000000..0427e383a --- /dev/null +++ b/template/v4/v4.6/dirs/etc/sagemaker-inference-server/__init__.py @@ -0,0 +1,3 @@ +from __future__ import absolute_import + +import utils.logger diff --git a/template/v4/v4.6/dirs/etc/sagemaker-inference-server/serve b/template/v4/v4.6/dirs/etc/sagemaker-inference-server/serve new file mode 100755 index 000000000..bd604df37 --- /dev/null +++ b/template/v4/v4.6/dirs/etc/sagemaker-inference-server/serve @@ -0,0 +1,2 @@ +#!/bin/bash +python /etc/sagemaker-inference-server/serve.py diff --git a/template/v4/v4.6/dirs/etc/sagemaker-inference-server/serve.py b/template/v4/v4.6/dirs/etc/sagemaker-inference-server/serve.py new file mode 100644 index 000000000..0d23ada86 --- /dev/null +++ b/template/v4/v4.6/dirs/etc/sagemaker-inference-server/serve.py @@ -0,0 +1,25 @@ +from __future__ import absolute_import + +""" +TODO: when adding support for more serving frameworks, move the below logic into a condition statement. +We also need to define the right environment variable for signify what serving framework to use. + +Ex. + +inference_server = None +serving_framework = os.getenv("SAGEMAKER_INFERENCE_FRAMEWORK", None) + +if serving_framework == "FastAPI": + inference_server = FastApiServer() +elif serving_framework == "Flask": + inference_server = FlaskServer() +else: + inference_server = TornadoServer() + +inference_server.serve() + +""" +from tornado_server.server import TornadoServer + +inference_server = TornadoServer() +inference_server.serve() diff --git a/template/v4/v4.6/dirs/etc/sagemaker-inference-server/tornado_server/__init__.py b/template/v4/v4.6/dirs/etc/sagemaker-inference-server/tornado_server/__init__.py new file mode 100644 index 000000000..28b0e2cc2 --- /dev/null +++ b/template/v4/v4.6/dirs/etc/sagemaker-inference-server/tornado_server/__init__.py @@ -0,0 +1,12 @@ +from __future__ import absolute_import + +import pathlib +import sys + +# make the utils modules accessible to modules from within the tornado_server folder +utils_path = pathlib.Path(__file__).parent.parent / "utils" +sys.path.insert(0, str(utils_path.resolve())) + +# make the tornado_server modules accessible to each other +tornado_module_path = pathlib.Path(__file__).parent +sys.path.insert(0, str(tornado_module_path.resolve())) diff --git a/template/v4/v4.6/dirs/etc/sagemaker-inference-server/tornado_server/async_handler.py b/template/v4/v4.6/dirs/etc/sagemaker-inference-server/tornado_server/async_handler.py new file mode 100644 index 000000000..9eb946086 --- /dev/null +++ b/template/v4/v4.6/dirs/etc/sagemaker-inference-server/tornado_server/async_handler.py @@ -0,0 +1,76 @@ +from __future__ import absolute_import + +import asyncio +import logging +from typing import AsyncIterator, Iterator + +import tornado.web +from stream_handler import StreamHandler + +from utils.environment import Environment +from utils.exception import AsyncInvocationsException +from utils.logger import SAGEMAKER_DISTRIBUTION_INFERENCE_LOGGER + +logger = logging.getLogger(SAGEMAKER_DISTRIBUTION_INFERENCE_LOGGER) + + +class InvocationsHandler(tornado.web.RequestHandler, StreamHandler): + """Handler mapped to the /invocations POST route. + + This handler wraps the async handler retrieved from the inference script + and encapsulates it behind the post() method. The post() method is done + asynchronously. + """ + + def initialize(self, handler: callable, environment: Environment): + """Initializes the handler function and the serving environment.""" + + self._handler = handler + self._environment = environment + + async def post(self): + """POST method used to encapsulate and invoke the async handle method asynchronously""" + + try: + response = await self._handler(self.request) + + if isinstance(response, Iterator): + await self.stream(response) + elif isinstance(response, AsyncIterator): + await self.astream(response) + else: + self.write(response) + except Exception as e: + raise AsyncInvocationsException(e) + + +class PingHandler(tornado.web.RequestHandler): + """Handler mapped to the /ping GET route. + + Ping handler to monitor the health of the Tornados server. + """ + + def get(self): + """Simple GET method to assess the health of the server.""" + + self.write("") + + +async def handle(handler: callable, environment: Environment): + """Serves the async handler function using Tornado. + + Opens the /invocations and /ping routes used by a SageMaker Endpoint + for inference serving capabilities. + """ + + logger.info("Starting inference server in asynchronous mode...") + + app = tornado.web.Application( + [ + (r"/invocations", InvocationsHandler, dict(handler=handler, environment=environment)), + (r"/ping", PingHandler), + ] + ) + app.listen(environment.port) + logger.debug(f"Asynchronous inference server listening on port: `{environment.port}`") + await asyncio.Event().wait() diff --git a/template/v4/v4.6/dirs/etc/sagemaker-inference-server/tornado_server/server.py b/template/v4/v4.6/dirs/etc/sagemaker-inference-server/tornado_server/server.py new file mode 100644 index 000000000..496bfac89 --- /dev/null +++ b/template/v4/v4.6/dirs/etc/sagemaker-inference-server/tornado_server/server.py @@ -0,0 +1,127 @@ +from __future__ import absolute_import + +import asyncio +import importlib +import logging +import subprocess +import sys +from pathlib import Path + +from utils.environment import Environment +from utils.exception import ( + InferenceCodeLoadException, + RequirementsInstallException, + ServerStartException, +) +from utils.logger import SAGEMAKER_DISTRIBUTION_INFERENCE_LOGGER + +logger = logging.getLogger(SAGEMAKER_DISTRIBUTION_INFERENCE_LOGGER) + + +class TornadoServer: + """Holds serving logic using the Tornado framework. + + The serve.py script will invoke TornadoServer.serve() to start the serving process. + The TornadoServer will install the runtime requirements specified through a requirements file. + It will then load an handler function within an inference script and then front it will an /invocations + route using the Tornado framework. + """ + + def __init__(self): + """Initialize the serving behaviors. + + Defines the serving behavior through Environment() and locate where + the inference code is contained. + """ + + self._environment = Environment() + logger.setLevel(int(self._environment.logging_level)) + logger.debug(f"Environment: {str(self._environment)}") + + self._path_to_inference_code = ( + Path(self._environment.base_directory).joinpath(self._environment.code_directory) + if self._environment.code_directory + else Path(self._environment.base_directory) + ) + logger.debug(f"Path to inference code: `{str(self._path_to_inference_code)}`") + + def initialize(self): + """Initialize the serving artifacts and dependencies. + + Install the runtime requirements and then locate the handler function from + the inference script. + """ + + logger.info("Initializing inference server...") + self._install_runtime_requirements() + self._handler = self._load_inference_handler() + + def serve(self): + """Orchestrate the initialization and server startup behavior. + + Call the initalize() method, determine the right Tornado serving behavior (async or sync), + and then start the Tornado server through asyncio + """ + + logger.info("Serving inference requests using Tornado...") + self.initialize() + + if asyncio.iscoroutinefunction(self._handler): + import async_handler as inference_handler + else: + import sync_handler as inference_handler + + try: + asyncio.run(inference_handler.handle(self._handler, self._environment)) + except Exception as e: + raise ServerStartException(e) + + def _install_runtime_requirements(self): + """Install the runtime requirements.""" + + logger.info("Installing runtime requirements...") + requirements_txt = self._path_to_inference_code.joinpath(self._environment.requirements) + if requirements_txt.is_file(): + try: + subprocess.check_call(["micromamba", "install", "--yes", "--file", str(requirements_txt)]) + except Exception as e: + logger.error( + "Failed to install requirements using `micromamba install`. Falling back to `pip install`..." + ) + try: + subprocess.check_call(["pip", "install", "-r", str(requirements_txt)]) + except Exception as e: + raise RequirementsInstallException(e) + else: + logger.debug(f"No requirements file was found at `{str(requirements_txt)}`") + + def _load_inference_handler(self) -> callable: + """Load the handler function from the inference script.""" + + logger.info("Loading inference handler...") + inference_module_name, handle_name = self._environment.code.split(".") + if inference_module_name and handle_name: + inference_module_file = f"{inference_module_name}.py" + module_spec = importlib.util.spec_from_file_location( + inference_module_file, str(self._path_to_inference_code.joinpath(inference_module_file)) + ) + if module_spec: + sys.path.insert(0, str(self._path_to_inference_code.resolve())) + module = importlib.util.module_from_spec(module_spec) + module_spec.loader.exec_module(module) + + if hasattr(module, handle_name): + handler = getattr(module, handle_name) + else: + raise InferenceCodeLoadException( + f"Handler `{handle_name}` could not be found in module `{inference_module_file}`" + ) + logger.debug(f"Loaded handler `{handle_name}` from module `{inference_module_name}`") + return handler + else: + raise InferenceCodeLoadException( + f"Inference code could not be found at `{str(self._path_to_inference_code.joinpath(inference_module_file))}`" + ) + raise InferenceCodeLoadException( + f"Inference code expected in the format of `.` but was provided as {self._environment.code}" + ) diff --git a/template/v4/v4.6/dirs/etc/sagemaker-inference-server/tornado_server/stream_handler.py b/template/v4/v4.6/dirs/etc/sagemaker-inference-server/tornado_server/stream_handler.py new file mode 100644 index 000000000..ab01f5878 --- /dev/null +++ b/template/v4/v4.6/dirs/etc/sagemaker-inference-server/tornado_server/stream_handler.py @@ -0,0 +1,59 @@ +from __future__ import absolute_import + +import logging +from typing import AsyncIterator, Iterator + +from tornado.ioloop import IOLoop + +from utils.logger import SAGEMAKER_DISTRIBUTION_INFERENCE_LOGGER + +logger = logging.getLogger(SAGEMAKER_DISTRIBUTION_INFERENCE_LOGGER) + + +class StreamHandler: + """Mixin that enables async and sync streaming capabilities to the async and sync handlers + + stream() runs a provided iterator/generator fn in an async manner. + astream() runs a provided async iterator/generator fn in an async manner. + """ + + async def stream(self, iterator: Iterator): + """Streams the response from a sync response iterator + + A sync iterator must be manually iterated through asynchronously. + In a loop, iterate through each next(iterator) call in an async execution. + """ + + self._set_stream_headers() + + while True: + try: + chunk = await IOLoop.current().run_in_executor(None, next, iterator) + # Some iterators do not throw a StopIteration upon exhaustion. + # Instead, they return an empty response. Account for this case. + if not chunk: + raise StopIteration() + + self.write(chunk) + await self.flush() + except StopIteration: + break + except Exception as e: + logger.error("Unexpected exception occurred when streaming response...") + break + + async def astream(self, aiterator: AsyncIterator): + """Streams the response from an async response iterator""" + + self._set_stream_headers() + + async for chunk in aiterator: + self.write(chunk) + await self.flush() + + def _set_stream_headers(self): + """Set the headers in preparation for the streamed response""" + + self.set_header("Content-Type", "text/event-stream") + self.set_header("Cache-Control", "no-cache") + self.set_header("Connection", "keep-alive") diff --git a/template/v4/v4.6/dirs/etc/sagemaker-inference-server/tornado_server/sync_handler.py b/template/v4/v4.6/dirs/etc/sagemaker-inference-server/tornado_server/sync_handler.py new file mode 100644 index 000000000..919f803ac --- /dev/null +++ b/template/v4/v4.6/dirs/etc/sagemaker-inference-server/tornado_server/sync_handler.py @@ -0,0 +1,77 @@ +from __future__ import absolute_import + +import asyncio +import logging +from typing import AsyncIterator, Iterator + +import tornado.web +from stream_handler import StreamHandler +from tornado.ioloop import IOLoop + +from utils.environment import Environment +from utils.exception import SyncInvocationsException +from utils.logger import SAGEMAKER_DISTRIBUTION_INFERENCE_LOGGER + +logger = logging.getLogger(SAGEMAKER_DISTRIBUTION_INFERENCE_LOGGER) + + +class InvocationsHandler(tornado.web.RequestHandler, StreamHandler): + """Handler mapped to the /invocations POST route. + + This handler wraps the sync handler retrieved from the inference script + and encapsulates it behind the post() method. The post() method is done + asynchronously. + """ + + def initialize(self, handler: callable, environment: Environment): + """Initializes the handler function and the serving environment.""" + + self._handler = handler + self._environment = environment + + async def post(self): + """POST method used to encapsulate and invoke the sync handle method asynchronously""" + + try: + response = await IOLoop.current().run_in_executor(None, self._handler, self.request) + + if isinstance(response, Iterator): + await self.stream(response) + elif isinstance(response, AsyncIterator): + await self.astream(response) + else: + self.write(response) + except Exception as e: + raise SyncInvocationsException(e) + + +class PingHandler(tornado.web.RequestHandler): + """Handler mapped to the /ping GET route. + + Ping handler to monitor the health of the Tornados server. + """ + + def get(self): + """Simple GET method to assess the health of the server.""" + + self.write("") + + +async def handle(handler: callable, environment: Environment): + """Serves the sync handler function using Tornado. + + Opens the /invocations and /ping routes used by a SageMaker Endpoint + for inference serving capabilities. + """ + + logger.info("Starting inference server in synchronous mode...") + + app = tornado.web.Application( + [ + (r"/invocations", InvocationsHandler, dict(handler=handler, environment=environment)), + (r"/ping", PingHandler), + ] + ) + app.listen(environment.port) + logger.debug(f"Synchronous inference server listening on port: `{environment.port}`") + await asyncio.Event().wait() diff --git a/template/v4/v4.6/dirs/etc/sagemaker-inference-server/utils/__init__.py b/template/v4/v4.6/dirs/etc/sagemaker-inference-server/utils/__init__.py new file mode 100644 index 000000000..c3961685a --- /dev/null +++ b/template/v4/v4.6/dirs/etc/sagemaker-inference-server/utils/__init__.py @@ -0,0 +1 @@ +from __future__ import absolute_import diff --git a/template/v4/v4.6/dirs/etc/sagemaker-inference-server/utils/environment.py b/template/v4/v4.6/dirs/etc/sagemaker-inference-server/utils/environment.py new file mode 100644 index 000000000..18870de27 --- /dev/null +++ b/template/v4/v4.6/dirs/etc/sagemaker-inference-server/utils/environment.py @@ -0,0 +1,59 @@ +from __future__ import absolute_import + +import json +import os +from enum import Enum + + +class SageMakerInference(str, Enum): + """Simple enum to define the mapping between dictionary key and environement variable.""" + + BASE_DIRECTORY = "SAGEMAKER_INFERENCE_BASE_DIRECTORY" + REQUIREMENTS = "SAGEMAKER_INFERENCE_REQUIREMENTS" + CODE_DIRECTORY = "SAGEMAKER_INFERENCE_CODE_DIRECTORY" + CODE = "SAGEMAKER_INFERENCE_CODE" + LOG_LEVEL = "SAGEMAKER_INFERENCE_LOG_LEVEL" + PORT = "SAGEMAKER_INFERENCE_PORT" + + +class Environment: + """Retrieves and encapsulates SAGEMAKER_INFERENCE prefixed environment variables.""" + + def __init__(self): + """Initialize the environment variable mapping""" + + self._environment_variables = { + SageMakerInference.BASE_DIRECTORY: "/opt/ml/model", + SageMakerInference.REQUIREMENTS: "requirements.txt", + SageMakerInference.CODE_DIRECTORY: os.getenv(SageMakerInference.CODE_DIRECTORY, None), + SageMakerInference.CODE: os.getenv(SageMakerInference.CODE, "inference.handler"), + SageMakerInference.LOG_LEVEL: os.getenv(SageMakerInference.LOG_LEVEL, 10), + SageMakerInference.PORT: 8080, + } + + def __str__(self): + return json.dumps(self._environment_variables) + + @property + def base_directory(self): + return self._environment_variables.get(SageMakerInference.BASE_DIRECTORY) + + @property + def requirements(self): + return self._environment_variables.get(SageMakerInference.REQUIREMENTS) + + @property + def code_directory(self): + return self._environment_variables.get(SageMakerInference.CODE_DIRECTORY) + + @property + def code(self): + return self._environment_variables.get(SageMakerInference.CODE) + + @property + def logging_level(self): + return self._environment_variables.get(SageMakerInference.LOG_LEVEL) + + @property + def port(self): + return self._environment_variables.get(SageMakerInference.PORT) diff --git a/template/v4/v4.6/dirs/etc/sagemaker-inference-server/utils/exception.py b/template/v4/v4.6/dirs/etc/sagemaker-inference-server/utils/exception.py new file mode 100644 index 000000000..eb961889d --- /dev/null +++ b/template/v4/v4.6/dirs/etc/sagemaker-inference-server/utils/exception.py @@ -0,0 +1,21 @@ +from __future__ import absolute_import + + +class RequirementsInstallException(Exception): + pass + + +class InferenceCodeLoadException(Exception): + pass + + +class ServerStartException(Exception): + pass + + +class SyncInvocationsException(Exception): + pass + + +class AsyncInvocationsException(Exception): + pass diff --git a/template/v4/v4.6/dirs/etc/sagemaker-inference-server/utils/logger.py b/template/v4/v4.6/dirs/etc/sagemaker-inference-server/utils/logger.py new file mode 100644 index 000000000..c88008689 --- /dev/null +++ b/template/v4/v4.6/dirs/etc/sagemaker-inference-server/utils/logger.py @@ -0,0 +1,43 @@ +from __future__ import absolute_import + +import logging.config + +SAGEMAKER_DISTRIBUTION_INFERENCE_LOGGER = "sagemaker_distribution.inference_server" +LOGGING_CONFIG = { + "version": 1, + "disable_existing_loggers": True, + "formatters": { + "standard": {"format": "%(asctime)s [%(levelname)s] %(name)s: %(message)s"}, + }, + "handlers": { + "default": { + "level": "DEBUG", + "formatter": "standard", + "class": "logging.StreamHandler", + "stream": "ext://sys.stdout", + }, + }, + "loggers": { + SAGEMAKER_DISTRIBUTION_INFERENCE_LOGGER: { + "level": "DEBUG", + "handlers": ["default"], + "propagate": True, + }, + "tornado.application": { + "level": "DEBUG", + "handlers": ["default"], + "propagate": True, + }, + "tornado.general": { + "level": "DEBUG", + "handlers": ["default"], + "propagate": True, + }, + "tornado.access": { + "level": "DEBUG", + "handlers": ["default"], + "propagate": True, + }, + }, +} +logging.config.dictConfig(LOGGING_CONFIG) diff --git a/template/v4/v4.6/dirs/etc/sagemaker-ui/fetch_feature_flags.py b/template/v4/v4.6/dirs/etc/sagemaker-ui/fetch_feature_flags.py new file mode 100644 index 000000000..778f47e9f --- /dev/null +++ b/template/v4/v4.6/dirs/etc/sagemaker-ui/fetch_feature_flags.py @@ -0,0 +1,100 @@ +#!/usr/bin/env python3 +""" +Fetch feature flags from DataZone domain and write to file. +This script is intended to be called from the post-startup script. +""" + +import html +import json +import logging +import os +import re +import sys +import urllib.parse +import urllib.request + +# Configure logging +logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s") +logger = logging.getLogger(__name__) + + +def fetch_feature_flags(): + """ + Read domain metadata, fetch feature flags from domain login page, + and write to ~/.aws/enabled_features/enabled_features.json + """ + try: + # Read resource metadata + metadata_path = "/opt/ml/metadata/resource-metadata.json" + logger.info(f"Reading metadata from {metadata_path}") + + with open(metadata_path, "r") as f: + data = json.load(f) + additional_metadata = data.get("AdditionalMetadata", {}) + domain_id = additional_metadata.get("DataZoneDomainId") + region = additional_metadata.get("DataZoneDomainRegion") + stage = additional_metadata.get("DataZoneStage") + + if not domain_id or not region: + logger.warning("Domain metadata not found in resource metadata") + return False + + # Construct domain login URL + stage_prefix = f"-{stage}" if stage and stage != "prod" else "" + domain_url = f"https://{domain_id}.sagemaker{stage_prefix}.{region}.on.aws/login" + logger.info(f"Fetching feature flags from {domain_url}") + + # Validate URL scheme for security + parsed_url = urllib.parse.urlparse(domain_url) + if parsed_url.scheme != "https": + logger.error(f"Only HTTPS URLs are allowed, got: {parsed_url.scheme}") + return False + + # Fetch domain login page + with urllib.request.urlopen(domain_url, timeout=10) as response: + html_content = response.read().decode("utf-8") + + # Parse feature flags from meta tag + match = re.search( + r']+name=["\']enabled-features["\'][^>]+content=["\']([^"\']+)["\']', + html_content, + re.IGNORECASE, + ) + + if not match: + logger.warning("Feature flags meta tag not found in domain login page") + return False + + # Unescape HTML entities (" -> ") + raw_content = html.unescape(match.group(1)) + feature_flags = json.loads(raw_content) + logger.info(f"Found {len(feature_flags)} feature flags") + + # Write feature flags to file + feature_flags_dir = os.path.expanduser("~/.aws/enabled_features") + os.makedirs(feature_flags_dir, exist_ok=True) + feature_flags_file = os.path.join(feature_flags_dir, "enabled_features.json") + + with open(feature_flags_file, "w") as f: + json.dump({"enabled_features": feature_flags}, f, indent=2) + + logger.info(f"Feature flags written to {feature_flags_file}") + return True + + except FileNotFoundError: + logger.error(f"Metadata file not found: {metadata_path}") + return False + except json.JSONDecodeError as e: + logger.error(f"Failed to parse JSON: {e}") + return False + except urllib.error.URLError as e: + logger.error(f"Failed to fetch domain page: {e}") + return False + except Exception as e: + logger.error(f"Unexpected error: {e}") + return False + + +if __name__ == "__main__": + success = fetch_feature_flags() + sys.exit(0 if success else 1) diff --git a/template/v4/v4.6/dirs/etc/sagemaker-ui/git_clone.sh b/template/v4/v4.6/dirs/etc/sagemaker-ui/git_clone.sh new file mode 100755 index 000000000..714d687e2 --- /dev/null +++ b/template/v4/v4.6/dirs/etc/sagemaker-ui/git_clone.sh @@ -0,0 +1,62 @@ +#!/bin/bash +set -eux + +sourceMetaData=/opt/ml/metadata/resource-metadata.json + +# Extract the required fields from meta data stored in opt/ml/metadata. +dataZoneDomainId=$(jq -r '.AdditionalMetadata.DataZoneDomainId' < $sourceMetaData) +dataZoneUserId=$(jq -r '.AdditionalMetadata.DataZoneUserId' < $sourceMetaData) +dataZoneEndPoint=$(jq -r '.AdditionalMetadata.DataZoneEndpoint' < $sourceMetaData) +dataZoneProjectId=$(jq -r '.AdditionalMetadata.DataZoneProjectId' < $sourceMetaData) + +DEFAULT_DESTINATION_PATH=$HOME/src +DESTINATION_PATH=${1:-$DEFAULT_DESTINATION_PATH} + +echo "Cloning to ${DESTINATION_PATH}" + +# Function to clone the CodeCommit repository +clone_code_commit_repo() { + if [ -d "${DESTINATION_PATH}/.git" ]; then + echo "Repository already exists at ${DESTINATION_PATH}" + else + rm -rf "${DESTINATION_PATH}" + local repoName=$1 + git clone codecommit::$AWS_REGION://$repoName $DESTINATION_PATH + # if the above command exit with nonzero exit code ,delete the partially cloned Repo. + if [ $? -ne 0 ]; then + echo "Git clone of the Project repository has failed. Please refer to the documentation to understand how to fix this." + if [ -d $DESTINATION_PATH ]; then + rm -rf $DESTINATION_PATH + fi + fi + fi +} + +# Get the clone URL for the project +response=$(sagemaker-studio git get-clone-url --domain-id "$dataZoneDomainId" --project-id "$dataZoneProjectId" --profile DomainExecutionRoleCreds) +cloneUrl=$(echo "$response" | jq -r '.cloneUrl') +# Get the project default environment and extract the gitConnectionArn and gitBranchName +getProjectDefaultEnvResponse=$(sagemaker-studio project get-project-default-environment --domain-id "$dataZoneDomainId" --project-id "$dataZoneProjectId" --profile DomainExecutionRoleCreds) +gitConnectionArn=$(echo "$getProjectDefaultEnvResponse" | jq -r '.provisionedResources[] | select(.name=="gitConnectionArn") | .value') +gitBranchName=$(echo "$getProjectDefaultEnvResponse" | jq -r '.provisionedResources[] | select(.name=="gitBranchName") | .value') +dataZoneProjectRepositoryName=$(echo "$getProjectDefaultEnvResponse" | jq -r '.provisionedResources[] | select(.name=="codeRepositoryName") | .value') + + # Check if the cloneUrl is available +if [[ -n "$cloneUrl" ]]; then + # Check if the cloneUrl contains "codeconnections" or "codestar-connections" (For customers created connection before Jun 7th) + if [[ "$cloneUrl" == *"codeconnections"* ]] || [[ "$cloneUrl" == *"codestar-connections"* ]]; then + # Check if the DomainExecutionRoleCreds profile exists in the AWS config file + if grep -q 'DomainExecutionRoleCreds' /home/sagemaker-user/.aws/config; then + /bin/bash /etc/sagemaker-ui/git_config.sh + # Clone the repository using the cloneUrl and gitBranchName + git clone "$cloneUrl" $DESTINATION_PATH -b "$gitBranchName" + fi + else + # Clone the codeCommit repository + clone_code_commit_repo "$dataZoneProjectRepositoryName" + fi +else + # If the cloneUrl is not available, check if the gitConnectionArn is available + # If not available, clone codeCommit repository. + [[ -z "$gitConnectionArn" ]] && clone_code_commit_repo "$dataZoneProjectRepositoryName" +fi diff --git a/template/v4/v4.6/dirs/etc/sagemaker-ui/git_config.sh b/template/v4/v4.6/dirs/etc/sagemaker-ui/git_config.sh new file mode 100644 index 000000000..5f4d61e5e --- /dev/null +++ b/template/v4/v4.6/dirs/etc/sagemaker-ui/git_config.sh @@ -0,0 +1,9 @@ +#!/bin/bash +set -eux + +sourceMetaData=/opt/ml/metadata/resource-metadata.json +dataZoneDomainRegion=$(jq -r '.AdditionalMetadata.DataZoneDomainRegion' < $sourceMetaData) + +# Configure Git to use the AWS CodeCommit credential helper with profile DomainExecutionRoleCreds +git config --global credential.helper "!aws --profile DomainExecutionRoleCreds --region $dataZoneDomainRegion codecommit credential-helper --ignore-host-check $@" +git config --global credential.UseHttpPath true diff --git a/template/v4/v4.6/dirs/etc/sagemaker-ui/jupyter/lab/settings/overrides.json b/template/v4/v4.6/dirs/etc/sagemaker-ui/jupyter/lab/settings/overrides.json new file mode 100644 index 000000000..4c84693d5 --- /dev/null +++ b/template/v4/v4.6/dirs/etc/sagemaker-ui/jupyter/lab/settings/overrides.json @@ -0,0 +1,5 @@ +{ + "@jupyterlab/apputils-extension:themes": { + "theme": "Amazon SageMaker Unified Studio Dark" + } +} diff --git a/template/v4/v4.6/dirs/etc/sagemaker-ui/jupyter/lab/settings/page_config.json b/template/v4/v4.6/dirs/etc/sagemaker-ui/jupyter/lab/settings/page_config.json new file mode 100644 index 000000000..f14872b09 --- /dev/null +++ b/template/v4/v4.6/dirs/etc/sagemaker-ui/jupyter/lab/settings/page_config.json @@ -0,0 +1,15 @@ +{ + "disabledExtensions": { + "@jupyterlab/apputils-extension:announcements": true, + "@amzn/sagemaker-jupyterlab-emr-extension": true, + "@amzn/sagemaker-jupyter-scheduler": true, + "@amzn/sagemaker-jupyterlab-extension-common:panorama": true, + "@amzn/sagemaker-jupyterlab-extensions:sessionmanagement": true, + "@amzn/sagemaker-jupyterlab-extensions:spacemenu": true, + "@amzn/amazon_sagemaker_sql_editor": true, + "@sagemaker-studio:EmrCluster": true, + "@jupyter/collaboration-extension": true, + "@jupyter/docprovider-extension": true, + "@jupyter-ai-contrib/server-documents": true + } +} diff --git a/template/v4/v4.6/dirs/etc/sagemaker-ui/jupyter/server/jupyter_server_config.d/zzz_sagemaker_ui_overrides.json b/template/v4/v4.6/dirs/etc/sagemaker-ui/jupyter/server/jupyter_server_config.d/zzz_sagemaker_ui_overrides.json new file mode 100644 index 000000000..337eb4651 --- /dev/null +++ b/template/v4/v4.6/dirs/etc/sagemaker-ui/jupyter/server/jupyter_server_config.d/zzz_sagemaker_ui_overrides.json @@ -0,0 +1,8 @@ +{ + "ServerApp": { + "jpserver_extensions": { + "jupyter_server_ydoc": false, + "jupyter_server_documents": false + } + } +} diff --git a/template/v4/v4.6/dirs/etc/sagemaker-ui/jupyter/server/jupyter_server_config.py b/template/v4/v4.6/dirs/etc/sagemaker-ui/jupyter/server/jupyter_server_config.py new file mode 100644 index 000000000..5a02869d0 --- /dev/null +++ b/template/v4/v4.6/dirs/etc/sagemaker-ui/jupyter/server/jupyter_server_config.py @@ -0,0 +1,43 @@ +import os + +from sagemaker_studio_jupyter_scheduler.scheduler import ( + SagemakerEnvironmentManager, + SageMakerJobFilesManager, + SageMakerUnifiedStudioScheduler, +) + +c.ServerApp.terminado_settings = {"shell_command": ["/bin/bash"]} +region = os.environ.get("AWS_REGION") +csp_rule = os.environ.get("JUPYTERSERVER_CSP_RULE") + +c.ServerApp.tornado_settings = {"compress_response": True, "headers": {"Content-Security-Policy": csp_rule}} + +# Do not delete files to trash. Instead, permanently delete files. +c.FileContentsManager.delete_to_trash = False + +# Allow deleting non-empty directory via file browser. Related documentation: +# https://github.com/jupyter-server/jupyter_server/blob/main/jupyter_server/services/contents/filemanager.py#L125-L129 +c.FileContentsManager.always_delete_dir = True + +# Enable `allow_hidden` by default, so hidden files are accessible via Jupyter server +# Related documentation: https://jupyterlab.readthedocs.io/en/stable/user/files.html#displaying-hidden-files +c.ContentsManager.allow_hidden = True + +# This will set the LanguageServerManager.extra_node_roots setting if amazon_sagemaker_sql_editor exists in the +# environment. Ignore otherwise, don't fail the JL server start +# Related documentation: https://jupyterlab-lsp.readthedocs.io/en/v3.4.0/Configuring.html +try: + import os + + module = __import__("amazon_sagemaker_sql_editor") + module_location = os.path.dirname(module.__file__) + c.LanguageServerManager.extra_node_roots = [f"{module_location}/sql-language-server"] +except: + pass + +c.SchedulerApp.scheduler_class = SageMakerUnifiedStudioScheduler +c.SchedulerApp.environment_manager_class = SagemakerEnvironmentManager +c.SchedulerApp.job_files_manager_class = SageMakerJobFilesManager + +# Set Kiro as the default AI persona +c.PersonaManager.default_persona_id = "jupyter-ai-personas::jupyter_ai_acp_client::KiroAcpPersona" diff --git a/template/v4/v4.6/dirs/etc/sagemaker-ui/kernels/kernel_launchers/python3_kernel_launcher.sh b/template/v4/v4.6/dirs/etc/sagemaker-ui/kernels/kernel_launchers/python3_kernel_launcher.sh new file mode 100755 index 000000000..ca1a8fb75 --- /dev/null +++ b/template/v4/v4.6/dirs/etc/sagemaker-ui/kernels/kernel_launchers/python3_kernel_launcher.sh @@ -0,0 +1,51 @@ +#!/bin/bash + +kernel_type=$2 +connection_file=$4 + +if [ ! -e "/opt/ml/metadata/resource-metadata.json" ] && [ -z "$SPARKMAGIC_CONF_DIR" ]; then + export SPARKMAGIC_CONF_DIR="$SM_EXECUTION_INPUT_PATH" +fi + +if [ -n "$SPARKMAGIC_CONF_DIR" ]; then + mkdir -p $SPARKMAGIC_CONF_DIR + config_file_path=${SPARKMAGIC_CONF_DIR}/config.json +else + sparkmagicHomeDir=${HOME}/.sparkmagic + mkdir -p $sparkmagicHomeDir + config_file_path=${sparkmagicHomeDir}/config.json +fi + +if [ ! -f "$config_file_path" ]; then + cat << EOT > "$config_file_path" +{ + "livy_session_startup_timeout_seconds": 180, + "logging_config": { + "version": 1, + "formatters": { + "magicsFormatter": { + "format": "%(asctime)s\t%(levelname)s\t%(message)s", + "datefmt": "" + } + }, + "handlers": { + "magicsHandler": { + "class": "sagemaker_studio_dataengineering_sessions.sagemaker_base_session_manager.common.logger_utils.SessionManagerFileHandler", + "formatter": "magicsFormatter", + "file_name": "spark_magic" + } + }, + "loggers": { + "magicsLogger": { + "handlers": ["magicsHandler"], + "level": "INFO", + "propagate": 0 + } + } + } +} +EOT +else + sed -i 's/\"sagemaker_base_session_manager/\"sagemaker_studio_dataengineering_sessions.sagemaker_base_session_manager/g' $config_file_path +fi +exec /opt/conda/bin/python -m ${kernel_type} -f ${connection_file} diff --git a/template/v4/v4.6/dirs/etc/sagemaker-ui/kernels/python3/kernel.json b/template/v4/v4.6/dirs/etc/sagemaker-ui/kernels/python3/kernel.json new file mode 100644 index 000000000..7db91492d --- /dev/null +++ b/template/v4/v4.6/dirs/etc/sagemaker-ui/kernels/python3/kernel.json @@ -0,0 +1,14 @@ +{ + "argv": [ + "/opt/conda/share/jupyter/kernels/kernel_launchers/python3_kernel_launcher.sh", + "-m", + "ipykernel_launcher", + "-f", + "{connection_file}" + ], + "display_name": "Python 3 (ipykernel)", + "language": "python", + "metadata": { + "debugger": true + } +} diff --git a/template/v4/v4.6/dirs/etc/sagemaker-ui/libmgmt/install-lib.sh b/template/v4/v4.6/dirs/etc/sagemaker-ui/libmgmt/install-lib.sh new file mode 100755 index 000000000..84999cf14 --- /dev/null +++ b/template/v4/v4.6/dirs/etc/sagemaker-ui/libmgmt/install-lib.sh @@ -0,0 +1,18 @@ +#!/bin/bash +set -eux +PROJECT_DIR=${SMUS_PROJECT_DIR:-"$HOME/src"} +# Check if the .libs.json file exists +if [ -e $PROJECT_DIR/.libs.json ]; then + lib_config_json=`cat $PROJECT_DIR/.libs.json` + + apply_change_to_space=`echo $lib_config_json | jq -r '.ApplyChangeToSpace'` + # Extract conda channels from the config, add `-c ` before each channel and join the strings + conda_channels=`echo $lib_config_json | jq -r '.Python.CondaPackages.Channels | .[]' | sed 's/^/-c /g'` + # Extract conda package spec from the config and join the strings + conda_package=`echo $lib_config_json | jq -r '.Python.CondaPackages.PackageSpecs | .[]'` + + if [ ${apply_change_to_space} == "true" -a -n "$conda_package" ]; then + # if conda package spec exists, install the packages + micromamba install --freeze-installed -y $conda_channels $conda_package + fi +fi \ No newline at end of file diff --git a/template/v4/v4.6/dirs/etc/sagemaker-ui/network_validation.sh b/template/v4/v4.6/dirs/etc/sagemaker-ui/network_validation.sh new file mode 100644 index 000000000..37c682810 --- /dev/null +++ b/template/v4/v4.6/dirs/etc/sagemaker-ui/network_validation.sh @@ -0,0 +1,220 @@ +#!/bin/bash +set -eux + +# Input parameters with defaults: +# Default to 1 (Git storage) if no parameter is passed. +is_s3_storage=${1:-"1"} + +# Output file path for unreachable services JSON +network_validation_file=${2:-"/tmp/.network_validation.json"} + +# Function to write unreachable services to a JSON file +write_unreachable_services_to_file() { + local value="$1" + local file="$network_validation_file" + + # Create the file if it doesn't exist + if [ ! -f "$file" ]; then + touch "$file" || { + echo "Failed to create $file" >&2 + return 0 + } + fi + + # Check file is writable + if [ ! -w "$file" ]; then + echo "Error: $file is not writable" >&2 + return 0 + fi + + # Write JSON object with UnreachableServices key and the comma-separated list value + jq -n --arg value "$value" '{"UnreachableServices": $value}' > "$file" +} + +# Configure AWS CLI region using environment variable REGION_NAME +aws configure set region "${REGION_NAME}" +echo "Successfully configured region to ${REGION_NAME}" + +# Metadata file location containing DataZone info +sourceMetaData=/opt/ml/metadata/resource-metadata.json + +# Extract necessary DataZone metadata fields via jq +dataZoneDomainId=$(jq -r '.AdditionalMetadata.DataZoneDomainId' < "$sourceMetaData") +dataZoneProjectId=$(jq -r '.AdditionalMetadata.DataZoneProjectId' < "$sourceMetaData") +dataZoneEndPoint=$(jq -r '.AdditionalMetadata.DataZoneEndpoint' < "$sourceMetaData") +dataZoneDomainRegion=$(jq -r '.AdditionalMetadata.DataZoneDomainRegion' < "$sourceMetaData") +s3Path=$(jq -r '.AdditionalMetadata.ProjectS3Path' < "$sourceMetaData") + +# Extract bucket name, fallback to empty string if not found +s3ValidationBucket=$(echo "${s3Path:-}" | sed -E 's#s3://([^/]+).*#\1#') +if [[ -n "$s3ValidationBucket" && ! "$s3ValidationBucket" =~ ^[a-z0-9][a-z0-9.-]{1,61}[a-z0-9]$ ]]; then + s3ValidationBucket="" +fi + +# Call AWS CLI list-connections, including endpoint if specified +if [ -n "$dataZoneEndPoint" ]; then + response=$(aws datazone list-connections \ + --endpoint-url "$dataZoneEndPoint" \ + --domain-identifier "$dataZoneDomainId" \ + --project-identifier "$dataZoneProjectId" \ + --region "$dataZoneDomainRegion") +else + response=$(aws datazone list-connections \ + --domain-identifier "$dataZoneDomainId" \ + --project-identifier "$dataZoneProjectId" \ + --region "$dataZoneDomainRegion") +fi + +# Extract each connection item as a compact JSON string +connection_items=$(echo "$response" | jq -c '.items[]') + +# Required AWS Services for Compute connections and Git +# Always check STS; add S3 only when a valid bucket was resolved +enabled_services=("STS") +[[ -n "$s3ValidationBucket" ]] && enabled_services+=("S3") + +emr_app_id="" + +# Track connection types found for conditional checks +declare -A seen_types=() + +# Iterate over each connection to enable service checks conditionally +while IFS= read -r item; do + # Extract connection type + type=$(echo "$item" | jq -r '.type') + seen_types["$type"]=1 + + # For SPARK connections, check for Glue and EMR properties + if [[ "$type" == "SPARK" ]]; then + # If sparkGlueProperties present, enable Glue check + if echo "$item" | jq -e '.props.sparkGlueProperties' > /dev/null; then + seen_types["__GLUE__"]=1 + fi + + # Check for emr-serverless in sparkEmrProperties.computeArn for EMR Serverless check + emr_arn=$(echo "$item" | jq -r '.props.sparkEmrProperties.computeArn // empty') + if [[ "$emr_arn" == *"emr-serverless"* && "$emr_arn" == *"/applications/"* ]]; then + # Extract the application ID from the ARN + candidate_id=$(echo "$emr_arn" | sed -E 's#.*/applications/([^/]+)#\1#') + # Only accept a strictly alphanumeric application id + if [[ "$candidate_id" =~ ^[0-9a-z]{1,64}$ ]]; then + emr_app_id="$candidate_id" + seen_types["__EMR__"]=1 + fi + fi + fi +done <<< "$connection_items" + +[[ -n "${seen_types["__GLUE__"]:-}" ]] && enabled_services+=("Glue") +[[ -n "${seen_types["__EMR__"]:-}" ]] && enabled_services+=("EMR Serverless") + +# Add Athena if ATHENA connection found +[[ -n "${seen_types["ATHENA"]:-}" ]] && enabled_services+=("Athena") + +# Add Redshift checks if REDSHIFT connection found +if [[ -n "${seen_types["REDSHIFT"]:-}" ]]; then + enabled_services+=("Redshift Clusters") + enabled_services+=("Redshift Serverless") +fi + +# If using Git Storage (S3 storage flag == 1), check CodeConnections connectivity +# Domain Execution role contains permissions for CodeConnections +if [[ "$is_s3_storage" == "1" ]]; then + enabled_services+=("CodeConnections") +fi + +# Timeout (seconds) for each API call +api_time_out_limit=10 + +# Run the check for a single service as real argv (no shell re-parse) +run_check() { + case "$1" in + "STS") + timeout "${api_time_out_limit}s" aws sts get-caller-identity ;; + "S3") + timeout "${api_time_out_limit}s" aws s3api list-objects --bucket "$s3ValidationBucket" --max-items 1 ;; + "Glue") + timeout "${api_time_out_limit}s" aws glue get-databases --max-items 1 ;; + "EMR Serverless") + timeout "${api_time_out_limit}s" aws emr-serverless get-application --application-id "$emr_app_id" ;; + "Athena") + timeout "${api_time_out_limit}s" aws athena list-data-catalogs --max-items 1 ;; + "Redshift Clusters") + timeout "${api_time_out_limit}s" aws redshift describe-clusters --max-records 20 ;; + "Redshift Serverless") + timeout "${api_time_out_limit}s" aws redshift-serverless list-namespaces --max-results 1 ;; + "CodeConnections") + timeout "${api_time_out_limit}s" aws codeconnections list-connections --max-results 1 --profile DomainExecutionRoleCreds ;; + *) + echo "Unknown service key: $1" >&2 + return 2 ;; + esac +} + +# Array to accumulate unreachable services +unreachable_services=() + +# Create a temporary directory to store individual service results +temp_dir=$(mktemp -d) + +# Launch all service API checks in parallel background jobs +for service in "${enabled_services[@]}"; do + { + output_file="$temp_dir/${service}_output" + if run_check "$service" > "$output_file" 2>&1; then + # Success: write OK to temp file + echo "OK" > "$temp_dir/$service" + else + # Get exit code to differentiate timeout or other errors + exit_code=$? + if grep -q "Could not connect to the endpoint URL" "$output_file"; then + echo "UNREACHABLE" > "$temp_dir/$service" + elif [ "$exit_code" -eq 124 ]; then + # Timeout exit code + echo "TIMEOUT" > "$temp_dir/$service" + else + # Other errors (e.g., permission denied) + echo "ERROR" > "$temp_dir/$service" + fi + fi + } & +done + +# Wait for all background jobs to complete before continuing +wait + +# Process each service's result file to identify unreachable ones +for service in "${enabled_services[@]}"; do + result_file="$temp_dir/$service" + if [ -f "$result_file" ]; then + result=$(<"$result_file") + if [[ "$result" == "TIMEOUT" ]]; then + echo "$service API did NOT resolve within ${api_time_out_limit}s. Marking as unreachable." + unreachable_services+=("$service") + elif [[ "$result" == "UNREACHABLE" ]]; then + echo "$service API failed to connect to the endpoint. Marking as unreachable." + unreachable_services+=("$service") + elif [[ "$result" == "OK" ]]; then + echo "$service API is reachable." + else + echo "$service API returned an error (but not a timeout or endpoint reachability failure). Ignored for network check." + fi + else + echo "$service check did not produce a result file. Skipping." + fi +done + +# Cleanup temporary directory +rm -rf "$temp_dir" + +# Write unreachable services to file if any, else write empty string +if (( ${#unreachable_services[@]} > 0 )); then + joined_services=$(IFS=','; echo "${unreachable_services[*]}") + # Add spaces after commas for readability + joined_services_with_spaces=${joined_services//,/,\ } + write_unreachable_services_to_file "$joined_services_with_spaces" + echo "Unreachable AWS Services: ${joined_services_with_spaces}" +else + write_unreachable_services_to_file "" + echo "All required AWS services reachable within ${api_time_out_limit}s" +fi diff --git a/template/v4/v4.6/dirs/etc/sagemaker-ui/project-storage/README.md b/template/v4/v4.6/dirs/etc/sagemaker-ui/project-storage/README.md new file mode 100644 index 000000000..a390943c7 --- /dev/null +++ b/template/v4/v4.6/dirs/etc/sagemaker-ui/project-storage/README.md @@ -0,0 +1,24 @@ +## SageMaker Unified Studio Space + +Welcome to your project space +This is the root folder for your project files. It contains: +- A shared folder for collaborative work +- Your personal local folder for private development + +### Personal local folder +Your personal local folder: +- Includes this root folder and any subfolders (except shared) +- Allows you to work on files privately +- Ideal for frequent file access and modification +- Is visible only in this space + +### Shared folder +The shared folder: +- Contains files visible to all project members +- Is accessible across all your tools +- Updates immediately when any member adds or modifies files +- Not well-suited for heavy file read/write workloads due to remote Amazon S3 origin of this folder and potential additional costs associated with frequent Amazon S3 access +- If two individuals are modifying the same file in this folder at the same time that might result in losing some changes + + +To share your files with other project members, copy or move them to the shared folder when ready. \ No newline at end of file diff --git a/template/v4/v4.6/dirs/etc/sagemaker-ui/project-storage/create-storage-readme.sh b/template/v4/v4.6/dirs/etc/sagemaker-ui/project-storage/create-storage-readme.sh new file mode 100644 index 000000000..14656f209 --- /dev/null +++ b/template/v4/v4.6/dirs/etc/sagemaker-ui/project-storage/create-storage-readme.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +if [ ! -f "$HOME/README.md" ]; then + echo "README file not found in $HOME, creating" + + cat /etc/sagemaker-ui/project-storage/README.md > "$HOME/README.md" +else + echo "README already exists, skipping" +fi + diff --git a/template/v4/v4.6/dirs/etc/sagemaker-ui/sagemaker-mcp/default.json b/template/v4/v4.6/dirs/etc/sagemaker-ui/sagemaker-mcp/default.json new file mode 100644 index 000000000..3ca19641c --- /dev/null +++ b/template/v4/v4.6/dirs/etc/sagemaker-ui/sagemaker-mcp/default.json @@ -0,0 +1,41 @@ +{ + "name": "default-agent", + "version": "1.0.0", + "description": "Default agent configuration", + "mcpServers": {}, + "tools": [ + "fsRead", + "fsWrite", + "fsReplace", + "listDirectory", + "fileSearch", + "executeBash", + "@smus-spark-upgrade", + "@aws-mcp" + ], + "allowedTools": [ + "fsRead", + "fsWrite", + "fsReplace", + "listDirectory", + "fileSearch" + ], + "toolsSettings": { + "execute_bash": { + "alwaysAllow": [ + { + "preset": "readOnly" + } + ] + }, + "use_aws": { + "alwaysAllow": [ + { + "preset": "readOnly" + } + ] + } + }, + "includedFiles": [], + "resources": [] +} diff --git a/template/v4/v4.6/dirs/etc/sagemaker-ui/sagemaker-mcp/mcp.json b/template/v4/v4.6/dirs/etc/sagemaker-ui/sagemaker-mcp/mcp.json new file mode 100644 index 000000000..ec85ba284 --- /dev/null +++ b/template/v4/v4.6/dirs/etc/sagemaker-ui/sagemaker-mcp/mcp.json @@ -0,0 +1,29 @@ +{ + "mcpServers": { + "smus-spark-upgrade": { + "type": "stdio", + "command": "uvx", + "args": [ + "mcp-proxy-for-aws@latest", + "https://sagemaker-unified-studio-mcp.AWS_REGION_NAME.api.aws/spark-upgrade/mcp", + "--service", + "sagemaker-unified-studio-mcp", + "--region", + "AWS_REGION_NAME", + "--read-timeout", + "180" + ], + "timeout": 180000 + }, + "aws-mcp": { + "type": "stdio", + "command": "uvx", + "args": [ + "mcp-proxy-for-aws@1.6.4", + "https://aws-mcp.AWS_MCP_REGION.api.aws/mcp", + "--metadata", + "INSTALL_SOURCE=sagemaker-distribution" + ] + } + } +} diff --git a/template/v4/v4.6/dirs/etc/sagemaker-ui/sagemaker-mcp/smus-mcp.py b/template/v4/v4.6/dirs/etc/sagemaker-ui/sagemaker-mcp/smus-mcp.py new file mode 100644 index 000000000..e37dbae19 --- /dev/null +++ b/template/v4/v4.6/dirs/etc/sagemaker-ui/sagemaker-mcp/smus-mcp.py @@ -0,0 +1,180 @@ +""" +SageMaker Unified Studio Project Context MCP Server in stdio transport. + +""" + +import json +import logging +import os +import re +import time +from typing import Any, Dict + +from mcp.server.fastmcp import FastMCP + +# Configure logging +logging.basicConfig(level=logging.INFO) +logger = logging.getLogger(__name__) + + +class ProjectContext: + """ + A class that encapsulates AWS session, project object, and region. + This class simplifies the common pattern of setting up an AWS session, + extracting credentials, and getting a project. + """ + + def __init__(self): + try: + datazone_domain_id = os.getenv("AmazonDataZoneDomain") + datazone_project_id = os.getenv("AmazonDataZoneProject") + aws_region = os.getenv("AWS_REGION") + if datazone_domain_id and datazone_project_id and aws_region: + self.domain_id = datazone_domain_id + self.project_id = datazone_project_id + self.region = aws_region + else: + with open("/opt/ml/metadata/resource-metadata.json", "r") as metadata_file: + metadata = json.load(metadata_file) + self.domain_id = metadata["AdditionalMetadata"]["DataZoneDomainId"] + self.project_id = metadata["AdditionalMetadata"]["DataZoneProjectId"] + self.region = metadata["AdditionalMetadata"]["DataZoneDomainRegion"] + except Exception as e: + raise RuntimeError(f"Failed to initialize project: {e}") + + if not re.match("^dzd[-_][a-zA-Z0-9_-]{1,36}$", self.domain_id): + raise RuntimeError(f"Invalid domain id") + if not re.match("^[a-zA-Z0-9_-]{1,36}$", self.project_id): + raise RuntimeError(f"Invalid project id") + if not re.match("^[a-z]{2}-[a-z]{4,10}-\\d$", self.region): + raise RuntimeError(f"Invalid region") + + +def safe_get_attr(obj: Any, attr: str, default: Any = None) -> Any: + """Safely get an attribute from an object.""" + if obj is None: + return default + + try: + if hasattr(obj, attr): + value = getattr(obj, attr) + # Handle case where attribute access might throw RuntimeError + if callable(value): + try: + return value() + except (RuntimeError, Exception) as e: + logger.error(f"Error calling attribute {attr}: {e}") + return default + return value + return default + except Exception as e: + logger.error(f"Error getting attribute {attr}: {e}") + return default + + +def create_smus_context_identifiers_response(domain_id: str, project_id: str, region: str) -> str: + + return f"""Selectively use the below parameters only when the parameter is required. + +domain identifier: "{domain_id}" +project identifier: "{project_id}" +region: "{region}" +aws profiles: "DomainExecutionRoleCreds, default" + +Again, include only required parameters. Any extra parameters may cause the API to fail. Stick strictly to the schema.""" + + +def write_log_entry( + operation: str, tool_name: str, error_count: int = 0, domain_id: str = "", latency: float = 0 +) -> None: + """ + Write a log entry to the SageMaker GenAI Jupyter Lab extension log file. + + Args: + operation: The operation being performed + tool_name: The name of the tool being used + error_count: Number of errors (0 for success, 1 for failure) + domain_id: The domain identifier (optional) + latency: Execution latency in milliseconds + """ + try: + log_entry = { + "Operation": operation, + "ToolName": tool_name, + "ErrorCount": error_count, + "DomainId": domain_id, + "Latency": latency, + "_aws": { + "Timestamp": int(time.time() * 1000), + "CloudWatchMetrics": [ + { + "Dimensions": [["Operation"], ["ToolName"]], + "Metrics": [ + {"Name": "ErrorCount", "Unit": "Count"}, + {"Name": "Latency", "Unit": "Milliseconds"}, + ], + "Namespace": "SagemakerGenAIJupyterLab", + } + ], + }, + } + + # Write to log file + log_file_path = "/var/log/studio/sagemaker_genai_jl_ext/sagemaker_genai_jl_extension.log" + os.makedirs(os.path.dirname(log_file_path), exist_ok=True) + with open(log_file_path, "a") as log_file: + log_file.write(json.dumps(log_entry) + "\n") + + except Exception: + # Fail quietly - logging failures shouldn't affect main functionality + pass + + +async def aws_context_provider() -> Dict[str, Any]: + """ + AWS Context Provider - MUST BE CALLED BEFORE ANY use_aws OPERATIONS + + This tool provides essential AWS context parameters that are required by subsequent AWS operations. + It returns configuration details including domain identifiers, project information, and region + settings that would otherwise need to be manually specified with each use_aws call. + + The returned parameters include: + - domain identifier: Unique identifier for the AWS DataZone domain + - project identifier: Identifier for the specific project being worked on + - profile name: Name of the AWS profile to use for credentials + - region: AWS region where operations should be performed + - aws profiles: use the aws profile named DomainExecutionRoleCreds for calling datazone APIs; otherwise use default AWS profile + + Returns: + dict: Parameter context to be used with subsequent use_aws operations + """ + start_time = time.time() + identifiers_response = "" + domain_id = "" + try: + ctx = ProjectContext() + domain_id = safe_get_attr(ctx, "domain_id", "") + project_id = safe_get_attr(ctx, "project_id", "") + region = safe_get_attr(ctx, "region", "") + identifiers_response = create_smus_context_identifiers_response(domain_id, project_id, region) + + latency = (time.time() - start_time) * 1000 + write_log_entry("SMUS-Local-MCP", "aws_context_provider", 0, domain_id, latency) + + return {"response": identifiers_response} + except Exception as e: + logger.error(f"Error providing SMUS context identifiers: {e}") + # Calculate latency and log error + latency = (time.time() - start_time) * 1000 + error_domain_id = domain_id if domain_id else "unable to retrieve domain id" + write_log_entry("SMUS-Local-MCP", "aws_context_provider", 1, error_domain_id, latency) + return {"response": identifiers_response, "error": "Error providing SMUS context identifiers"} + + +if __name__ == "__main__": + mcp: FastMCP = FastMCP("SageMakerUnififedStudio Project Context MCP Server") + + # Register the tools from tools.py + mcp.tool()(aws_context_provider) # use the doc string of the function as description, do not overwrite here. + + mcp.run(transport="stdio") diff --git a/template/v4/v4.6/dirs/etc/sagemaker-ui/sagemaker_ui_post_startup.sh b/template/v4/v4.6/dirs/etc/sagemaker-ui/sagemaker_ui_post_startup.sh new file mode 100755 index 000000000..fb0755eb3 --- /dev/null +++ b/template/v4/v4.6/dirs/etc/sagemaker-ui/sagemaker_ui_post_startup.sh @@ -0,0 +1,509 @@ +#!/bin/bash +set -eux + +# Writes script status to file. This file is read by an IDE extension responsible for dispatching UI post-startup-status to the user. +write_status_to_file() { + local status="$1" + local message="$2" + local file="/tmp/.post-startup-status.json" + + # Check if the file exists, if not, create it + if [ ! -f "$file" ]; then + touch "$file" || { + echo "Failed to create $file" >&2 + return 0 + } + fi + + # Ensure the file is writable + if [ ! -w "$file" ]; then + echo "Error: $file is not writable" >&2 + return 0 + fi + + # Create the JSON object and write to file + jq -n --arg status "$status" --arg message "$message" '{"status":$status,"message":$message}' > "$file" + +} + +# checks if the script status is "in-progress". If so, no errors were detected and it can be marked successful. +write_status_to_file_on_script_complete() { + local file="/tmp/.post-startup-status.json" + local check_key="status" + local check_value="in-progress" + + + if jq -e --arg key "$check_key" --arg value "$check_value" '.[$key] == $value' "$file" > /dev/null; then + write_status_to_file "success" "IDE configured successfully." + echo "Post-startup script completed successfully. Success status written to $file" + else + echo "Skipping writing post-startup script "success" status. An error was detected during execution and written to $file". + fi +} + +write_status_to_file "in-progress" "IDE configuration in progress." + +sourceMetaData=/opt/ml/metadata/resource-metadata.json + +# Extract the required fields from meta data stored in opt/ml/metadata. +dataZoneDomainId=$(jq -r '.AdditionalMetadata.DataZoneDomainId' < $sourceMetaData) +dataZoneUserId=$(jq -r '.AdditionalMetadata.DataZoneUserId' < $sourceMetaData) +dataZoneProjectRepositoryName=$(jq -r '.AdditionalMetadata.DataZoneProjectRepositoryName' < $sourceMetaData) +dataZoneEndPoint=$(jq -r '.AdditionalMetadata.DataZoneEndpoint' < $sourceMetaData) +dataZoneProjectId=$(jq -r '.AdditionalMetadata.DataZoneProjectId' < $sourceMetaData) +dataZoneDomainRegion=$(jq -r '.AdditionalMetadata.DataZoneDomainRegion' < $sourceMetaData) + +# Fetch feature flags from domain landing page +echo "Fetching feature flags from domain..." +python3 /etc/sagemaker-ui/fetch_feature_flags.py || echo "Warning: Failed to fetch feature flags, continuing..." + +set +e + +# Remove the ~/.aws/config file to start clean when space restart +rm -f /home/sagemaker-user/.aws/config +echo "Successfully removed the ~/.aws/config file" + +aws configure set credential_source EcsContainer +echo "Successfully configured default profile" + +# Add region configuration using REGION_NAME environment variable +aws configure set region "${REGION_NAME}" +echo "Successfully configured region to ${REGION_NAME}" + +# add SparkMonitor and Connection Magic entrypoint +NB_USER=sagemaker-user + +config_path=/home/${NB_USER}/.ipython/profile_default/ipython_config.py + +if [ ! -f "$config_path" ] || ! grep -q "sagemaker_studio_dataengineering_sessions" "$config_path"; then + ipython profile create && echo "c.InteractiveShellApp.extensions.extend(['sagemaker_sparkmonitor.kernelextension','sagemaker_studio_dataengineering_sessions.sagemaker_connection_magic'])" >> $config_path + cat << EOT >> "$config_path" +c.Application.logging_config = { + "loggers": { + "": { + "level": "INFO", + # console handler is required to keep the default behavior of jupyter logging. + # https://jupyter-server.readthedocs.io/en/latest/operators/configuring-logging.html + "handlers": ["console"], + }, + }, +} +EOT +fi + +# Check if domain is in express mode by looking for a default IAM connection +if [ ! -z "$dataZoneEndPoint" ]; then + iam_connections=$(aws datazone list-connections --endpoint-url "$dataZoneEndPoint" --domain-identifier "$dataZoneDomainId" --project-identifier "$dataZoneProjectId" --type IAM --name "default.iam" --region "$dataZoneDomainRegion" --query "items" --output json 2>&1) +else + iam_connections=$(aws datazone list-connections --domain-identifier "$dataZoneDomainId" --project-identifier "$dataZoneProjectId" --type IAM --name "default.iam" --region "$dataZoneDomainRegion" --query "items" --output json 2>&1) +fi + +iam_connection_count=$(echo "$iam_connections" | jq -r 'if type == "array" then length else 0 end' 2>/dev/null || echo "0") +if [ "$iam_connection_count" -gt 0 ]; then + is_express_mode="true" +else + is_express_mode="false" +fi + +if [ "$is_express_mode" = "true" ]; then + echo "Domain is in express mode. Using default credentials" + if grep -q "^DOMAIN_MODE=" ~/.bashrc; then + echo "DOMAIN_MODE is defined in the env" + else + echo DOMAIN_MODE="EXPRESS" >> ~/.bashrc + echo readonly DOMAIN_MODE >> ~/.bashrc + fi + # Use default credentials - no additional configuration needed + aws configure set credential_source EcsContainer --profile DomainExecutionRoleCreds + echo "Successfully configured DomainExecutionRoleCreds profile with default credentials" +else + echo "Domain is not in express mode" + if grep -q "^DOMAIN_MODE=" ~/.bashrc; then + echo "DOMAIN_MODE is defined in the env" + else + echo DOMAIN_MODE="NON_EXPRESS" >> ~/.bashrc + echo readonly DOMAIN_MODE >> ~/.bashrc + fi + # Setting this to +x to not log credentials from the response of fetching credentials. + set +x + # Note: The $? check immediately follows the sagemaker-studio command to ensure we're checking its exit status. + # Adding commands between these lines could lead to incorrect error handling. + response=$(timeout 30 sagemaker-studio credentials get-domain-execution-role-credential-in-space --domain-id "$dataZoneDomainId" --profile default) + responseStatus=$? + + set -x + + if [ $responseStatus -ne 0 ]; then + echo "Failed to fetch domain execution role credentials. Will skip adding new credentials profile: DomainExecutionRoleCreds." + write_status_to_file "error" "Network issue detected. Your domain may be using a public subnet, which affects IDE functionality. Please contact your admin." + else + aws configure set credential_process "sagemaker-studio credentials get-domain-execution-role-credential-in-space --domain-id $dataZoneDomainId --profile default" --profile DomainExecutionRoleCreds + echo "Successfully configured DomainExecutionRoleCreds profile" + fi +fi + + +# Run AWS CLI command to get the username from DataZone User Profile. +if [ ! -z "$dataZoneEndPoint" ]; then + response=$( aws datazone get-user-profile --endpoint-url "$dataZoneEndPoint" --domain-identifier "$dataZoneDomainId" --user-identifier "$dataZoneUserId" --region "$dataZoneDomainRegion" ) +else + response=$( aws datazone get-user-profile --domain-identifier "$dataZoneDomainId" --user-identifier "$dataZoneUserId" --region "$dataZoneDomainRegion" ) +fi + +# Extract the Auth Mode from the response. Unified Studio currently supports IAM, SSO and SAML. +auth_mode=$(echo "$response" | jq -r '.type') + +case "$auth_mode" in + "IAM") + # For IAM users - extract IAM ARN from response. Response does not contain username or email. + arn=$(echo "$response" | jq -r '.details.iam.arn') + # Split ARN by / and return the last field + username=$(echo "$arn" | awk -F'/' '{print $NF}') + email="$arn" + # For git identity, use session name if available (matches Git Compute image behavior) + session_name=$(echo "$response" | jq -r '.details.iam.sessionName // empty') + if [ -n "$session_name" ]; then + git_username="$session_name" + else + git_username="$username" + fi + git_email="$git_username" + ;; + "SSO"|"SAML") + # For SSO and SAML user, extract username and email if present in response. + username=$(echo "$response" | jq -r '.details.sso.username') + email=$(echo "$response" | jq -r '.details.sso.email') + # Setting up the email as username if email is not present + if [ -z "$email" ] || [ "$email" = "null" ]; then + email="$username" + fi + git_username="$username" + git_email="$email" + ;; + *) + echo "Unknown authentication mode: $auth_mode" + exit 1 + ;; +esac + +# Checks if the project is using Git or S3 storage +is_s3_storage() { + getProjectDefaultEnvResponse=$(sagemaker-studio project get-project-default-environment --domain-id "$dataZoneDomainId" --project-id "$dataZoneProjectId" --profile DomainExecutionRoleCreds) + gitConnectionArn=$(echo "$getProjectDefaultEnvResponse" | jq -r '.provisionedResources[] | select(.name=="gitConnectionArn") | .value') + codeRepositoryName=$(echo "$getProjectDefaultEnvResponse" | jq -r '.provisionedResources[] | select(.name=="codeRepositoryName") | .value') + + if [ -z "$gitConnectionArn" ] && [ -z "$codeRepositoryName" ]; then + return 0 + else + return 1 + fi +} + +echo "Checking Project Storage Type" + +# Execute once to store the result +is_s3_storage +is_s3_storage_flag=$? # 0 if S3 storage, 1 if Git + +if [ "$is_s3_storage_flag" -eq 0 ]; then + export IS_GIT_PROJECT=false + export SMUS_PROJECT_DIR="$HOME/shared" + echo "Project is using S3 storage, project directory set to: $SMUS_PROJECT_DIR" +else + export IS_GIT_PROJECT=true + export SMUS_PROJECT_DIR="$HOME/src" + echo "Project is using Git storage, project directory set to: $SMUS_PROJECT_DIR" +fi + +if grep -q "^SMUS_PROJECT_DIR=" ~/.bashrc; then + echo "SMUS_PROJECT_DIR is defined in the env" +else + echo SMUS_PROJECT_DIR="$SMUS_PROJECT_DIR" >> ~/.bashrc + echo readonly SMUS_PROJECT_DIR >> ~/.bashrc +fi + +# Write SMUS_PROJECT_DIR to a JSON file to be accessed by JupyterLab Extensions +mkdir -p "$HOME/.config" # Create config directory if it doesn't exist +jq -n \ + --arg smusProjectDirectory "$SMUS_PROJECT_DIR" \ + --arg isGitProject "$IS_GIT_PROJECT" \ + '{ + smusProjectDirectory: $smusProjectDirectory, + isGitProject: ($isGitProject == "true") + }' > "$HOME/.config/smus-storage-metadata.json" + +if [ $is_s3_storage_flag -ne 0 ]; then + # Creating a directory where the repository will be cloned + mkdir -p "$HOME/src" + + echo "Starting execution of Git Cloning script" + bash /etc/sagemaker-ui/git_clone.sh + + # Setting up the Git identity for the user. + git config --global user.email "$git_email" + git config --global user.name "$git_username" + if [ -d "$HOME/shared" ]; then + echo "Git project with /shared folder detected, creating README" + bash /etc/sagemaker-ui/project-storage/create-storage-readme.sh + else + echo "Git project without /shared folder, skipping README creation" + fi +else + # New Git v2 / S3 project: configure credential helper and identity so that + # git push/pull works for repos cloned by the SMUS Git backend into ~/shared/repos/. + git config --global user.email "$git_email" + git config --global user.name "$git_username" + git config --global credential.helper "!aws codecommit credential-helper --ignore-host-check \$@" + git config --global credential.UseHttpPath true + echo "Project is using Non-Git storage, skipping git repository setup and ~/src dir creation and creating README" + bash /etc/sagemaker-ui/project-storage/create-storage-readme.sh +fi + +# MLFlow tracking server uses the LOGNAME environment variable to track identity. Set the LOGNAME to the username of the user associated with the space +export LOGNAME=$username +if grep -q "^LOGNAME=" ~/.bashrc; then + echo "LOGNAME is defined in the env" +else + echo LOGNAME=$username >> ~/.bashrc + echo readonly LOGNAME >> ~/.bashrc +fi + +# Setup Q CLI auth mode +q_settings_file="$HOME/.aws/amazon_q/settings.json" +if [ -f "$q_settings_file" ]; then + q_auth_mode=$(jq -r '.auth_mode' < $q_settings_file) + if [ "$q_auth_mode" == "IAM" ]; then + export AMAZON_Q_SIGV4=true + else + export AMAZON_Q_SIGV4=false + fi +else + export AMAZON_Q_SIGV4=true +fi + +if $AMAZON_Q_SIGV4; then + if grep -q "^export AMAZON_Q_SIGV4=" ~/.bashrc; then + echo "AMAZON_Q_SIGV4 is defined in the env" + else + echo export AMAZON_Q_SIGV4=$AMAZON_Q_SIGV4 >> ~/.bashrc + fi +else + # Remove from .bashrc if it exists + sed -i '/^export AMAZON_Q_SIGV4=/d' ~/.bashrc +fi + +# Setup Q CLI telemetry +if [ "${SAGEMAKER_APP_TYPE_LOWERCASE}" = "jupyterlab" ]; then + q_cli_client_application="SMUS_JUPYTER_LAB" +else + q_cli_client_application="SMUS_CODE_EDITOR" +fi +if [ "$is_express_mode" = "true" ]; then + q_cli_client_application="${q_cli_client_application}_EXPRESS" +fi + +if grep -q "^export Q_CLI_CLIENT_APPLICATION=" ~/.bashrc; then + echo Q_CLI_CLIENT_APPLICATION is defined in the env +else + echo export Q_CLI_CLIENT_APPLICATION=$q_cli_client_application >> ~/.bashrc + echo readonly Q_CLI_CLIENT_APPLICATION >> ~/.bashrc +fi + +# Setup SageMaker MCP configuration +echo "Setting up SageMaker MCP configuration..." +source_file="/etc/sagemaker-ui/sagemaker-mcp/mcp.json" + +# Write MCP config to both qcli and Kiro CLI paths +mkdir -p "$HOME/.aws/amazonq/" "$HOME/.kiro/settings/" +mcp_target_files=( + "$HOME/.aws/amazonq/mcp.json" + "$HOME/.kiro/settings/mcp.json" +) + +if [ -f "$source_file" ]; then + for mcp_target_file in "${mcp_target_files[@]}"; do + if [ -f "$mcp_target_file" ]; then + # Target file exists - merge configurations + echo "Existing MCP configuration found at $mcp_target_file, merging configurations..." + + # Check if it's valid JSON first + if jq empty "$mcp_target_file" 2>/dev/null; then + # Initialize mcpServers object if it doesn't exist + if ! jq -e '.mcpServers' "$mcp_target_file" >/dev/null 2>&1; then + echo "Creating mcpServers object in existing configuration" + jq '. + {"mcpServers":{}}' "$mcp_target_file" > "$mcp_target_file.tmp" + mv "$mcp_target_file.tmp" "$mcp_target_file" + fi + + servers=$(jq '.mcpServers | keys[]' "$source_file" | tr -d '"') + + # Add each server from source to target if it doesn't exist + for server in $servers; do + if ! jq -e ".mcpServers.\"$server\"" "$mcp_target_file" >/dev/null 2>&1; then + server_config=$(jq ".mcpServers.\"$server\"" "$source_file") + jq --arg name "$server" --argjson config "$server_config" \ + '.mcpServers[$name] = $config' "$mcp_target_file" > "$mcp_target_file.tmp" + mv "$mcp_target_file.tmp" "$mcp_target_file" + echo "Added server '$server' to $mcp_target_file" + else + echo "Server '$server' already exists in $mcp_target_file" + fi + done + else + echo "Warning: $mcp_target_file is not valid JSON, replacing with default configuration" + cp "$source_file" "$mcp_target_file" + fi + else + # File doesn't exist, copy our configuration + cp "$source_file" "$mcp_target_file" + echo "Created new MCP configuration at $mcp_target_file" + fi + # Replace AWS_REGION_NAME placeholder with actual region name + echo "Updating MCP configuration with AWS Region $REGION_NAME..." + sed -i "s/AWS_REGION_NAME/$REGION_NAME/g" "$mcp_target_file" + # Replace AWS_MCP_REGION with the appropriate aws-mcp endpoint region + # EU regions use eu-central-1, all others use us-east-1 + case "$REGION_NAME" in + eu-*) AWS_MCP_REGION="eu-central-1" ;; + *) AWS_MCP_REGION="us-east-1" ;; + esac + sed -i "s/AWS_MCP_REGION/$AWS_MCP_REGION/g" "$mcp_target_file" + echo "Successfully added AWS Region $REGION_NAME to $mcp_target_file" + done + echo "Successfully configured MCP for SageMaker" +else + echo "Warning: MCP configuration file not found at $source_file" +fi + +# Migrating MCP configuration to new config file +echo "Migrating MCP configuration to Amazon Q agents..." +target_file="$HOME/.aws/amazonq/mcp.json" +agents_target_file="$HOME/.aws/amazonq/agents/default.json" +agents_source_file="/etc/sagemaker-ui/sagemaker-mcp/default.json" + +if [ -f "$agents_source_file" ]; then + mkdir -p "$HOME/.aws/amazonq/agents/" + + if [ -f "$agents_target_file" ]; then + echo "Existing Amazon Q agents configuration found, merging mcpServers..." + + # Check if target file is valid JSON + if jq empty "$agents_target_file" 2>/dev/null; then + # Initialize mcpServers object if it doesn't exist in target + if ! jq -e '.mcpServers' "$agents_target_file" >/dev/null 2>&1; then + echo "Creating mcpServers object in existing agents configuration" + jq '. + {"mcpServers":{}}' "$agents_target_file" > "$agents_target_file.tmp" + mv "$agents_target_file.tmp" "$agents_target_file" + fi + + # Add servers from source that don't exist in target and update tools + if jq -e '.mcpServers' "$agents_source_file" >/dev/null 2>&1; then + source_server_names=$(jq -r '.mcpServers | keys[]' "$agents_source_file") + + for server_name in $source_server_names; do + if ! jq -e ".mcpServers.\"$server_name\"" "$agents_target_file" >/dev/null 2>&1; then + # Server doesn't exist in target - add it + server_config=$(jq ".mcpServers.\"$server_name\"" "$agents_source_file") + jq --arg name "$server_name" --argjson config "$server_config" \ + '.mcpServers[$name] = $config' "$agents_target_file" > "$agents_target_file.tmp" + mv "$agents_target_file.tmp" "$agents_target_file" + echo "Added server '$server_name' to agents configuration" + + # Check if source has tools that reference this server and add them + server_tool_ref="@$server_name" + if jq -e --arg tool "$server_tool_ref" '.tools | index($tool)' "$agents_source_file" >/dev/null 2>&1; then + # Initialize tools array if it doesn't exist + if ! jq -e '.tools' "$agents_target_file" >/dev/null 2>&1; then + jq '. + {"tools":[]}' "$agents_target_file" > "$agents_target_file.tmp" + mv "$agents_target_file.tmp" "$agents_target_file" + fi + + # Add tool reference if it doesn't exist + if ! jq -e --arg tool "$server_tool_ref" '.tools | index($tool)' "$agents_target_file" >/dev/null 2>&1; then + jq --arg tool "$server_tool_ref" '.tools += [$tool]' "$agents_target_file" > "$agents_target_file.tmp" + mv "$agents_target_file.tmp" "$agents_target_file" + echo "Added tool reference '$server_tool_ref' to agents configuration" + fi + fi + else + echo "Server '$server_name' already exists in configuration, skipping" + fi + done + # Replace AWS_REGION_NAME placeholder with actual region name + echo "Updating MCP configuration with AWS Region $REGION_NAME..." + sed -i "s/AWS_REGION_NAME/$REGION_NAME/g" "$target_file" + # Replace AWS_MCP_REGION with the appropriate aws-mcp endpoint region + # EU regions use eu-central-1, all others use us-east-1 + case "$REGION_NAME" in + eu-*) AWS_MCP_REGION="eu-central-1" ;; + *) AWS_MCP_REGION="us-east-1" ;; + esac + sed -i "s/AWS_MCP_REGION/$AWS_MCP_REGION/g" "$target_file" + echo "Successfully added AWS Region $REGION_NAME to $target_file" + echo "Successfully added missing mcpServers and tools from default.json to agents configuration" + else + echo "No mcpServers found in source configuration" + fi + else + echo "Warning: Existing agents configuration is not valid JSON, replacing with default configuration" + cp "$agents_source_file" "$agents_target_file" + fi + else + cp "$agents_source_file" "$agents_target_file" + echo "Created new Amazon Q agents configuration file" + fi + + echo "Successfully migrated MCP configuration to Amazon Q agents" +else + echo "Warning: Source configuration file not found at $agents_source_file" +fi + +# Generate sagemaker pysdk intelligent default config +nohup python /etc/sagemaker/sm_pysdk_default_config.py & +# Only run the following commands if SAGEMAKER_APP_TYPE_LOWERCASE is jupyterlab and domain is not in express mode +if [ "${SAGEMAKER_APP_TYPE_LOWERCASE}" = "jupyterlab" ] && [ "$is_express_mode" != "true" ]; then + # clean up gen ai debugging file + rm -rf /home/sagemaker-user/src/.temp_sagemaker_unified_studio_debugging_info + + # Create workflows resources (directories, config files, sample DAG) + bash /etc/sagemaker-ui/workflows/create-workflows-resources.sh || echo "Warning: workflows resource creation failed, continuing..." + + # ensure functions inherit traps and fail immediately + set -eE + + # write unexpected error to file if any of the remaining scripts fail. + trap 'write_status_to_file "error" "An unexpected error occurred. Please stop and restart your space to retry."' ERR + + # Install conda and pip dependencies if lib mgmt config existing + bash /etc/sagemaker-ui/libmgmt/install-lib.sh + + # Install sm-spark-cli + bash /etc/sagemaker-ui/workflows/sm-spark-cli-install.sh || echo "Warning: sm-spark-cli installation failed, continuing..." +fi + +# Execute network validation script, to check if any required AWS Services are unreachable +echo "Starting network validation script..." + +network_validation_file="/tmp/.network_validation.json" + +# Run the validation script; only if it succeeds, check unreachable services +if bash /etc/sagemaker-ui/network_validation.sh "$is_s3_storage_flag" "$network_validation_file"; then + # Read unreachable services from JSON file + failed_services=$(jq -r '.UnreachableServices // empty' "$network_validation_file" || echo "") + if [[ -n "$failed_services" ]]; then + # Count number of services by splitting on comma + IFS=',' read -ra failed_array <<< "$failed_services" + count=${#failed_array[@]} + verb="are" + [[ "$count" -eq 1 ]] && verb="is" + + error_message="$failed_services $verb unreachable. Please contact your admin." + # Example error message: Redshift Clusters, Athena, STS, Glue are unreachable. Please contact your admin. + write_status_to_file "error" "$error_message" + echo "$error_message" + fi +else + echo "Warning: network_validation.sh failed, skipping unreachable services check." +fi + +write_status_to_file_on_script_complete diff --git a/template/v4/v4.6/dirs/etc/sagemaker-ui/set_code_editor_theme.sh b/template/v4/v4.6/dirs/etc/sagemaker-ui/set_code_editor_theme.sh new file mode 100755 index 000000000..f295052c5 --- /dev/null +++ b/template/v4/v4.6/dirs/etc/sagemaker-ui/set_code_editor_theme.sh @@ -0,0 +1,23 @@ +#!/bin/bash +set -e + +USER_SETTINGS_FILE="/home/sagemaker-user/sagemaker-code-editor-server-data/data/User/settings.json" +COLOR_THEME_KEY="workbench.colorTheme" +COLOR_THEME_VALUE="Default Dark Modern" + +# Check if the settings file exists +if [ ! -f "$USER_SETTINGS_FILE" ]; then + echo "Code Editor user settings file not found. Creating..." + mkdir -p "$(dirname "$USER_SETTINGS_FILE")" + echo "{}" > "$USER_SETTINGS_FILE" +fi + +EXISTING_COLOR_THEME_VALUE=$(jq -r --arg key "$COLOR_THEME_KEY" '.[$key] // empty' "$USER_SETTINGS_FILE") + +if [[ -n "$EXISTING_COLOR_THEME_VALUE" ]]; then + echo "Theme is already set in user settings as '$EXISTING_COLOR_THEME_VALUE'. No changes made." +else + # Set theme + jq --arg key "$COLOR_THEME_KEY" --arg value "$COLOR_THEME_VALUE" '.[$key] = $value' "$USER_SETTINGS_FILE" > "${USER_SETTINGS_FILE}.tmp" && mv "${USER_SETTINGS_FILE}.tmp" "$USER_SETTINGS_FILE" + echo "Successfully set Code Editor theme to '$COLOR_THEME_VALUE'." +fi diff --git a/template/v4/v4.6/dirs/etc/sagemaker-ui/steering/smus-rules.md b/template/v4/v4.6/dirs/etc/sagemaker-ui/steering/smus-rules.md new file mode 100644 index 000000000..0a7571429 --- /dev/null +++ b/template/v4/v4.6/dirs/etc/sagemaker-ui/steering/smus-rules.md @@ -0,0 +1,169 @@ +--- +inclusion: always +--- +# SageMaker Unified Studio Space Context + +This workspace is running on an Amazon SageMaker Unified Studio Space. + +## Environment +- Operating system: Ubuntu-based SageMaker Distribution +- User: sagemaker-user +- Home directory: /home/sagemaker-user +- AWS credentials are available via the container credentials provider (AWS_CONTAINER_CREDENTIALS_RELATIVE_URI) +- Do NOT hardcode AWS credentials; use the default credential chain (e.g., boto3.Session()) + +## Project Info +- Use `from sagemaker_studio import Project; project = Project()` to discover connections, databases, and compute resources. +- `project.connections()` lists all data connections (Glue, Redshift, Athena, etc.) +- `project.connection("").catalog()` returns databases and tables for a connection. +- Environment variables `SAGEMAKER_SPACE_DOMAIN_ID` and `SAGEMAKER_SPACE_NAME` identify the current project context. + +## Workspace Folders +- The **root folder** (`/home/sagemaker-user/`) and all subfolders (except `/home/sagemaker-user/shared` and `/home/sagemaker-user/src`) are the user's **personal local folder** — private, visible only in this space, ideal for frequent file access. +- The **`shared/`** folder is S3-backed and visible to all project members across all tools. Not suited for heavy read/write workloads due to S3 latency and potential costs. +- The **`/home/sagemaker-user/src`** folder holds git-based projects. It is not automatically synced (unlike the S3-backed `shared/` folder); manage its contents with git. +- To share files with other project members, copy or move them to `shared/` when ready. +- **Do not save sensitive files (credentials, chat logs) to `shared/`** — they would be visible to all project members. + +## Project Library (`sagemaker_studio`) + +The `sagemaker_studio` package is pre-installed and provides access to project resources. + +### Project + +```python +from sagemaker_studio import Project +project = Project() +project.id +project.name +project.iam_role # project IAM role ARN +project.kms_key_arn # project KMS key ARN (if configured) +project.mlflow_tracking_server_arn # MLflow ARN (if configured) +project.s3.root # project S3 root path +``` + +### Connections + +```python +project.connections # list all connections +project.connection() # default IAM connection +project.connection("redshift") # named connection +conn.name, conn.id, conn.iam_role +conn.physical_endpoints[0].host # endpoint host +conn.data # all connection properties +conn.secret # credentials (dict or string) +conn.create_client() # boto3 client with connection credentials +conn.create_client("glue") # boto3 client for specific service +``` + +### Catalogs, Databases, and Tables + +```python +catalog = project.connection().catalog() # default catalog +catalog = project.connection().catalog("catalog_id") +catalog.databases # list databases +db = catalog.database("my_db") +db.tables # list tables +table = db.table("my_table") +table.columns # list columns (name, type) +``` + +### SQL Utilities + +```python +from sagemaker_studio import sqlutils + +# DuckDB (local, no connection needed) +result = sqlutils.sql("SELECT * FROM my_df WHERE id > 1") + +# Athena +result = sqlutils.sql("SELECT * FROM orders", connection_name="project.athena") + +# Redshift +result = sqlutils.sql("SELECT * FROM products", connection_name="project.redshift") + +# Parameterized queries +result = sqlutils.sql( + "SELECT * FROM orders WHERE status = :status", + parameters={"status": "completed"}, + connection_name="project.redshift" +) + +# Get SQLAlchemy engine +engine = sqlutils.get_engine(connection_name="project.redshift") +``` + +### DataFrame Utilities + +```python +from sagemaker_studio import dataframeutils +import pandas as pd + +# Read from catalog table +df = pd.read_catalog_table(database="my_db", table="my_table") + +# Write to catalog table +df.to_catalog_table(database="my_db", table="my_table") + +# S3 Tables catalog +df = pd.read_catalog_table( + database="my_db", table="my_table", + catalog="s3tablescatalog/my_catalog" +) +``` + +### Spark Utilities + +```python +from sagemaker_studio import sparkutils + +# Initialize Spark Connect session +spark = sparkutils.init() +spark = sparkutils.init(connection_name="my_spark_connection") + +# Get Spark options for JDBC connections +options = sparkutils.get_spark_options("my_redshift_connection") +df = spark.read.format("jdbc").options(**options).option("dbtable", "my_table").load() +``` + +## Compute Options +- **Local Python**: Runs directly on the Space instance. Use for single-machine Python, ML, and AI workloads. +- **Apache Spark (AWS Glue / Amazon EMR)**: Use `%%pyspark`, `%%scalaspark`, or `%%sql` cell magics in notebooks. Default Spark connection is `project.spark.compatibility`. +- **SQL (Athena)**: Use `%%sql project.athena` for Trino SQL queries via Amazon Athena. +- **SQL (Redshift)**: Use `%%sql project.redshift` if a Redshift connection is available. + +## Code Patterns +- Use `sagemaker_studio.Project()` for project-aware sessions and resource discovery +- Reference data using S3 URIs in s3://bucket/prefix format +- Write Spark DataFrames to the project catalog: `df.write.saveAsTable(f"{database}.table_name", format='parquet', mode='overwrite')` +- SQL query results are available as DataFrames in subsequent cells via the `_` variable +- Use `sqlutils.sql()` for programmatic SQL execution against any connection +- Use `pd.read_catalog_table()` / `df.to_catalog_table()` for pandas catalog I/O + +## MCP Server Configuration + +MCP servers in this environment may need AWS credentials forwarded from the container. If an MCP tool returns "Unable to locate credentials", add the `env` block to the affected server in MCP server config file: + +```json +{ + "mcpServers": { + "example-server": { + "command": "uvx", + "args": ["example-server@latest"], + "env": { + "AWS_CONTAINER_CREDENTIALS_RELATIVE_URI": "${AWS_CONTAINER_CREDENTIALS_RELATIVE_URI}" + }, + "disabled": false, + "autoApprove": [] + } + } +} +``` + +If you cannot edit the config directly, suggest the user add the `env` block to their MCP server entry in MCP server config. + +## AWS API Safety +- Prefer read/describe/list operations over modify/update/delete operations. +- Always confirm with the user before performing destructive actions (delete, terminate, drop). +- Do NOT call `secretsmanager get-secret-value` or output secrets, credentials, or tokens into chat. +- Before starting a task, check whether a relevant AWS skill is available in ~/.kiro/skills/. Load the skill and prefer its guidance over general knowledge. diff --git a/template/v4/v4.6/dirs/etc/sagemaker-ui/workflows/create-workflows-resources.sh b/template/v4/v4.6/dirs/etc/sagemaker-ui/workflows/create-workflows-resources.sh new file mode 100644 index 000000000..ced1963d7 --- /dev/null +++ b/template/v4/v4.6/dirs/etc/sagemaker-ui/workflows/create-workflows-resources.sh @@ -0,0 +1,95 @@ +#!/bin/bash +set -eu + +# Get project directory based on storage type +PROJECT_DIR=${SMUS_PROJECT_DIR:-"$HOME/src"} +if [ -z "${SMUS_PROJECT_DIR:-}" ]; then + MOUNT_DIR=$PROJECT_DIR +else + MOUNT_DIR=$(readlink -f "$PROJECT_DIR") # get the symlink source +fi + +# Datazone project metadata +RESOURCE_METADATA_FILE=/opt/ml/metadata/resource-metadata.json + +DZ_DOMAIN_ID=$(jq -r '.AdditionalMetadata.DataZoneDomainId' < $RESOURCE_METADATA_FILE) +DZ_PROJECT_ID=$(jq -r '.AdditionalMetadata.DataZoneProjectId' < $RESOURCE_METADATA_FILE) +DZ_ENV_ID=$(jq -r '.AdditionalMetadata.DataZoneEnvironmentId' < $RESOURCE_METADATA_FILE) +DZ_DOMAIN_REGION=$(jq -r '.AdditionalMetadata.DataZoneDomainRegion' < $RESOURCE_METADATA_FILE) +DZ_ENDPOINT=$(jq -r '.AdditionalMetadata.DataZoneEndpoint' < $RESOURCE_METADATA_FILE) +DZ_PROJECT_S3PATH=$(jq -r '.AdditionalMetadata.ProjectS3Path' < $RESOURCE_METADATA_FILE) + +# Workflows paths in JL +WORKFLOW_DAG_PATH="${PROJECT_DIR}/workflows/dags" +WORKFLOW_CONFIG_PATH="${PROJECT_DIR}/workflows/config" +WORKFLOW_DB_DATA_PATH="$HOME/.workflows_setup/db-data" +WORKFLOW_REQUIREMENTS_PATH="$HOME/.workflows_setup/requirements/" +WORKFLOW_PLUGINS_PATH="$HOME/.workflows_setup/plugins" +WORKFLOW_STARTUP_PATH="$HOME/.workflows_setup/startup/" +WORKFLOW_ARTIFACTS_SOURCE_DIR="/etc/sagemaker-ui/workflows" +WORKFLOW_PLUGINS_SOURCE_PATH="${WORKFLOW_ARTIFACTS_SOURCE_DIR}/plugins/*.whl" +WORKFLOW_REQUIREMENTS_SOURCE_PATH="${WORKFLOW_ARTIFACTS_SOURCE_DIR}/requirements/requirements.txt" +WORKFLOW_OUTPUT_PATH="$HOME/jobs" +USER_REQUIREMENTS_FILE="${WORKFLOW_CONFIG_PATH}/requirements.txt" +USER_PLUGINS_FOLDER="${WORKFLOW_CONFIG_PATH}/plugins" +USER_STARTUP_FILE="${WORKFLOW_CONFIG_PATH}/startup.sh" + +# Only proceed if Workflows blueprint is enabled +if [ "$(python /etc/sagemaker-ui/workflows/workflow_client.py check-blueprint --region "$DZ_DOMAIN_REGION" --domain-id "$DZ_DOMAIN_ID" --endpoint "$DZ_ENDPOINT" --project-id "$DZ_PROJECT_ID")" = "False" ]; then + echo "Workflows blueprint is not enabled. Skipping workflows resource creation." + exit 0 +fi + +# Create necessary directories +mkdir -p $WORKFLOW_DAG_PATH +mkdir -p $WORKFLOW_CONFIG_PATH +mkdir -p $WORKFLOW_DB_DATA_PATH +mkdir -p $WORKFLOW_REQUIREMENTS_PATH +mkdir -p $WORKFLOW_PLUGINS_PATH +mkdir -p $WORKFLOW_STARTUP_PATH +mkdir -p $WORKFLOW_OUTPUT_PATH + +# Copy sample dag if it does not exist +cp -n "/etc/sagemaker-ui/workflows/sample_dag.py" "${WORKFLOW_DAG_PATH}/" + +# Create .airflowignore file +cat >>"$WORKFLOW_DAG_PATH/.airflowignore" <<'END' +.ipynb_checkpoints +END + +# Copy plugins from conda +cp $WORKFLOW_PLUGINS_SOURCE_PATH $WORKFLOW_PLUGINS_PATH + +# Copy requirements from conda +cp $WORKFLOW_REQUIREMENTS_SOURCE_PATH $WORKFLOW_REQUIREMENTS_PATH + +# Copy system startup +cp /etc/sagemaker-ui/workflows/startup/startup.sh $WORKFLOW_STARTUP_PATH + +# Append user's custom startup script, if exists +if [ -f $USER_STARTUP_FILE ]; then + tail -n +2 $USER_STARTUP_FILE >> "${WORKFLOW_STARTUP_PATH}startup.sh" +else + # Give the user a template startup script + echo "#!/bin/bash" > "${USER_STARTUP_FILE}" + echo "# Place any special instructions you'd like run during your workflows environment startup here" >> "${USER_STARTUP_FILE}" + echo "# Note that you will need to restart your space for changes to take effect." >> "${USER_STARTUP_FILE}" + echo "# For example:" >> "${USER_STARTUP_FILE}" + echo "# pip install dbt-core" >> "${USER_STARTUP_FILE}" +fi + +# Append user's custom requirements, if exists +if [ -f $USER_REQUIREMENTS_FILE ]; then + cat $USER_REQUIREMENTS_FILE >> "${WORKFLOW_REQUIREMENTS_PATH}requirements.txt" +else + # Give the user a template requirements.txt file + echo "# Place any requirements you'd like included in your workflows environment here" > "${USER_REQUIREMENTS_FILE}" + echo "# Note that you will need to restart your space for changes to take effect." >> "${USER_REQUIREMENTS_FILE}" + echo "# For example:" >> "${USER_REQUIREMENTS_FILE}" + echo "# numpy==1.26.4" >> "${USER_REQUIREMENTS_FILE}" +fi + +# Copy over any user-specified plugins, if they exist +if [ -d $USER_PLUGINS_FOLDER ]; then + cp -r $USER_PLUGINS_FOLDER/* $WORKFLOW_PLUGINS_PATH +fi diff --git a/template/v4/v4.6/dirs/etc/sagemaker-ui/workflows/plugins/amzn_SagemakerWorkflowsOperator-1.0-py3-none-any.whl b/template/v4/v4.6/dirs/etc/sagemaker-ui/workflows/plugins/amzn_SagemakerWorkflowsOperator-1.0-py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..3f14c1ec58eca6c157f982638c536126aac1d168 GIT binary patch literal 23090 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%0Duky0D$#hOKfjzXleJa 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
qtcEl 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 JMgXo7^ncP%7_$HX literal 0 HcmV?d00001 diff --git a/template/v4/v4.6/dirs/etc/sagemaker-ui/workflows/requirements/requirements.txt b/template/v4/v4.6/dirs/etc/sagemaker-ui/workflows/requirements/requirements.txt new file mode 100644 index 000000000..1ce361735 --- /dev/null +++ b/template/v4/v4.6/dirs/etc/sagemaker-ui/workflows/requirements/requirements.txt @@ -0,0 +1,5 @@ +--find-links /usr/local/airflow/plugins +--no-index + +amzn_sagemaker_studio +amzn_SagemakerWorkflowsOperator diff --git a/template/v4/v4.6/dirs/etc/sagemaker-ui/workflows/sample_dag.py b/template/v4/v4.6/dirs/etc/sagemaker-ui/workflows/sample_dag.py new file mode 100644 index 000000000..aa3fc2f14 --- /dev/null +++ b/template/v4/v4.6/dirs/etc/sagemaker-ui/workflows/sample_dag.py @@ -0,0 +1,18 @@ +from airflow.decorators import dag +from airflow.operators.bash import BashOperator + +default_args = { + "owner": "airflow", +} + + +@dag(default_args=default_args, tags=["sample"]) +def sample_dag(): + def sample_task(): + _task = BashOperator(task_id="hello_world", bash_command="echo 'hello world!'") + return _task + + task = sample_task() + + +sample_dag = sample_dag() diff --git a/template/v4/v4.6/dirs/etc/sagemaker-ui/workflows/sm-spark-cli-install.sh b/template/v4/v4.6/dirs/etc/sagemaker-ui/workflows/sm-spark-cli-install.sh new file mode 100755 index 000000000..9b3918e74 --- /dev/null +++ b/template/v4/v4.6/dirs/etc/sagemaker-ui/workflows/sm-spark-cli-install.sh @@ -0,0 +1,18 @@ +#!/bin/bash +RESOURCE_METADATA_FILE=/opt/ml/metadata/resource-metadata.json +DZ_DOMAIN_ID=$(jq -r '.AdditionalMetadata.DataZoneDomainId' < $RESOURCE_METADATA_FILE) +DZ_PROJECT_ID=$(jq -r '.AdditionalMetadata.DataZoneProjectId' < $RESOURCE_METADATA_FILE) +DZ_DOMAIN_REGION=$(jq -r '.AdditionalMetadata.DataZoneDomainRegion' < $RESOURCE_METADATA_FILE) +DZ_ENDPOINT=$(jq -r '.AdditionalMetadata.DataZoneEndpoint' < $RESOURCE_METADATA_FILE) + +# install sm-spark-cli if workflows blueprint is enabled +if [ "$(python /etc/sagemaker-ui/workflows/workflow_client.py check-blueprint --region "$DZ_DOMAIN_REGION" --domain-id "$DZ_DOMAIN_ID" --endpoint "$DZ_ENDPOINT" --project-id "$DZ_PROJECT_ID")" = "True" ]; then + echo "Workflows blueprint is enabled. Installing sm-spark-cli." + # install sm-spark-cli + sudo curl -LO https://github.com/aws-samples/amazon-sagemaker-spark-ui/releases/download/v0.9.1/amazon-sagemaker-spark-ui.tar.gz && \ + sudo tar -xvzf amazon-sagemaker-spark-ui.tar.gz && \ + sudo chmod +x amazon-sagemaker-spark-ui/install-scripts/studio/install-history-server.sh && \ + sudo amazon-sagemaker-spark-ui/install-scripts/studio/install-history-server.sh && \ + rm -rf ~/.m2 && \ + sudo rm -rf amazon-sagemaker-spark-ui* +fi \ No newline at end of file diff --git a/template/v4/v4.6/dirs/etc/sagemaker-ui/workflows/sm_init_script.sh b/template/v4/v4.6/dirs/etc/sagemaker-ui/workflows/sm_init_script.sh new file mode 100755 index 000000000..57a4616fa --- /dev/null +++ b/template/v4/v4.6/dirs/etc/sagemaker-ui/workflows/sm_init_script.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +# Create a default aws profile in SM training container +aws configure set credential_source EcsContainer + +# Create a default ipython profile and load extensions in SM processing container +NB_USER=sagemaker-user +config_path=/home/${NB_USER}/.ipython/profile_default/ipython_config.py +# SparkMonitor Widget and Connection Magic - create entrypoint +if [ ! -f "$config_path" ] || ! grep -q "sagemaker_studio_dataengineering_sessions" "$config_path"; then + ipython profile create && echo "c.InteractiveShellApp.extensions.extend(['sagemaker_sparkmonitor.kernelextension','sagemaker_studio_dataengineering_sessions.sagemaker_connection_magic'])" >> $config_path + cat << EOT >> "$config_path" +c.Application.logging_config = { + "loggers": { + "": { + "level": "INFO", + # console handler is required to keep the default behavior of jupyter logging. + # https://jupyter-server.readthedocs.io/en/latest/operators/configuring-logging.html + "handlers": ["console"], + }, + }, +} +EOT +fi \ No newline at end of file diff --git a/template/v4/v4.6/dirs/etc/sagemaker-ui/workflows/startup/startup.sh b/template/v4/v4.6/dirs/etc/sagemaker-ui/workflows/startup/startup.sh new file mode 100755 index 000000000..1a2485251 --- /dev/null +++ b/template/v4/v4.6/dirs/etc/sagemaker-ui/workflows/startup/startup.sh @@ -0,0 +1 @@ +#!/bin/sh diff --git a/template/v4/v4.6/dirs/etc/sagemaker-ui/workflows/workflow_client.py b/template/v4/v4.6/dirs/etc/sagemaker-ui/workflows/workflow_client.py new file mode 100644 index 000000000..5c47e9536 --- /dev/null +++ b/template/v4/v4.6/dirs/etc/sagemaker-ui/workflows/workflow_client.py @@ -0,0 +1,77 @@ +import argparse + +import boto3 + + +def check_blueprint(region: str, domain_id: str, endpoint: str, project_id: str, **kwargs): + DZ_CLIENT = boto3.client("datazone") + # add correct endpoint for gamma env + if endpoint != "": + DZ_CLIENT = boto3.client("datazone", endpoint_url=endpoint) + try: + # check if workflows blueprint is enabled in project profile + project_profile_id = DZ_CLIENT.get_project(domainIdentifier=domain_id, identifier=project_id)[ + "projectProfileId" + ] + project_blueprints = DZ_CLIENT.get_project_profile(domainIdentifier=domain_id, identifier=project_profile_id)[ + "environmentConfigurations" + ] + proj_blueprint_ids = [proj_env_config["environmentBlueprintId"] for proj_env_config in project_blueprints] + blueprint_id = DZ_CLIENT.list_environment_blueprints( + managed=True, domainIdentifier=domain_id, name="Workflows" + )["items"][0]["id"] + + if blueprint_id in proj_blueprint_ids: + blueprint_config = DZ_CLIENT.get_environment_blueprint_configuration( + domainIdentifier=domain_id, environmentBlueprintIdentifier=blueprint_id + ) + enabled_regions = blueprint_config["enabledRegions"] + print(str(region in enabled_regions)) + else: + print("False") + except: + # fallback to checking if only workflows blueprint exists + try: + blueprint_id = DZ_CLIENT.list_environment_blueprints( + managed=True, domainIdentifier=domain_id, name="Workflows" + )["items"][0]["id"] + blueprint_config = DZ_CLIENT.get_environment_blueprint_configuration( + domainIdentifier=domain_id, environmentBlueprintIdentifier=blueprint_id + ) + enabled_regions = blueprint_config["enabledRegions"] + print(str(region in enabled_regions)) + except: + print("False") + + +COMMAND_REGISTRY = { + "check-blueprint": check_blueprint, +} + + +def main(): + parser = argparse.ArgumentParser(description="Workflow blueprint checker") + subparsers = parser.add_subparsers(dest="command", help="Available commands") + + check_blueprint_parser = subparsers.add_parser("check-blueprint", help="Check Workflows blueprint") + check_blueprint_parser.add_argument( + "--domain-id", type=str, required=True, help="Datazone Domain ID for blueprint check" + ) + check_blueprint_parser.add_argument("--region", type=str, required=True, help="Datazone Domain region") + check_blueprint_parser.add_argument( + "--endpoint", type=str, required=True, help="Datazone endpoint for blueprint check" + ) + check_blueprint_parser.add_argument( + "--project-id", type=str, required=True, help="Datazone Project ID for blueprint check" + ) + + args = parser.parse_args() + + if args.command in COMMAND_REGISTRY: + COMMAND_REGISTRY[args.command](**vars(args)) + else: + parser.print_help() + + +if __name__ == "__main__": + main() diff --git a/template/v4/v4.6/dirs/etc/sagemaker/jupyter/lab/settings/overrides.json b/template/v4/v4.6/dirs/etc/sagemaker/jupyter/lab/settings/overrides.json new file mode 100644 index 000000000..18624c313 --- /dev/null +++ b/template/v4/v4.6/dirs/etc/sagemaker/jupyter/lab/settings/overrides.json @@ -0,0 +1,14 @@ +{ + "@jupyterlab/application-extension:shell": { + "layout": { + "multiple": { + "JupyterlabChat:sidepanel": { + "area": "right" + } + } + } + }, + "@jupyterlab/filebrowser-extension:browser": { + "showHiddenFiles": true + } +} diff --git a/template/v4/v4.6/dirs/etc/sagemaker/jupyter/private/jupyter_server_config.d/zzz_disable_rtc.json b/template/v4/v4.6/dirs/etc/sagemaker/jupyter/private/jupyter_server_config.d/zzz_disable_rtc.json new file mode 100644 index 000000000..2d04be3c0 --- /dev/null +++ b/template/v4/v4.6/dirs/etc/sagemaker/jupyter/private/jupyter_server_config.d/zzz_disable_rtc.json @@ -0,0 +1,7 @@ +{ + "ServerApp": { + "jpserver_extensions": { + "jupyter_server_ydoc": false + } + } +} diff --git a/template/v4/v4.6/dirs/etc/sagemaker/jupyter/private/labconfig/page_config.json b/template/v4/v4.6/dirs/etc/sagemaker/jupyter/private/labconfig/page_config.json new file mode 100644 index 000000000..4b9346564 --- /dev/null +++ b/template/v4/v4.6/dirs/etc/sagemaker/jupyter/private/labconfig/page_config.json @@ -0,0 +1,6 @@ +{ + "disabledExtensions": { + "@jupyter/collaboration-extension": true, + "@jupyter/docprovider-extension": true + } +} diff --git a/template/v4/v4.6/dirs/etc/sagemaker/jupyter/server/jupyter_server_config.d/zzz_sagemaker_overrides.json b/template/v4/v4.6/dirs/etc/sagemaker/jupyter/server/jupyter_server_config.d/zzz_sagemaker_overrides.json new file mode 100644 index 000000000..f7496322d --- /dev/null +++ b/template/v4/v4.6/dirs/etc/sagemaker/jupyter/server/jupyter_server_config.d/zzz_sagemaker_overrides.json @@ -0,0 +1,10 @@ +{ + "ServerApp": { + "jpserver_extensions": { + "sagemaker_studio_jupyter_scheduler": false, + "sagemaker_jupyter_server_extension": false, + "panel.io.jupyter_server_extension": false, + "sagemaker_gen_ai_jupyterlab_extension": false + } + } +} diff --git a/template/v4/v4.6/dirs/etc/sagemaker/jupyter/shared/jupyter_server_config.d/zzz_disable_jai.json b/template/v4/v4.6/dirs/etc/sagemaker/jupyter/shared/jupyter_server_config.d/zzz_disable_jai.json new file mode 100644 index 000000000..82847e3be --- /dev/null +++ b/template/v4/v4.6/dirs/etc/sagemaker/jupyter/shared/jupyter_server_config.d/zzz_disable_jai.json @@ -0,0 +1,16 @@ +{ + "ServerApp": { + "jpserver_extensions": { + "jupyter_ai": false, + "jupyter_ai_acp_client": false, + "jupyter_ai_tools": false, + "jupyter_ai_persona_manager": false, + "jupyter_ai_router": false, + "jupyter_ai_chat_commands": false, + "jupyter_server_mcp": false, + "jupyterlab_chat": false, + "jupyterlab_commands_toolkit": false, + "jupyter_live_content": false + } + } +} diff --git a/template/v4/v4.6/dirs/etc/sagemaker/jupyter/shared/labconfig/page_config.json b/template/v4/v4.6/dirs/etc/sagemaker/jupyter/shared/labconfig/page_config.json new file mode 100644 index 000000000..bd8d3ab4c --- /dev/null +++ b/template/v4/v4.6/dirs/etc/sagemaker/jupyter/shared/labconfig/page_config.json @@ -0,0 +1,14 @@ +{ + "disabledExtensions": { + "jupyterlab-chat-extension": true, + "@jupyter-ai/router": true, + "@jupyter-ai/persona-manager": true, + "@jupyter-ai/acp-client": true, + "@jupyter-ai/chat-commands": true, + "jupyterlab-commands-toolkit": true, + "jupyterlab-ai-commands": true, + "@jupyter-ai-contrib/live-content": true, + "jupyterlab-diff": true, + "jupyterlab-cell-input-footer-extension": true + } +} diff --git a/template/v4/v4.6/dirs/etc/sagemaker/sagemaker-default-agent.json b/template/v4/v4.6/dirs/etc/sagemaker/sagemaker-default-agent.json new file mode 100644 index 000000000..63c59fe9f --- /dev/null +++ b/template/v4/v4.6/dirs/etc/sagemaker/sagemaker-default-agent.json @@ -0,0 +1,23 @@ +{ + "name": "sagemaker_default", + "description": "SageMaker AI assistant with pre-installed skills for model customization, evaluation, deployment, and HyperPod operations.", + "prompt": "You are a specialized AI assistant for Amazon SageMaker Studio. You can help with general purpose tasks, but you also have expertise in SageMaker workflows and skills.", + "mcpServers": {}, + "tools": ["*"], + "toolAliases": {}, + "allowedTools": [ + "@jupyter_mcp_server/read_notebook", + "@jupyter_mcp_server/read_notebook_cells", + "@jupyter_mcp_server/read_cell", + "@jupyter_mcp_server/get_cell_id_from_index", + "@jupyter_mcp_server/open_file", + "@jupyter_mcp_server/select_cell", + "@jupyter_mcp_server/get_active_notebook", + "@jupyter_mcp_server/get_active_cell_id", + "@jupyter_mcp_server/get_open_documents" + ], + "resources": ["skill://.kiro/skills/**/SKILL.md"], + "hooks": {}, + "toolsSettings": {}, + "includeMcpJson": true +} diff --git a/template/v4/v4.6/dirs/etc/sagemaker/skills/clone_skills.sh b/template/v4/v4.6/dirs/etc/sagemaker/skills/clone_skills.sh new file mode 100755 index 000000000..d531ca5f4 --- /dev/null +++ b/template/v4/v4.6/dirs/etc/sagemaker/skills/clone_skills.sh @@ -0,0 +1,18 @@ +#!/bin/bash +# Clones skills from repos listed in skills-manifest.json during Docker build. +set -eu + +MANIFEST="/etc/sagemaker/skills/skills-manifest.json" +DEST="/etc/sagemaker/skills" + +jq -c '.[]' "$MANIFEST" | while read -r entry; do + repo=$(echo "$entry" | jq -r '.repo') + spath=$(echo "$entry" | jq -r '.path') + skill_name=$(basename "$spath") + git clone --depth 1 "$repo" /tmp/skill-repo + # Copy the skill directory itself into DEST. Clear any pre-existing target + # first so a repeat copy can't nest it as DEST//. + rm -rf "${DEST:?}/$skill_name" + cp -r "/tmp/skill-repo/$spath" "$DEST/" + rm -rf /tmp/skill-repo +done diff --git a/template/v4/v4.6/dirs/etc/sagemaker/skills/skills-manifest.json b/template/v4/v4.6/dirs/etc/sagemaker/skills/skills-manifest.json new file mode 100644 index 000000000..46bb5c898 --- /dev/null +++ b/template/v4/v4.6/dirs/etc/sagemaker/skills/skills-manifest.json @@ -0,0 +1,6 @@ +[ + { + "repo": "https://github.com/aws/agent-toolkit-for-aws.git", + "path": "plugins/aws-core/skills/aws-ai-ml" + } +] diff --git a/template/v4/v4.6/dirs/etc/sagemaker/skills/sync_skills.sh b/template/v4/v4.6/dirs/etc/sagemaker/skills/sync_skills.sh new file mode 100755 index 000000000..a91087d20 --- /dev/null +++ b/template/v4/v4.6/dirs/etc/sagemaker/skills/sync_skills.sh @@ -0,0 +1,174 @@ +#!/bin/bash +# Syncs pre-packaged SageMaker skills from image to user's EBS. +set -eu + +IMAGE_SKILLS_DIR="${1:-/etc/sagemaker/skills}" +EBS_SKILLS_DIR="$HOME/.agent/skills" +LOCK_FILE="$EBS_SKILLS_DIR/.sagemaker-lock" + +# Agent targets to symlink skills into (add new agents here) +AGENT_SKILLS_DIRS=("$HOME/.kiro/skills" "$HOME/.claude/skills") + +compute_checksum() { + (cd "$1" && find . -type f -print0 | sort -z | xargs -0 sha256sum | sha256sum | awk '{print $1}') +} + +get_locked_checksum() { + [ -f "$LOCK_FILE" ] && jq -r --arg s "$1" '.skills[$s].checksum // empty' "$LOCK_FILE" 2>/dev/null +} + +set_locked_checksum() { + [ -f "$LOCK_FILE" ] || echo '{"skills":{}}' > "$LOCK_FILE" + jq --arg s "$1" --arg c "$2" '.skills[$s].checksum = $c' "$LOCK_FILE" > "$LOCK_FILE.tmp" + mv "$LOCK_FILE.tmp" "$LOCK_FILE" +} + +# Migration to the unified agent-toolkit-for-aws skills. +TOOLKIT_SOURCE="agent-toolkit-for-aws" + +get_lock_source() { + [ -f "$LOCK_FILE" ] || return 0 + jq -r '.source // empty' "$LOCK_FILE" 2>/dev/null || true +} + +set_lock_source() { + [ -f "$LOCK_FILE" ] || echo '{"skills":{}}' > "$LOCK_FILE" + jq --arg v "$1" '.source = $v' "$LOCK_FILE" > "$LOCK_FILE.tmp" + mv "$LOCK_FILE.tmp" "$LOCK_FILE" +} + +# List skill names recorded in the lock (the old agent-plugins skills). +list_locked_skills() { + [ -f "$LOCK_FILE" ] || return 0 + jq -r '.skills | keys[]' "$LOCK_FILE" 2>/dev/null || true +} + +# Remove a agent-plugins skill from EBS, its agent symlinks, and the lock entry. +remove_managed_skill() { + local name="$1" + local ebs_skill="$EBS_SKILLS_DIR/$name" + for agent_dir in "${AGENT_SKILLS_DIRS[@]}"; do + local link="$agent_dir/$name" + # Only remove the symlink if it still points at the EBS copy we manage, + # so a symlink the user re-pointed elsewhere is left alone. + if [ -L "$link" ] && [ "$(readlink "$link")" = "$ebs_skill" ]; then + rm -f "$link" + fi + done + rm -rf "$ebs_skill" + if [ -f "$LOCK_FILE" ]; then + jq --arg s "$name" 'del(.skills[$s])' "$LOCK_FILE" > "$LOCK_FILE.tmp" + mv "$LOCK_FILE.tmp" "$LOCK_FILE" + fi +} + +# Returns 0 (clean) if every lock-named skill still matches its recorded +# checksum (a missing EBS folder counts as clean); 1 if any was modified. +managed_skills_are_clean() { + local name recorded current + while IFS= read -r name; do + [ -n "$name" ] || continue + local ebs_skill="$EBS_SKILLS_DIR/$name" + [ -d "$ebs_skill" ] || continue # missing == not user-modified + recorded=$(get_locked_checksum "$name") + current=$(compute_checksum "$ebs_skill") + [ "$current" = "$recorded" ] || return 1 + done < <(list_locked_skills) + return 0 +} + +# Run the one-time migration. Sets MIGRATION_BLOCKS_SYNC=1 when the normal sync +# loop must be skipped, leaves it 0 otherwise. +MIGRATION_BLOCKS_SYNC=0 +STAMP_SOURCE_AFTER_SYNC=0 +run_migration() { + local current_source + current_source=$(get_lock_source) + + # Already migrated; normal loop maintains the unified skill. + if [ "$current_source" = "$TOOLKIT_SOURCE" ]; then + return 0 + fi + + # No managed skills recorded (or nothing to migrate). + # Fall through to the normal loop to install the unified skill, and stamp + # source afterwards so future runs short-circuit. + if [ -z "$(list_locked_skills)" ]; then + STAMP_SOURCE_AFTER_SYNC=1 + return 0 + fi + + # Existing legacy user: gate on whether they modified any managed skill. + if managed_skills_are_clean; then + local name + while IFS= read -r name; do + [ -n "$name" ] || continue + remove_managed_skill "$name" + echo "Migration: removed old skill '$name'" + done < <(list_locked_skills) + STAMP_SOURCE_AFTER_SYNC=1 + else + echo "Migration: user-modified skills detected; keeping existing skills, skipping unified skills." + MIGRATION_BLOCKS_SYNC=1 + fi + return 0 +} + +mkdir -p "$EBS_SKILLS_DIR" +for dir in "${AGENT_SKILLS_DIRS[@]}"; do mkdir -p "$dir"; done + +if [ ! -d "$IMAGE_SKILLS_DIR" ]; then + echo "No bundled skills found at $IMAGE_SKILLS_DIR, skipping." + exit 0 +fi + +run_migration +if [ "$MIGRATION_BLOCKS_SYNC" -eq 1 ]; then + echo "Skills sync complete." + exit 0 +fi + +for skill_path in "$IMAGE_SKILLS_DIR"/*/; do + [ -d "$skill_path" ] || continue + skill_name=$(basename "$skill_path") + ebs_skill="$EBS_SKILLS_DIR/$skill_name" + image_checksum=$(compute_checksum "$skill_path") + + if [ ! -d "$ebs_skill" ]; then + cp -r "$skill_path" "$ebs_skill" + set_locked_checksum "$skill_name" "$image_checksum" + echo "Installed skill '$skill_name'" + else + recorded_checksum=$(get_locked_checksum "$skill_name") + current_checksum=$(compute_checksum "$ebs_skill") + + if [ "$current_checksum" = "$recorded_checksum" ]; then + if [ "$image_checksum" != "$recorded_checksum" ]; then + rm -rf "$ebs_skill" + cp -r "$skill_path" "$ebs_skill" + set_locked_checksum "$skill_name" "$image_checksum" + echo "Updated skill '$skill_name'" + else + echo "Skill '$skill_name' already current, skipping" + fi + else + echo "Skipping skill '$skill_name' — user modified" + fi + fi + + # Create symlinks for all agent targets + for agent_dir in "${AGENT_SKILLS_DIRS[@]}"; do + link="$agent_dir/$skill_name" + if [ ! -e "$link" ]; then + ln -s "$ebs_skill" "$link" + echo "Created symlink $link -> $ebs_skill" + fi + done +done + +if [ "$STAMP_SOURCE_AFTER_SYNC" -eq 1 ]; then + set_lock_source "$TOOLKIT_SOURCE" + echo "Migration: stamped source=$TOOLKIT_SOURCE" +fi + +echo "Skills sync complete." diff --git a/template/v4/v4.6/dirs/etc/sagemaker/sm_pysdk_default_config.py b/template/v4/v4.6/dirs/etc/sagemaker/sm_pysdk_default_config.py new file mode 100644 index 000000000..9a56bd81d --- /dev/null +++ b/template/v4/v4.6/dirs/etc/sagemaker/sm_pysdk_default_config.py @@ -0,0 +1,113 @@ +import json +import os +import re + +import yaml + + +def generate_intelligent_default_config(metadata: str) -> dict: + has_vpc = ( + metadata["SecurityGroupIds"] + and metadata["Subnets"] + and metadata["SecurityGroupIds"] != [""] + and metadata["Subnets"] != [""] + ) + vpc_config = {"SecurityGroupIds": metadata["SecurityGroupIds"], "Subnets": metadata["Subnets"]} if has_vpc else None + + config = { + "SchemaVersion": "1.0", + "SageMaker": { + "PythonSDK": { + "Modules": { + "Session": { + "DefaultS3Bucket": metadata["S3Bucket"], + "DefaultS3ObjectKeyPrefix": metadata["S3ObjectKeyPrefix"], + }, + "RemoteFunction": { + "IncludeLocalWorkDir": True, + }, + "NotebookJob": { + "RoleArn": metadata["UserRoleArn"], + "S3RootUri": f"s3://{metadata['S3Bucket']}/{metadata['S3ObjectKeyPrefix']}", + }, + "Serve": {"S3ModelDataUri": f"s3://{metadata['S3Bucket']}/{metadata['S3ObjectKeyPrefix']}"}, + } + }, + "Pipeline": {"RoleArn": metadata["UserRoleArn"]}, + "Model": {"ExecutionRoleArn": metadata["UserRoleArn"]}, + "ModelPackage": {"ValidationSpecification": {"ValidationRole": metadata["UserRoleArn"]}}, + "ProcessingJob": {"RoleArn": metadata["UserRoleArn"]}, + "TrainingJob": { + "RoleArn": metadata["UserRoleArn"], + "Environment": { + "BOTOCORE_EXPERIMENTAL__PLUGINS": "S3AccessGrantsPlugin=aws_s3_access_grants_boto3_plugin.s3_access_grants_plugin" + }, + }, + }, + } + + if has_vpc: + config["SageMaker"]["PythonSDK"]["Modules"]["RemoteFunction"]["VpcConfig"] = vpc_config + config["SageMaker"]["PythonSDK"]["Modules"]["NotebookJob"]["VpcConfig"] = vpc_config + config["SageMaker"]["MonitoringSchedule"] = { + "MonitoringScheduleConfig": {"MonitoringJobDefinition": {"NetworkConfig": {"VpcConfig": vpc_config}}} + } + config["SageMaker"]["AutoMLJob"] = {"AutoMLJobConfig": {"SecurityConfig": {"VpcConfig": vpc_config}}} + config["SageMaker"]["AutoMLJobV2"] = {"SecurityConfig": {"VpcConfig": vpc_config}} + config["SageMaker"]["CompilationJob"] = {"VpcConfig": vpc_config} + config["SageMaker"]["Model"]["VpcConfig"] = vpc_config + config["SageMaker"]["ProcessingJob"]["NetworkConfig"] = {"VpcConfig": vpc_config} + config["SageMaker"]["TrainingJob"]["VpcConfig"] = vpc_config + + return config + + +if __name__ == "__main__": + try: + config = {} + resource_metadata = "/opt/ml/metadata/resource-metadata.json" + + PROJECT_S3_PATH = "ProjectS3Path" + SECURITY_GROUP = "SecurityGroup" + PRIVATE_SUBNETS = "PrivateSubnets" + META_DATA = "AdditionalMetadata" + EXECUTION_ROLE_ARN = "ExecutionRoleArn" + CONFIG_FILE_NAME = "config.yaml" + CONFIG_DIR = "/etc/xdg/sagemaker/" + + if os.path.exists(resource_metadata): + with open(resource_metadata, "r") as file: + data = json.load(file) + + s3_path = data[META_DATA].get(PROJECT_S3_PATH, "") + metadata = { + # user provided bucket + "S3Bucket": re.search(r"s3://([^/]+)/", s3_path).group(1), + # ${datazoneEnvironmentDomainId}/${datazoneEnvironmentProjectId}/${datazoneScopeName}/ + "S3ObjectKeyPrefix": s3_path.split("//")[1].split("/", 1)[1], + # TODO: Is this a billing concern if set default + # 'InstanceType': 'ml.m5.xlarge', + "SecurityGroupIds": data[META_DATA].get(SECURITY_GROUP, "").split(","), + "Subnets": data[META_DATA].get(PRIVATE_SUBNETS, "").split(","), + "UserRoleArn": data[EXECUTION_ROLE_ARN], + } + + # Not create config file when invalid value exists in metadata + empty_values = [ + key + for key, value in metadata.items() + if key not in ["SecurityGroupIds", "Subnets"] and (value == "" or value == [""]) + ] + if empty_values: + raise AttributeError(f"There are empty values in the metadata: {empty_values}") + + config = generate_intelligent_default_config(metadata) + else: + raise FileNotFoundError("No resource-metadata.json exists on host!") + + # Write the config YAML file to default location of the admin config file + with open(os.path.join(CONFIG_DIR, CONFIG_FILE_NAME), "w") as f: + yaml.dump(config, f, default_flow_style=False, sort_keys=False) + + except Exception as e: + print(f"Error: {e}, SageMaker PySDK intelligent config file is not valid!") diff --git a/template/v4/v4.6/dirs/etc/sagemaker/sync_agent.sh b/template/v4/v4.6/dirs/etc/sagemaker/sync_agent.sh new file mode 100755 index 000000000..348a38a55 --- /dev/null +++ b/template/v4/v4.6/dirs/etc/sagemaker/sync_agent.sh @@ -0,0 +1,23 @@ +#!/bin/bash +# Syncs agent config (subagent, default agent settings) for SMAI spaces. +set -eu + +AGENT_CONFIG_SRC="/etc/sagemaker/sagemaker-default-agent.json" +AGENT_CONFIG_DST="$HOME/.kiro/agents/sagemaker-default-agent.json" +KIRO_CLI_SETTINGS="$HOME/.kiro/settings/cli.json" + +# Install subagent config (always overwrite) +mkdir -p "$HOME/.kiro/agents" +cp "$AGENT_CONFIG_SRC" "$AGENT_CONFIG_DST" +echo "Installed agent config to $AGENT_CONFIG_DST" + +# Set default agent only if user hasn't configured one +mkdir -p "$HOME/.kiro/settings" +if [ ! -f "$KIRO_CLI_SETTINGS" ]; then + echo '{"chat.defaultAgent":"sagemaker_default"}' > "$KIRO_CLI_SETTINGS" + echo "Created default agent settings" +elif ! jq -e '."chat.defaultAgent"' "$KIRO_CLI_SETTINGS" >/dev/null 2>&1; then + jq '. + {"chat.defaultAgent":"sagemaker_default"}' "$KIRO_CLI_SETTINGS" > "$KIRO_CLI_SETTINGS.tmp" + mv "$KIRO_CLI_SETTINGS.tmp" "$KIRO_CLI_SETTINGS" + echo "Added default agent to existing settings" +fi diff --git a/template/v4/v4.6/dirs/etc/supervisor/conf.d/supervisord-code-editor.conf b/template/v4/v4.6/dirs/etc/supervisor/conf.d/supervisord-code-editor.conf new file mode 100644 index 000000000..58e187d02 --- /dev/null +++ b/template/v4/v4.6/dirs/etc/supervisor/conf.d/supervisord-code-editor.conf @@ -0,0 +1,12 @@ +[include] +files = supervisord-common.conf + +[program:codeeditorserver] +directory=%(ENV_HOME)s +command=start-code-editor +autostart=true +autorestart=true +stdout_logfile=/dev/fd/1 ; Redirect web server logs to stdout +stderr_logfile=/dev/fd/1 +stdout_logfile_maxbytes = 0 ; Fix: https://github.com/Supervisor/supervisor/issues/935 +stderr_logfile_maxbytes = 0 ; Fix: https://github.com/Supervisor/supervisor/issues/935 diff --git a/template/v4/v4.6/dirs/etc/supervisor/conf.d/supervisord-common.conf b/template/v4/v4.6/dirs/etc/supervisor/conf.d/supervisord-common.conf new file mode 100644 index 000000000..27820d4c4 --- /dev/null +++ b/template/v4/v4.6/dirs/etc/supervisor/conf.d/supervisord-common.conf @@ -0,0 +1,18 @@ +[supervisord] +nodaemon=true + +pidfile=/var/run/supervisord/supervisord.pid +logfile=%(ENV_STUDIO_LOGGING_DIR)s/%(ENV_SAGEMAKER_APP_TYPE_LOWERCASE)s/supervisord/supervisord.log +logfile_maxbytes=5MB +logfile_backups=10 +redirect_stderr=true + +[unix_http_server] +file=/var/run/supervisord/supervisor.sock +chmod=0700 + +[supervisorctl] +serverurl=unix:///var/run/supervisord/supervisor.sock + +[rpcinterface:supervisor] +supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface diff --git a/template/v4/v4.6/dirs/etc/supervisor/conf.d/supervisord-jupyter-lab.conf b/template/v4/v4.6/dirs/etc/supervisor/conf.d/supervisord-jupyter-lab.conf new file mode 100644 index 000000000..5694ac116 --- /dev/null +++ b/template/v4/v4.6/dirs/etc/supervisor/conf.d/supervisord-jupyter-lab.conf @@ -0,0 +1,11 @@ +[include] +files = supervisord-common.conf + +[program:jupyterlabserver] +directory=%(ENV_HOME)s +command=start-jupyter-server +stopasgroup=true +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 diff --git a/template/v4/v4.6/dirs/etc/supervisor/conf.d/supervisord-sagemaker-ui-code-editor.conf b/template/v4/v4.6/dirs/etc/supervisor/conf.d/supervisord-sagemaker-ui-code-editor.conf new file mode 100644 index 000000000..41dec7fe1 --- /dev/null +++ b/template/v4/v4.6/dirs/etc/supervisor/conf.d/supervisord-sagemaker-ui-code-editor.conf @@ -0,0 +1,28 @@ +[supervisord] +nodaemon=true + +pidfile=/var/run/supervisord/supervisord.pid +logfile=%(ENV_STUDIO_LOGGING_DIR)s/%(ENV_SAGEMAKER_APP_TYPE_LOWERCASE)s/supervisord/supervisord.log +logfile_maxbytes=5MB +logfile_backups=10 +redirect_stderr=true + +[unix_http_server] +file=/var/run/supervisord/supervisor.sock +chmod=0700 + +[supervisorctl] +serverurl=unix:///var/run/supervisord/supervisor.sock + +[rpcinterface:supervisor] +supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface + +[program:codeeditorserver] +directory=%(ENV_HOME)s +command=start-sagemaker-ui-code-editor +autostart=true +autorestart=true +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 \ No newline at end of file diff --git a/template/v4/v4.6/dirs/etc/supervisor/conf.d/supervisord-sagemaker-ui-default.conf b/template/v4/v4.6/dirs/etc/supervisor/conf.d/supervisord-sagemaker-ui-default.conf new file mode 100644 index 000000000..13ffc89f3 --- /dev/null +++ b/template/v4/v4.6/dirs/etc/supervisor/conf.d/supervisord-sagemaker-ui-default.conf @@ -0,0 +1,27 @@ +[supervisord] +nodaemon=true + +pidfile=/var/run/supervisord/supervisord.pid +logfile=%(ENV_STUDIO_LOGGING_DIR)s/%(ENV_SAGEMAKER_APP_TYPE_LOWERCASE)s/supervisord/supervisord.log +logfile_maxbytes=5MB +logfile_backups=10 +redirect_stderr=true + +[unix_http_server] +file=/var/run/supervisord/supervisor.sock +chmod=0700 + +[supervisorctl] +serverurl=unix:///var/run/supervisord/supervisor.sock + +[rpcinterface:supervisor] +supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface + +[program:jupyterlabserver] +directory=%(ENV_HOME)s +command=start-sagemaker-ui-default-jupyter-server +stopasgroup=true +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 diff --git a/template/v4/v4.6/dirs/etc/supervisor/conf.d/supervisord-sagemaker-ui.conf b/template/v4/v4.6/dirs/etc/supervisor/conf.d/supervisord-sagemaker-ui.conf new file mode 100644 index 000000000..9447374e3 --- /dev/null +++ b/template/v4/v4.6/dirs/etc/supervisor/conf.d/supervisord-sagemaker-ui.conf @@ -0,0 +1,27 @@ +[supervisord] +nodaemon=true + +pidfile=/var/run/supervisord/supervisord.pid +logfile=%(ENV_STUDIO_LOGGING_DIR)s/%(ENV_SAGEMAKER_APP_TYPE_LOWERCASE)s/supervisord/supervisord.log +logfile_maxbytes=5MB +logfile_backups=10 +redirect_stderr=true + +[unix_http_server] +file=/var/run/supervisord/supervisor.sock +chmod=0700 + +[supervisorctl] +serverurl=unix:///var/run/supervisord/supervisor.sock + +[rpcinterface:supervisor] +supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface + +[program:jupyterlabserver] +directory=%(ENV_HOME)s +command=start-sagemaker-ui-jupyter-server +stopasgroup=true +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 diff --git a/template/v4/v4.6/dirs/etc/supervisor/conf.d/supervisord.conf b/template/v4/v4.6/dirs/etc/supervisor/conf.d/supervisord.conf new file mode 100644 index 000000000..686f4a5c4 --- /dev/null +++ b/template/v4/v4.6/dirs/etc/supervisor/conf.d/supervisord.conf @@ -0,0 +1,27 @@ +[supervisord] +nodaemon=true + +pidfile=/var/run/supervisord/supervisord.pid +logfile=%(ENV_STUDIO_LOGGING_DIR)s/%(ENV_SAGEMAKER_APP_TYPE_LOWERCASE)s/supervisord/supervisord.log +logfile_maxbytes=5MB +logfile_backups=10 +redirect_stderr=true + +[unix_http_server] +file=/var/run/supervisord/supervisor.sock +chmod=0700 + +[supervisorctl] +serverurl=unix:///var/run/supervisord/supervisor.sock + +[rpcinterface:supervisor] +supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface + +[program:jupyterlabserver] +directory=%(ENV_HOME)s +command=start-jupyter-server +stopasgroup=true +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 diff --git a/template/v4/v4.6/dirs/usr/local/bin/entrypoint-code-editor b/template/v4/v4.6/dirs/usr/local/bin/entrypoint-code-editor new file mode 100755 index 000000000..bf55a3713 --- /dev/null +++ b/template/v4/v4.6/dirs/usr/local/bin/entrypoint-code-editor @@ -0,0 +1,16 @@ +#!/bin/bash + +set -e + +# Generate and execute the shell code to modifies shell variables to include +# micromamba commands (e.g. using `micromamba activate` to activate environments) +eval "$(micromamba shell hook --shell=bash)" + +# Activate conda environment 'base', where supervisord is installed +micromamba activate base + +# Set up SAGEMAKER_APP_TYPE_LOWERCASE based on SAGEMAKER_APP_TYPE +export SAGEMAKER_APP_TYPE_LOWERCASE=$(echo $SAGEMAKER_APP_TYPE | tr '[:upper:]' '[:lower:]') + +mkdir -p $STUDIO_LOGGING_DIR/$SAGEMAKER_APP_TYPE_LOWERCASE/supervisord +exec supervisord -c /etc/supervisor/conf.d/supervisord-code-editor.conf -n diff --git a/template/v4/v4.6/dirs/usr/local/bin/entrypoint-jupyter-server b/template/v4/v4.6/dirs/usr/local/bin/entrypoint-jupyter-server new file mode 100755 index 000000000..f71e97f79 --- /dev/null +++ b/template/v4/v4.6/dirs/usr/local/bin/entrypoint-jupyter-server @@ -0,0 +1,25 @@ +#!/bin/bash + +set -e + +# Generate and execute the shell code to modifies shell variables to include +# micromamba commands (e.g. using `micromamba activate` to activate environments) +eval "$(micromamba shell hook --shell=bash)" + +if [ -n "$SAGEMAKER_RECOVERY_MODE" ]; then + export HOME=$SAGEMAKER_RECOVERY_MODE_HOME + # Activate conda environment `sagemaker-recovery-mode` + micromamba activate /opt/conda/envs/sagemaker-recovery-mode +else + # Activate conda environment 'base' + micromamba activate base +fi + +# Set up SAGEMAKER_APP_TYPE_LOWERCASE based on SAGEMAKER_APP_TYPE +export SAGEMAKER_APP_TYPE_LOWERCASE=$(echo $SAGEMAKER_APP_TYPE | tr '[:upper:]' '[:lower:]') + +# Start supervisord with supervisord configuration +# Since program 'jupyterlabserver' autostarts by default, it will be started +# automatically along with supervisord +mkdir -p $STUDIO_LOGGING_DIR/$SAGEMAKER_APP_TYPE_LOWERCASE/supervisord +exec supervisord -c /etc/supervisor/conf.d/supervisord.conf -n diff --git a/template/v4/v4.6/dirs/usr/local/bin/entrypoint-sagemaker-ui-code-editor b/template/v4/v4.6/dirs/usr/local/bin/entrypoint-sagemaker-ui-code-editor new file mode 100755 index 000000000..9217669a1 --- /dev/null +++ b/template/v4/v4.6/dirs/usr/local/bin/entrypoint-sagemaker-ui-code-editor @@ -0,0 +1,19 @@ +#!/bin/bash + +set -e + +# Generate and execute the shell code to modifies shell variables to include +# micromamba commands (e.g. using `micromamba activate` to activate environments) +eval "$(micromamba shell hook --shell=bash)" + +# apply patches for SMUS +/etc/patches/apply_patches.sh smus-code-editor && sudo rm -rf /etc/patches + +# Activate conda environment 'base', where supervisord is installed +micromamba activate base + +export SAGEMAKER_APP_TYPE_LOWERCASE=$(echo $SAGEMAKER_APP_TYPE | tr '[:upper:]' '[:lower:]') +export SERVICE_NAME='SageMakerUnifiedStudio' + +mkdir -p $STUDIO_LOGGING_DIR/$SAGEMAKER_APP_TYPE_LOWERCASE/supervisord +exec supervisord -c /etc/supervisor/conf.d/supervisord-sagemaker-ui-code-editor.conf -n diff --git a/template/v4/v4.6/dirs/usr/local/bin/entrypoint-sagemaker-ui-jupyter-server b/template/v4/v4.6/dirs/usr/local/bin/entrypoint-sagemaker-ui-jupyter-server new file mode 100755 index 000000000..49c34623a --- /dev/null +++ b/template/v4/v4.6/dirs/usr/local/bin/entrypoint-sagemaker-ui-jupyter-server @@ -0,0 +1,26 @@ +#!/bin/bash + +set -e + +# Generate and execute the shell code to modifies shell variables to include +# micromamba commands (e.g. using `micromamba activate` to activate environments) +eval "$(micromamba shell hook --shell=bash)" + +# apply patches for SMUS +/etc/patches/apply_patches.sh smus && sudo rm -rf /etc/patches + +# Activate conda environment depending on if we are in Recovery or Standard mode. +if [ -n "$SAGEMAKER_RECOVERY_MODE" ]; then + export HOME=$SAGEMAKER_RECOVERY_MODE_HOME + # Activate conda environment `sagemaker-recovery-mode` + micromamba activate sagemaker-recovery-mode +else + # Activate conda environment 'base', where supervisord is installed + micromamba activate base +fi + +export SAGEMAKER_APP_TYPE_LOWERCASE=$(echo $SAGEMAKER_APP_TYPE | tr '[:upper:]' '[:lower:]') +export SERVICE_NAME='SageMakerUnifiedStudio' + +mkdir -p $STUDIO_LOGGING_DIR/$SAGEMAKER_APP_TYPE_LOWERCASE/supervisord +exec supervisord -c /etc/supervisor/conf.d/supervisord-sagemaker-ui.conf -n diff --git a/template/v4/v4.6/dirs/usr/local/bin/merge-settings-util.py b/template/v4/v4.6/dirs/usr/local/bin/merge-settings-util.py new file mode 100644 index 000000000..8b93cae1c --- /dev/null +++ b/template/v4/v4.6/dirs/usr/local/bin/merge-settings-util.py @@ -0,0 +1,22 @@ +import json +from sys import argv + + +# merges json files file1 and file2, keys in file2 overwriting any keys that already exist in file1 +def main(): + file1, file2 = argv[1], argv[2] + # Read JSON data from files + with open(file1, "r") as f1, open(file2, "r") as f2: + data1 = json.load(f1) + data2 = json.load(f2) + + # Merge the data (simple update) + merged_data = {**data1, **data2} + + # Write the merged data to a new file + with open(file1, "w") as f: + json.dump(merged_data, f) + + +if __name__ == "__main__": + main() diff --git a/template/v4/v4.6/dirs/usr/local/bin/restart-jupyter-server b/template/v4/v4.6/dirs/usr/local/bin/restart-jupyter-server new file mode 100755 index 000000000..6f2af98d3 --- /dev/null +++ b/template/v4/v4.6/dirs/usr/local/bin/restart-jupyter-server @@ -0,0 +1,6 @@ +#!/bin/bash +set -e +echo "Restarting the Jupyter server. This page should refresh in a few seconds. Note that any terminals will be closed." +echo "If this page doesn't refresh after a few seconds, try reloading your browser window." +echo "Restarting now..." +nohup supervisorctl -c /etc/supervisor/conf.d/supervisord.conf restart jupyterlabserver > /dev/null 2>&1 & diff --git a/template/v4/v4.6/dirs/usr/local/bin/restart-sagemaker-ui-jupyter-server b/template/v4/v4.6/dirs/usr/local/bin/restart-sagemaker-ui-jupyter-server new file mode 100755 index 000000000..8f5207b8a --- /dev/null +++ b/template/v4/v4.6/dirs/usr/local/bin/restart-sagemaker-ui-jupyter-server @@ -0,0 +1,6 @@ +#!/bin/bash +set -e +echo "Restarting the Jupyter server. This page should refresh in a few seconds. Note that any terminals will be closed." +echo "If this page doesn't refresh after a few seconds, try reloading your browser window." +echo "Restarting now..." +nohup supervisorctl -c /etc/supervisor/conf.d/supervisord-sagemaker-ui.conf restart jupyterlabserver > /dev/null 2>&1 & diff --git a/template/v4/v4.6/dirs/usr/local/bin/start-code-editor b/template/v4/v4.6/dirs/usr/local/bin/start-code-editor new file mode 100755 index 000000000..6d2da925c --- /dev/null +++ b/template/v4/v4.6/dirs/usr/local/bin/start-code-editor @@ -0,0 +1,109 @@ +#!/bin/bash +set -e + +EFS_MOUNT_POINT="/opt/amazon/sagemaker" +EBS_MOUNT_POINT="/home/sagemaker-user" + +persistent_settings_folder="${EBS_MOUNT_POINT}/sagemaker-code-editor-server-data" +default_settings_folder="${EFS_MOUNT_POINT}/sagemaker-code-editor-server-data" +# SAGEMAKER_RECOVERY_MODE_HOME env variable is set in Dockerfile +recovery_mode_settings_folder="${SAGEMAKER_RECOVERY_MODE_HOME}/sagemaker-code-editor-server-data" + +override_machine_settings() { + # create a new settings file with preset defaults or merge the defaults into the existing settings file + local settings_relative_path="data/Machine" + local settings_file_path_suffix="${settings_relative_path}/settings.json" + local persistent_machine_settings_file="${persistent_settings_folder}/${settings_file_path_suffix}" + local default_machine_settings_file="${default_settings_folder}/${settings_file_path_suffix}" + + if [ ! -f "$persistent_machine_settings_file" ]; then + # copy settings file to EBS if it doesn't exist in EBS + mkdir -p "${persistent_settings_folder}/${settings_relative_path}" + cp "$default_machine_settings_file" "$persistent_machine_settings_file" + echo "Created persistent settings file with default settings at $persistent_machine_settings_file" + else + # if it does exist then merge settings + echo "File already exists: ${persistent_machine_settings_file}. Merging default settings with existing settings." + python3 /usr/local/bin/merge-settings-util.py "$persistent_machine_settings_file" "$default_machine_settings_file" + fi +} + +copy_user_settings() { + local settings_relative_path="data/User" + local settings_file_path_suffix="${settings_relative_path}/settings.json" + local persistent_user_settings_file="${persistent_settings_folder}/${settings_file_path_suffix}" + local default_user_settings_file="${default_settings_folder}/${settings_file_path_suffix}" + if [ ! -f "$persistent_user_settings_file" ]; then + # copy user settings file to EBS if it doesn't exist in EBS + mkdir -p "${persistent_settings_folder}/${settings_relative_path}" + cp "$default_user_settings_file" "$persistent_user_settings_file" + echo "Created persistent settings file with default settings at $persistent_user_settings_file" + fi +} + +install_prepackaged_extensions() { + local prepackaged_extensions_dir="${default_settings_folder}/extensions" + local persistent_extensions_dir="${persistent_settings_folder}/extensions" + + # if extensions directory doesn't exist then this is the first time opening the app + if [ ! -d "${persistent_extensions_dir}" ]; then + mkdir -p $persistent_extensions_dir + + # find all pre-packaged extensions folders, symlink them to the persistent volume + find "$prepackaged_extensions_dir" -mindepth 1 -maxdepth 1 -type d | while read -r dir; do + dir_name=$(basename "$dir") + + ln -s "$dir" "${persistent_extensions_dir}/${dir_name}" + echo "Added extension: $dir" + done + fi +} + +eval "$(micromamba shell hook --shell=bash)" + +# Activate conda environment 'base', which is the default environment for sagemaker-distribution +micromamba activate base + +# Setup skills and subagent for SMAI spaces +if [ -n "$SAGEMAKER_APP_TYPE_LOWERCASE" ]; then + bash /etc/sagemaker/skills/sync_skills.sh 2>&1 || echo "Warning: skills sync failed, continuing..." + bash /etc/sagemaker/sync_agent.sh 2>&1 || echo "Warning: agent config sync failed, continuing..." +fi + +# Start code-editor server +if [ -n "$SAGEMAKER_APP_TYPE_LOWERCASE" ]; then + # SAGEMAKER_APP_TYPE is set, indicating the server is running within a SageMaker app. + if [ -n "$SAGEMAKER_RECOVERY_MODE" ]; then + # SAGEMAKER_RECOVERY_MODE is set, indicating the SageMaker app is running in recovery mode + export HOME=$SAGEMAKER_RECOVERY_MODE_HOME + + # Create recovery mode directories and set ownership + mkdir -p $recovery_mode_settings_folder ${recovery_mode_settings_folder}/extensions + chown -R $MAMBA_USER:$MAMBA_USER $recovery_mode_settings_folder + + # Configure the base url to be `//default` and use clean temporary directories in recovery mode + sagemaker-code-editor --host 0.0.0.0 --port 8888 \ + --without-connection-token \ + --base-path "/$SAGEMAKER_APP_TYPE_LOWERCASE/default" \ + --server-data-dir $recovery_mode_settings_folder \ + --extensions-dir ${recovery_mode_settings_folder}/extensions \ + --user-data-dir /opt/amazon/sagemaker/sagemaker-code-editor-user-data + else + override_machine_settings + copy_user_settings + install_prepackaged_extensions + # Configure the base url to be `//default` + sagemaker-code-editor --host 0.0.0.0 --port 8888 \ + --without-connection-token \ + --base-path "/$SAGEMAKER_APP_TYPE_LOWERCASE/default" \ + --server-data-dir $persistent_settings_folder \ + --extensions-dir ${persistent_settings_folder}/extensions \ + --user-data-dir /opt/amazon/sagemaker/sagemaker-code-editor-user-data + fi +else + sagemaker-code-editor --host 0.0.0.0 --port 8888 \ + --without-connection-token \ + --server-data-dir /opt/amazon/sagemaker/sagemaker-code-editor-server-data \ + --extension-dir /opt/amazon/sagemaker/sagemaker-code-editor-server-data/extensions \ + --user-data-dir /opt/amazon/sagemaker/sagemaker-code-editor-user-data +fi diff --git a/template/v4/v4.6/dirs/usr/local/bin/start-jupyter-server b/template/v4/v4.6/dirs/usr/local/bin/start-jupyter-server new file mode 100755 index 000000000..bd50279cb --- /dev/null +++ b/template/v4/v4.6/dirs/usr/local/bin/start-jupyter-server @@ -0,0 +1,87 @@ +#!/bin/bash +set -e + +eval "$(micromamba shell hook --shell=bash)" + +if [ -n "$SAGEMAKER_RECOVERY_MODE" ]; then + export HOME=$SAGEMAKER_RECOVERY_MODE_HOME + # Activate conda environment `sagemaker-recovery-mode` + micromamba activate /opt/conda/envs/sagemaker-recovery-mode +else + # Activate conda environment 'base' + micromamba activate base + + # Disable SMUS server extensions + cp /etc/sagemaker/jupyter/server/jupyter_server_config.d/zzz_sagemaker_overrides.json /opt/conda/etc/jupyter/jupyter_server_config.d/ + + # Prevent SMUS lab extensions from loading + rm -f /opt/conda/share/jupyter/labextensions/@amzn/sagemaker-data-explorer-jl-plugin/package.json \ + /opt/conda/share/jupyter/labextensions/@amzn/sagemaker-connection-magics-jlextension/package.json \ + /opt/conda/share/jupyter/labextensions/@amzn/sagemaker-studio-jupyter-scheduler/package.json \ + /opt/conda/share/jupyter/labextensions/@amzn/sagemaker-ui-doc-manager-jl-plugin/package.json \ + /opt/conda/share/jupyter/labextensions/@amzn/sagemaker-ui-theme-jlplugin/package.json \ + /opt/conda/share/jupyter/labextensions/sagemaker_sparkmonitor/package.json \ + /opt/conda/share/jupyter/labextensions/@pyviz/jupyterlab_pyviz/package.json \ + /opt/conda/share/jupyter/labextensions/@amzn/sagemaker_post_startup_notification_plugin/package.json + + # Disable the Amazon Q gen-AI lab extension (chat panel) in SMAI + rm -f /opt/conda/share/jupyter/labextensions/@amzn/sagemaker_gen_ai_jupyterlab_extension/package.json +fi + +# Setup skills and subagent for SMAI private spaces only +if [ -n "$SAGEMAKER_APP_TYPE_LOWERCASE" ] && [ "$SAGEMAKER_SPACE_TYPE_LOWERCASE" != "shared" ]; then + # Sync pre-packaged skills to EBS + bash /etc/sagemaker/skills/sync_skills.sh 2>&1 || echo "Warning: skills sync failed, continuing..." + + # Sync agent config (subagent + default agent settings) + bash /etc/sagemaker/sync_agent.sh 2>&1 || echo "Warning: agent config sync failed, continuing..." +fi + +# Setup for SMAI spaces +if [ -n "$SAGEMAKER_APP_TYPE_LOWERCASE" ]; then + # Copy JupyterLab settings (overrides) + mkdir -p /opt/conda/share/jupyter/lab/settings + cp -r /etc/sagemaker/jupyter/lab/settings/. /opt/conda/share/jupyter/lab/settings/ +fi + +# Enable S3AG plugin if TIP is enabled +if [ -n "$TRUSTED_IDENTITY_PROPOGATION_ENABLED" ]; then + export BOTOCORE_EXPERIMENTAL__PLUGINS=S3AccessGrantsPlugin=aws_s3_access_grants_boto3_plugin.s3_access_grants_plugin + echo BOTOCORE_EXPERIMENTAL__PLUGINS=S3AccessGrantsPlugin=aws_s3_access_grants_boto3_plugin.s3_access_grants_plugin >> ~/.bashrc +fi + +# Start Jupyter server in rtc mode for shared spaces (skip in recovery mode) +if [ -n "$SAGEMAKER_APP_TYPE_LOWERCASE" ] && [ "$SAGEMAKER_SPACE_TYPE_LOWERCASE" == "shared" ] && [ -z "$SAGEMAKER_RECOVERY_MODE" ]; then + # SMAI shared: enable RTC and disable Jupyter AI via static config. + cp /etc/sagemaker/jupyter/shared/labconfig/page_config.json /opt/conda/share/jupyter/lab/settings/page_config.json + cp /etc/sagemaker/jupyter/shared/jupyter_server_config.d/zzz_disable_jai.json /opt/conda/etc/jupyter/jupyter_server_config.d/ + # SAGEMAKER_APP_TYPE is set, indicating the server is running within a SageMaker + # app. Configure the base url to be `//default`. + # SAGEMAKER_SPACE_TYPE_LOWERCASE flag is used to determine if the server should start + # in real-time-collaboration mode for a given space. + exec jupyter lab --ip 0.0.0.0 --port 8888 \ + --ServerApp.base_url="/$SAGEMAKER_APP_TYPE_LOWERCASE/default" \ + --ServerApp.token='' \ + --ServerApp.allow_origin='*' \ + --collaborative \ + --ServerApp.identity_provider_class=sagemaker_jupyterlab_extension_common.identity.SagemakerIdentityProvider \ + --YDocExtension.ystore_class=sagemaker_jupyterlab_extension_common.ydoc_override.ydoc.MySQLiteYStore + +# Start Jupyter server +elif [ -n "$SAGEMAKER_APP_TYPE_LOWERCASE" ]; then + # Disable real-time collaboration in private spaces via static config. + if [ -z "$SAGEMAKER_RECOVERY_MODE" ]; then + cp /etc/sagemaker/jupyter/private/labconfig/page_config.json /opt/conda/share/jupyter/lab/settings/page_config.json + cp /etc/sagemaker/jupyter/private/jupyter_server_config.d/zzz_disable_rtc.json /opt/conda/etc/jupyter/jupyter_server_config.d/ + fi + # SAGEMAKER_APP_TYPE is set, indicating the server is running within a SageMaker + # app. Configure the base url to be `//default`. + exec jupyter lab --ip 0.0.0.0 --port 8888 \ + --ServerApp.base_url="/$SAGEMAKER_APP_TYPE_LOWERCASE/default" \ + --ServerApp.token='' \ + --ServerApp.allow_origin='*' +else + exec jupyter lab --ip 0.0.0.0 --port 8888 \ + --ServerApp.token='' \ + --ServerApp.allow_origin='*' +fi diff --git a/template/v4/v4.6/dirs/usr/local/bin/start-sagemaker-ui-code-editor b/template/v4/v4.6/dirs/usr/local/bin/start-sagemaker-ui-code-editor new file mode 100755 index 000000000..3fee4bd91 --- /dev/null +++ b/template/v4/v4.6/dirs/usr/local/bin/start-sagemaker-ui-code-editor @@ -0,0 +1,110 @@ +#!/bin/bash +set -e + +export PERSISTENT_VOLUME_EXTENSIONS_DIR="/home/sagemaker-user/sagemaker-code-editor-server-data/extensions" +export IMAGE_EXTENSIONS_DIR="/opt/amazon/sagemaker/sagemaker-ui-code-editor-server-data/extensions" + +CONTAINER_SAGEMAKER_METADATA_PATH="/opt/amazon/sagemaker" +EBS_MOUNT_PATH="/home/sagemaker-user" + +persistent_ebs_server_data_folder="${EBS_MOUNT_PATH}/sagemaker-code-editor-server-data" +container_server_data_folder="${CONTAINER_SAGEMAKER_METADATA_PATH}/sagemaker-ui-code-editor-server-data" + +override_machine_settings() { + # create a new settings file with preset defaults or merge the defaults into the existing settings file + local settings_relative_path="data/Machine" + local settings_file_path_suffix="${settings_relative_path}/settings.json" + local persistent_machine_settings_file="${persistent_ebs_server_data_folder}/${settings_file_path_suffix}" + local default_machine_settings_file="${container_server_data_folder}/${settings_file_path_suffix}" + + if [ ! -f "$persistent_machine_settings_file" ]; then + # copy settings file to EBS if it doesn't exist in EBS + mkdir -p "${persistent_ebs_server_data_folder}/${settings_relative_path}" + cp "$default_machine_settings_file" "$persistent_machine_settings_file" + echo "Created persistent settings file with default settings at $persistent_machine_settings_file" + else + # if it does exist then merge settings + echo "File already exists: ${persistent_machine_settings_file}. Merging default settings with existing settings." + python3 /usr/local/bin/merge-settings-util.py "$persistent_machine_settings_file" "$default_machine_settings_file" + fi +} + +copy_user_settings() { + local settings_relative_path="data/User" + local settings_file_path_suffix="${settings_relative_path}/settings.json" + local persistent_user_settings_file="${persistent_ebs_server_data_folder}/${settings_file_path_suffix}" + local default_user_settings_file="${container_server_data_folder}/${settings_file_path_suffix}" + if [ ! -f "$persistent_user_settings_file" ]; then + # copy user settings file to EBS if it doesn't exist in EBS + mkdir -p "${persistent_ebs_server_data_folder}/${settings_relative_path}" + cp "$default_user_settings_file" "$persistent_user_settings_file" + echo "Created persistent settings file with default settings at $persistent_user_settings_file" + fi +} + +install_prepackaged_extensions() { + local prepackaged_extensions_dir="${container_server_data_folder}/extensions" + local persistent_extensions_dir="${persistent_ebs_server_data_folder}/extensions" + + # if extensions directory doesn't exist then this is the first time opening the app + if [ ! -d "${persistent_extensions_dir}" ]; then + mkdir -p $persistent_extensions_dir + + # find all pre-packaged extensions folders, symlink them to the persistent volume + find "$prepackaged_extensions_dir" -mindepth 1 -maxdepth 1 -type d | while read -r dir; do + dir_name=$(basename "$dir") + + ln -s "$dir" "${persistent_extensions_dir}/${dir_name}" + echo "Added extension: $dir" + done + fi +} + +set_code_editor_theme() { + echo "Setting code editor theme" + bash /etc/sagemaker-ui/set_code_editor_theme.sh +} + +disableJupyterKernels() { + local kernel_list + kernel_list=$(jupyter kernelspec list) + + for kernel in "$@"; do + if echo "$kernel_list" | grep -q "$kernel"; then + echo "Removing kernel: $kernel" + jupyter kernelspec remove -f -y "$kernel" + else + echo "Kernel not found: $kernel" + fi + done +} + +eval "$(micromamba shell hook --shell=bash)" + +# Activate conda environment 'base', which is the default environment for sagemaker-distribution +micromamba activate base + +# Disable Jupyter Kernels +disableJupyterKernels pysparkkernel sparkkernel glue_spark glue_pyspark + +# Start code-editor server +if [ -n "$SAGEMAKER_APP_TYPE_LOWERCASE" ]; then + # SAGEMAKER_APP_TYPE is set, indicating the server is running within a SageMaker app. + override_machine_settings + copy_user_settings + install_prepackaged_extensions + set_code_editor_theme + # Configure the base url to be `//default`. + sagemaker-code-editor --host 0.0.0.0 --port 8888 \ + --without-connection-token \ + --base-path "/$SAGEMAKER_APP_TYPE_LOWERCASE/default" \ + --server-data-dir $persistent_ebs_server_data_folder \ + --extensions-dir ${persistent_ebs_server_data_folder}/extensions \ + --user-data-dir /opt/amazon/sagemaker/sagemaker-code-editor-user-data +else + sagemaker-code-editor --host 0.0.0.0 --port 8888 \ + --without-connection-token \ + --server-data-dir /opt/amazon/sagemaker/sagemaker-code-editor-server-data \ + --extension-dir /opt/amazon/sagemaker/sagemaker-code-editor-server-data/extensions \ + --user-data-dir /opt/amazon/sagemaker/sagemaker-code-editor-user-data +fi \ No newline at end of file diff --git a/template/v4/v4.6/dirs/usr/local/bin/start-sagemaker-ui-jupyter-server b/template/v4/v4.6/dirs/usr/local/bin/start-sagemaker-ui-jupyter-server new file mode 100755 index 000000000..d4c2e16d9 --- /dev/null +++ b/template/v4/v4.6/dirs/usr/local/bin/start-sagemaker-ui-jupyter-server @@ -0,0 +1,90 @@ +#!/bin/bash +set -e + +eval "$(micromamba shell hook --shell=bash)" + +# Activate conda environment depending on if we are in Recovery or Standard mode. +if [ -n "$SAGEMAKER_RECOVERY_MODE" ]; then + # Activate conda environment `sagemaker-recovery-mode` + micromamba activate sagemaker-recovery-mode +else + # Activate conda environment 'base' which is the default for Cosmos + micromamba activate base + + # Disable the Amazon Q gen-AI JupyterLab experience for SMUS (replaced by Kiro Chat) + # Server-ext disable stops _load_jupyter_server_extension -> initialize_lsp_server() + jupyter server extension disable sagemaker_gen_ai_jupyterlab_extension + # Labext disable removes the chat panel from the sidebar + jupyter labextension disable @amzn/sagemaker_gen_ai_jupyterlab_extension +fi + +sudo cp -r /etc/sagemaker-ui/kernels/. /opt/conda/share/jupyter/kernels/ +sudo cp /etc/sagemaker-ui/jupyter/server/jupyter_server_config.py /opt/conda/etc/jupyter/ +sudo cp /etc/sagemaker-ui/jupyter/server/jupyter_server_config.d/zzz_sagemaker_ui_overrides.json /opt/conda/etc/jupyter/jupyter_server_config.d/ + +mkdir -p /opt/conda/share/jupyter/lab/settings +cp -r /etc/sagemaker-ui/jupyter/lab/settings/. /opt/conda/share/jupyter/lab/settings + +if [[ $(jupyter kernelspec list | grep pysparkkernel) ]]; then + jupyter-kernelspec remove -f -y pysparkkernel +fi + +if [[ $(jupyter kernelspec list | grep sparkkernel) ]]; then + jupyter-kernelspec remove -f -y sparkkernel +fi + +if [[ $(jupyter kernelspec list | grep glue_spark) ]]; then + jupyter-kernelspec remove -f -y glue_spark +fi + +if [[ $(jupyter kernelspec list | grep glue_pyspark) ]]; then + jupyter-kernelspec remove -f -y glue_pyspark +fi + +# Enable S3 Access Grant plugin by default +export BOTOCORE_EXPERIMENTAL__PLUGINS=S3AccessGrantsPlugin=aws_s3_access_grants_boto3_plugin.s3_access_grants_plugin +echo BOTOCORE_EXPERIMENTAL__PLUGINS=S3AccessGrantsPlugin=aws_s3_access_grants_boto3_plugin.s3_access_grants_plugin >> ~/.bashrc + +# Setup skills and subagent for SMUS spaces +bash /etc/sagemaker/skills/sync_skills.sh /etc/sagemaker-ui/skills 2>&1 || echo "Warning: skills sync failed, continuing..." +bash /etc/sagemaker/sync_agent.sh 2>&1 || echo "Warning: agent config sync failed, continuing..." + +# Override the default agent prompt/description with SMUS-specific wording (SMUS spaces only). +# sync_agent.sh installs the shared (SMAI-worded) config; here we patch the installed copy in place +# so SMAI (which uses start-jupyter-server) is unaffected. +AGENT_CFG="$HOME/.kiro/agents/sagemaker-default-agent.json" +if [ -f "$AGENT_CFG" ]; then + SMUS_DESC="SageMaker Unified Studio assistant with pre-installed skills for data analytics, connecting to data sources, and building with Glue, Athena, Redshift, and Spark." + SMUS_PROMPT="You are a specialized AI assistant for Amazon SageMaker Unified Studio. You can help with general purpose tasks, but you also have expertise in SageMaker Unified Studio projects, data connections, the data catalog, and analytics workflows using Glue, Athena, Redshift, and Spark." + jq --arg d "$SMUS_DESC" --arg p "$SMUS_PROMPT" '.description = $d | .prompt = $p' "$AGENT_CFG" > "$AGENT_CFG.tmp" \ + && mv "$AGENT_CFG.tmp" "$AGENT_CFG" \ + && echo "Applied SMUS-specific agent prompt/description" \ + || echo "Warning: failed to apply SMUS agent prompt, continuing..." +fi + +# Sync SMUS steering rules +if [ -d "/etc/sagemaker-ui/steering" ]; then + mkdir -p "$HOME/.kiro/steering" + cp -r /etc/sagemaker-ui/steering/. "$HOME/.kiro/steering/" +fi + +if [ -n "$SAGEMAKER_RECOVERY_MODE" ]; then + # Disabling collaboration and identity_provider_class flags for recovery mode + jupyter lab --ip 0.0.0.0 --port 8888 \ + --ServerApp.base_url="/$SAGEMAKER_APP_TYPE_LOWERCASE/default" \ + --ServerApp.token='' \ + --ServerApp.allow_origin='*' \ + --SchedulerApp.db_url='sqlite:////tmp/.jupyter_scheduler_do_not_delete.sqlite' \ + --SQLiteYStore.db_path='/tmp/.ydoc_db_do_not_delete.sqlite' \ + --ArbitraryFileIdManager.db_path='/tmp/.fileid_do_not_delete.sqlite' +else + jupyter lab --ip 0.0.0.0 --port 8888 \ + --ServerApp.base_url="/$SAGEMAKER_APP_TYPE_LOWERCASE/default" \ + --ServerApp.token='' \ + --ServerApp.allow_origin='*' \ + --SchedulerApp.db_url='sqlite:////tmp/.jupyter_scheduler_do_not_delete.sqlite' \ + --collaborative \ + --ServerApp.identity_provider_class='sagemaker_jupyter_server_extension.identity.SageMakerIdentityProvider' \ + --SQLiteYStore.db_path='/tmp/.ydoc_db_do_not_delete.sqlite' \ + --ArbitraryFileIdManager.db_path='/tmp/.fileid_do_not_delete.sqlite' +fi