From 3e72ea82944713b95fb35e24de47aaa70eb68100 Mon Sep 17 00:00:00 2001 From: Aaron Kanzer Date: Thu, 10 Oct 2024 11:34:29 -0400 Subject: [PATCH 1/8] Include environment configuration for LINC Hub --- envs/linc/jupyterhub-overrides.yaml | 100 ++++++++ envs/linc/managed-jupyterhub.yaml | 356 ++++++++++++++++++++++++++++ envs/linc/s3.tfbackend | 5 + envs/linc/terraform.tfvars | 6 + 4 files changed, 467 insertions(+) create mode 100644 envs/linc/jupyterhub-overrides.yaml create mode 100644 envs/linc/managed-jupyterhub.yaml create mode 100644 envs/linc/s3.tfbackend create mode 100644 envs/linc/terraform.tfvars diff --git a/envs/linc/jupyterhub-overrides.yaml b/envs/linc/jupyterhub-overrides.yaml new file mode 100644 index 00000000..a26755e0 --- /dev/null +++ b/envs/linc/jupyterhub-overrides.yaml @@ -0,0 +1,100 @@ +hub: + config: + Authenticator: + admin_users: + - "asmacdo" + - "dandibot" + - "satra" + - "aaron" + - "kabilar" + extraConfig: + myConfig: | + # Python executed by jupyterhub at startup + import json + import os + import warnings + from kubernetes_asyncio import client + from oauthenticator.github import GitHubOAuthenticator + from tornado.httpclient import AsyncHTTPClient, HTTPClientError, HTTPRequest + + def modify_pod_hook(spawner, pod): # noqa + pod.spec.containers[0].security_context = client.V1SecurityContext(privileged=True) + return pod + + # define our OAuthenticator with `.pre_spawn_start` + # for passing auth_state into the user environment + # Based on : # noqa + class IsDandiUserAuthenticator(GitHubOAuthenticator): + async def check_allowed(self, username, auth_model): + """ + Query DANDI API to ensure user is registered. + """ + if auth_model["auth_state"].get("scope", []): + scopes = [] + for val in auth_model["auth_state"]["scope"]: + scopes.extend(val.split(",")) + auth_model["auth_state"]["scope"] = scopes + auth_model = await self.update_auth_model(auth_model) + + # Allowed if admin + if await super().check_allowed(username, auth_model): + return True + + # Allowed if user is a registered DANDI user. + req = HTTPRequest( + f"${dandi_api_domain}/api/users/search/?username={username}", # noqa + method="GET", + headers={ + "Accept": "application/json", + "User-Agent": "JupyterHub", + "Authorization": "token ${danditoken}", + }, + validate_cert=self.validate_server_cert, + ) + try: + client = AsyncHTTPClient() + print(f"Attempting to validate {username} with ${dandi_api_domain}") # noqa + resp = await client.fetch(req) + except HTTPClientError as e: + print( + f"Dandi API request to validate {username} returned HTTPClientError: {e}" + ) + return False + else: + if resp.body: + resp_json = json.loads(resp.body.decode("utf8", "replace")) + for val in resp_json: + if val["username"].lower() == username.lower(): + return True + + # If not explicitly allowed, not allowed. + return False + + async def pre_spawn_start(self, user, spawner): + auth_state = await user.get_auth_state() + if not auth_state: + # user has no auth state + return + # define some environment variables from auth_state + spawner.environment["GITHUB_TOKEN"] = auth_state["access_token"] + spawner.environment["GITHUB_USER"] = auth_state["github_user"]["login"] + spawner.environment["GITHUB_EMAIL"] = auth_state["github_user"]["email"] + c.KubeSpawner.modify_pod_hook = modify_pod_hook # noqa + c.JupyterHub.authenticator_class = IsDandiUserAuthenticator # noqa + c.GitHubOAuthenticator.enable_auth_state = True # noqa + +singleuser: + lifecycleHooks: + postStart: + exec: + command: + - "sh" + - "-c" + - > + gitpuller https://github.com/dandi/example-notebooks master dandi-notebooks; + chown -R jovyan:users dandi-notebooks; + datalad install https://github.com/dandi/dandisets; + /opt/conda/envs/allen/bin/python -m ipykernel install --user --name allen --display-name "Python (Allen SDK)"; + /opt/conda/bin/pip install --upgrade dandi; + git config --global user.email "$${GITHUB_EMAIL}"; + git config --global user.name "$${GITHUB_USER}" diff --git a/envs/linc/managed-jupyterhub.yaml b/envs/linc/managed-jupyterhub.yaml new file mode 100644 index 00000000..88c5424f --- /dev/null +++ b/envs/linc/managed-jupyterhub.yaml @@ -0,0 +1,356 @@ +# WARNING: This file is managed by a script. +# Any changes made to this file will be overwritten. +# DO NOT EDIT THIS FILE MANUALLY. +cull: + enabled: true + every: 300 + timeout: 3600 +global: + safeToShowValues: false +hub: + authenticatePrometheus: false + command: + - sh + - -c + - pip install boto3 && jupyterhub --config /usr/local/etc/jupyterhub/jupyterhub_config.py + config: + Authenticator: + admin_users: + - asmacdo + - dandibot + - satra + - aaron + - kabilar + GitHubOAuthenticator: + client_id: ${client_id} + client_secret: ${client_secret} + oauth_callback_url: https://${jupyterhub_domain}/hub/oauth_callback + scope: + - read:user + - read:gist + - user:email + db: + pvc: + storage: 50Gi + storageClassName: gp3 + extraConfig: + myConfig: | + # Python executed by jupyterhub at startup + import json + import os + import warnings + from kubernetes_asyncio import client + from oauthenticator.github import GitHubOAuthenticator + from tornado.httpclient import AsyncHTTPClient, HTTPClientError, HTTPRequest + + def modify_pod_hook(spawner, pod): # noqa + pod.spec.containers[0].security_context = client.V1SecurityContext(privileged=True) + return pod + + # define our OAuthenticator with `.pre_spawn_start` + # for passing auth_state into the user environment + # Based on : # noqa + class IsDandiUserAuthenticator(GitHubOAuthenticator): + async def check_allowed(self, username, auth_model): + """ + Query DANDI API to ensure user is registered. + """ + if auth_model["auth_state"].get("scope", []): + scopes = [] + for val in auth_model["auth_state"]["scope"]: + scopes.extend(val.split(",")) + auth_model["auth_state"]["scope"] = scopes + auth_model = await self.update_auth_model(auth_model) + + # Allowed if admin + if await super().check_allowed(username, auth_model): + return True + + # Allowed if user is a registered DANDI user. + req = HTTPRequest( + f"${dandi_api_domain}/api/users/search/?username={username}", # noqa + method="GET", + headers={ + "Accept": "application/json", + "User-Agent": "JupyterHub", + "Authorization": "token ${danditoken}", + }, + validate_cert=self.validate_server_cert, + ) + try: + client = AsyncHTTPClient() + print(f"Attempting to validate {username} with ${dandi_api_domain}") # noqa + resp = await client.fetch(req) + except HTTPClientError as e: + print( + f"Dandi API request to validate {username} returned HTTPClientError: {e}" + ) + return False + else: + if resp.body: + resp_json = json.loads(resp.body.decode("utf8", "replace")) + for val in resp_json: + if val["username"].lower() == username.lower(): + return True + + # If not explicitly allowed, not allowed. + return False + + async def pre_spawn_start(self, user, spawner): + auth_state = await user.get_auth_state() + if not auth_state: + # user has no auth state + return + # define some environment variables from auth_state + spawner.environment["GITHUB_TOKEN"] = auth_state["access_token"] + spawner.environment["GITHUB_USER"] = auth_state["github_user"]["login"] + spawner.environment["GITHUB_EMAIL"] = auth_state["github_user"]["email"] + c.KubeSpawner.modify_pod_hook = modify_pod_hook # noqa + c.JupyterHub.authenticator_class = IsDandiUserAuthenticator # noqa + c.GitHubOAuthenticator.enable_auth_state = True # noqa +prePuller: + continuous: + enabled: false + hook: + enabled: false +proxy: + https: + enabled: true + hosts: + - ${jupyterhub_domain} + type: offload + service: + annotations: + service.beta.kubernetes.io/aws-load-balancer-backend-protocol: tcp + service.beta.kubernetes.io/aws-load-balancer-connection-idle-timeout: '3600' + service.beta.kubernetes.io/aws-load-balancer-cross-zone-load-balancing-enabled: 'true' + service.beta.kubernetes.io/aws-load-balancer-ip-address-type: ipv4 + service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: ip + service.beta.kubernetes.io/aws-load-balancer-scheme: internet-facing + service.beta.kubernetes.io/aws-load-balancer-ssl-cert: ${ssl_cert_arn} + service.beta.kubernetes.io/aws-load-balancer-ssl-ports: https + service.beta.kubernetes.io/aws-load-balancer-type: external +scheduling: + podPriority: + enabled: true + userPlaceholder: + enabled: false + replicas: 1 + userPods: + nodeAffinity: + matchNodePurpose: require + userScheduler: + enabled: true +singleuser: + allowPrivilegeEscalation: true + cmd: null + cpu: + guarantee: 0.5 + limit: 12 + defaultUrl: /lab + extraEnv: + CHOWN_EXTRA: /home/shared + CHOWN_HOME: 'yes' + CHOWN_HOME_OPTS: -R + GRANT_SUDO: 'yes' + NOTEBOOK_ARGS: --allow-root + extraPodConfig: + securityContext: + fsGroup: 100 + fsGid: 0 + initContainers: + - command: + - sh + - -c + - 'chmod 0775 /nfs; chown 1000:100 /nfs; chmod 0775 /shared; chown 1000:100 + /shared; chmod 0555 /readonly + + ' + image: alpine + name: nfs-fixer + securityContext: + runAsUser: 0 + volumeMounts: + - mountPath: /nfs + name: persistent-storage + subPath: home/{username} + - mountPath: /shared + name: persistent-storage + subPath: shared + - mountPath: /readonly + name: persistent-storage + subPath: readonly + lifecycleHooks: + postStart: + exec: + command: + - sh + - -c + - 'gitpuller https://github.com/dandi/example-notebooks master dandi-notebooks; + chown -R jovyan:users dandi-notebooks; datalad install https://github.com/dandi/dandisets; + /opt/conda/envs/allen/bin/python -m ipykernel install --user --name allen + --display-name "Python (Allen SDK)"; /opt/conda/bin/pip install --upgrade + dandi; git config --global user.email "$${GITHUB_EMAIL}"; git config --global + user.name "$${GITHUB_USER}" + + ' + memory: + guarantee: 1G + limit: 16G + profileList: + - description: 0.5 CPU / 1 GB + display_name: Tiny. Useful for many quick things + kubespawner_override: + cpu_guarantee: 0.25 + cpu_limit: 2 + image_pull_policy: Always + mem_guarantee: 0.5G + mem_limit: 2G + node_selector: + NodePool: default + profile_options: + image: + choices: + standard: + default: true + display_name: Standard + kubespawner_override: + image: ${singleuser_image_repo}:${singleuser_image_tag} + display_name: Image + - default: true + description: 6 CPU / 16 GB up to 12C/32G. May take up to 15 mins to start. + display_name: Base + kubespawner_override: + cpu_guarantee: 6 + cpu_limit: 12 + image_pull_policy: Always + mem_guarantee: 16G + mem_limit: 32G + node_selector: + NodePool: default + profile_options: + image: + choices: + matlab: + display_name: MATLAB (must provide your own license) + kubespawner_override: + image: ${singleuser_image_repo}:${singleuser_image_tag}-matlab + standard: + default: true + display_name: Standard + kubespawner_override: + image: ${singleuser_image_repo}:${singleuser_image_tag} + display_name: Image + - description: 12C/32G up to 24C/64G. May take up to 15 mins to start. + display_name: Medium + kubespawner_override: + cpu_guarantee: 12 + cpu_limit: 24 + image_pull_policy: Always + mem_guarantee: 32G + mem_limit: 64G + node_selector: + NodePool: default + profile_options: + image: + choices: + matlab: + display_name: MATLAB (must provide your own license) + kubespawner_override: + image: ${singleuser_image_repo}:${singleuser_image_tag}-matlab + standard: + default: true + display_name: Standard + kubespawner_override: + image: ${singleuser_image_repo}:${singleuser_image_tag} + display_name: Image + - description: 24C/64G up to 48C/96G. May take up to 15 mins to start. + display_name: Large + kubespawner_override: + cpu_guarantee: 24 + cpu_limit: 48 + image_pull_policy: Always + mem_guarantee: 64G + mem_limit: 96G + node_selector: + NodePool: default + profile_options: + image: + choices: + matlab: + display_name: MATLAB (must provide your own license) + kubespawner_override: + image: ${singleuser_image_repo}:${singleuser_image_tag}-matlab + standard: + default: true + display_name: Standard + kubespawner_override: + image: ${singleuser_image_repo}:${singleuser_image_tag} + display_name: Image + - description: 8 CPU / 30 GB / 1 T4 GPU. May take up to 15 mins to start. + display_name: T4 GPU for inference + kubespawner_override: + cpu_guarantee: 6 + cpu_limit: 8 + extra_resource_limits: + nvidia.com/gpu: '1' + image_pull_policy: Always + mem_guarantee: 25G + mem_limit: 31G + node_selector: + NodePool: gpu + node.kubernetes.io/instance-type: g4dn.2xlarge + tolerations: + - effect: NoSchedule + key: nvidia.com/gpu + operator: Exists + - effect: NoSchedule + key: hub.jupyter.org/dedicated + operator: Equal + value: user + profile_options: + image: + choices: + matlab: + display_name: MATLAB GPU (must provide your own license) + kubespawner_override: + image: ${singleuser_image_repo}:${singleuser_image_tag}-gpu-matlab + standard: + default: true + display_name: Standard GPU + kubespawner_override: + image: ${singleuser_image_repo}:${singleuser_image_tag}-gpu + display_name: Image + serviceAccountName: ${jupyter_single_user_sa_name} + startTimeout: 2400 + storage: + extraVolumeMounts: + - mountPath: /dev/fuse + name: fuse + - mountPath: /dev/shm + name: shm-volume + - mountPath: /home/jovyan + name: persistent-storage + subPath: home/{username} + - mountPath: /shared + name: persistent-storage-shared + subPath: shared + - mountPath: /readonly + name: persistent-storage-shared + readOnly: true + subPath: readonly + extraVolumes: + - hostPath: + path: /dev/fuse + name: fuse + - emptyDir: + medium: Memory + name: shm-volume + - name: persistent-storage-shared + persistentVolumeClaim: + claimName: efs-persist-shared + - name: persistent-storage + persistentVolumeClaim: + claimName: efs-persist + type: none + uid: 0 diff --git a/envs/linc/s3.tfbackend b/envs/linc/s3.tfbackend new file mode 100644 index 00000000..10be9e68 --- /dev/null +++ b/envs/linc/s3.tfbackend @@ -0,0 +1,5 @@ +bucket = "eks-linc-tfstate" +key = "terraform.tfstate" +region = "us-east-2" +encrypt = true +dynamodb_table = "eks-jupyterhub-tf-lock" diff --git a/envs/linc/terraform.tfvars b/envs/linc/terraform.tfvars new file mode 100644 index 00000000..6c80384c --- /dev/null +++ b/envs/linc/terraform.tfvars @@ -0,0 +1,6 @@ +name = "eks-linchub" +singleuser_image_repo = "dandiarchive/dandihub" +region = "us-east-2" +singleuser_image_tag = "latest" +jupyterhub_domain = "hub.lincbrain.org" +dandi_api_domain = "https://api.lincbrain.org" From 08e67f9f6efe3363bfaa47986368812bb11ada24 Mon Sep 17 00:00:00 2001 From: Aaron Kanzer Date: Thu, 10 Oct 2024 13:52:37 -0400 Subject: [PATCH 2/8] bump aaron to aaronkanzer --- envs/linc/jupyterhub-overrides.yaml | 2 +- envs/linc/managed-jupyterhub.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/envs/linc/jupyterhub-overrides.yaml b/envs/linc/jupyterhub-overrides.yaml index a26755e0..47f646a8 100644 --- a/envs/linc/jupyterhub-overrides.yaml +++ b/envs/linc/jupyterhub-overrides.yaml @@ -5,7 +5,7 @@ hub: - "asmacdo" - "dandibot" - "satra" - - "aaron" + - "aaronkanzer" - "kabilar" extraConfig: myConfig: | diff --git a/envs/linc/managed-jupyterhub.yaml b/envs/linc/managed-jupyterhub.yaml index 88c5424f..5380d52c 100644 --- a/envs/linc/managed-jupyterhub.yaml +++ b/envs/linc/managed-jupyterhub.yaml @@ -19,7 +19,7 @@ hub: - asmacdo - dandibot - satra - - aaron + - aaronkanzer - kabilar GitHubOAuthenticator: client_id: ${client_id} From 8ecaaf3f07fe13f484f7df6cee2e46caee059a85 Mon Sep 17 00:00:00 2001 From: aaronkanzer <36093535+aaronkanzer@users.noreply.github.com> Date: Thu, 17 Oct 2024 10:32:06 -0400 Subject: [PATCH 3/8] Update envs/linc/jupyterhub-overrides.yaml Co-authored-by: Kabilar Gunalan --- envs/linc/jupyterhub-overrides.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/envs/linc/jupyterhub-overrides.yaml b/envs/linc/jupyterhub-overrides.yaml index 47f646a8..4033743d 100644 --- a/envs/linc/jupyterhub-overrides.yaml +++ b/envs/linc/jupyterhub-overrides.yaml @@ -96,5 +96,6 @@ singleuser: datalad install https://github.com/dandi/dandisets; /opt/conda/envs/allen/bin/python -m ipykernel install --user --name allen --display-name "Python (Allen SDK)"; /opt/conda/bin/pip install --upgrade dandi; + /opt/conda/bin/pip install --upgrade lincbrain-cli; git config --global user.email "$${GITHUB_EMAIL}"; git config --global user.name "$${GITHUB_USER}" From 4d65081257d4bf7ad37863d9053b6dd96a6baa57 Mon Sep 17 00:00:00 2001 From: aaronkanzer <36093535+aaronkanzer@users.noreply.github.com> Date: Thu, 17 Oct 2024 10:32:14 -0400 Subject: [PATCH 4/8] Update envs/linc/jupyterhub-overrides.yaml Co-authored-by: Kabilar Gunalan --- envs/linc/jupyterhub-overrides.yaml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/envs/linc/jupyterhub-overrides.yaml b/envs/linc/jupyterhub-overrides.yaml index 4033743d..b467f6f3 100644 --- a/envs/linc/jupyterhub-overrides.yaml +++ b/envs/linc/jupyterhub-overrides.yaml @@ -91,10 +91,6 @@ singleuser: - "sh" - "-c" - > - gitpuller https://github.com/dandi/example-notebooks master dandi-notebooks; - chown -R jovyan:users dandi-notebooks; - datalad install https://github.com/dandi/dandisets; - /opt/conda/envs/allen/bin/python -m ipykernel install --user --name allen --display-name "Python (Allen SDK)"; /opt/conda/bin/pip install --upgrade dandi; /opt/conda/bin/pip install --upgrade lincbrain-cli; git config --global user.email "$${GITHUB_EMAIL}"; From f5d81f32cae82cfbc8fc7b84a118343fcbebe2c8 Mon Sep 17 00:00:00 2001 From: Aaron Kanzer Date: Fri, 18 Oct 2024 11:06:42 -0400 Subject: [PATCH 5/8] revert to kernel --- envs/.DS_Store | Bin 0 -> 6148 bytes envs/linc/jupyterhub-overrides.yaml | 2 ++ 2 files changed, 2 insertions(+) create mode 100644 envs/.DS_Store diff --git a/envs/.DS_Store b/envs/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..fbb43a645b31b474503b5f503cd04c73a0e7739c GIT binary patch literal 6148 zcmeHKy-EW?5T4ajf+D0)u)IdCEb<0xJf9$yV3D7bB#=M+DeMkJY%R1AU%K*>e$4Of`sMk3$NqMCt*_jyc*tvX zTZL8~Xmv)Xl!n~9Z{QB%KEHm*wVB8%)R>nO_Mt%|_Cp1*XS0>oEs7TfL;+DCSAf@t z7=uwe%q*Iv1I`=)fDxvR;hN79ToXIg4l|30z?3Zo+EV3?7|NDoK6ZK9VP?^mlX8a- z<(QQ_p(w+S=f@_Ul(r~d6c7bM1(xk?nfL#r`RD(zNbW=dQQ%)GprWLfRPjn~Z=HHM v-fLrwItCl(Wfn~doZF7g1#iXM7{(Bb`2wgNW)?96lRpAR263XmuPX2fJ8`RN literal 0 HcmV?d00001 diff --git a/envs/linc/jupyterhub-overrides.yaml b/envs/linc/jupyterhub-overrides.yaml index b467f6f3..8a22aca7 100644 --- a/envs/linc/jupyterhub-overrides.yaml +++ b/envs/linc/jupyterhub-overrides.yaml @@ -91,6 +91,8 @@ singleuser: - "sh" - "-c" - > + gitpuller https://github.com/dandi/example-notebooks master dandi-notebooks; + /opt/conda/envs/allen/bin/python -m ipykernel install --user --name allen --display-name "Python (Allen SDK)"; /opt/conda/bin/pip install --upgrade dandi; /opt/conda/bin/pip install --upgrade lincbrain-cli; git config --global user.email "$${GITHUB_EMAIL}"; From 658d0f5c881193bdfb1500b220490146f79cff3b Mon Sep 17 00:00:00 2001 From: Aaron Kanzer Date: Fri, 18 Oct 2024 11:18:43 -0400 Subject: [PATCH 6/8] updates per Kabi's review --- .gitignore | 2 ++ envs/linc/jupyterhub-overrides.yaml | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index cefc78e9..b8b2d867 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,5 @@ scripts/__pycache__/ # Env secrets *.env + +.DS_Store \ No newline at end of file diff --git a/envs/linc/jupyterhub-overrides.yaml b/envs/linc/jupyterhub-overrides.yaml index 8a22aca7..60b6295e 100644 --- a/envs/linc/jupyterhub-overrides.yaml +++ b/envs/linc/jupyterhub-overrides.yaml @@ -91,7 +91,6 @@ singleuser: - "sh" - "-c" - > - gitpuller https://github.com/dandi/example-notebooks master dandi-notebooks; /opt/conda/envs/allen/bin/python -m ipykernel install --user --name allen --display-name "Python (Allen SDK)"; /opt/conda/bin/pip install --upgrade dandi; /opt/conda/bin/pip install --upgrade lincbrain-cli; From 212bcce82985176e5ac42ab985260f02c0591fbc Mon Sep 17 00:00:00 2001 From: Aaron Kanzer Date: Fri, 18 Oct 2024 11:35:26 -0400 Subject: [PATCH 7/8] deletE DS Store --- envs/.DS_Store | Bin 6148 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 envs/.DS_Store diff --git a/envs/.DS_Store b/envs/.DS_Store deleted file mode 100644 index fbb43a645b31b474503b5f503cd04c73a0e7739c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHKy-EW?5T4ajf+D0)u)IdCEb<0xJf9$yV3D7bB#=M+DeMkJY%R1AU%K*>e$4Of`sMk3$NqMCt*_jyc*tvX zTZL8~Xmv)Xl!n~9Z{QB%KEHm*wVB8%)R>nO_Mt%|_Cp1*XS0>oEs7TfL;+DCSAf@t z7=uwe%q*Iv1I`=)fDxvR;hN79ToXIg4l|30z?3Zo+EV3?7|NDoK6ZK9VP?^mlX8a- z<(QQ_p(w+S=f@_Ul(r~d6c7bM1(xk?nfL#r`RD(zNbW=dQQ%)GprWLfRPjn~Z=HHM v-fLrwItCl(Wfn~doZF7g1#iXM7{(Bb`2wgNW)?96lRpAR263XmuPX2fJ8`RN From 36070cca1166ce52c057f297781fff5677605e3a Mon Sep 17 00:00:00 2001 From: Aaron Kanzer Date: Thu, 24 Oct 2024 10:52:54 -0400 Subject: [PATCH 8/8] include proper override jupyterhub files --- envs/linc/managed-jupyterhub.yaml | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/envs/linc/managed-jupyterhub.yaml b/envs/linc/managed-jupyterhub.yaml index 5380d52c..abe5619c 100644 --- a/envs/linc/managed-jupyterhub.yaml +++ b/envs/linc/managed-jupyterhub.yaml @@ -186,12 +186,11 @@ singleuser: command: - sh - -c - - 'gitpuller https://github.com/dandi/example-notebooks master dandi-notebooks; - chown -R jovyan:users dandi-notebooks; datalad install https://github.com/dandi/dandisets; - /opt/conda/envs/allen/bin/python -m ipykernel install --user --name allen + - '/opt/conda/envs/allen/bin/python -m ipykernel install --user --name allen --display-name "Python (Allen SDK)"; /opt/conda/bin/pip install --upgrade - dandi; git config --global user.email "$${GITHUB_EMAIL}"; git config --global - user.name "$${GITHUB_USER}" + dandi; /opt/conda/bin/pip install --upgrade lincbrain-cli; git config + --global user.email "$${GITHUB_EMAIL}"; git config --global user.name + "$${GITHUB_USER}" ' memory: