Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/develop' into split-1928-test-…
Browse files Browse the repository at this point in the history
…render
  • Loading branch information
fangchenli committed Feb 20, 2024
2 parents f3e3b02 + 195738e commit 21581f9
Show file tree
Hide file tree
Showing 11 changed files with 150 additions and 13 deletions.
9 changes: 9 additions & 0 deletions .github/workflows/test_local_integration.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,15 @@ jobs:
sed -i -E 's/(cpu_guarantee):\s+[0-9\.]+/\1: 0.25/g' "nebari-config.yaml"
sed -i -E 's/(mem_guarantee):\s+[A-Za-z0-9\.]+/\1: 0.25G/g' "nebari-config.yaml"
# Change default JupyterLab theme
cat >> nebari-config.yaml <<- EOM
jupyterlab:
default_settings:
"@jupyterlab/apputils-extension:themes":
theme: JupyterLab Dark
EOM
cat nebari-config.yaml
- name: Deploy Nebari
Expand Down
10 changes: 10 additions & 0 deletions src/_nebari/stages/kubernetes_services/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -227,8 +227,10 @@ class IdleCuller(schema.Base):


class JupyterLab(schema.Base):
default_settings: typing.Dict[str, typing.Any] = {}
idle_culler: IdleCuller = IdleCuller()
initial_repositories: typing.List[typing.Dict[str, str]] = []
preferred_dir: typing.Optional[str] = None


class InputSchema(schema.Base):
Expand Down Expand Up @@ -352,6 +354,9 @@ class CondaStoreInputVars(schema.Base):
class JupyterhubInputVars(schema.Base):
jupyterhub_theme: Dict[str, Any] = Field(alias="jupyterhub-theme")
jupyterlab_image: ImageNameTag = Field(alias="jupyterlab-image")
jupyterlab_default_settings: Dict[str, Any] = Field(
alias="jupyterlab-default-settings"
)
initial_repositories: str = Field(alias="initial-repositories")
jupyterhub_overrides: List[str] = Field(alias="jupyterhub-overrides")
jupyterhub_stared_storage: str = Field(alias="jupyterhub-shared-storage")
Expand All @@ -363,6 +368,9 @@ class JupyterhubInputVars(schema.Base):
argo_workflows_enabled: bool = Field(alias="argo-workflows-enabled")
jhub_apps_enabled: bool = Field(alias="jhub-apps-enabled")
cloud_provider: str = Field(alias="cloud-provider")
jupyterlab_preferred_dir: typing.Optional[str] = Field(
alias="jupyterlab-preferred-dir"
)


class DaskGatewayInputVars(schema.Base):
Expand Down Expand Up @@ -501,6 +509,8 @@ def input_vars(self, stage_outputs: Dict[str, Dict[str, Any]]):
argo_workflows_enabled=self.config.argo_workflows.enabled,
jhub_apps_enabled=self.config.jhub_apps.enabled,
initial_repositories=str(self.config.jupyterlab.initial_repositories),
jupyterlab_default_settings=self.config.jupyterlab.default_settings,
jupyterlab_preferred_dir=self.config.jupyterlab.preferred_dir,
)

