Skip to content
This repository has been archived by the owner on Apr 29, 2021. It is now read-only.

Commit

Permalink
Merge pull request #66 from NERSC/19-07
Browse files Browse the repository at this point in the history
19 07
  • Loading branch information
rcthomas authored Aug 13, 2019
2 parents 3972991 + 8474598 commit a51450d
Show file tree
Hide file tree
Showing 12 changed files with 67 additions and 99 deletions.
4 changes: 2 additions & 2 deletions jupyter-base/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ RUN \

RUN \
curl -s -o /tmp/miniconda3.sh https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh && \
bash /tmp/miniconda3.sh -f -b -p /opt/anaconda3 && \
bash /tmp/miniconda3.sh -b -p /opt/anaconda3 && \
rm -rf /tmp/miniconda3.sh && \
echo "python 3.7.*" >> /opt/anaconda3/conda-meta/pinned && \
echo "python 3.7.3" >> /opt/anaconda3/conda-meta/pinned && \
/opt/anaconda3/bin/conda update --yes conda && \
/opt/anaconda3/bin/conda install --yes \
alembic \
Expand Down
7 changes: 4 additions & 3 deletions jupyter-nersc/app-notebooks/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ RUN \
ADD packages2.txt /tmp/packages2.txt
RUN \
wget -q -O /tmp/miniconda2.sh https://repo.continuum.io/miniconda/Miniconda2-latest-Linux-x86_64.sh && \
bash /tmp/miniconda2.sh -f -b -p /opt/anaconda2 && \
bash /tmp/miniconda2.sh -b -p /opt/anaconda2 && \
rm /tmp/miniconda2.sh && \
/opt/anaconda2/bin/conda update --yes conda && \
/opt/anaconda2/bin/conda install --yes anaconda && \
Expand Down Expand Up @@ -74,11 +74,12 @@ RUN \
pip install --no-cache-dir ipympl && \
jupyter nbextension enable --sys-prefix --py widgetsnbextension && \
jupyter labextension install \
@jupyterlab/hub-extension \
@jupyter-widgets/jupyterlab-manager \
jupyter-matplotlib \
@jupyterlab/toc \
jupyterlab_bokeh
jupyterlab_bokeh \
jupyterlab-favorites \
jupyterlab-recents

RUN \
/opt/anaconda2/bin/jupyter nbextension enable --sys-prefix --py widgetsnbextension
Expand Down
4 changes: 2 additions & 2 deletions jupyter-nersc/app-notebooks/packages2.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
basemap
beautiful-soup
beautifulsoup4
biopython
netcdf4
notebook=5.7.8
notebook
r-car
r-essentials
rpy2
Expand Down
2 changes: 1 addition & 1 deletion jupyter-nersc/app-notebooks/packages3.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ blaze
jupyter
jupyterlab
netcdf4
notebook=5.7.8
notebook
r-essentials
rpy2
scipy
Expand Down
2 changes: 0 additions & 2 deletions jupyter-nersc/web-jupyterhub/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ WORKDIR /srv

# Authenticator and spawner

# pip install git+https://github.com/nersc/nerscspawner.git && \

