├── .gitignore ├── .kitchen.yml ├── Berksfile ├── Gemfile ├── LICENSE ├── README.md ├── Thorfile ├── attributes └── default.rb ├── chefignore ├── libraries └── ipython_utils.rb ├── metadata.rb ├── providers └── profile.rb ├── recipes ├── default.rb ├── proxy.rb └── virtenv_launch.rb ├── resources └── profile.rb ├── templates └── default │ ├── jupyter_notebook_config.py.erb │ └── nginx-proxy.erb └── test └── integration └── default └── jupyter_service.rb /.gitignore: -------------------------------------------------------------------------------- 1 | .vagrant 2 | Berksfile.lock 3 | *~ 4 | *# 5 | .#* 6 | \#*# 7 | .*.sw[a-z] 8 | *.un~ 9 | /cookbooks 10 | 11 | # Bundler 12 | Gemfile.lock 13 | bin/* 14 | .bundle/* 15 | 16 | *.bak 17 | .kitchen/ -------------------------------------------------------------------------------- /.kitchen.yml: -------------------------------------------------------------------------------- 1 | --- 2 | driver: 3 | name: vagrant 4 | network: 5 | - ["private_network", ip: "33.33.33.10"] 6 | - ["forwarded_port", {guest: 8888, host: 9999}] 7 | platforms: 8 | - name: ubuntu-16.04 9 | - name: ubuntu-14.04 10 | provisioner: 11 | name: chef_zero 12 | suites: 13 | - attributes: 14 | ipynb: 15 | NotebookApp: 16 | password: test 17 | scientific_stack: [] 18 | ssl_certificate: /etc/nginx/ssl.pem 19 | ssl_certificate_key: /etc/nginx/ssl.key 20 | ssl_certificate_key_text: |- 21 | -----BEGIN RSA PRIVATE KEY----- 22 | MIICXQIBAAKBgQDKDv8EmwzlrhoN7XknVNDyZFMC3eQl60fSrNgjYjMojMmNlrRx 23 | p770h5Y9dosEuQXuXMbYyvyQpQemDWiQEt6rkGhOB5lZ9NheWn6nnW+9YBbtwkqz 24 | ZuAoq6asuvH4faXivg6d8Qxt0xa+g3vFUNVzKBLoRziYFN4NEO+gxrXbXwIDAQAB 25 | AoGBAIJMhVtc+UYrrZWJq/UXFt8YnwdcO8HQJbLPz1mR+9eMYnUx2A7q05Mw1Euy 26 | ZBeZkR+TKI+o5pIIOhR01RcDdB8dPtoVCgiDSyb/kzhqnEvY/8IvvHdvGQU2V5q3 27 | 6NVISp/SIRUuFxoTuPq5tF0cvPYSp4U+BBFavnXwe1y9KUSxAkEA6gs2rDyMVU7K 28 | 0yY+pzWM6/OdNKPWYRCBeCRxo1d2k4xlkoPOq8xVm5+RyNq9NBGWkUSROz6zOuwH 29 | swExKq3sswJBAN0DoHMks6o/vw2Z86FJEEffWuDXRHZeMfgaug8vuDHLzrkZcUzb 30 | WJcbNTF1H1FeF3ITevt98CZOhrZHCXcwhKUCQQDorCc5SaR1trQ7AB1vW/RyKimS 31 | SIL60k70Ir76lRwkCYJ9Cx5ueuBsq1FibduFJSsb1h/P10CVhksNMVUwyeGzAkA9 32 | YVl5QPMo0CVmSKBR5bHA1DYwBXj9CrID/qA3wX/9TGXwIDHIL47OAH9oaee1uFT4 33 | mJJqMBK3AM4G53mogXAFAkBSpcRbCXlWBUJjGiE9qrpaqrDhncNhMA5zqxkxmGEF 34 | WfBxaOjp9wsQZZHX+bSQLp92WjW0Uq712dtL7CVOWqxb 35 | -----END RSA PRIVATE KEY----- 36 | ssl_certificate_text: |- 37 | -----BEGIN CERTIFICATE----- 38 | MIICmDCCAgGgAwIBAgIJAONj1DIGs9lkMA0GCSqGSIb3DQEBBQUAMD0xCzAJBgNV 39 | BAYTAlVTMQswCQYDVQQIEwJUWDEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQ 40 | dHkgTHRkMB4XDTEzMDgxOTIwNDE0NloXDTE0MDgxOTIwNDE0NlowPTELMAkGA1UE 41 | BhMCVVMxCzAJBgNVBAgTAlRYMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0 42 | eSBMdGQwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMoO/wSbDOWuGg3teSdU 43 | 0PJkUwLd5CXrR9Ks2CNiMyiMyY2WtHGnvvSHlj12iwS5Be5cxtjK/JClB6YNaJAS 44 | 3quQaE4HmVn02F5afqedb71gFu3CSrNm4Cirpqy68fh9peK+Dp3xDG3TFr6De8VQ 45 | 1XMoEuhHOJgU3g0Q76DGtdtfAgMBAAGjgZ8wgZwwHQYDVR0OBBYEFKJEzyGWKl47 46 | WecMx/gocolKLN1IMG0GA1UdIwRmMGSAFKJEzyGWKl47WecMx/gocolKLN1IoUGk 47 | PzA9MQswCQYDVQQGEwJVUzELMAkGA1UECBMCVFgxITAfBgNVBAoTGEludGVybmV0 48 | IFdpZGdpdHMgUHR5IEx0ZIIJAONj1DIGs9lkMAwGA1UdEwQFMAMBAf8wDQYJKoZI 49 | hvcNAQEFBQADgYEAUxagzwBN/fCJlKh1eIdO/oWBqtt9Ca70VSylD0WJrtgznreG 50 | fZJ4bEzYsCAsWcQowSmEkzQeXzB60EUT3I09SbyFe7+JD+/CGiBfET42ABGwGNUV 51 | dE3w7J7Coc46rYXAqMg05hBYrOe43nra2RHTFxQr5V+oDLMcZuPI2Ozo4e4= 52 | -----END CERTIFICATE----- 53 | name: default 54 | run_list: 55 | - "recipe[apt]" 56 | - "recipe[yum]" 57 | - "recipe[ipynb::default]" 58 | - "recipe[ipynb::virtenv_launch]" 59 | - "recipe[ipynb::proxy]" 60 | verifier: 61 | name: inspec 62 | -------------------------------------------------------------------------------- /Berksfile: -------------------------------------------------------------------------------- 1 | source 'https://supermarket.chef.io' 2 | 3 | metadata 4 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'berkshelf' 4 | gem 'thor-foodcritic' 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, and 10 | distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by the copyright 13 | owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all other entities 16 | that control, are controlled by, or are under common control with that entity. 17 | For the purposes of this definition, "control" means (i) the power, direct or 18 | indirect, to cause the direction or management of such entity, whether by 19 | contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the 20 | outstanding shares, or (iii) beneficial ownership of such entity. 21 | 22 | "You" (or "Your") shall mean an individual or Legal Entity exercising 23 | permissions granted by this License. 24 | 25 | "Source" form shall mean the preferred form for making modifications, including 26 | but not limited to software source code, documentation source, and configuration 27 | files. 28 | 29 | "Object" form shall mean any form resulting from mechanical transformation or 30 | translation of a Source form, including but not limited to compiled object code, 31 | generated documentation, and conversions to other media types. 32 | 33 | "Work" shall mean the work of authorship, whether in Source or Object form, made 34 | available under the License, as indicated by a copyright notice that is included 35 | in or attached to the work (an example is provided in the Appendix below). 36 | 37 | "Derivative Works" shall mean any work, whether in Source or Object form, that 38 | is based on (or derived from) the Work and for which the editorial revisions, 39 | annotations, elaborations, or other modifications represent, as a whole, an 40 | original work of authorship. For the purposes of this License, Derivative Works 41 | shall not include works that remain separable from, or merely link (or bind by 42 | name) to the interfaces of, the Work and Derivative Works thereof. 43 | 44 | "Contribution" shall mean any work of authorship, including the original version 45 | of the Work and any modifications or additions to that Work or Derivative Works 46 | thereof, that is intentionally submitted to Licensor for inclusion in the Work 47 | by the copyright owner or by an individual or Legal Entity authorized to submit 48 | on behalf of the copyright owner. For the purposes of this definition, 49 | "submitted" means any form of electronic, verbal, or written communication sent 50 | to the Licensor or its representatives, including but not limited to 51 | communication on electronic mailing lists, source code control systems, and 52 | issue tracking systems that are managed by, or on behalf of, the Licensor for 53 | the purpose of discussing and improving the Work, but excluding communication 54 | that is conspicuously marked or otherwise designated in writing by the copyright 55 | owner as "Not a Contribution." 56 | 57 | "Contributor" shall mean Licensor and any individual or Legal Entity on behalf 58 | of whom a Contribution has been received by Licensor and subsequently 59 | incorporated within the Work. 60 | 61 | 2. Grant of Copyright License. 62 | 63 | Subject to the terms and conditions of this License, each Contributor hereby 64 | grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, 65 | irrevocable copyright license to reproduce, prepare Derivative Works of, 66 | publicly display, publicly perform, sublicense, and distribute the Work and such 67 | Derivative Works in Source or Object form. 68 | 69 | 3. Grant of Patent License. 70 | 71 | Subject to the terms and conditions of this License, each Contributor hereby 72 | grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, 73 | irrevocable (except as stated in this section) patent license to make, have 74 | made, use, offer to sell, sell, import, and otherwise transfer the Work, where 75 | such license applies only to those patent claims licensable by such Contributor 76 | that are necessarily infringed by their Contribution(s) alone or by combination 77 | of their Contribution(s) with the Work to which such Contribution(s) was 78 | submitted. If You institute patent litigation against any entity (including a 79 | cross-claim or counterclaim in a lawsuit) alleging that the Work or a 80 | Contribution incorporated within the Work constitutes direct or contributory 81 | patent infringement, then any patent licenses granted to You under this License 82 | for that Work shall terminate as of the date such litigation is filed. 83 | 84 | 4. Redistribution. 85 | 86 | You may reproduce and distribute copies of the Work or Derivative Works thereof 87 | in any medium, with or without modifications, and in Source or Object form, 88 | provided that You meet the following conditions: 89 | 90 | You must give any other recipients of the Work or Derivative Works a copy of 91 | this License; and 92 | You must cause any modified files to carry prominent notices stating that You 93 | changed the files; and 94 | You must retain, in the Source form of any Derivative Works that You distribute, 95 | all copyright, patent, trademark, and attribution notices from the Source form 96 | of the Work, excluding those notices that do not pertain to any part of the 97 | Derivative Works; and 98 | If the Work includes a "NOTICE" text file as part of its distribution, then any 99 | Derivative Works that You distribute must include a readable copy of the 100 | attribution notices contained within such NOTICE file, excluding those notices 101 | that do not pertain to any part of the Derivative Works, in at least one of the 102 | following places: within a NOTICE text file distributed as part of the 103 | Derivative Works; within the Source form or documentation, if provided along 104 | with the Derivative Works; or, within a display generated by the Derivative 105 | Works, if and wherever such third-party notices normally appear. The contents of 106 | the NOTICE file are for informational purposes only and do not modify the 107 | License. You may add Your own attribution notices within Derivative Works that 108 | You distribute, alongside or as an addendum to the NOTICE text from the Work, 109 | provided that such additional attribution notices cannot be construed as 110 | modifying the License. 111 | You may add Your own copyright statement to Your modifications and may provide 112 | additional or different license terms and conditions for use, reproduction, or 113 | distribution of Your modifications, or for any such Derivative Works as a whole, 114 | provided Your use, reproduction, and distribution of the Work otherwise complies 115 | with the conditions stated in this License. 116 | 117 | 5. Submission of Contributions. 118 | 119 | Unless You explicitly state otherwise, any Contribution intentionally submitted 120 | for inclusion in the Work by You to the Licensor shall be under the terms and 121 | conditions of this License, without any additional terms or conditions. 122 | Notwithstanding the above, nothing herein shall supersede or modify the terms of 123 | any separate license agreement you may have executed with Licensor regarding 124 | such Contributions. 125 | 126 | 6. Trademarks. 127 | 128 | This License does not grant permission to use the trade names, trademarks, 129 | service marks, or product names of the Licensor, except as required for 130 | reasonable and customary use in describing the origin of the Work and 131 | reproducing the content of the NOTICE file. 132 | 133 | 7. Disclaimer of Warranty. 134 | 135 | Unless required by applicable law or agreed to in writing, Licensor provides the 136 | Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, 137 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, 138 | including, without limitation, any warranties or conditions of TITLE, 139 | NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are 140 | solely responsible for determining the appropriateness of using or 141 | redistributing the Work and assume any risks associated with Your exercise of 142 | permissions under this License. 143 | 144 | 8. Limitation of Liability. 145 | 146 | In no event and under no legal theory, whether in tort (including negligence), 147 | contract, or otherwise, unless required by applicable law (such as deliberate 148 | and grossly negligent acts) or agreed to in writing, shall any Contributor be 149 | liable to You for damages, including any direct, indirect, special, incidental, 150 | or consequential damages of any character arising as a result of this License or 151 | out of the use or inability to use the Work (including but not limited to 152 | damages for loss of goodwill, work stoppage, computer failure or malfunction, or 153 | any and all other commercial damages or losses), even if such Contributor has 154 | been advised of the possibility of such damages. 155 | 156 | 9. Accepting Warranty or Additional Liability. 157 | 158 | While redistributing the Work or Derivative Works thereof, You may choose to 159 | offer, and charge a fee for, acceptance of support, warranty, indemnity, or 160 | other liability obligations and/or rights consistent with this License. However, 161 | in accepting such obligations, You may act only on Your own behalf and on Your 162 | sole responsibility, not on behalf of any other Contributor, and only if You 163 | agree to indemnify, defend, and hold each Contributor harmless for any liability 164 | incurred by, or claims asserted against, such Contributor by reason of your 165 | accepting any such warranty or additional liability. 166 | 167 | END OF TERMS AND CONDITIONS 168 | 169 | APPENDIX: How to apply the Apache License to your work 170 | 171 | To apply the Apache License to your work, attach the following boilerplate 172 | notice, with the fields enclosed by brackets "[]" replaced with your own 173 | identifying information. (Don't include the brackets!) The text should be 174 | enclosed in the appropriate comment syntax for the file format. We also 175 | recommend that a file or class name and description of purpose be included on 176 | the same "printed page" as the copyright notice for easier identification within 177 | third-party archives. 178 | 179 | Copyright [yyyy] [name of copyright owner] 180 | 181 | Licensed under the Apache License, Version 2.0 (the "License"); 182 | you may not use this file except in compliance with the License. 183 | You may obtain a copy of the License at 184 | 185 | http://www.apache.org/licenses/LICENSE-2.0 186 | 187 | Unless required by applicable law or agreed to in writing, software 188 | distributed under the License is distributed on an "AS IS" BASIS, 189 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 190 | See the License for the specific language governing permissions and 191 | limitations under the License. 192 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # IPython Notebook Cookbook 2 | 3 | Sets up an IPython Notebook server using Chef. 4 | 5 | This cookbook targets Jupyter/IPython 4.x environment. 6 | 7 | CAUTION: This cookbook now (Jan, 2017) defaults to using Jupyter and IPython versus the old 8 | monolithic IPython stack. While testing has been performed, if you are dependent on the 9 | old behavior, you should use the V1.1.1 tagged release of this cookbook. 10 | 11 | # Requirements 12 | 13 | This cookbook uses Chef 12.1+. 14 | 15 | # Usage 16 | 17 | ## Include this cookbook 18 | 19 | This cookbook isn't on supermarket (yet), so for now you'll have to use Berkshelf and point to it in your Berksfile 20 | 21 | ```ruby 22 | cookbook 'ipynb', github: 'rgbkrk/ipynb-cookbook' 23 | ``` 24 | 25 | ## Bootstrap VirtualBox 26 | 27 | You can also try it out using test-kitchen. 28 | 29 | test-kitchen converge ubuntu-16 30 | 31 | Once finished, the IPython notebook can be accessed from your host machine (through port forwarding) on 127.0.0.1:9999. 32 | 33 | # Attributes 34 | 35 | See `attributes/default.rb` for default values. Most values including `:linux_user`, `:linux_group`, and `:service_name` default to `'ipynb'`. 36 | 37 | Particularly important parameters for configuration of the notebook are located in `node[:ipynb][:NotebookApp]`. 38 | 39 | * `node[:ipynb][:NotebookApp][:password]` - Password to use when accessing the notebook. (Please use an encrypted data bag to set this attribute in a real deployment). 40 | 41 | If you're using the virtualenv recipe, you can either install more to the same virtualenv (`node[:ipynb][:virtenv]`) or add additional packages to `node[:ipynb][:extra_packages]`. 42 | 43 | # Recipes 44 | 45 | The `default` recipe simply installs (using system packages) IPython Notebook, numpy, Pandas, matplotlib, and all the dependencies for these. 46 | 47 | The `virtenv_launch` recipe creates user and group *ipynb*, creates a spot to store notebooks, and sets up ipython notebook as a service using supervisord. 48 | 49 | The `proxy` recipe adds an nginx proxy to the notebook and requires you to set the certificate and key attributes. 50 | 51 | * `node[:ipynb][:ssl_certificate]` - Location to install the SSL certificate (e.g. /etc/nginx/ssl.crt) 52 | * `node[:ipynb][:ssl_certificate_text]` - Text for the SSL Certificate 53 | * `node[:ipynb][:ssl_certificate_key]` - Location to install the SSL private key (e.g. /etc/nginx/ssl.key) 54 | * `node[:ipynb][:ssl_certificate_key_text]` - Text for the SSL private key 55 | 56 | On a real deployment, these should be set using an encrypted data bag. 57 | 58 | # Contributing 59 | 60 | 1. Fork it 61 | 2. Create your feature branch (`git checkout -b feature1`) 62 | 3. Commit your changes (`git commit -am 'Added new provider to ...'`) 63 | 4. Push to the branch (`git push origin feature1`) 64 | 5. Create a new Pull Request 65 | 66 | # Future Directions 67 | 68 | This cookbook satisfies the needs of the current collaborators. To do items include: 69 | - Supporting non-Ubuntu platforms (Amazon, Centos, etc.) 70 | - Support for non-IPython kernels (Rstats) 71 | - Submission to Supermarket 72 | - CI testing 73 | 74 | Contributions are most welcome! 75 | 76 | # Author 77 | 78 | Author:: Kyle Kelley (kyle.kelley@rackspace.com) 79 | 80 | Copyright 2013, Rackspace Hosting 81 | 82 | Licensed under the Apache License, Version 2.0 (the "License"); 83 | you may not use this file except in compliance with the License. 84 | You may obtain a copy of the License at 85 | 86 | http://www.apache.org/licenses/LICENSE-2.0 87 | 88 | Unless required by applicable law or agreed to in writing, software 89 | distributed under the License is distributed on an "AS IS" BASIS, 90 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 91 | See the License for the specific language governing permissions and 92 | limitations under the License. 93 | 94 | [Vagrant]:http://vagrantup.com/ 95 | [Berkshelf]:http://berkshelf.com/ 96 | [Bundler]:http://gembundler.com/ 97 | -------------------------------------------------------------------------------- /Thorfile: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | require 'bundler' 4 | require 'bundler/setup' 5 | require 'thor/foodcritic' 6 | require 'berkshelf/thor' 7 | -------------------------------------------------------------------------------- /attributes/default.rb: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # 3 | # IPython Notebook Cookbook Default Attributes 4 | # 5 | ################################################################################ 6 | 7 | ################################################################################ 8 | # Server side configuration 9 | ################################################################################ 10 | 11 | # user and group for the system IPython is being deployed to 12 | default['ipynb']['linux_user'] = 'ipynb' 13 | default['ipynb']['linux_group'] = 'ipynb' 14 | 15 | # Home directory for the system user 16 | default['ipynb']['home_dir'] = nil # File.join('/home/', default['ipynb']['linux_user']) 17 | 18 | # Spot to store the notebook files 19 | default['ipynb']['notebook_dir'] = nil # File.join(default[:ipynb][:home_dir], 20 | # "notebooks") 21 | 22 | # Service name 23 | default['ipynb']['service_name'] = 'jupyter' 24 | 25 | # IPython profile 26 | default['ipynb']['profile_name'] = 'cooked' 27 | 28 | default['ipynb']['proxy']['enable'] = true 29 | default['ipynb']['proxy']['hostname'] = fqdn 30 | default['ipynb']['proxy']['alias_hostnames'] = [] 31 | 32 | default['nginx']['default_site_enabled'] = false 33 | 34 | default['nginx']['version'] = '1.10.2' 35 | default['nginx']['source']['version'] = '1.10.2' 36 | # The Chef checksum of a binary is determined by: shasum -a 256 FILE_NAME 37 | default['nginx']['source']['checksum'] = '1045AC4987A396E2FA5D0011DAF8987B612DD2F05181B67507DA68CBE7D765C2' 38 | default['nginx']['source']['prefix'] = "/opt/nginx-#{node['nginx']['source']['version']}" 39 | default['nginx']['source']['url'] = "http://nginx.org/download/nginx-#{node['nginx']['source']['version']}.tar.gz" 40 | default['nginx']['source']['sbin_path'] = "#{node['nginx']['source']['prefix']}/sbin/nginx" 41 | 42 | default['nginx']['source']['default_configure_flags'] = [ 43 | "--prefix=#{node['nginx']['source']['prefix']}", 44 | "--conf-path=#{node['nginx']['dir']}/nginx.conf", 45 | "--sbin-path=#{node['nginx']['source']['sbin_path']}", 46 | ] 47 | node.default['nginx']['init_style'] = 'runit' 48 | 49 | ################################################################################ 50 | # IPython Notebook runtime configuration 51 | ################################################################################ 52 | 53 | # IP to host on, defaults to all interfaces 54 | default['ipynb']['NotebookApp']['ip'] = '127.0.0.1' 55 | 56 | # Port to host on 57 | default['ipynb']['NotebookApp']['port'] = 8888 58 | 59 | # Choose whether to open a browser, default is server mode (no browser run on 60 | # server -- interact on client) 61 | default['ipynb']['NotebookApp']['open_browser'] = 'False' 62 | 63 | # SSL Certificate file (private), should be the absolute path of the PEM file 64 | # you want to use. 65 | # 66 | # Example for self-generating: 67 | # 68 | # openssl req -x509 -nodes -days 365 -newkey rsa:1024 -keyout mycert.pem -out \ 69 | # mycert.pem 70 | # 71 | # Can acquire a signed certificate by following this tutorial, through StartSSL: 72 | # 73 | # http://arstechnica.com/security/news/2009/12/how-to-get-set-with-a- 74 | # 75 | default['ipynb']['ssl_certificate'] = nil 76 | default['ipynb']['ssl_certificate_text'] = nil 77 | default['ipynb']['ssl_certificate_key'] = nil 78 | default['ipynb']['ssl_certificate_key_text'] = nil 79 | 80 | # Hashed Password with Salt, Algorithm for accessing the Jupyter Notebook 81 | # 82 | # You can generate one using notebook.auth.passwd 83 | # 84 | # In [1]: from notebook.auth import passwd 85 | # 86 | # In [2]: passwd() 87 | # Enter password: 88 | # Verify password: 89 | # Out[2]: 'sha1:47850f246447:2886935dc08e949f84aeaa41c0030d95253b61b3' 90 | # 91 | # The structure of the result is ALGORITHM:SALT:HASH. 92 | # 93 | # Roughly speaking the password is converted to UTF-8 (when in Python 2.7) using 94 | # string.encode 95 | # 96 | # >>> user_password = "IPassword" 97 | # >>> normalized_password = user_password.encode("utf-8", "replace") 98 | # >>> # Python 3 encodes the salt to ascii (it remains the same for Python 2.7) 99 | # >>> normalized_salt = salt.encode("ascii") 100 | # >>> h = hashlib.new(algorithm) # e.g. sha1 101 | # >>> h.update(normalized_password + normalized_salt) 102 | # 103 | # In [10]: passwd("IPassword") 104 | # Out[10]: 'sha1:7f4bcfc8850f:eb4a986083f011b8f7a2604265a7282b74964dc2' 105 | # 106 | # In [11]: h = hashlib.new("sha1"); h.update("IPassword".encode("utf-8","replace")+"7f4bcfc8850f"); h.hexdigest() 107 | # Out[11]: 'eb4a986083f011b8f7a2604265a7282b74964dc2' 108 | # 109 | # Default shown here is "IPassword" (without the quotes) 110 | # 'sha1:f918d238efbd:4a250470288eb6a41f5df648a39f82606cbd33dd' 111 | # 112 | default['ipynb']['NotebookApp']['password_hash'] = nil 113 | 114 | # Token for authenticating first connections to the server 115 | # Only used if password_hash is set to nil 116 | # Setting both password_hash and token to nil disables auth 117 | # THIS IS NOT ADVISED! 118 | default['ipynb']['NotebookApp']['token'] = 'IPassword' 119 | 120 | # Landing page settings 121 | default['ipynb']['NotebookApp']['base_project_url'] = nil 122 | default['ipynb']['NotebookApp']['base_kernel_url'] = nil 123 | default['ipynb']['NotebookApp']['webapp_settings']['static_url_prefix'] = nil 124 | 125 | # Any additional configuration for Notebooks, to complete 126 | # jupyter_notebook_config.py ruby template 127 | default['ipynb']['NotebookApp']['additional_config'] = nil 128 | 129 | ################################################################################ 130 | # Virtualenv 131 | ################################################################################ 132 | 133 | # Where to store the virtual environment IPython runs in 134 | default['ipynb']['virtenv'] = nil # File.join(default['ipynb']['home_dir'], '.ipyvirt') 135 | 136 | # Version of Python to use 137 | default['ipynb']['py_version'] = case node['platform_version'].to_f 138 | when 16.04 139 | '3.5' 140 | when 14.04 141 | '3.4' 142 | else 143 | '3.5' 144 | end 145 | 146 | ################################################################################ 147 | # Software Stack (system packages) 148 | ################################################################################ 149 | 150 | # System packages, at least for Ubuntu (naming may change) 151 | default['ipynb']['system_packages'] = case node['platform_version'].to_f 152 | when 16.04 153 | %w( 154 | libcurl4-openssl-dev libssl-dev zlib1g-dev libpcre3-dev 155 | gfortran libblas-dev liblapack-dev libncurses5-dev 156 | libatlas-base-dev libscalapack-openmpi1 libscalapack-pvm1 157 | libjpeg-turbo8 libjpeg8 158 | libpng12-0 libpng12-dev 159 | libfreetype6 libfreetype6-dev git-core 160 | libhdf5-serial-dev pandoc 161 | ) 162 | when 14.04 163 | %w( 164 | libcurl4-openssl-dev libssl-dev zlib1g-dev libpcre3-dev 165 | gfortran libblas-dev libblas3gf liblapack3gf liblapack-dev libncurses5-dev 166 | libatlas-dev libatlas-base-dev libscalapack-mpi1 libscalapack-pvm1 167 | liblcms-utils 168 | libamd2.3.1 libjpeg-turbo8 libjpeg8 liblcms1 libumfpack5.6.2 169 | libpng12-0 libpng12-dev libfreetype6 libfreetype6-dev 170 | git-core 171 | libhdf5-7 libhdf5-serial-dev 172 | pandoc 173 | ) 174 | else 175 | %w( 176 | libcurl4-openssl-dev libssl-dev zlib1g-dev libpcre3-dev 177 | gfortran libblas-dev libblas3gf liblapack3gf liblapack-dev libncurses5-dev 178 | libatlas-dev libatlas-base-dev libscalapack-mpi1 libscalapack-pvm1 179 | liblcms-utils 180 | libamd2.2.0 libjpeg-turbo8 libjpeg8 liblcms1 libumfpack5.4.0 181 | libpng12-0 libpng12-dev libfreetype6 libfreetype6-dev 182 | git-core 183 | libhdf5-7 libhdf5-serial-dev 184 | pandoc 185 | ) 186 | end 187 | 188 | ################################################################################ 189 | # Software Stack (pip installs) 190 | ################################################################################ 191 | 192 | # The scientific computing stack, installed in order 193 | # Note that numpy must be first and the dependencies for matplotlib also have 194 | # to start first due to the way numpy+matplotlib are packaged 195 | default['ipynb']['scientific_stack'] = { 'numpy' => nil, 196 | 'freetype-py' => '1.0.2', 197 | 'pillow' => '4.0.0', 198 | 'scipy' => '0.18.1', 199 | 'python-dateutil' => nil, 200 | 'pytz' => '2016.10', 201 | 'six' => '1.10.0', 202 | 'scikit-learn' => '0.18.1', 203 | 'pandas' => '0.19.2', 204 | 'matplotlib' => '1.5.3', 205 | 'pygments' => '2.1.3', 206 | 'readline' => '6.2.4.1', 207 | 'nose' => '1.3.7', 208 | 'pexpect' => '4.2.1', 209 | 'cython' => '0.25.2', 210 | 'networkx' => '1.11', 211 | 'numexpr' => '2.6.1', 212 | 'tables' => '3.3.0', 213 | 'patsy' => '0.4.1', 214 | 'statsmodels' => '0.6.1', 215 | 'sympy' => '1.0', 216 | 'scikit-image' => '0.12.3', 217 | 'theano' => '0.8.2', 218 | 'xlrd' => '1.0.0', 219 | 'xlwt' => '1.1.2', 220 | } 221 | 222 | # Let users configure exactly what version of Jupyter they are going to pull (from git, PyPI, etc.) 223 | # Most of the attributes, configuration, etc. rely on Jupyter 4.x so be wary on changing 224 | # Note that we default to the jupyter meta-package, which is jupyter1.0.0 225 | default['ipynb']['ipython_package'] = 'jupyter' 226 | default['ipynb']['ipython_package_version'] = nil 227 | 228 | # Additional packages to install into the same virtualenv as the IPython notebook 229 | default['ipynb']['extra_packages'] = {} 230 | -------------------------------------------------------------------------------- /chefignore: -------------------------------------------------------------------------------- 1 | # Put files/directories that should be ignored in this file when uploading 2 | # or sharing to the community site. 3 | # Lines that start with '# ' are comments. 4 | 5 | # OS generated files # 6 | ###################### 7 | .DS_Store 8 | Icon? 9 | nohup.out 10 | ehthumbs.db 11 | Thumbs.db 12 | 13 | # SASS # 14 | ######## 15 | .sass-cache 16 | 17 | # EDITORS # 18 | ########### 19 | \#* 20 | .#* 21 | *~ 22 | *.sw[a-z] 23 | *.bak 24 | REVISION 25 | TAGS* 26 | tmtags 27 | *_flymake.* 28 | *_flymake 29 | *.tmproj 30 | .project 31 | .settings 32 | mkmf.log 33 | 34 | ## COMPILED ## 35 | ############## 36 | a.out 37 | *.o 38 | *.pyc 39 | *.so 40 | *.com 41 | *.class 42 | *.dll 43 | *.exe 44 | */rdoc/ 45 | 46 | # Testing # 47 | ########### 48 | .watchr 49 | .rspec 50 | spec/* 51 | spec/fixtures/* 52 | test/* 53 | features/* 54 | Guardfile 55 | Procfile 56 | 57 | # SCM # 58 | ####### 59 | .git 60 | */.git 61 | .gitignore 62 | .gitmodules 63 | .gitconfig 64 | .gitattributes 65 | .svn 66 | */.bzr/* 67 | */.hg/* 68 | */.svn/* 69 | 70 | # Berkshelf # 71 | ############# 72 | Berksfile 73 | Berksfile.lock 74 | cookbooks/* 75 | tmp 76 | 77 | # Cookbooks # 78 | ############# 79 | CONTRIBUTING 80 | CHANGELOG* 81 | 82 | # Strainer # 83 | ############ 84 | Colanderfile 85 | Strainerfile 86 | .colander 87 | .strainer 88 | 89 | # Vagrant # 90 | ########### 91 | .vagrant 92 | Vagrantfile 93 | 94 | # Travis # 95 | ########## 96 | .travis.yml 97 | 98 | # Test-Kitchen # 99 | ################ 100 | .kitchen -------------------------------------------------------------------------------- /libraries/ipython_utils.rb: -------------------------------------------------------------------------------- 1 | #!ruby19 2 | # encoding: utf-8 3 | 4 | require 'digest' 5 | require 'securerandom' 6 | 7 | module IPythonAuth 8 | def self.ipython_hash(password) 9 | hash_alg = Digest::SHA512 10 | hash_name = 'sha512' 11 | 12 | salt = SecureRandom.hex(6) 13 | password_hash = hash_alg.hexdigest(password + salt) 14 | [hash_name, salt, password_hash].join(':') 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /metadata.rb: -------------------------------------------------------------------------------- 1 | name 'ipynb' 2 | maintainer 'Kyle Kelley' 3 | maintainer_email 'rgbkrk@gmail.com' 4 | license 'Apache 2.0' 5 | description 'Installs/Configures IPython Notebook' 6 | long_description IO.read(File.join(File.dirname(__FILE__), 'README.md')) 7 | version '1.1.0' 8 | source_url 'https://github.com/rgbkrk/ipython-notebook-cookbook' if respond_to?(:source_url) 9 | issues_url 'https://github.com/rgbkrk/ipython-notebook-cookbook/issues' if respond_to?(:issues_url) 10 | chef_version '>= 12.1' 11 | 12 | depends 'poise-python', '~> 1.5' 13 | depends 'poise-service', '~> 1.4.2' 14 | depends 'apt', '~> 2.2' 15 | depends 'build-essential', '>= 2' 16 | # depends 'nginx', '~> 1.8' 17 | depends 'nginx', '~> 2.7' 18 | 19 | supports 'ubuntu', '>= 14.04' 20 | -------------------------------------------------------------------------------- /providers/profile.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Author:: Kyle Kelley 3 | # Cookbook Name:: ipynb 4 | # Provider:: profile 5 | # 6 | # Copyright:: 2013, Rackspace 7 | # 8 | # Licensed under the Apache License, Version 2.0 (the "License"); 9 | # you may not use this file except in compliance with the License. 10 | # You may obtain a copy of the License at 11 | # 12 | # http://www.apache.org/licenses/LICENSE-2.0 13 | # 14 | # Unless required by applicable law or agreed to in writing, software 15 | # distributed under the License is distributed on an "AS IS" BASIS, 16 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | # See the License for the specific language governing permissions and 18 | # limitations under the License. 19 | # 20 | 21 | action :create do 22 | Chef::Log.info("Creating profile \"#{new_resource.name}\" for #{new_resource.owner}") 23 | Chef::Log.info("IPython path is at #{new_resource.ipython_path}") 24 | Chef::Log.info("IPython settings are at #{new_resource.ipython_settings_dir}") 25 | create_profile(new_resource.ipython_path, new_resource.owner, 26 | new_resource.name, new_resource.ipython_settings_dir) 27 | end 28 | 29 | # TO DO - FIX JUPYTER CONFIG! 30 | def create_profile(ipython_path, owner, _name, _ipython_settings_dir) 31 | bash 'create_profile' do 32 | user owner 33 | group owner 34 | code <<-EOH 35 | # #{ipython_path} notebook --generate-config 36 | EOH 37 | environment 38 | end 39 | end 40 | -------------------------------------------------------------------------------- /recipes/default.rb: -------------------------------------------------------------------------------- 1 | # Cookbook Name:: ipynb 2 | # Recipe:: default 3 | # 4 | # Copyright (C) 2013 Rackspace 5 | # 6 | # Licensed under the Apache 2.0 License. 7 | # 8 | 9 | # include build-essential 10 | include_recipe 'build-essential::default' 11 | 12 | # Unless the paths got overridden, we set them up here 13 | if node['ipynb']['home_dir'].nil? || node['ipynb']['home_dir'].empty? 14 | node.default['ipynb']['home_dir'] = File.join('/home/', node['ipynb']['linux_user']) 15 | end 16 | 17 | if node['ipynb']['notebook_dir'].nil? || node['ipynb']['notebook_dir'].empty? 18 | node.default['ipynb']['notebook_dir'] = File.join(node['ipynb']['home_dir'], 19 | 'notebooks') 20 | end 21 | 22 | if node['ipynb']['virtenv'].nil? || node['ipynb']['virtenv'].empty? 23 | node.default['ipynb']['virtenv'] = File.join(node['ipynb']['home_dir'], '.ipyvirt') 24 | end 25 | 26 | # Make the package manager handle an initial install so that we 27 | # have system dependencies, whether we run IPython from site-packages or a 28 | # virtualenv. 29 | node['ipynb']['system_packages'].each do |pkg| 30 | package pkg do 31 | action :install 32 | end 33 | end 34 | 35 | # Group running the IPython notebook (*nix permissions) 36 | group node['ipynb']['linux_group'] do 37 | group_name node['ipynb']['linux_group'] 38 | action :create 39 | end 40 | 41 | # User (also runs the IPython notebook) 42 | user node['ipynb']['linux_user'] do 43 | comment 'User for ipython notebook' 44 | gid node['ipynb']['linux_group'] 45 | home node['ipynb']['home_dir'] 46 | shell '/bin/bash' 47 | manage_home true 48 | action :create 49 | end 50 | 51 | # Ensure the requested python version is available 52 | python_runtime 'notebook_interpreter' do 53 | version node['ipynb']['py_version'] 54 | end 55 | 56 | # Create a virtual environment 57 | python_virtualenv node['ipynb']['virtenv'] do 58 | python 'notebook_interpreter' 59 | user node['ipynb']['linux_user'] 60 | group node['ipynb']['linux_group'] 61 | action :create 62 | system_site_packages true 63 | end 64 | 65 | # Make sure uwsgi gets installed 66 | # python_package 'uwsgi' do 67 | # virtualenv node['ipynb']['virtenv'] 68 | # user node['ipynb']['linux_user'] 69 | # group node['ipynb']['linux_group'] 70 | # action :install 71 | # end 72 | 73 | # Install the entire scientific computing stack 74 | node[:ipynb][:scientific_stack].each do |pkg, version| 75 | python_package pkg do 76 | version version unless version.nil? 77 | virtualenv node['ipynb']['virtenv'] 78 | user node['ipynb']['linux_user'] 79 | group node['ipynb']['linux_group'] 80 | action :install 81 | end 82 | end 83 | 84 | # IPython proper 85 | python_package node['ipynb']['ipython_package'] do 86 | version node['ipynb']['ipython_package_version'] unless node['ipynb']['ipython_package_version'].nil? 87 | virtualenv node['ipynb']['virtenv'] 88 | user node['ipynb']['linux_user'] 89 | group node['ipynb']['linux_group'] 90 | action :install 91 | end 92 | 93 | # Any additional packages to build into the same virtual environment 94 | node[:ipynb][:extra_packages].each do |pkg, version| 95 | python_package pkg do 96 | version version unless version.nil? 97 | virtualenv node['ipynb']['virtenv'] 98 | user node['ipynb']['linux_user'] 99 | group node['ipynb']['linux_group'] 100 | action :install 101 | end 102 | end 103 | -------------------------------------------------------------------------------- /recipes/proxy.rb: -------------------------------------------------------------------------------- 1 | 2 | def cert_up(cert_file, cert_file_text) 3 | # If certificate file is passed as an attribute 4 | # Set a default spot for the certificate file 5 | file cert_file do 6 | owner 'root' 7 | group 'root' 8 | mode '0600' 9 | action :create 10 | content cert_file_text 11 | sensitive true 12 | not_if { cert_file_text.nil? } 13 | end 14 | end 15 | 16 | ########################################################################### 17 | # NGINX proxying 18 | # 19 | # nginx version must be greater than 1.4.x in order to support 20 | # web sockets (for interacting with the IPython kernel) 21 | # 22 | ########################################################################### 23 | 24 | include_recipe 'nginx::source' 25 | 26 | # Install certs 27 | cert_up(node['ipynb']['ssl_certificate'], node['ipynb']['ssl_certificate_text']) 28 | cert_up(node['ipynb']['ssl_certificate_key'], node['ipynb']['ssl_certificate_key_text']) 29 | 30 | template "/etc/nginx/sites-available/#{node['ipynb']['proxy']['hostname']}" do 31 | source 'nginx-proxy.erb' 32 | notifies :restart, 'service[nginx]' 33 | end 34 | 35 | nginx_site 'default' do 36 | enable false 37 | end 38 | 39 | nginx_site node['ipynb']['proxy']['hostname'] do 40 | enable true 41 | end 42 | -------------------------------------------------------------------------------- /recipes/virtenv_launch.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Author:: Kyle Kelley 3 | # Cookbook Name:: ipynb 4 | # Recipe:: virtenv_launch 5 | # 6 | # Copyright:: 2013, Rackspace 7 | # 8 | # Licensed under the Apache License, Version 2.0 (the "License"); 9 | # you may not use this file except in compliance with the License. 10 | # You may obtain a copy of the License at 11 | # 12 | # http://www.apache.org/licenses/LICENSE-2.0 13 | # 14 | # Unless required by applicable law or agreed to in writing, software 15 | # distributed under the License is distributed on an "AS IS" BASIS, 16 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | # See the License for the specific language governing permissions and 18 | # limitations under the License. 19 | # 20 | 21 | # Create a full IPython installation along with standard scientific computing tools 22 | 23 | ipython_settings_dir = File.join(node['ipynb']['home_dir'], '.jupyter') 24 | 25 | # Create the directory for storing notebooks 26 | directory node['ipynb']['notebook_dir'] do 27 | owner node['ipynb']['linux_user'] 28 | group node['ipynb']['linux_group'] 29 | mode '0775' 30 | action :create 31 | end 32 | 33 | # Make sure the default profile exists, to deal with IPython bugs/strangeness 34 | # ipynb_profile 'default' do 35 | # action :create 36 | # owner node['ipynb']['linux_user'] 37 | # ipython_path "#{node['ipynb']['virtenv']}/bin/jupyter" 38 | # ipython_settings_dir ipython_settings_dir 39 | # end 40 | 41 | # ipynb_profile node['ipynb']['profile_name'] do 42 | # action :create 43 | # owner node['ipynb']['linux_user'] 44 | # ipython_path "#{node['ipynb']['virtenv']}/bin/jupyter" 45 | # ipython_settings_dir ipython_settings_dir 46 | # end 47 | 48 | nb_config = File.join(ipython_settings_dir, 'jupyter_notebook_config.py') 49 | 50 | # Set the password hash if the password is set 51 | unless node['ipynb']['NotebookApp']['password'].nil? 52 | ipy_hash = IPythonAuth.ipython_hash(node['ipynb']['NotebookApp']['password']) 53 | node.set['ipynb']['NotebookApp']['password_hash'] = ipy_hash 54 | end 55 | 56 | directory "/home/#{node['ipynb']['linux_user']}/.jupyter" do 57 | owner node['ipynb']['linux_user'] 58 | group node['ipynb']['linux_group'] 59 | end 60 | 61 | # Write over the configuration with our own built template 62 | template nb_config do 63 | owner node['ipynb']['linux_user'] 64 | group node['ipynb']['linux_group'] 65 | mode 00644 66 | source 'jupyter_notebook_config.py.erb' 67 | end 68 | 69 | poise_service node['ipynb']['service_name'] do 70 | user node['ipynb']['linux_user'] 71 | command "#{node['ipynb']['virtenv']}/bin/jupyter notebook" 72 | directory node['ipynb']['home_dir'] 73 | environment 'HOME' => node['ipynb']['home_dir'], 74 | 'SHELL' => '/bin/bash', 75 | 'USER' => node['ipynb']['linux_user'], 76 | 'PATH' => "#{node['ipynb']['virtenv']}/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games", 77 | 'VIRTUAL_ENV' => node['ipynb']['virtenv'] 78 | end 79 | -------------------------------------------------------------------------------- /resources/profile.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Author:: Kyle Kelley 3 | # Cookbook Name:: ipynb 4 | # Resource:: profile 5 | # 6 | # Copyright:: 2013, Rackspace 7 | # 8 | # Licensed under the Apache License, Version 2.0 (the "License"); 9 | # you may not use this file except in compliance with the License. 10 | # You may obtain a copy of the License at 11 | # 12 | # http://www.apache.org/licenses/LICENSE-2.0 13 | # 14 | # Unless required by applicable law or agreed to in writing, software 15 | # distributed under the License is distributed on an "AS IS" BASIS, 16 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | # See the License for the specific language governing permissions and 18 | # limitations under the License. 19 | # 20 | 21 | actions :create # , :delete, :create_if_missing 22 | default_action :create if defined?(default_action) 23 | 24 | # Default action for Chef <= 10.8 25 | def initialize(*args) 26 | super 27 | @action = :create 28 | end 29 | 30 | attribute :owner, regex: [/^([a-z]|[A-Z]|[0-9]|_|-)+$/, /^\d+$/], default: node['ipynb']['linux_user'] 31 | attribute :ipython_path, kind_of: String, default: "#{node['ipynb']['virtenv']}/bin/ipython" 32 | attribute :ipython_settings_dir, kind_of: String 33 | -------------------------------------------------------------------------------- /templates/default/jupyter_notebook_config.py.erb: -------------------------------------------------------------------------------- 1 | # -*- mode: python -*- 2 | # vi: set ft=python : 3 | 4 | # 5 | # Generated by Chef for <%= node['ipynb']['linux_user'] %> using the ipython-notebook-cookbook 6 | # 7 | # Find out more at 8 | # 9 | # https://github.com/rgbkrk/ipython-notebook-cookbook 10 | # 11 | 12 | c = get_config() 13 | 14 | # Kernel config 15 | 16 | <% unless node['ipynb']['notebook_dir'].nil? %> 17 | # Set notebook home directory 18 | c.NotebookApp.notebook_dir = u'<%= node['ipynb']['notebook_dir'] %>' 19 | <% end %> 20 | 21 | <% unless node['ipynb']['proxy']['enable'] %> 22 | <% unless node['ipynb']['NotebookApp']['certfile'].nil? %> 23 | 24 | # SSL Certificate 25 | c.NotebookApp.certfile = '<%= node['ipynb']['NotebookApp']['certfile'] %>' 26 | <% end %> 27 | <% end %> 28 | <% unless node['ipynb']['NotebookApp']['ip'].nil? %> 29 | 30 | # The IP address the notebook server will listen on. 31 | # If set to '*', will listen on all interfaces. 32 | c.NotebookApp.ip= '<%= node['ipynb']['NotebookApp']['ip'] %>' 33 | <% end %> 34 | <% unless node['ipynb']['NotebookApp']['port'].nil? %> 35 | 36 | # Port to host on (e.g. 8888, the default) 37 | c.NotebookApp.port = <%= node['ipynb']['NotebookApp']['port'] %> 38 | <% end %> 39 | <% unless node['ipynb']['NotebookApp']['open_browser'].nil? %> 40 | 41 | # Open browser (probably want False) 42 | c.NotebookApp.open_browser = <%= node['ipynb']['NotebookApp']['open_browser'] %> 43 | <% end %> 44 | <% unless node['ipynb']['NotebookApp']['password_hash'].nil? %> 45 | 46 | # 47 | # Password created using notebook.lib.passwd 48 | # 49 | # Example: 50 | # 51 | # In [1]: from notebook.auth import passwd; 52 | # In [2]: passwd() 53 | # Enter password: 54 | # Verify password: 55 | # Out[2]: 'sha1:d2fb9930b3ed:8facdbc05c08e1affbc8424a0717c2b21d10f4a3' 56 | # 57 | c.NotebookApp.password = '<%= node['ipynb']['NotebookApp']['password_hash'] %>' 58 | <% end %> 59 | 60 | # Initial login token, used if pasword is not set 61 | <% if node['ipynb']['NotebookApp']['password_hash'].nil? %> 62 | c.NotebookApp.token = '<%= node['ipynb']['NotebookApp']['token'] %>' 63 | <% end %> 64 | 65 | 66 | c.NotebookApp.tornado_settings = {'static_url_prefix':'/static/'} 67 | 68 | # 69 | # Adding whatever content you feel like to the notebook config file. You 70 | # have to make sure it does not interfere with parameters already covered 71 | # in jupyter_notebook_config.py ruby template. 72 | # 73 | 74 | <%= node['ipynb']['NotebookApp']['additional_config'] %> 75 | -------------------------------------------------------------------------------- /templates/default/nginx-proxy.erb: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80; 3 | rewrite ^ https://$host$request_uri? permanent; 4 | } 5 | 6 | server { 7 | listen 443; 8 | ssl on; 9 | ssl_certificate <%= node[:ipynb][:ssl_certificate] %>; 10 | ssl_certificate_key <%= node[:ipynb][:ssl_certificate_key] %>; 11 | ssl_session_timeout 5m; 12 | ssl_protocols SSLv2 SSLv3 TLSv1; 13 | ssl_ciphers HIGH:!aNULL:!MD5; 14 | ssl_prefer_server_ciphers on; 15 | 16 | error_log <%= File.join(node[:nginx][:log_dir],'error.log') %>; 17 | 18 | location ^~ /static/ { 19 | alias <%= File.join(node[:ipynb][:virtenv], 'lib/python2.7/site-packages/IPython/html/static/') %>; 20 | } 21 | 22 | location / { 23 | proxy_pass http://localhost:<%= node[:ipynb][:NotebookApp][:port] %>; 24 | 25 | proxy_set_header X-Real-IP $remote_addr; 26 | proxy_set_header Host $host; 27 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 28 | 29 | proxy_set_header X-NginX-Proxy true; 30 | 31 | # WebSocket support 32 | proxy_http_version 1.1; 33 | proxy_set_header Upgrade $http_upgrade; 34 | proxy_set_header Connection "upgrade"; 35 | proxy_read_timeout 86400; 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /test/integration/default/jupyter_service.rb: -------------------------------------------------------------------------------- 1 | # ensure configuration file exists 2 | file '/home/vagrant/.jupyter/jupyter_notebook_config.py' do 3 | it { should exist } 4 | end 5 | 6 | # ensure our service is running 7 | describe service 'jupyter' do 8 | it { should be_running } 9 | end 10 | 11 | # verify service is listening 12 | describe port(8888) do 13 | its('addresses') { should include '127.0.0.1' } 14 | its('protocols') { should eq ['tcp'] } 15 | it { should be_listening } 16 | end 17 | --------------------------------------------------------------------------------