dask_gateway_vars = DaskGatewayInputVars(
Expand Down
14 changes: 14 additions & 0 deletions src/_nebari/stages/kubernetes_services/template/jupyterhub.tf
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,21 @@ variable "jupyterlab-profiles" {
description = "JupyterHub profiles to expose to user"
}

variable "jupyterlab-preferred-dir" {
description = "Directory in which the JupyterLab should open the file browser"
type = string
}

variable "initial-repositories" {
description = "Map of folder location and git repo url to clone"
type = string
}

variable "jupyterlab-default-settings" {
description = "Default settings for JupyterLab to be placed in overrides.json"
type = map(any)
}

variable "jupyterhub-hub-extraEnv" {
description = "Extracted overrides to merge with jupyterhub.hub.extraEnv"
type = string
Expand Down Expand Up @@ -142,6 +152,10 @@ module "jupyterhub" {
idle-culler-settings = var.idle-culler-settings
initial-repositories = var.initial-repositories

jupyterlab-default-settings = var.jupyterlab-default-settings

jupyterlab-pioneer-enabled = var.jupyterlab-pioneer-enabled
jupyterlab-pioneer-log-format = var.jupyterlab-pioneer-log-format

jupyterlab-preferred-dir = var.jupyterlab-preferred-dir
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,18 @@ locals {
kernel_cull_connected = var.idle-culler-settings.kernel_cull_connected ? "True" : "False" # for Python compatible boolean values
kernel_cull_busy = var.idle-culler-settings.kernel_cull_busy ? "True" : "False" # for Python compatible boolean values
server_shutdown_no_activity_timeout = var.idle-culler-settings.server_shutdown_no_activity_timeout
jupyterlab_preferred_dir = var.jupyterlab-preferred-dir != null ? var.jupyterlab-preferred-dir : ""
}
)
}

locals {
jupyterlab-overrides-json-object = merge(
jsondecode(file("${path.module}/files/jupyterlab/overrides.json")),
var.jupyterlab-default-settings
)
}

locals {
jupyter-pioneer-config-py-template = templatefile("${path.module}/files/jupyter/jupyter_jupyterlab_pioneer_config.py.tpl", {
log_format = var.jupyterlab-pioneer-log-format != null ? var.jupyterlab-pioneer-log-format : ""
Expand All @@ -30,6 +38,12 @@ resource "local_file" "jupyter_jupyterlab_pioneer_config_py" {
}


resource "local_file" "overrides_json" {
content = jsonencode(local.jupyterlab-overrides-json-object)
filename = "${path.module}/files/jupyterlab/overrides.json"
}


resource "kubernetes_config_map" "etc-ipython" {
metadata {
name = "etc-ipython"
Expand All @@ -56,6 +70,12 @@ locals {
)
}

locals {
etc-jupyterlab-settings = {
"overrides.json" = local_file.overrides_json.content
}
}

resource "kubernetes_config_map" "etc-jupyter" {
depends_on = [
local_file.jupyter_server_config_py,
Expand Down Expand Up @@ -85,15 +105,16 @@ resource "kubernetes_config_map" "etc-skel" {


resource "kubernetes_config_map" "jupyterlab-settings" {
depends_on = [
local_file.overrides_json
]

metadata {
name = "jupyterlab-settings"
namespace = var.namespace
}

data = {
for filename in fileset("${path.module}/files/jupyterlab", "*") :
filename => file("${path.module}/files/jupyterlab/${filename}")
}
data = local.etc-jupyterlab-settings
}

resource "kubernetes_config_map" "git_clone_update" {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,22 @@ if [ "$#" -lt 1 ] || [ "$1" = "--help" ]; then
[ "$1" = "--help" ] && exit 0 || exit 1
fi

fix_parent_dir_permissions() {
# Fix parent directory permissions to allow the JupyterLab user to access the cloned repository

local folder_path="$1"

# Retrieve the very first parent directory
local parent_dir=$(echo "$folder_path" | cut -d '/' -f1)

# Check if the parent directory has the correct permissions
if [ "$(stat -c "%u:%g" "$parent_dir")" != "1000:100" ]; then
echo "Fixing permissions for parent directory: $parent_dir"
chown -R 1000:100 "$parent_dir" || { echo "Error: Unable to set ownership for $parent_dir"; return 1; }
chmod -R 755 "$parent_dir" || { echo "Error: Unable to set permissions for $parent_dir"; return 1; }
fi
}

clone_update_repository() {
# Clone or update a Git repository into a specified folder,
# and create a `.firstrun` file to mark the script's execution.
Expand All @@ -47,6 +63,8 @@ clone_update_repository() {
mkdir -p "$folder_path"
fi

fix_parent_dir_permissions "$folder_path" || return 1

if [ -d "$folder_path/.git" ]; then
echo -e "Updating Git repository in ${folder_path}..."
(cd "$folder_path" && git pull)
Expand All @@ -55,7 +73,13 @@ clone_update_repository() {
(git clone "$git_repo_url" "$folder_path")
fi

echo -e "Creating .firstrun file in ${folder_path}..."
touch "$firstrun_file"

# User permissions for JupyterLab user to newly created git folders
echo -e "Setting permissions for ${folder_path}..."
chown -R 1000:100 "$folder_path" || { echo "Error: Unable to set ownership for $folder_path"; return 1; }

echo -e "Execution for ${folder_path} completed. ${GREEN}${NC}"
fi
}
Expand All @@ -72,7 +96,6 @@ for pair in "$@"; do
echo -e "${RED}Invalid argument format: \"${pair}\". Please provide folder path and Git repository URL in the correct order.${NC}" >> "$ERROR_LOG"
else
clone_update_repository "$folder_path" "$git_repo_url" || echo -e "${RED}Error executing for ${folder_path}.${NC}" >> "$ERROR_LOG"
chown -R 1000:100 "$folder_path" # User permissions for JupyterLab user
fi
done

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@
c.ContentsManager.allow_hidden = True
c.FileContentsManager.allow_hidden = True

# Set the preferred path for the frontend to start in
preferred_dir = ${jupyterlab_preferred_dir}
c.FileContentsManager.preferred_dir = preferred_dir if preferred_dir else None

# Timeout (in seconds) in which a terminal has been inactive and ready to
# be culled.
c.TerminalManager.cull_inactive_timeout = ${terminal_cull_inactive_timeout} * 60
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,40 @@
"@jupyterlab/mainmenu-extension:plugin": {
"menus": [
{
"id": "jp-mainmenu-nebari",
"disabled": false,
"label": "Nebari",
"rank": 1001,
"id": "jp-mainmenu-file",
"items": [
{
"command": "help:open",
"rank": 0,
"args": {
"url": "/hub/home",
"text": "Home",
"newBrowserTab": true
}
},
{
"type": "submenu",
"submenu": {
"id": "jp-mainmenu-file-new"
},
"rank": 0.5
},
{
"command": "hub:control-panel",
"rank": 0
"disabled": true
},
{
"command": "hub:logout",
"disabled": true
}
]
},
{
"id": "jp-mainmenu-services",
"disabled": false,
"label": "Services",
"rank": 1000,
"items": [
{
"command": "help:open",
"rank": 1,
Expand Down Expand Up @@ -61,6 +86,21 @@
}
}
]
},
{
"id": "jp-mainmenu-help",
"rank": 1001,
"items": [
{
"command": "help:open",
"rank": 1001,
"args": {
"url": "https://www.nebari.dev/docs/welcome/",
"text": "Nebari documentation",
"newBrowserTab": true
}
}
]
}
]
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,11 @@ variable "argo-workflows-enabled" {
type = bool
}

variable "jupyterlab-default-settings" {
description = "Default settings for JupyterLab to be placed in overrides.json"
type = map(any)
}

variable "jupyterlab-pioneer-enabled" {
description = "Enable JupyterLab Pioneer for telemetry"
type = bool
Expand All @@ -168,6 +173,11 @@ variable "jupyterlab-pioneer-log-format" {
type = string
}

variable "jupyterlab-preferred-dir" {
description = "Directory in which the JupyterLab should open the file browser"
type = string
}

variable "cloud-provider" {
description = "Name of cloud provider."
type = string
Expand Down
4 changes: 1 addition & 3 deletions tests/common/navigator.py
Original file line number Diff line number Diff line change
Expand Up @@ -413,9 +413,7 @@ def stop_server(self) -> None:
self.page.get_by_text("File", exact=True).click()

with self.context.expect_page() as page_info:
self.page.get_by_role(
"menuitem", name="Hub Control Panel", exact=True
).click()
self.page.get_by_role("menuitem", name="Home", exact=True).click()

home_page = page_info.value
home_page.wait_for_load_state()
Expand Down
3 changes: 3 additions & 0 deletions tests/tests_e2e/cypress/integration/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ describe('First Test', () => {
// Click VS Code Launcher exists
cy.get('div.jp-LauncherCard[title="VS Code [↗]"]').should('exist');

// Should reflect theme set by default_settings
cy.get('body[data-jp-theme-name="JupyterLab Dark"]').should('exist');

// Stop my Jupyter server - must do this so PVC can be destroyed on Minikube
cy.visit('/hub/home');

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
project_name: test
jupyterlab:
default_settings:
"@jupyterlab/apputils-extension:themes":
theme: JupyterLab Dark

0 comments on commit 21581f9

Please sign in to comment.