Skip to content

Commit

Permalink
Merge pull request #23 from betatim/deployment-lessons
Browse files Browse the repository at this point in the history
Lessons learnt from 'deploying' to everware-beta.cern.ch
  • Loading branch information
anaderi committed Nov 5, 2015
2 parents 417572d + b3da736 commit 943e846
Show file tree
Hide file tree
Showing 6 changed files with 114 additions and 20 deletions.
74 changes: 65 additions & 9 deletions everware/spawner.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
Unicode,
)
from tornado import gen
from tornado.ioloop import IOLoop

from escapism import escape

Expand All @@ -34,7 +35,13 @@ def _docker(self, method, *args, **kwargs):
m = getattr(self.client, method)

if method in generator_methods:
return list(m(*args, **kwargs))
def lister(mm):
ret = []
for l in mm:
self.log.debug("build %s", l)
ret.append(l)
return ret
return lister(m(*args, **kwargs))
else:
return m(*args, **kwargs)

Expand Down Expand Up @@ -71,6 +78,10 @@ def git(self, method, *args, **kwargs):
"""
return self.git_executor.submit(self._git, method, *args, **kwargs)

def clear_state(self):
state = super(CustomDockerSpawner, self).clear_state()
self.container_id = ''

@property
def repo_url(self):
return self.user.last_repo_url
Expand Down Expand Up @@ -109,9 +120,19 @@ def get_container(self):
raise
return container

@gen.coroutine
def get_image(self, image_name):
images = yield self.docker('images')
for img in images:
tags = [tag.split(':')[0] for tag in img['RepoTags']]
if image_name in tags:
return img

@gen.coroutine
def start(self, image=None):
"""start the single-user server in a docker container"""
tic = IOLoop.current().time()

tmp_dir = mkdtemp(suffix='-everware')
yield self.git('clone', self.repo_url, tmp_dir)
# is this blocking?
Expand All @@ -124,15 +145,19 @@ def start(self, image=None):
self.escaped_repo_url,
self.repo_sha)

self.log.debug("Building image {}".format(image_name))
build_log = yield self.docker('build',
path=tmp_dir,
tag=image_name,
rm=True)
self.log.debug("".join(str(line) for line in build_log))
image = yield self.get_image(image_name)
if image is None:
self.log.debug("Building image {}".format(image_name))
build_log = yield self.docker('build',
path=tmp_dir,
tag=image_name,
rm=True)
self.log.debug("".join(str(line) for line in build_log))

images = yield self.docker('images', image_name)
self.log.debug(images)
# If the build took too long, do not start the container
toc = IOLoop.current().time()
if toc - tic > self.start_timeout:
return

yield super(CustomDockerSpawner, self).start(
image=image_name
Expand All @@ -144,3 +169,34 @@ def _env_default(self):
env.update({'JPY_GITHUBURL': self.repo_url})

return env


class CustomSwarmSpawner(CustomDockerSpawner):
container_ip = '0.0.0.0'
#start_timeout = 42 #180

def __init__(self, **kwargs):
super(CustomSwarmSpawner, self).__init__(**kwargs)

@gen.coroutine
def lookup_node_name(self):
"""Find the name of the swarm node that the container is running on."""
containers = yield self.docker('containers', all=True)
for container in containers:
if container['Id'] == self.container_id:
name, = container['Names']
node, container_name = name.lstrip("/").split("/")
raise gen.Return(node)

@gen.coroutine
def start(self, image=None, extra_create_kwargs=None):
yield super(CustomSwarmSpawner, self).start(
image=image
)

container = yield self.get_container()
if container is not None:
node_name = container['Node']['Name']
self.user.server.ip = node_name
self.log.info("{} was started on {} ({}:{})".format(
self.container_name, node_name, self.user.server.ip, self.user.server.port))
14 changes: 8 additions & 6 deletions jupyterhub_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,17 @@
c = get_config()

# spawn with custom docker containers
c.JupyterHub.spawner_class = 'everware.CustomDockerSpawner'
#c.JupyterHub.spawner_class = 'everware.CustomDockerSpawner'
c.JupyterHub.spawner_class = 'everware.CustomSwarmSpawner'

# The docker instances need access to the Hub, so the default loopback port doesn't work:
from IPython.utils.localinterfaces import public_ips
c.JupyterHub.hub_ip = public_ips()[0]
c.JupyterHub.hub_api_ip = public_ips()[0]
# Find it easier to hardcode the IP of the machine it is deployed on
#from IPython.utils.localinterfaces import public_ips
c.JupyterHub.hub_ip = '128.142.143.186'#public_ips()[0]
c.JupyterHub.hub_api_ip = '128.142.143.186'#public_ips()[0]

c.JupyterHub.authenticator_class = 'everware.GitHubOAuthenticator'
c.Authenticator.whitelist = set()
c.Authenticator.whitelist = set(['betatim', 'ibab', 'kdungs', 'seneubert', 'alexpearce'])

c.GitHubOAuthenticator.oauth_callback_url = os.environ['OAUTH_CALLBACK_URL']
c.GitHubOAuthenticator.client_id = os.environ['GITHUB_CLIENT_ID']
Expand All @@ -26,7 +28,7 @@
# Set to False when running docker directly (i.e. on Linux)
#c.Spawner.tls = False
c.Spawner.debug = True
c.Spawner.http_timeout = 32
c.Spawner.start_timeout = 180*2
c.Spawner.remove_containers = True
c.Spawner.tls_assert_hostname = False
c.Spawner.use_docker_client_env = True
Expand Down
22 changes: 19 additions & 3 deletions share/static/html/home.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<div id="login-main">
<header class="jumbotron masthead">
<h1>everware</h1>
<p>Run your notebooks in the cloud</p>
<p>Sharing is caring</p>
</header>

<form class="form-horizontal" action="/hub/home" method="post" role="form" id="repo_url_entry">
Expand Down Expand Up @@ -33,12 +33,28 @@ <h1>everware</h1>
</div>
</form>

<div class="container">
<div class="row row-centered">
<div class="col-sm-6" style="float:none; margin:0 auto">
Paste the link to the git repository you want to try out. If you
need some inspiration try one of the following repositories:
<ul>
<li>https://github.com/everware/everware-dimuon-example</li>
<li>https://github.com/betatim/everware-demo</li>
</ul>
Read the documentation
to <a href="https://github.com/everware/everware/wiki/Being-everware-compatible">learn
how to make your repositories work</a> with everware.
</div>
</div>
</div>

<footer class="footer">
<div class="footer-inside">
<div class="col-sm-10">
<div class="col-sm-8">
Powered by <a href="https://jupyter.org/">Jupyter</a> and <a href="https://www.docker.com/">Docker</a>
</div>
<p style="float: right;">Logged in as {{user.name}}</p>
<div style="float: right;">Logged in as {{user.name}} (<a id="logout" href="{{logout_url}}">Logout</a>)</div>
</div>
</footer>

Expand Down
21 changes: 20 additions & 1 deletion share/static/html/login.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<div id="login-main">
<header class="jumbotron masthead">
<h1>everware</h1>
<p>Run your notebooks in the cloud</p>
<p>Sharing is caring</p>
</header>

<div class="container">
Expand Down Expand Up @@ -80,6 +80,25 @@ <h1>everware</h1>
</div>
</form>
{% endif %}

<div class="container">
<div class="row row-centered">
<div class="col-sm-6" style="float:none; margin:0 auto">
<a href="https://github.com/everware">Everware</a> is a
project that allows you to edit and run someone else's code with one
click. Even if that code has complicated setup instructions. The main
aim of the project is to encourage reuse of software between
researchers.
</div>
<div class="col-sm-6" style="float:none; margin:0 auto">
Currently Everware is in private beta, if you are interested in
trying it out:
<a href="http://goo.gl/forms/vbZXgYgj3N">join the waiting list</a>.

</div>
</div>
</div>

</div>
</div>
{% endblock login %}
Expand Down
2 changes: 1 addition & 1 deletion share/static/html/page.html
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ <h4 class="modal-title" id="{{key}}-label">{{title}}</h4>

<noscript>
<div id='noscript'>
Jupyter Hub requires JavaScript.<br>
Everware requires JavaScript.<br>
Please enable it to proceed.
</div>
</noscript>
Expand Down
1 change: 1 addition & 0 deletions share/static/html/spawn_pending.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
<div class="row">
<div class="text-center">
<p>Your server is starting up.</p>
<p>This can take seconds or minutes, please be patient</p>
<p>You will be redirected automatically when it's ready for you.</p>
<a id="refresh" class="btn btn-lg btn-primary" href="#">refresh</a>
</div>
Expand Down

0 comments on commit 943e846

Please sign in to comment.