mirror of
https://github.com/jupyterhub/jupyterhub.git
synced 2025-10-10 03:23:04 +00:00
Compare commits
15 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
3d3ad2929c | ||
![]() |
00287ff5ba | ||
![]() |
805d063d1d | ||
![]() |
e6bacf7109 | ||
![]() |
33ccfa7963 | ||
![]() |
593404f558 | ||
![]() |
e7bc282c80 | ||
![]() |
b939b482a1 | ||
![]() |
8afc2c9ae9 | ||
![]() |
d11eda14ed | ||
![]() |
ab79251fe2 | ||
![]() |
484dbf48de | ||
![]() |
6eb526d08a | ||
![]() |
e0a17db5f1 | ||
![]() |
45132b7244 |
@@ -6,7 +6,7 @@ info:
|
||||
description: The REST API for JupyterHub
|
||||
license:
|
||||
name: BSD-3-Clause
|
||||
version: 2.2.0
|
||||
version: 2.2.1
|
||||
servers:
|
||||
- url: /hub/api
|
||||
security:
|
||||
|
37
docs/source/admin/log-messages.md
Normal file
37
docs/source/admin/log-messages.md
Normal file
@@ -0,0 +1,37 @@
|
||||
# Common log messages emitted by JupyterHub
|
||||
|
||||
When debugging errors and outages, looking at the logs emitted by
|
||||
JupyterHub is very helpful. This document tries to document some common
|
||||
log messages, and what they mean.
|
||||
|
||||
## Failing suspected API request to not-running server
|
||||
|
||||
### Example
|
||||
|
||||
Your logs might be littered with lines that might look slightly scary
|
||||
|
||||
```
|
||||
[W 2022-03-10 17:25:19.774 JupyterHub base:1349] Failing suspected API request to not-running server: /hub/user/<user-name>/api/metrics/v1
|
||||
```
|
||||
|
||||
### Most likely cause
|
||||
|
||||
This likely means is that the user's server has stopped running but they
|
||||
still have a browser tab open. For example, you might have 3 tabs open, and shut
|
||||
your server down via one. Or you closed your laptop, your server was
|
||||
culled for inactivity, and then you reopen your laptop again! The
|
||||
client side code (JupyterLab, Classic Notebook, etc) does not know
|
||||
yet that the server is dead, and continues to make some API requests.
|
||||
JupyterHub's architecture means that the proxy routes all requests that
|
||||
don't go to a running user server to the hub process itself. The hub
|
||||
process then explicitly returns a failure response, so the client knows
|
||||
that the server is not running anymore. This is used by JupyterLab to
|
||||
tell you your server is not running anymore, and offer you the option
|
||||
to let you restart it.
|
||||
|
||||
Most commonly, you'll see this in reference to the `/api/metrics/v1`
|
||||
URL, used by [jupyter-resource-usage](https://github.com/jupyter-server/jupyter-resource-usage).
|
||||
|
||||
### Actions you can take
|
||||
|
||||
This log message is benign, and there is usually no action for you to take.
|
@@ -8,6 +8,31 @@ command line for details.
|
||||
|
||||
## 2.2
|
||||
|
||||
### 2.2.1 2021-03-11
|
||||
|
||||
2.2.1 fixes a few small regressions in 2.2.0.
|
||||
|
||||
([full changelog](https://github.com/jupyterhub/jupyterhub/compare/2.2.0...2.2.1))
|
||||
|
||||
#### Bugs fixed
|
||||
|
||||
- Fix clearing cookie with custom xsrf cookie options [#3823](https://github.com/jupyterhub/jupyterhub/pull/3823) ([@minrk](https://github.com/minrk), [@consideRatio](https://github.com/consideRatio))
|
||||
- Fix admin dashboard table sorting [#3822](https://github.com/jupyterhub/jupyterhub/pull/3822) ([@NarekA](https://github.com/NarekA), [@minrk](https://github.com/minrk), [@consideRatio](https://github.com/consideRatio))
|
||||
|
||||
#### Maintenance and upkeep improvements
|
||||
|
||||
- allow Spawner.server to be mocked without underlying orm_spawner [#3819](https://github.com/jupyterhub/jupyterhub/pull/3819) ([@minrk](https://github.com/minrk), [@yuvipanda](https://github.com/yuvipanda), [@consideRatio](https://github.com/consideRatio))
|
||||
|
||||
#### Documentation
|
||||
|
||||
- Add some docs on common log messages [#3820](https://github.com/jupyterhub/jupyterhub/pull/3820) ([@yuvipanda](https://github.com/yuvipanda), [@choldgraf](https://github.com/choldgraf), [@consideRatio](https://github.com/consideRatio))
|
||||
|
||||
#### Contributors to this release
|
||||
|
||||
([GitHub contributors page for this release](https://github.com/jupyterhub/jupyterhub/graphs/contributors?from=2022-03-07&to=2022-03-11&type=c))
|
||||
|
||||
[@choldgraf](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Acholdgraf+updated%3A2022-03-07..2022-03-11&type=Issues) | [@consideRatio](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3AconsideRatio+updated%3A2022-03-07..2022-03-11&type=Issues) | [@minrk](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Aminrk+updated%3A2022-03-07..2022-03-11&type=Issues) | [@NarekA](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3ANarekA+updated%3A2022-03-07..2022-03-11&type=Issues) | [@yuvipanda](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Ayuvipanda+updated%3A2022-03-07..2022-03-11&type=Issues)
|
||||
|
||||
# 2.2.0 2021-03-07
|
||||
|
||||
JupyterHub 2.2.0 is a small release.
|
||||
|
@@ -10,4 +10,5 @@ well as other information relevant to running your own JupyterHub over time.
|
||||
|
||||
troubleshooting
|
||||
admin/upgrading
|
||||
admin/log-messages
|
||||
changelog
|
||||
|
@@ -153,10 +153,9 @@ const ServerDashboard = (props) => {
|
||||
);
|
||||
};
|
||||
|
||||
const EditUserCell = ({ user, numServers, serverName }) => {
|
||||
if (serverName) return null;
|
||||
const EditUserCell = ({ user }) => {
|
||||
return (
|
||||
<td rowspan={numServers}>
|
||||
<td>
|
||||
<button
|
||||
className="btn btn-primary btn-xs"
|
||||
style={{ marginRight: 20 }}
|
||||
@@ -176,6 +175,14 @@ const ServerDashboard = (props) => {
|
||||
);
|
||||
};
|
||||
|
||||
let servers = user_data.flatMap((user) => {
|
||||
let userServers = Object.values({
|
||||
"": user.server || {},
|
||||
...(user.servers || {}),
|
||||
});
|
||||
return userServers.map((server) => [user, server]);
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="container" data-testid="container">
|
||||
{errorAlert != null ? (
|
||||
@@ -339,87 +346,65 @@ const ServerDashboard = (props) => {
|
||||
</Button>
|
||||
</td>
|
||||
</tr>
|
||||
{user_data.flatMap((e, i) => {
|
||||
let userServers = Object.values({
|
||||
"": e.server,
|
||||
...(e.servers || {}),
|
||||
});
|
||||
return userServers.map((server) => {
|
||||
server = { name: "", ...server };
|
||||
return (
|
||||
<tr key={i + "row"} className="user-row">
|
||||
{!server.name && (
|
||||
<td
|
||||
data-testid="user-row-name"
|
||||
rowspan={userServers.length}
|
||||
>
|
||||
{e.name}
|
||||
</td>
|
||||
)}
|
||||
{!server.name && (
|
||||
<td
|
||||
data-testid="user-row-admin"
|
||||
rowspan={userServers.length}
|
||||
>
|
||||
{e.admin ? "admin" : ""}
|
||||
</td>
|
||||
)}
|
||||
{servers.map(([user, server], i) => {
|
||||
server.name = server.name || "";
|
||||
return (
|
||||
<tr key={i + "row"} className="user-row">
|
||||
<td data-testid="user-row-name">{user.name}</td>
|
||||
<td data-testid="user-row-admin">
|
||||
{user.admin ? "admin" : ""}
|
||||
</td>
|
||||
|
||||
<td data-testid="user-row-server">
|
||||
{server.name ? (
|
||||
<p class="text-secondary">{server.name}</p>
|
||||
) : (
|
||||
<p style={{ color: "lightgrey" }}>[MAIN]</p>
|
||||
)}
|
||||
</td>
|
||||
<td data-testid="user-row-last-activity">
|
||||
{server.last_activity
|
||||
? timeSince(server.last_activity)
|
||||
: "Never"}
|
||||
</td>
|
||||
<td data-testid="user-row-server-activity">
|
||||
{server.started ? (
|
||||
// Stop Single-user server
|
||||
<>
|
||||
<StopServerButton
|
||||
serverName={server.name}
|
||||
userName={e.name}
|
||||
/>
|
||||
<AccessServerButton
|
||||
serverName={server.name}
|
||||
userName={e.name}
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
// Start Single-user server
|
||||
<>
|
||||
<StartServerButton
|
||||
serverName={server.name}
|
||||
userName={e.name}
|
||||
/>
|
||||
<a
|
||||
href={`/spawn/${e.name}${
|
||||
server.name && "/" + server.name
|
||||
}`}
|
||||
<td data-testid="user-row-server">
|
||||
{server.name ? (
|
||||
<p class="text-secondary">{server.name}</p>
|
||||
) : (
|
||||
<p style={{ color: "lightgrey" }}>[MAIN]</p>
|
||||
)}
|
||||
</td>
|
||||
<td data-testid="user-row-last-activity">
|
||||
{server.last_activity
|
||||
? timeSince(server.last_activity)
|
||||
: "Never"}
|
||||
</td>
|
||||
<td data-testid="user-row-server-activity">
|
||||
{server.started ? (
|
||||
// Stop Single-user server
|
||||
<>
|
||||
<StopServerButton
|
||||
serverName={server.name}
|
||||
userName={user.name}
|
||||
/>
|
||||
<AccessServerButton
|
||||
serverName={server.name}
|
||||
userName={user.name}
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
// Start Single-user server
|
||||
<>
|
||||
<StartServerButton
|
||||
serverName={server.name}
|
||||
userName={user.name}
|
||||
/>
|
||||
<a
|
||||
href={`/spawn/${user.name}${
|
||||
server.name && "/" + server.name
|
||||
}`}
|
||||
>
|
||||
<button
|
||||
className="btn btn-secondary btn-xs"
|
||||
style={{ marginRight: 20 }}
|
||||
>
|
||||
<button
|
||||
className="btn btn-secondary btn-xs"
|
||||
style={{ marginRight: 20 }}
|
||||
>
|
||||
Spawn Page
|
||||
</button>
|
||||
</a>
|
||||
</>
|
||||
)}
|
||||
</td>
|
||||
<EditUserCell
|
||||
user={e}
|
||||
numServers={userServers.length}
|
||||
serverName={server.name}
|
||||
/>
|
||||
</tr>
|
||||
);
|
||||
});
|
||||
Spawn Page
|
||||
</button>
|
||||
</a>
|
||||
</>
|
||||
)}
|
||||
</td>
|
||||
<EditUserCell user={user} />
|
||||
</tr>
|
||||
);
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
|
@@ -2,7 +2,7 @@
|
||||
# Copyright (c) Jupyter Development Team.
|
||||
# Distributed under the terms of the Modified BSD License.
|
||||
# version_info updated by running `tbump`
|
||||
version_info = (2, 2, 0, "", "")
|
||||
version_info = (2, 2, 1, "", "")
|
||||
|
||||
# pep 440 version: no dot before beta/rc, but before .dev
|
||||
# 0.1.0rc1
|
||||
|
@@ -526,10 +526,16 @@ class BaseHandler(RequestHandler):
|
||||
path=url_path_join(self.base_url, 'services'),
|
||||
**kwargs,
|
||||
)
|
||||
# clear tornado cookie
|
||||
# clear_cookie only accepts a subset of set_cookie's kwargs
|
||||
clear_xsrf_cookie_kwargs = {
|
||||
key: value
|
||||
for key, value in self.settings.get('xsrf_cookie_kwargs', {})
|
||||
if key in {"path", "domain"}
|
||||
}
|
||||
|
||||
self.clear_cookie(
|
||||
'_xsrf',
|
||||
**self.settings.get('xsrf_cookie_kwargs', {}),
|
||||
**clear_xsrf_cookie_kwargs,
|
||||
)
|
||||
# Reset _jupyterhub_user
|
||||
self._jupyterhub_user = None
|
||||
|
@@ -195,8 +195,7 @@ class Spawner(LoggingConfigurable):
|
||||
# always check that we're in sync with orm_spawner
|
||||
if not self.orm_spawner:
|
||||
# no ORM spawner, nothing to check
|
||||
self._server = None
|
||||
return None
|
||||
return self._server
|
||||
|
||||
orm_server = self.orm_spawner.server
|
||||
|
||||
@@ -227,6 +226,10 @@ class Spawner(LoggingConfigurable):
|
||||
if server.orm_server is None:
|
||||
self.log.warning(f"No ORM server for {self._log_name}")
|
||||
self.orm_spawner.server = server.orm_server
|
||||
elif server is not None:
|
||||
self.log.warning(
|
||||
"Setting Spawner.server for {self._log_name} with no underlying orm_spawner"
|
||||
)
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
|
@@ -529,3 +529,10 @@ def test_spawner_server(db):
|
||||
spawner.server = None
|
||||
db.commit()
|
||||
assert spawner.orm_spawner.server is None
|
||||
|
||||
# test with no underlying orm.Spawner
|
||||
# (only relevant for mocking, never true for actual Spawners)
|
||||
spawner = Spawner()
|
||||
spawner.server = Server.from_url("http://1.2.3.4")
|
||||
assert spawner.server is not None
|
||||
assert spawner.server.ip == "1.2.3.4"
|
||||
|
@@ -11,7 +11,7 @@ target_version = [
|
||||
github_url = "https://github.com/jupyterhub/jupyterhub"
|
||||
|
||||
[tool.tbump.version]
|
||||
current = "2.2.0"
|
||||
current = "2.2.1"
|
||||
|
||||
# Example of a semver regexp.
|
||||
# Make sure this matches current_version before
|
||||
|
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user