Compare commits

...

24 Commits
0.7.0 ... 0.7.1

Author SHA1 Message Date
Min RK
94978ea9e0 release 0.7.1 2017-01-02 13:53:43 +01:00
Min RK
bf6999e439 changelog for 0.7.1 2017-01-02 13:53:43 +01:00
Carol Willing
020ee7378f Merge pull request #916 from rachmaninovquartet/master
Added Toree troubleshooting to docs
2016-12-22 13:56:51 -08:00
Min RK
e4a0569961 Merge pull request #915 from jupyterhub/willingc-patch-1
Update README to clarify docker image contents
2016-12-22 16:43:02 +01:00
Ian Maloney
4ff525d5bd updated docs/source/troubleshooting.md per conversation with @willingc in issue 889 2016-12-21 15:21:50 -05:00
Carol Willing
37a31b01b2 Update README to clarify docker image contents
Addresses #879 and #772 re: confusion about the docker image contents
2016-12-21 10:46:30 -08:00
Carol Willing
1604cb1b0b Merge pull request #914 from minrk/update-bootprint
fix rest-api doc building
2016-12-21 10:29:08 -08:00
Min RK
45702ac18c update bootprint to 0.10
0.8 has stopped working for some reason
2016-12-21 14:51:12 +01:00
Min RK
c81e9d60e4 fix rest-api link
link to REST API, not Python API
2016-12-21 14:51:12 +01:00
Carol Willing
224865b894 Merge pull request #910 from minrk/cleanup-server-token
Avoid cleaning up API tokens for Spawners that will resume
2016-12-20 08:29:06 -08:00
Min RK
3b3bc8224b comment review 2016-12-20 16:41:26 +01:00
Carol Willing
c56dc2ea6f Merge pull request #911 from jjaraalm/master
Update Service Docs

Closes #908
2016-12-19 10:28:30 -08:00
jjaraalm
62202bbb74 Revert "Revert "Update service docs""
This reverts commit 7ba28c0207.
2016-12-19 13:00:48 -05:00
jjaraalm
7ba28c0207 Revert "Update service docs"
This reverts commit 9392a29dad.
2016-12-19 12:59:42 -05:00
jjaraalm
9392a29dad Update service docs
Fixes #908
2016-12-19 12:56:26 -05:00
Min RK
72ab8f99ec Avoid cleaning up API tokens for Spawners that will resume
in which case the previous API token should be left alone.
2016-12-19 10:50:25 +01:00
Min RK
fcf32c7e50 Merge pull request #909 from willingc/update-travis
Add 3.6 to travis
2016-12-19 09:59:47 +01:00
Carol Willing
da451d6552 Add 3.6 to travis 2016-12-18 21:26:52 -08:00
Carol Willing
662b1a4d4a Merge pull request #902 from minrk/redirect-empty-msg
Don't warn about empty next_url
2016-12-09 08:04:56 -08:00
Min RK
732adea997 Don't warn about empty next_url
empty next_url is fine
2016-12-09 15:34:32 +01:00
Carol Willing
7e1dbf3515 Merge pull request #896 from minrk/whitelist-warning
Warn about single-character names in whitelist
2016-12-05 11:16:30 -06:00
Min RK
65b92ec246 Warn about single-character names in whitelist
likely cause is `set('string')` typo instead of `set(['string'])`,
so include that in the error message:

    whitelist contains single-character names: ['i', 'k', 'm', 'n', 'r']; did you mean set(['ikmnr']) instead of set('ikmnr')?
2016-12-05 09:46:52 +01:00
Min RK
dc42ee4779 typo in changelog link 2016-12-02 18:12:28 +01:00
Min RK
c04441c1b2 back to dev 2016-12-02 18:08:03 +01:00
14 changed files with 115 additions and 44 deletions

View File

@@ -2,6 +2,7 @@
language: python
sudo: false
python:
- 3.6-dev
- 3.5
- 3.4
- 3.3

View File

