mirror of
https://github.com/jupyterhub/jupyterhub.git
synced 2025-10-13 13:03:01 +00:00
compare hub and single-user server versions
in both directions - Hub checks singleuser server on spawn and singleuser server checks Hub on startup if minor versions mismatch, log at warning level, otherwise debug
This commit is contained in:
@@ -1 +1 @@
|
|||||||
from .version import version_info, __version__
|
from ._version import version_info, __version__
|
||||||
|
40
jupyterhub/_version.py
Normal file
40
jupyterhub/_version.py
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
"""JupyterHub version info"""
|
||||||
|
|
||||||
|
# Copyright (c) Jupyter Development Team.
|
||||||
|
# Distributed under the terms of the Modified BSD License.
|
||||||
|
|
||||||
|
version_info = (
|
||||||
|
0,
|
||||||
|
8,
|
||||||
|
0,
|
||||||
|
'dev',
|
||||||
|
)
|
||||||
|
|
||||||
|
__version__ = '.'.join(map(str, version_info))
|
||||||
|
|
||||||
|
|
||||||
|
def _check_version(hub_version, singleuser_version, log):
|
||||||
|
"""Compare Hub and single-user server versions"""
|
||||||
|
if not hub_version:
|
||||||
|
log.warning("Hub has no version header, which means it is likely < 0.8. Expected %s", __version__)
|
||||||
|
return
|
||||||
|
|
||||||
|
if not singleuser_version:
|
||||||
|
log.warning("Single-user server has no version header, which means it is likely < 0.8. Expected %s", __version__)
|
||||||
|
return
|
||||||
|
|
||||||
|
# compare minor X.Y versions
|
||||||
|
if hub_version != singleuser_version:
|
||||||
|
from distutils.version import LooseVersion as V
|
||||||
|
hub_major_minor = V(hub_version).version[:2]
|
||||||
|
singleuser_major_minor = V(__version__).version[:2]
|
||||||
|
if singleuser_major_minor == hub_major_minor:
|
||||||
|
# patch-level mismatch or lower, log difference at debug-level
|
||||||
|
# because this should be fine
|
||||||
|
log_method = log.debug
|
||||||
|
else:
|
||||||
|
# log warning-level for more significant mismatch, such as 0.8 vs 0.9, etc.
|
||||||
|
log_method = log.warning
|
||||||
|
log_method("jupyterhub version %s != jupyterhub-singleuser version %s",
|
||||||
|
hub_version, __version__,
|
||||||
|
)
|
@@ -11,7 +11,7 @@ from tornado.ioloop import IOLoop
|
|||||||
|
|
||||||
from ..utils import admin_only
|
from ..utils import admin_only
|
||||||
from .base import APIHandler
|
from .base import APIHandler
|
||||||
from ..version import __version__
|
from .._version import __version__
|
||||||
|
|
||||||
|
|
||||||
class ShutdownAPIHandler(APIHandler):
|
class ShutdownAPIHandler(APIHandler):
|
||||||
|
@@ -4,12 +4,16 @@
|
|||||||
# Copyright (c) Jupyter Development Team.
|
# Copyright (c) Jupyter Development Team.
|
||||||
# Distributed under the terms of the Modified BSD License.
|
# Distributed under the terms of the Modified BSD License.
|
||||||
|
|
||||||
|
from distutils.version import LooseVersion as V
|
||||||
import os
|
import os
|
||||||
|
import re
|
||||||
from textwrap import dedent
|
from textwrap import dedent
|
||||||
from urllib.parse import urlparse
|
from urllib.parse import urlparse
|
||||||
|
|
||||||
from jinja2 import ChoiceLoader, FunctionLoader
|
from jinja2 import ChoiceLoader, FunctionLoader
|
||||||
|
|
||||||
|
from tornado.httpclient import AsyncHTTPClient
|
||||||
|
from tornado import gen
|
||||||
from tornado import ioloop
|
from tornado import ioloop
|
||||||
from tornado.web import HTTPError
|
from tornado.web import HTTPError
|
||||||
|
|
||||||
@@ -37,7 +41,7 @@ from notebook.auth.login import LoginHandler
|
|||||||
from notebook.auth.logout import LogoutHandler
|
from notebook.auth.logout import LogoutHandler
|
||||||
from notebook.base.handlers import IPythonHandler
|
from notebook.base.handlers import IPythonHandler
|
||||||
|
|
||||||
from jupyterhub import __version__
|
from ._version import __version__, _check_version
|
||||||
from .log import log_request
|
from .log import log_request
|
||||||
from .services.auth import HubOAuth, HubOAuthenticated, HubOAuthCallbackHandler
|
from .services.auth import HubOAuth, HubOAuthenticated, HubOAuthCallbackHandler
|
||||||
from .utils import url_path_join
|
from .utils import url_path_join
|
||||||
@@ -337,7 +341,27 @@ class SingleUserNotebookApp(NotebookApp):
|
|||||||
path = list(_exclude_home(path))
|
path = list(_exclude_home(path))
|
||||||
return path
|
return path
|
||||||
|
|
||||||
|
@gen.coroutine
|
||||||
|
def check_hub_version(self):
|
||||||
|
"""Test a connection to my Hub
|
||||||
|
|
||||||
|
- exit if I can't connect at all
|
||||||
|
- check version and warn on sufficient mismatch
|
||||||
|
"""
|
||||||
|
client = AsyncHTTPClient()
|
||||||
|
try:
|
||||||
|
resp = yield client.fetch(self.hub_api_url)
|
||||||
|
except Exception:
|
||||||
|
self.log.exception("Failed to connect to my Hub at %s. Is it running?", self.hub_api_url)
|
||||||
|
self.exit(1)
|
||||||
|
|
||||||
|
hub_version = resp.headers.get('X-JupyterHub-Version')
|
||||||
|
_check_version(hub_version, __version__, self.log)
|
||||||
|
|
||||||
def start(self):
|
def start(self):
|
||||||
|
self.log.info("Starting jupyterhub-singleuser server version %s", __version__)
|
||||||
|
# start by hitting Hub to check version
|
||||||
|
ioloop.IOLoop.current().run_sync(self.check_hub_version)
|
||||||
super(SingleUserNotebookApp, self).start()
|
super(SingleUserNotebookApp, self).start()
|
||||||
|
|
||||||
def init_hub_auth(self):
|
def init_hub_auth(self):
|
||||||
|
@@ -12,6 +12,7 @@ from tornado.log import app_log
|
|||||||
from .utils import url_path_join, default_server_name
|
from .utils import url_path_join, default_server_name
|
||||||
|
|
||||||
from . import orm
|
from . import orm
|
||||||
|
from ._version import _check_version, __version__
|
||||||
from .objects import Server
|
from .objects import Server
|
||||||
from traitlets import HasTraits, Any, Dict, observe, default
|
from traitlets import HasTraits, Any, Dict, observe, default
|
||||||
from .spawner import LocalProcessSpawner
|
from .spawner import LocalProcessSpawner
|
||||||
@@ -328,7 +329,7 @@ class User(HasTraits):
|
|||||||
db.commit()
|
db.commit()
|
||||||
self.waiting_for_response = True
|
self.waiting_for_response = True
|
||||||
try:
|
try:
|
||||||
yield server.wait_up(http=True, timeout=spawner.http_timeout)
|
resp = yield server.wait_up(http=True, timeout=spawner.http_timeout)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
if isinstance(e, TimeoutError):
|
if isinstance(e, TimeoutError):
|
||||||
self.log.warning(
|
self.log.warning(
|
||||||
@@ -353,6 +354,9 @@ class User(HasTraits):
|
|||||||
), exc_info=True)
|
), exc_info=True)
|
||||||
# raise original TimeoutError
|
# raise original TimeoutError
|
||||||
raise e
|
raise e
|
||||||
|
else:
|
||||||
|
server_version = resp.headers.get('X-JupyterHub-Version')
|
||||||
|
_check_version(__version__, server_version, self.log)
|
||||||
finally:
|
finally:
|
||||||
self.waiting_for_response = False
|
self.waiting_for_response = False
|
||||||
self.spawn_pending = False
|
self.spawn_pending = False
|
||||||
|
@@ -1,13 +0,0 @@
|
|||||||
"""JupyterHub version info"""
|
|
||||||
|
|
||||||
# Copyright (c) Jupyter Development Team.
|
|
||||||
# Distributed under the terms of the Modified BSD License.
|
|
||||||
|
|
||||||
version_info = (
|
|
||||||
0,
|
|
||||||
8,
|
|
||||||
0,
|
|
||||||
'dev',
|
|
||||||
)
|
|
||||||
|
|
||||||
__version__ = '.'.join(map(str, version_info))
|
|
Reference in New Issue
Block a user