RUN \
pip install git+https://github.com/nersc/sshapiauthenticator.git && \
pip install git+https://github.com/jupyterhub/batchspawner.git@4747946 && \
Expand Down
2 changes: 2 additions & 0 deletions jupyter-nersc/web-jupyterhub/docker-entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,7 @@ file_env() {
file_env 'POSTGRES_PASSWORD'
file_env 'SKEY'
file_env 'MODS_JUPYTERHUB_API_TOKEN'
file_env 'CONFIGPROXY_AUTH_TOKEN'
file_env 'JUPYTERHUB_CRYPT_KEY'

exec "$@"
92 changes: 21 additions & 71 deletions jupyter-nersc/web-jupyterhub/jupyterhub_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -393,11 +393,11 @@ def comma_split(string):
{
'name': 'cull-idle',
'admin': True,
'command': 'cull_idle_servers.py --timeout=86400'.split(),
'command': 'cull_idle_servers.py --timeout=57600'.split(),
},
{
'name': 'announcement',
'url': 'http://127.0.0.1:8888',
'url': 'http://web-jupyterhub:8888',
'command': ["python", "-m", "announcement"],
},
{
Expand Down Expand Up @@ -505,6 +505,7 @@ def comma_split(string):
# environment variables here. Most, including the default, do not. Consult the
# documentation for your spawner to verify!
#c.Spawner.args = []
c.Spawner.args = ["--transport=ipc"]

## The command used for starting the single-user server.
#
Expand Down Expand Up @@ -706,7 +707,7 @@ def comma_split(string):
# JupyterHub modifies its own state accordingly and removes appropriate routes
# from the configurable proxy.
#c.Spawner.poll_interval = 30
c.Spawner.poll_interval = 900
c.Spawner.poll_interval = 300

## The port for single-user servers to listen on.
#
Expand Down Expand Up @@ -747,7 +748,7 @@ def comma_split(string):
# takes longer than this. start should return when the server process is started
# and its location is known.
#c.Spawner.start_timeout = 60
c.Spawner.start_timeout = 900
c.Spawner.start_timeout = 120

#------------------------------------------------------------------------------
# LocalProcessSpawner(Spawner) configuration
Expand Down Expand Up @@ -1057,52 +1058,52 @@ def comma_split(string):
"gerty-shared-node-cpu": (
"sshspawner.sshspawner.SSHSpawner", {
"cmd": ["/global/common/cori/das/jupyterhub/jupyter-launcher.sh",
"/global/common/cori/software/python/3.6-anaconda-5.2/bin/jupyter-labhub"],
"/usr/common/software/python/3.7-anaconda-2019.07/bin/jupyter-labhub"],
"environment": {"OMP_NUM_THREADS" : "2"},
"remote_hosts": ["gert01.nersc.gov"],
"remote_hosts": ["gerty.nersc.gov"],
"remote_port_command": "/usr/bin/python /global/common/cori/das/jupyterhub/new-get-port.py --ip",
"hub_api_url": "http://{}:8081/hub/api".format(ip),
"path": "/global/common/cori/software/python/3.6-anaconda-5.2/bin:/global/common/cori/das/jupyterhub:/usr/common/usg/bin:/usr/bin:/bin",
"path": "/usr/common/software/python/3.7-anaconda-2019.07/bin:/global/common/cori/das/jupyterhub:/usr/common/usg/bin:/usr/bin:/bin",
"ssh_keyfile": '/certs/{username}.key'
}
),
"cori-shared-node-cpu": (
"sshspawner.sshspawner.SSHSpawner", {
"cmd": ["/global/common/cori/das/jupyterhub/jupyter-launcher.sh",
"/global/common/cori/software/python/3.6-anaconda-5.2/bin/jupyter-labhub"],
"/usr/common/software/python/3.7-anaconda-2019.07/bin/jupyter-labhub"],
"environment": {"OMP_NUM_THREADS" : "2"},
"remote_hosts": ["corijupyter.nersc.gov"],
"remote_port_command": "/usr/bin/python /global/common/cori/das/jupyterhub/new-get-port.py --ip",
"hub_api_url": "http://{}:8081/hub/api".format(ip),
"path": "/global/common/cori/software/python/3.6-anaconda-5.2/bin:/global/common/cori/das/jupyterhub:/usr/common/usg/bin:/usr/bin:/bin",
"path": "/global/common/cori/software/python/3.7-anaconda-2019.07/bin:/global/common/cori/das/jupyterhub:/usr/common/usg/bin:/usr/bin:/bin",
"ssh_keyfile": '/certs/{username}.key'
}
),
"cori-exclusive-node-cpu": (
"nerscslurmspawner.NERSCExclusiveSlurmSpawner", {
"cmd": ["/global/common/cori/das/jupyterhub/jupyter-launcher.sh",
"/global/common/cori/software/python/3.6-anaconda-5.2/bin/jupyter-labhub"],
"/usr/common/software/python/3.7-anaconda-2019.07/bin/jupyter-labhub"],
"exec_prefix": "/usr/bin/ssh -q -o StrictHostKeyChecking=no -o preferredauthentications=publickey -l {username} -i /certs/{username}.key {remote_host}",
"http_timeout": 300,
"startup_poll_interval": 30.0,
"req_remote_host": "cori19-224.nersc.gov",
"req_homedir": "/tmp",
"req_runtime": "240",
"hub_api_url": "http://{}:8081/hub/api".format(ip),
"path": "/global/common/cori/software/python/3.6-anaconda-5.2/bin:/global/common/cori/das/jupyterhub:/usr/common/usg/bin:/usr/bin:/bin",
"path": "/global/common/cori/software/python/3.7-anaconda-2019.07/bin:/global/common/cori/das/jupyterhub:/usr/common/usg/bin:/usr/bin:/bin",
}
),
"cori-exclusive-node-gpu": (
"nerscslurmspawner.NERSCExclusiveGPUSlurmSpawner", {
"cmd": ["/global/common/cori/das/jupyterhub/jupyter-launcher.sh",
"/global/common/cori/software/python/3.6-anaconda-5.2/bin/jupyter-labhub"],
"/usr/common/software/python/3.7-anaconda-2019.07/bin/jupyter-labhub"],
"exec_prefix": "/usr/bin/ssh -q -o StrictHostKeyChecking=no -o preferredauthentications=publickey -l {username} -i /certs/{username}.key {remote_host}",
"startup_poll_interval": 30.0,
"req_remote_host": "cori19-224.nersc.gov",
"req_homedir": "/tmp",
"req_runtime": "240",
"hub_api_url": "http://{}:8081/hub/api".format(ip),
"path": "/global/common/cori/software/python/3.6-anaconda-5.2/bin:/global/common/cori/das/jupyterhub:/usr/common/usg/bin:/usr/bin:/bin",
"path": "/global/common/cori/software/python/3.7-anaconda-2019.07/bin:/global/common/cori/das/jupyterhub:/usr/common/usg/bin:/usr/bin:/bin",
}
),
"spin-shared-node-cpu": (
Expand All @@ -1121,37 +1122,26 @@ def comma_split(string):

# Pre-spawn myquota check

def space_error(home):
"""Extra message pointing users to try spawning again from /hub/home. """
home = url_path_join(home, 'home')
return ("There is insufficient space in your home directory; please clear up some files and then " +
"<a href='{home}'>navigate to the hub home</a> and start your server.".format(home=home))

async def setup(spawner):
username = spawner.user.name
remote_host = "corijupyter.nersc.gov"
# keyfile = spawner.ssh_keyfile.format(username=username)
keyfile = "/certs/{username}.key".format(username=username) # NEED to have in NERSCSpawner now
certfile = keyfile + "-cert.pub"
k = asyncssh.read_private_key(keyfile)
c = asyncssh.read_certificate(certfile)
# print(username, remote_host, keyfile, certfile)
async with asyncssh.connect(remote_host, username=username,
client_keys=[(k,c)], known_hosts=None) as conn:
home = "/global/homes/{}/{}".format(username[0], username)
result = await conn.run("myquota -c {}".format(home))
result = await conn.run("myquota -c $HOME")
retcode = result.exit_status
# result = await conn.run(spawner.remote_port_command)
# remote_port = int(result.stdout)
if retcode:
e = web.HTTPError(507,reason="Insufficient Storage")
em = space_error(spawner.hub.base_url)
e.my_message = em
from jinja2 import Markup
e = web.HTTPError(507, reason="Insufficient Storage")
e.jupyterhub_message = Markup("<br>Your home directory is over quota! " +
"Try moving or archiving and deleting some files from there, " +
"then come back and try again.<br>")
raise e
# spawner.remote_host = remote_host
# spawner.port = remote_port

# c.Spawner.pre_spawn_hook = setup
c.Spawner.pre_spawn_hook = setup

###

Expand All @@ -1177,43 +1167,3 @@ def auth_state_hook(spawner, auth_state):
### Prometheus

c.JupyterHub.authenticate_prometheus = False


## c.NERSCSpawner.spawners = [
## ("spin", "sshspawner.sshspawner.SSHSpawner", {
## "remote_hosts" : ["jupyter"],
## "remote_port" : "22",
## "hub_api_url" : "http://{}:8081/hub/api".format(ip),
## "path" : "/opt/anaconda3/bin:/usr/bin:/usr/local/bin:/bin",
## "remote_port_command" : "/opt/anaconda3/bin/get_port.py",
## "ssh_keyfile" : "/tmp/{username}.key",
## }),
## ("cori-shared", "sshspawner.sshspawner.SSHSpawner", {
## "remote_hosts" : ["cori19-224.nersc.gov"],
## "remote_port" : "22",
## "hub_api_url" : "http://{}:8081/hub/api".format(ip),
## "path" : bindir + ":/global/common/cori/das/jupyterhub/:/usr/common/usg/bin:/usr/bin:/bin",
## "remote_port_command" : "/global/common/cori/das/jupyterhub/get_port.py",
## "ssh_keyfile" : "/tmp/{username}.key",
## }),
## ("cori-exclusive-cpu", "nerscspawner.nerscspawner.NERSCSlurmSpawner", {
## "exec_prefix" :
## "/usr/bin/ssh -q -o StrictHostKeyChecking=no -o preferredauthentications=publickey -l {username} -i /tmp/{username}.key {remote_host}",
## "startup_poll_interval" : 10.0,
## "req_remote_host" : "cori19-224.nersc.gov",
## "req_homedir" : "/tmp",
## "req_runtime" : "30",
## "hub_api_url" : "http://{}:8081/hub/api".format(ip),
## "path" : bindir + ":/global/common/cori/das/jupyterhub/:/usr/common/usg/bin:/usr/bin:/bin",
## }),
## ("cori-config", "nerscspawner.nerscspawner.NERSCSlurmSpawner", {
## "exec_prefix" :
## "/usr/bin/ssh -q -o StrictHostKeyChecking=no -o preferredauthentications=publickey -l {username} -i /tmp/{username}.key {remote_host}",
## "startup_poll_interval" : 10.0,
## "req_remote_host" : "cori19-224.nersc.gov",
## "req_homedir" : "/tmp",
## "req_runtime" : "30",
## "hub_api_url" : "http://{}:8081/hub/api".format(ip),
## "path" : bindir + ":/global/common/cori/das/jupyterhub/:/usr/common/usg/bin:/usr/bin:/bin",
## }),
## ]
1 change: 0 additions & 1 deletion jupyter-nersc/web-jupyterhub/nerscslurmspawner.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,6 @@ class NERSCExclusiveGPUSlurmSpawner(NERSCSlurmSpawner):
#SBATCH --constraint=gpu
#SBATCH --gres=gpu:1
#SBATCH --job-name=jupyter
#SBATCH --mem=30GB
#SBATCH --nodes={{ nodes }}
#SBATCH --time={{ runtime }}
{{ env_text }}
Expand Down
9 changes: 7 additions & 2 deletions jupyter-nersc/web-jupyterhub/nerscspawner.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

import os

from jupyterhub.spawner import Spawner
from jupyterhub.spawner import LocalProcessSpawner

from tornado import httpclient, web
from traitlets import List, Dict, Unicode, observe
Expand Down Expand Up @@ -77,10 +77,15 @@ def user_allocations(self, repos=[]):
continue
yield allocation

def start(self):
if self.name not in self.spawners:
raise web.HTTPError(404)
return super().start()

def select_profile(self, profile):
self.log.debug("select_profile: " + profile)
if profile == "":
self.child_class, self.child_config = Spawner, {}
self.child_class, self.child_config = LocalProcessSpawner, {}
else:
try:
self.child_class, self.child_config = self.spawners[profile]
Expand Down
19 changes: 12 additions & 7 deletions jupyter-nersc/web-offline/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -22,26 +22,31 @@ RUN \
ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && \
echo $TZ > /etc/timezone

# Add flask and gunicorn
# Miniconda

RUN \
curl -s -o /tmp/miniconda3.sh https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh && \
bash /tmp/miniconda3.sh -f -b -p /opt/anaconda3 && \
bash /tmp/miniconda3.sh -b -p /opt/anaconda3 && \
rm -rf /tmp/miniconda3.sh && \
echo "python 3.7.*" >> /opt/anaconda3/conda-meta/pinned && \
echo "python 3.7.3" >> /opt/anaconda3/conda-meta/pinned && \
/opt/anaconda3/bin/conda update --yes conda && \
/opt/anaconda3/bin/conda install --yes \
flask \
gunicorn && \
/opt/anaconda3/bin/conda clean --yes --all

ENV PATH=/opt/anaconda3/bin:$PATH

# Packages

RUN \
conda install --yes \
--channel=conda-forge \
jinja2 \
sanic

# Application

WORKDIR /srv
ADD app.py /srv/
ADD templates /srv/templates
ADD static /srv/static

CMD ["gunicorn", "app:app", "-b", ":8000", "--name", "app", "--workers=4", "--log-file=-"]
CMD ["python", "-m", "sanic", "app.app", "--host=0.0.0.0", "--workers=4"]
20 changes: 14 additions & 6 deletions jupyter-nersc/web-offline/app.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,25 @@
import os

from flask import Flask, render_template
from sanic import Sanic
from sanic.response import html

app = Flask(__name__)
from jinja2 import Environment, PackageLoader

@app.route('/', defaults={'path': ''})
env = Environment(loader=PackageLoader('app', 'templates'))

app = Sanic(__name__)
app.static("/static", "./static")

@app.route('/')
@app.route('/<path:path>')
def catch_all(path):
async def catch_all(request, path=""):
default_message = "NERSC's Jupyter service is offline. It will return when maintenance is over. Please try again later."
message = os.environ.get("MESSAGE", default_message).strip()
if not message:
message = default_message
return render_template("index.html", message=message), 503
template = env.get_template("index.html")
content = template.render(message=message, app=app)
return html(content, status=503)

if __name__ == '__main__':
app.run(host="0.0.0.0")
app.run()
4 changes: 2 additions & 2 deletions jupyter-nersc/web-offline/templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@
<div class="container">
<div class="row">
<div class="col-6">
<img src="{{ url_for('static', filename='rectanglelogo-greytext-orangebody-greymoons.png') }}" class="float-left" height="80">
<img src="{{ app.url_for('static', filename='rectanglelogo-greytext-orangebody-greymoons.png') }}" class="float-left" height="80">
</div>
<div class="col-6">
<img src="{{ url_for('static', filename='logo.png') }}" class="float-right" height="80">
<img src="{{ app.url_for('static', filename='logo.png') }}" class="float-right" height="80">
</div>
</div>
<hr>
Expand Down

0 comments on commit a51450d

Please sign in to comment.