From 48eefab5b360ae6be0e708496736773bc7548f5c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=A9rome=20Perrin?= <jerome@nexedi.com>
Date: Sat, 10 Jan 2015 19:53:21 +0100
Subject: [PATCH] ipython notebook

---
 component/ipython/buildout.cfg                |  27 ++++
 software/ipython_notebook/instance.cfg        | 120 ++++++++++++++++
 software/ipython_notebook/software.cfg        | 129 ++++++++++++++++++
 .../template/ipython_notebook_config.jinja    |  13 ++
 .../template/ipython_set_password.jinja       |  64 +++++++++
 5 files changed, 353 insertions(+)
 create mode 100644 component/ipython/buildout.cfg
 create mode 100644 software/ipython_notebook/instance.cfg
 create mode 100644 software/ipython_notebook/software.cfg
 create mode 100644 software/ipython_notebook/template/ipython_notebook_config.jinja
 create mode 100644 software/ipython_notebook/template/ipython_set_password.jinja

diff --git a/component/ipython/buildout.cfg b/component/ipython/buildout.cfg
new file mode 100644
index 0000000000..d1f2e39ca7
--- /dev/null
+++ b/component/ipython/buildout.cfg
@@ -0,0 +1,27 @@
+[buildout]
+extends =
+  ../numpy/buildout.cfg
+  ../matplotlib/buildout.cfg
+
+parts =
+  ipython
+
+[ipython-env]
+<= numpy-env
+
+[ipython]
+recipe = zc.recipe.egg:custom
+egg = ipython
+environment = ipython-env
+setup-eggs = ${numpy:egg}
+
+[ipython_notebook]
+recipe = zc.recipe.egg:scripts
+eggs = ipython[notebook]
+  ${matplotlib:egg}
+environment = ipython-env
+setup-eggs = ${numpy:egg}
+initialization =
+  # https://github.com/ipython/ipython/issues/5420
+  import os
+  os.environ['PYTHONPATH'] = ':'.join(sys.path)
diff --git a/software/ipython_notebook/instance.cfg b/software/ipython_notebook/instance.cfg
new file mode 100644
index 0000000000..36de927dd2
--- /dev/null
+++ b/software/ipython_notebook/instance.cfg
@@ -0,0 +1,120 @@
+[buildout]
+parts =
+  instance
+  publish-connection-parameter
+## Monitoring part XXX whe should not have to specify all parts like this
+## Parts to add for monitoring
+  certificate-authority
+  cron
+  cron-entry-monitor
+  cron-entry-rss
+  deploy-index
+  deploy-settings-cgi
+  deploy-status-cgi
+  deploy-status-history-cgi
+  setup-static-files
+  certificate-authority
+  zero-parameters
+  public-symlink
+  cgi-httpd-wrapper
+  cgi-httpd-graceful-wrapper
+  monitor-promise
+  monitor-instance-log-access
+## Monitor for ipython
+  monitor-current-log-access
+  monitor-deploy-set-password-cgi
+
+extends = ${monitor-template:output}
+
+eggs-directory = ${buildout:eggs-directory}
+develop-eggs-directory = ${buildout:develop-eggs-directory}
+offline = true
+
+[slapconfiguration]
+recipe = slapos.cookbook:slapconfiguration
+computer = $${slap_connection:computer_id}
+partition = $${slap_connection:partition_id}
+url = $${slap_connection:server_url}
+key = $${slap_connection:key_file}
+cert = $${slap_connection:cert_file}
+
+[instance-parameter]
+port = 8888
+host = $${slapconfiguration:ipv6-random}
+cert_file = $${generate-certificate:cert_file}
+key_file = $${generate-certificate:key_file}
+logfile = $${directory:log}/ipython_notebook.log
+notebook_dir = $${directory:notebook_dir}
+
+[generate-certificate]
+; TODO: there is a slapos recipe to generate certificates. Use it instead
+recipe = plone.recipe.command
+command =
+  if [ ! -e $${instance-parameter:key_file} ]
+  then
+    ${openssl-output:openssl} req -x509 -nodes -days 3650 \
+      -subj "/C=AA/ST=X/L=X/O=Dis/CN=$${instance-parameter:host}" \
+      -newkey rsa:1024 -keyout $${instance-parameter:key_file} \
+      -out $${instance-parameter:cert_file}
+  fi
+update-command = $${:command}
+cert_file = $${directory:etc}/ipython_notebook_cert.crt
+key_file = $${directory:etc}/ipython_notebook_cert.key
+
+[instance]
+recipe = slapos.cookbook:wrapper
+command-line =
+  ${buildout:bin-directory}/ipython notebook
+  --no-browser
+  --matplotlib=inline
+  --ip=$${instance-parameter:host}
+  --port=$${instance-parameter:port}
+  --port-retries=0
+  --certfile=$${instance-parameter:cert_file}
+  --keyfile=$${instance-parameter:key_file}
+  --notebook-dir=$${instance-parameter:notebook_dir}
+  --logfile=$${instance-parameter:logfile}
+  --config=$${ipython_notebook_config:rendered}
+wrapper-path = $${directory:service}/ipython_notebook
+parameters-extra = true
+
+[ipython_notebook_config]
+recipe = slapos.recipe.template:jinja2
+template = ${ipython_notebook_config:location}/${ipython_notebook_config:filename}
+rendered = $${directory:etc}/ipython_notebook_config.py
+mode = 0744
+context =
+  raw config_cfg $${buildout:directory}/knowledge0.cfg
+
+[monitor-current-log-access]
+< = monitor-directory-access
+source = $${instance-parameter:logfile}
+
+[monitor-deploy-set-password-cgi]
+recipe = slapos.recipe.template:jinja2
+template = ${ipython_notebook_set_password:location}/${ipython_notebook_set_password:filename}
+rendered = $${monitor-directory:knowledge0-cgi}/$${:filename}
+filename = ipython-notebook-password.cgi
+mode = 0744
+context =
+  raw config_cfg $${buildout:directory}/knowledge0.cfg
+  raw python_executable ${buildout:bin-directory}/ipython
+  key pwd monitor-directory:knowledge0-cgi
+  key this_file :filename
+  key httpd_graceful cgi-httpd-graceful-wrapper:rendered
+
+[directory]
+recipe = slapos.cookbook:mkdirectory
+home = $${buildout:directory}
+etc = $${:home}/etc
+var = $${:home}/var
+script = $${:etc}/run/
+service = $${:etc}/service
+promise = $${:etc}/promise/
+log = $${:var}/log
+notebook_dir = $${:var}/notebooks
+
+[publish-connection-parameter]
+recipe = slapos.cookbook:publish
+url = https://[$${instance-parameter:host}]:$${instance-parameter:port}
+monitor_url = $${monitor-parameters:url}
diff --git a/software/ipython_notebook/software.cfg b/software/ipython_notebook/software.cfg
new file mode 100644
index 0000000000..b1adcc092b
--- /dev/null
+++ b/software/ipython_notebook/software.cfg
@@ -0,0 +1,129 @@
+[buildout]
+versions = versions
+extends = 
+  ../../stack/slapos.cfg
+  ../../stack/monitor/buildout.cfg
+  ../../component/ipython/buildout.cfg
+  ../../component/scipy/buildout.cfg
+  ../../component/scikit-learn/buildout.cfg
+  ../../component/pandas/buildout.cfg
+  ../../component/manpy/buildout.cfg
+  ../../component/openssl/buildout.cfg
+parts =
+  monitor-eggs
+  slapos-cookbook
+  ipython_notebook
+  ipython_notebook_set_password
+  instance
+
+[ipython_notebook]
+; In the ipython notebook software, we use more eggs than in the minimal
+; ipython notebook component
+eggs +=
+  ${scipy:egg}
+  ${pandas:egg}
+  ${scikit-learn:egg}
+  ${manpy:eggs}
+initialization +=
+  ${manpy:initialization}
+
+[ipython_notebook_config]
+recipe = hexagonit.recipe.download
+url = ${:_profile_base_location_}/template/${:filename}
+download-only = true
+md5sum = a5bc4ee8539109d1de7ab33b4c2c97ea
+destination = ${buildout:parts-directory}/${:_buildout_section_name_}
+filename = ipython_notebook_config.jinja
+mode = 0644
+
+[ipython_notebook_set_password]
+recipe = hexagonit.recipe.download
+url = ${:_profile_base_location_}/template/${:filename}
+download-only = true
+md5sum = d7d4a7e19d55bf14007819258bf42100
+destination = ${buildout:parts-directory}/${:_buildout_section_name_}
+filename = ipython_set_password.jinja
+mode = 0644
+
+[instance]
+recipe = slapos.recipe.template
+url = ${:_profile_base_location_}/instance.cfg
+output = ${buildout:directory}/instance.cfg
+
+
+
+
+[versions]
+PyRSS2Gen = 1.1
+Pygments = 2.0.2
+cns.recipe.symlink = 0.2.3
+ipython = 3.1.0
+matplotlib = 1.4.3
+mistune = 0.5.1
+nose = 1.3.6
+pandas = 0.16.0
+plone.recipe.command = 1.1
+pyzmq = 14.6.0
+scikit-learn = 0.16.1
+scipy = 0.15.1
+simpy = 3.0.7
+slapos.recipe.template = 2.6
+terminado = 0.5
+tornado = 4.1
+
+# Required by:
+# dream==0.0.1
+MySQL-python = 1.2.5
+
+# Required by:
+# tornado==4.1
+backports.ssl-match-hostname = 3.4.0.2
+
+# Required by:
+# tornado==4.1
+certifi = 2015.4.28
+
+# Required by:
+# matplotlib==1.4.3
+mock = 1.0.1
+
+# Required by:
+# dream==0.0.1
+numpy = 1.9.2
+
+# Required by:
+# terminado==0.5
+ptyprocess = 0.4
+
+# Required by:
+# dream==0.0.1
+pydot = 1.0.28
+
+# Required by:
+# matplotlib==1.4.3
+# pandas==0.16.0
+python-dateutil = 2.4.2
+
+# Required by:
+# dream==0.0.1
+rpy2 = 2.5.6
+
+# Required by:
+# rpy2==2.5.6
+singledispatch = 3.4.0.3
+
+# Required by:
+# dream==0.0.1
+tablib = 0.10.0
+
+# Required by:
+# dream==0.0.1
+xlrd = 0.9.3
+
+# Required by:
+# dream==0.0.1
+xlwt = 1.0.0
+
+# Required by:
+# dream==0.0.1
+zope.dottedname = 4.1.0
\ No newline at end of file
diff --git a/software/ipython_notebook/template/ipython_notebook_config.jinja b/software/ipython_notebook/template/ipython_notebook_config.jinja
new file mode 100644
index 0000000000..aafdb10161
--- /dev/null
+++ b/software/ipython_notebook/template/ipython_notebook_config.jinja
@@ -0,0 +1,13 @@
+
+import ConfigParser
+
+knowledge_0 = '{{ config_cfg }}'
+
+c = get_config()
+
+parser = ConfigParser.ConfigParser()
+parser.read(knowledge_0)
+
+if parser.has_option("ipython_notebook", "password"):
+  c.NotebookApp.password = parser.get("ipython_notebook", "password")
+
diff --git a/software/ipython_notebook/template/ipython_set_password.jinja b/software/ipython_notebook/template/ipython_set_password.jinja
new file mode 100644
index 0000000000..18d6490206
--- /dev/null
+++ b/software/ipython_notebook/template/ipython_set_password.jinja
@@ -0,0 +1,64 @@
+#!{{ python_executable }}
+
+import cgi
+import cgitb
+import ConfigParser
+import os
+import re
+import subprocess
+
+from IPython.lib import passwd
+
+#cgitb.enable(display=0, logdir="/tmp/cgi.log")
+cgitb.enable()
+form = cgi.FieldStorage()
+
+config_file = "{{ config_cfg }}"
+
+
+if not os.path.exists(config_file):
+  print "Your software does <b>not</b> embed 0-knowledge. \
+  This interface is useless in this case</body></html>"
+  exit(0)
+
+
+parser = ConfigParser.ConfigParser()
+parser.read(config_file)
+if not parser.has_section("ipython_notebook"):
+  parser.add_section("ipython_notebook")
+
+if not parser.has_option("ipython_notebook", "password"):
+  parser.set("ipython_notebook", "password", "")
+
+if "password" in form:
+  parser.set("ipython_notebook", "password", passwd(form["password"].value))
+  # subprocess.call('{{ httpd_graceful }}')
+  # TODO: we should restart ipython
+
+with open(config_file, 'w') as file:
+  parser.write(file)
+
+# TODO cleanup
+print "<html><head>"
+print "<link rel=\"stylesheet\" href=\"static/pure-min.css\">"
+print "<link rel=\"stylesheet\" href=\"static/style.css\">"
+print "</head><body>"
+print "<h1>IPython Notebook Password :</h1>"
+print "<form action=\"/index.cgi\" method=\"post\" class=\"pure-form-aligned\">"
+print "<input type=\"hidden\" name=\"posting-script\" value=\"{{ pwd }}/{{ this_file }}\">"
+
+print """<div class="pure-control-group">
+<label for="password">Password*:</label>
+<input placeholder="Set your password" type="password" name="password" id="password"></br>
+</div><div class="pure-control-group">
+<label for="password">Verify Password*:</label>
+<input placeholder="Verify password" type="password" name="password_2" id="password_2"></br>
+</div><p id="validate-status" style="color:red"></p>
+<div class="pure-controls">
+<button id="register-button" type="submit" class="pure-button pure-button-primary" disabled>Access</button></div>
+</form>
+<script type="text/javascript" src="static/jquery-1.10.2.min.js"></script>
+<script type="text/javascript" src="static/monitor-register.js"></script>
+</body></html>
+"""
+
-- 
2.30.9