@@ -131,11 +131,11 @@ Some examples, meant as illustration and testing of this concept:
----
## Docker
A ready to go [docker image for JupyterHub](https://hub.docker.com/r/jupyterhub/jupyterhub/) gives a straightforward deployment of JupyterHub.
A starter [docker image for JupyterHub](https://hub.docker.com/r/jupyterhub/jupyterhub/) gives a baseline deployment of JupyterHub.
*Note: This `jupyterhub/jupyterhub` docker image is only an image for running the Hub service itself.
It does not require the other Jupyter components, such as Notebook installation, which are needed by the single-user servers.
To run the single-user servers, which may be on the same system as the Hub or not, Jupyter Notebook version 4 or greater must be installed.*
**Important:** This `jupyterhub/jupyterhub` image contains only the Hub itself, with no configuration. In general, one needs
to make a derivative image, with at least a `jupyterhub_config.py` setting up an Authenticator and/or a Spawner. To run the
single-user servers, which may be on the same system as the Hub or not, Jupyter Notebook version 4 or greater must be installed.
#### Starting JupyterHub with docker
The JupyterHub docker image can be started with the following command:

View File

@@ -8,7 +8,7 @@
"author": "",
"license": "BSD-3-Clause",
"devDependencies": {
"bootprint": "^0.8.5",
"bootprint": "^0.10.0",
"bootprint-openapi": "^0.17.0"
}
}

View File

@@ -9,6 +9,20 @@ command line for details.
## 0.7
### [0.7.1] - 2016-01-02
#### Added
- `Spawner.will_resume` for signalling that a single-user server is paused instead of stopped.
This is needed for cases like `DockerSpawner.remove_containers = False`,
where the first API token is re-used for subsequent spawns.
- Warning on startup about single-character usernames,
caused by common `set('string')` typo in config.
#### Fixed
- Removed spurious warning about empty `next_url`, which is AOK.
### [0.7.0] - 2016-12-2
#### Added
@@ -118,8 +132,9 @@ Fix removal of `/login` page in 0.4.0, breaking some OAuth providers.
First preview release
[Unreleased]: https://github.com/jupyterhub/jupyterhub/compare/0.7.0...HEAD
[Unreleased]: https://github.com/jupyterhub/jupyterhub/compare/0.6.1...0.7.0
[Unreleased]: https://github.com/jupyterhub/jupyterhub/compare/0.7.1...HEAD
[0.7.1]: https://github.com/jupyterhub/jupyterhub/compare/0.7.0...0.7.1
[0.7.0]: https://github.com/jupyterhub/jupyterhub/compare/0.6.1...0.7.0
[0.6.1]: https://github.com/jupyterhub/jupyterhub/compare/0.6.0...0.6.1
[0.6.0]: https://github.com/jupyterhub/jupyterhub/compare/0.5.0...0.6.0
[0.5]: https://github.com/jupyterhub/jupyterhub/compare/0.4.1...0.5.0

View File

@@ -67,4 +67,4 @@ Note: The Swagger specification is being renamed the [OpenAPI Initiative][].
[on swagger's petstore]: http://petstore.swagger.io/?url=https://raw.githubusercontent.com/jupyterhub/jupyterhub/master/docs/rest-api.yml#!/default
[OpenAPI Initiative]: https://www.openapis.org/
[JupyterHub REST API]: ./api/index.html
[JupyterHub REST API]: ./_static/rest-api/index.html

View File

@@ -54,7 +54,7 @@ If a service is also to be managed by the Hub, it has a few extra options:
externally.
- If a command is specified for launching the Service, the Service will
be started and managed by the Hub.
- `env: dict` - environment variables to add to the current env
- `environment: dict` - additional environment variables for the Service.
- `user: str` - the name of a system user to manage the Service. If
unspecified, run as the same user as the Hub.
@@ -99,7 +99,7 @@ c.JupyterHub.services = [
A Hub-Managed Service may also be configured with additional optional
parameters, which describe the environment needed to start the Service process:
- `env: dict` - additional environment variables for the Service.
- `environment: dict` - additional environment variables for the Service.
- `user: str` - name of the user to run the server if different from the Hub.
Requires Hub to be root.
- `cwd: path` directory in which to run the Service, if different from the

View File

@@ -249,3 +249,26 @@ jupyter kernelspec list
```bash
jupyterhub --debug
```
## Toree integration with HDFS rack awareness script
The Apache Toree kernel will an issue, when running with JupyterHub, if the standard HDFS
rack awareness script is used. This will materialize in the logs as a repeated WARN:
```bash
16/11/29 16:24:20 WARN ScriptBasedMapping: Exception running /etc/hadoop/conf/topology_script.py some.ip.address
ExitCodeException exitCode=1: File "/etc/hadoop/conf/topology_script.py", line 63
print rack
^
SyntaxError: Missing parentheses in call to 'print'
at `org.apache.hadoop.util.Shell.runCommand(Shell.java:576)`
```
In order to resolve this issue, there are two potential options.
1. Update HDFS core-site.xml, so the parameter "net.topology.script.file.name" points to a custom
script (e.g. /etc/hadoop/conf/custom_topology_script.py). Copy the original script and change the first line point
to a python two installation (e.g. /usr/bin/python).
2. In spark-env.sh add a Python 2 installation to your path (e.g. export PATH=/opt/anaconda2/bin:$PATH).

View File

@@ -146,18 +146,18 @@ class NewToken(Application):
class UpgradeDB(Application):
"""Upgrade the JupyterHub database schema."""
name = 'jupyterhub-upgrade-db'
version = jupyterhub.__version__
description = """Upgrade the JupyterHub database to the current schema.
Usage:
jupyterhub upgrade-db
"""
aliases = common_aliases
classes = []
def _backup_db_file(self, db_file):
"""Backup a database file"""
if not os.path.exists(db_file):
@@ -171,7 +171,7 @@ class UpgradeDB(Application):
backup_db_file = '{}.{}.{}'.format(db_file, timestamp, i)
if os.path.exists(backup_db_file):
self.exit("backup db file already exists: %s" % backup_db_file)
self.log.info("Backing up %s => %s", db_file, backup_db_file)
shutil.copy(db_file, backup_db_file)
@@ -222,12 +222,12 @@ class JupyterHub(Application):
Authenticator,
PAMAuthenticator,
])
load_groups = Dict(List(Unicode()),
help="""Dict of 'group': ['usernames'] to load at startup.
This strictly *adds* groups and users to groups.
Loading one set of groups, then starting JupyterHub again with a different
set will not remove users or groups from previous launches.
That must be done through the API.
@@ -414,7 +414,7 @@ class JupyterHub(Application):
api_tokens = Dict(Unicode(),
help="""PENDING DEPRECATION: consider using service_tokens
Dict of token:username to be loaded into the database.
Allows ahead-of-time generation of API tokens for use by externally managed services,
@@ -437,14 +437,14 @@ class JupyterHub(Application):
Allows ahead-of-time generation of API tokens for use by externally managed services.
"""
).tag(config=True)
services = List(Dict(),
help="""List of service specification dictionaries.
A service
For instance::
services = [
{
'name': 'cull_idle',
@@ -454,7 +454,7 @@ class JupyterHub(Application):
'name': 'formgrader',
'url': 'http://127.0.0.1:1234',
'token': 'super-secret',
'env':
'environment':
}
]
"""
@@ -608,7 +608,7 @@ class JupyterHub(Application):
Instance(logging.Handler),
help="Extra log handlers to set on JupyterHub logger",
).tag(config=True)
statsd = Any(allow_none=False, help="The statsd client, if any. A mock will be used if we aren't using statsd")
@default('statsd')
def _statsd(self):
@@ -919,7 +919,7 @@ class JupyterHub(Application):
# The whitelist set and the users in the db are now the same.
# From this point on, any user changes should be done simultaneously
# to the whitelist set and user db, unless the whitelist is empty (all users allowed).
@gen.coroutine
def init_groups(self):
"""Load predefined groups into the database"""
@@ -941,7 +941,7 @@ class JupyterHub(Application):
db.add(user)
group.users.append(user)
db.commit()
@gen.coroutine
def _add_tokens(self, token_dict, kind):
"""Add tokens for users or services to the database"""
@@ -982,13 +982,13 @@ class JupyterHub(Application):
else:
self.log.debug("Not duplicating token %s", orm_token)
db.commit()
@gen.coroutine
def init_api_tokens(self):
"""Load predefined API tokens (for services) into database"""
yield self._add_tokens(self.service_tokens, kind='service')
yield self._add_tokens(self.api_tokens, kind='user')
def init_services(self):
self._service_map.clear()
if self.domain:
@@ -1458,7 +1458,7 @@ class JupyterHub(Application):
except Exception as e:
self.log.critical("Failed to start proxy", exc_info=True)
self.exit(1)
for service_name, service in self._service_map.items():
if not service.managed:
continue

View File

@@ -56,6 +56,17 @@ class Authenticator(LoggingConfigurable):
"""
).tag(config=True)
@observe('whitelist')
def _check_whitelist(self, change):
short_names = [name for name in change['new'] if len(name) <= 1]
if short_names:
sorted_names = sorted(short_names)
single = ''.join(sorted_names)
string_set_typo = "set('%s')" % single
self.log.warning("whitelist contains single-character names: %s; did you mean set([%r]) instead of %s?",
sorted_names[:8], single, string_set_typo,
)
custom_html = Unicode(
help="""
HTML form to be overridden by authenticators if they want a custom authentication form.

View File

@@ -28,7 +28,7 @@ class RootHandler(BaseHandler):
"""
def get(self):
next_url = self.get_argument('next', '')
if not next_url.startswith('/'):
if next_url and not next_url.startswith('/'):
self.log.warning("Disallowing redirect outside JupyterHub: %r", next_url)
next_url = ''
if next_url and next_url.startswith(url_path_join(self.base_url, 'user/')):

View File

@@ -70,12 +70,12 @@ class _MockUser(HasTraits):
class _ServiceSpawner(LocalProcessSpawner):
"""Subclass of LocalProcessSpawner
Removes notebook-specific-ness from LocalProcessSpawner.
"""
cwd = Unicode()
cmd = Command(minlen=0)
def make_preexec_fn(self, name):
if not name or name == getuser():
# no setuid if no name
@@ -116,25 +116,25 @@ class Service(LoggingConfigurable):
- url: str (None)
The URL where the service is/should be.
If specified, the service will be added to the proxy at /services/:name
If a service is to be managed by the Hub, it has a few extra options:
- command: (str/Popen list)
Command for JupyterHub to spawn the service.
Only use this if the service should be a subprocess.
If command is not specified, it is assumed to be managed
by a
- env: dict
environment variables to add to the current env
- environment: dict
Additional environment variables for the service.
- user: str
The name of a system user to become.
If unspecified, run as the same user as the Hub.
"""
# inputs:
name = Unicode(
help="""The name of the service.
If the service has an http endpoint, it
"""
).tag(input=True)
@@ -143,14 +143,14 @@ class Service(LoggingConfigurable):
).tag(input=True)
url = Unicode(
help="""URL of the service.
Only specify if the service runs an HTTP(s) endpoint that.
If managed, will be passed as JUPYTERHUB_SERVICE_URL env.
"""
).tag(input=True)
api_token = Unicode(
help="""The API token to use for the service.
If unspecified, an API token will be generated for managed services.
"""
).tag(input=True)

View File

@@ -52,6 +52,17 @@ class Spawner(LoggingConfigurable):
authenticator = Any()
api_token = Unicode()
will_resume = Bool(False,
help="""Whether the Spawner will resume on next start
Default is False where each launch of the Spawner will be a new instance.
If True, an existing Spawner will resume instead of starting anew
(e.g. resuming a Docker container),
and API tokens in use when the Spawner stops will not be deleted.
"""
)
ip = Unicode('127.0.0.1',
help="""
The IP address (or hostname) the single-user server should listen on.

View File

@@ -234,6 +234,12 @@ class User(HasTraits):
# prior to 0.7, spawners had to store this info in user.server themselves.
# Handle < 0.7 behavior with a warning, assuming info was stored in db by the Spawner.
self.log.warning("DEPRECATION: Spawner.start should return (ip, port) in JupyterHub >= 0.7")
if spawner.api_token != api_token:
# Spawner re-used an API token, discard the unused api_token
orm_token = orm.APIToken.find(self.db, api_token)
if orm_token is not None:
self.db.delete(orm_token)
self.db.commit()
except Exception as e:
if isinstance(e, gen.TimeoutError):
self.log.warning("{user}'s server failed to start in {s} seconds, giving up".format(
@@ -313,10 +319,13 @@ class User(HasTraits):
if self.server:
# cleanup server entry from db
self.db.delete(self.server)
orm_token = orm.APIToken.find(self.db, api_token)
if orm_token:
self.db.delete(orm_token)
self.server = None
if not spawner.will_resume:
# find and remove the API token if the spawner isn't
# going to re-use it next time
orm_token = orm.APIToken.find(self.db, api_token)
if orm_token:
self.db.delete(orm_token)
self.db.commit()
finally:
self.stop_pending = False

View File

@@ -6,7 +6,8 @@
version_info = (
0,
7,
0,
1,
# 'dev',
)
__version__ = '.'.join(map(str, version_info))