mirror of
https://github.com/jupyterhub/jupyterhub.git
synced 2025-10-08 02:24:08 +00:00
Compare commits
27 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
3590d16e30 | ||
![]() |
572d258cd2 | ||
![]() |
11d0954551 | ||
![]() |
650d47d5c1 | ||
![]() |
945fc824d8 | ||
![]() |
a8aa737b00 | ||
![]() |
cd689a1fab | ||
![]() |
fbcf857991 | ||
![]() |
6c5e5452bc | ||
![]() |
2f5ba7ba30 | ||
![]() |
a045eefa64 | ||
![]() |
6ea4f2af0d | ||
![]() |
3d3ad2929c | ||
![]() |
00287ff5ba | ||
![]() |
805d063d1d | ||
![]() |
e6bacf7109 | ||
![]() |
33ccfa7963 | ||
![]() |
593404f558 | ||
![]() |
e7bc282c80 | ||
![]() |
b939b482a1 | ||
![]() |
8afc2c9ae9 | ||
![]() |
d11eda14ed | ||
![]() |
ab79251fe2 | ||
![]() |
484dbf48de | ||
![]() |
6eb526d08a | ||
![]() |
e0a17db5f1 | ||
![]() |
45132b7244 |
108
.github/workflows/test-jsx.yml
vendored
Normal file
108
.github/workflows/test-jsx.yml
vendored
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
# This is a GitHub workflow defining a set of jobs with a set of steps.
|
||||||
|
# ref: https://docs.github.com/en/actions/learn-github-actions/workflow-syntax-for-github-actions
|
||||||
|
#
|
||||||
|
name: Test jsx (admin-react.js)
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
paths:
|
||||||
|
- "jsx/**"
|
||||||
|
- ".github/workflows/test-jsx.yml"
|
||||||
|
push:
|
||||||
|
paths:
|
||||||
|
- "jsx/**"
|
||||||
|
- ".github/workflows/test-jsx.yml"
|
||||||
|
branches-ignore:
|
||||||
|
- "dependabot/**"
|
||||||
|
- "pre-commit-ci-update-config"
|
||||||
|
tags:
|
||||||
|
- "**"
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
# The ./jsx folder contains React based source code files that are to compile
|
||||||
|
# to share/jupyterhub/static/js/admin-react.js. The ./jsx folder includes
|
||||||
|
# tests also has tests that this job is meant to run with `yarn test`
|
||||||
|
# according to the documentation in jsx/README.md.
|
||||||
|
test-jsx-admin-react:
|
||||||
|
runs-on: ubuntu-20.04
|
||||||
|
timeout-minutes: 5
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- uses: actions/setup-node@v1
|
||||||
|
with:
|
||||||
|
node-version: "14"
|
||||||
|
|
||||||
|
- name: Install yarn
|
||||||
|
run: |
|
||||||
|
npm install -g yarn
|
||||||
|
|
||||||
|
- name: yarn
|
||||||
|
run: |
|
||||||
|
cd jsx
|
||||||
|
yarn
|
||||||
|
|
||||||
|
- name: yarn test
|
||||||
|
run: |
|
||||||
|
cd jsx
|
||||||
|
yarn test
|
||||||
|
|
||||||
|
# The ./jsx folder contains React based source files that are to compile to
|
||||||
|
# share/jupyterhub/static/js/admin-react.js. This job makes sure that whatever
|
||||||
|
# we have in jsx/src matches the compiled asset that we package and
|
||||||
|
# distribute.
|
||||||
|
#
|
||||||
|
# This job's purpose is to make sure we don't forget to compile changes and to
|
||||||
|
# verify nobody sneaks in a change in the hard to review compiled asset.
|
||||||
|
#
|
||||||
|
# NOTE: In the future we may want to stop version controlling the compiled
|
||||||
|
# artifact and instead generate it whenever we package JupyterHub. If we
|
||||||
|
# do this, we are required to setup node and compile the source code
|
||||||
|
# more often, at the same time we could avoid having this check be made.
|
||||||
|
#
|
||||||
|
compile-jsx-admin-react:
|
||||||
|
runs-on: ubuntu-20.04
|
||||||
|
timeout-minutes: 5
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- uses: actions/setup-node@v1
|
||||||
|
with:
|
||||||
|
node-version: "14"
|
||||||
|
|
||||||
|
- name: Install yarn
|
||||||
|
run: |
|
||||||
|
npm install -g yarn
|
||||||
|
|
||||||
|
- name: yarn
|
||||||
|
run: |
|
||||||
|
cd jsx
|
||||||
|
yarn
|
||||||
|
|
||||||
|
- name: yarn build
|
||||||
|
run: |
|
||||||
|
cd jsx
|
||||||
|
yarn build
|
||||||
|
|
||||||
|
- name: yarn place
|
||||||
|
run: |
|
||||||
|
cd jsx
|
||||||
|
yarn place
|
||||||
|
|
||||||
|
- name: Verify compiled jsx/src matches version controlled artifact
|
||||||
|
run: |
|
||||||
|
if [[ `git status --porcelain=v1` ]]; then
|
||||||
|
echo "The source code in ./jsx compiles to something different than found in ./share/jupyterhub/static/js/admin-react.js!"
|
||||||
|
echo
|
||||||
|
echo "Please re-compile the source code in ./jsx with the following commands:"
|
||||||
|
echo
|
||||||
|
echo "yarn"
|
||||||
|
echo "yarn build"
|
||||||
|
echo "yarn place"
|
||||||
|
echo
|
||||||
|
echo "See ./jsx/README.md for more details."
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
echo "Compilation of jsx/src to share/jupyterhub/static/js/admin-react.js didn't lead to changes."
|
||||||
|
fi
|
27
.github/workflows/test.yml
vendored
27
.github/workflows/test.yml
vendored
@@ -31,33 +31,6 @@ env:
|
|||||||
PYTEST_ADDOPTS: "--verbose --color=yes"
|
PYTEST_ADDOPTS: "--verbose --color=yes"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
jstest:
|
|
||||||
# Run javascript tests
|
|
||||||
runs-on: ubuntu-20.04
|
|
||||||
timeout-minutes: 5
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
# NOTE: actions/setup-node@v1 make use of a cache within the GitHub base
|
|
||||||
# environment and setup in a fraction of a second.
|
|
||||||
- name: Install Node
|
|
||||||
uses: actions/setup-node@v1
|
|
||||||
with:
|
|
||||||
node-version: "14"
|
|
||||||
|
|
||||||
- name: Install Node dependencies
|
|
||||||
run: |
|
|
||||||
npm install -g yarn
|
|
||||||
|
|
||||||
- name: Run yarn
|
|
||||||
run: |
|
|
||||||
cd jsx
|
|
||||||
yarn
|
|
||||||
|
|
||||||
- name: yarn test
|
|
||||||
run: |
|
|
||||||
cd jsx
|
|
||||||
yarn test
|
|
||||||
|
|
||||||
# Run "pytest jupyterhub/tests" in various configurations
|
# Run "pytest jupyterhub/tests" in various configurations
|
||||||
pytest:
|
pytest:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
|
@@ -1,30 +1,53 @@
|
|||||||
|
# pre-commit is a tool to perform a predefined set of tasks manually and/or
|
||||||
|
# automatically before git commits are made.
|
||||||
|
#
|
||||||
|
# Config reference: https://pre-commit.com/#pre-commit-configyaml---top-level
|
||||||
|
#
|
||||||
|
# Common tasks
|
||||||
|
#
|
||||||
|
# - Run on all files: pre-commit run --all-files
|
||||||
|
# - Register git hooks: pre-commit install --install-hooks
|
||||||
|
#
|
||||||
repos:
|
repos:
|
||||||
|
# Autoformat: Python code, syntax patterns are modernized
|
||||||
- repo: https://github.com/asottile/pyupgrade
|
- repo: https://github.com/asottile/pyupgrade
|
||||||
rev: v2.31.0
|
rev: v2.31.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: pyupgrade
|
- id: pyupgrade
|
||||||
args:
|
args:
|
||||||
- --py36-plus
|
- --py36-plus
|
||||||
|
|
||||||
|
# Autoformat: Python code
|
||||||
- repo: https://github.com/asottile/reorder_python_imports
|
- repo: https://github.com/asottile/reorder_python_imports
|
||||||
rev: v2.7.1
|
rev: v2.7.1
|
||||||
hooks:
|
hooks:
|
||||||
- id: reorder-python-imports
|
- id: reorder-python-imports
|
||||||
|
|
||||||
|
# Autoformat: Python code
|
||||||
- repo: https://github.com/psf/black
|
- repo: https://github.com/psf/black
|
||||||
rev: 22.1.0
|
rev: 22.1.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: black
|
- id: black
|
||||||
|
args: [--target-version=py36]
|
||||||
|
|
||||||
|
# Autoformat: markdown, yaml, javascript (see the file .prettierignore)
|
||||||
- repo: https://github.com/pre-commit/mirrors-prettier
|
- repo: https://github.com/pre-commit/mirrors-prettier
|
||||||
rev: v2.5.1
|
rev: v2.5.1
|
||||||
hooks:
|
hooks:
|
||||||
- id: prettier
|
- id: prettier
|
||||||
- repo: https://github.com/PyCQA/flake8
|
|
||||||
rev: "4.0.1"
|
# Autoformat and linting, misc. details
|
||||||
hooks:
|
|
||||||
- id: flake8
|
|
||||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||||
rev: v4.1.0
|
rev: v4.1.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: end-of-file-fixer
|
- id: end-of-file-fixer
|
||||||
|
exclude: share/jupyterhub/static/js/admin-react.js
|
||||||
|
- id: requirements-txt-fixer
|
||||||
- id: check-case-conflict
|
- id: check-case-conflict
|
||||||
- id: check-executables-have-shebangs
|
- id: check-executables-have-shebangs
|
||||||
- id: requirements-txt-fixer
|
|
||||||
|
# Linting: Python code (see the file .flake8)
|
||||||
|
- repo: https://github.com/PyCQA/flake8
|
||||||
|
rev: "4.0.1"
|
||||||
|
hooks:
|
||||||
|
- id: flake8
|
||||||
|
@@ -6,7 +6,7 @@ info:
|
|||||||
description: The REST API for JupyterHub
|
description: The REST API for JupyterHub
|
||||||
license:
|
license:
|
||||||
name: BSD-3-Clause
|
name: BSD-3-Clause
|
||||||
version: 2.2.0
|
version: 2.2.2
|
||||||
servers:
|
servers:
|
||||||
- url: /hub/api
|
- url: /hub/api
|
||||||
security:
|
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,7 +8,52 @@ command line for details.
|
|||||||
|
|
||||||
## 2.2
|
## 2.2
|
||||||
|
|
||||||
# 2.2.0 2021-03-07
|
### 2.2.2 2022-03-14
|
||||||
|
|
||||||
|
2.2.2 fixes a small regressions in 2.2.1.
|
||||||
|
|
||||||
|
([full changelog](https://github.com/jupyterhub/jupyterhub/compare/2.2.1...6c5e5452bc734dfd5c5a9482e4980b988ddd304e))
|
||||||
|
|
||||||
|
#### Bugs fixed
|
||||||
|
|
||||||
|
- Fix failure to update admin-react.js by re-compiling from our source [#3825](https://github.com/jupyterhub/jupyterhub/pull/3825) ([@NarekA](https://github.com/NarekA), [@consideRatio](https://github.com/consideRatio), [@minrk](https://github.com/minrk), [@manics](https://github.com/manics))
|
||||||
|
|
||||||
|
#### Continuous integration improvements
|
||||||
|
|
||||||
|
- ci: standalone jsx workflow and verify compiled asset matches source code [#3826](https://github.com/jupyterhub/jupyterhub/pull/3826) ([@consideRatio](https://github.com/consideRatio), [@NarekA](https://github.com/NarekA))
|
||||||
|
|
||||||
|
#### Contributors to this release
|
||||||
|
|
||||||
|
([GitHub contributors page for this release](https://github.com/jupyterhub/jupyterhub/graphs/contributors?from=2022-03-11&to=2022-03-14&type=c))
|
||||||
|
|
||||||
|
[@consideRatio](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3AconsideRatio+updated%3A2022-03-11..2022-03-14&type=Issues) | [@manics](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Amanics+updated%3A2022-03-11..2022-03-14&type=Issues) | [@minrk](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3Aminrk+updated%3A2022-03-11..2022-03-14&type=Issues) | [@NarekA](https://github.com/search?q=repo%3Ajupyterhub%2Fjupyterhub+involves%3ANarekA+updated%3A2022-03-11..2022-03-14&type=Issues)
|
||||||
|
|
||||||
|
### 2.2.1 2022-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 2022-03-07
|
||||||
|
|
||||||
JupyterHub 2.2.0 is a small release.
|
JupyterHub 2.2.0 is a small release.
|
||||||
The main new feature is the ability of Authenticators to [manage group membership](authenticator-groups),
|
The main new feature is the ability of Authenticators to [manage group membership](authenticator-groups),
|
||||||
@@ -56,7 +101,7 @@ The links to access user servers from the admin page have been restored.
|
|||||||
|
|
||||||
## 2.1
|
## 2.1
|
||||||
|
|
||||||
### 2.1.1 2021-01-25
|
### 2.1.1 2022-01-25
|
||||||
|
|
||||||
2.1.1 is a tiny bugfix release,
|
2.1.1 is a tiny bugfix release,
|
||||||
fixing an issue where admins did not receive the new `read:metrics` permission.
|
fixing an issue where admins did not receive the new `read:metrics` permission.
|
||||||
|
@@ -10,4 +10,5 @@ well as other information relevant to running your own JupyterHub over time.
|
|||||||
|
|
||||||
troubleshooting
|
troubleshooting
|
||||||
admin/upgrading
|
admin/upgrading
|
||||||
|
admin/log-messages
|
||||||
changelog
|
changelog
|
||||||
|
@@ -153,10 +153,9 @@ const ServerDashboard = (props) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const EditUserCell = ({ user, numServers, serverName }) => {
|
const EditUserCell = ({ user }) => {
|
||||||
if (serverName) return null;
|
|
||||||
return (
|
return (
|
||||||
<td rowspan={numServers}>
|
<td>
|
||||||
<button
|
<button
|
||||||
className="btn btn-primary btn-xs"
|
className="btn btn-primary btn-xs"
|
||||||
style={{ marginRight: 20 }}
|
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 (
|
return (
|
||||||
<div className="container" data-testid="container">
|
<div className="container" data-testid="container">
|
||||||
{errorAlert != null ? (
|
{errorAlert != null ? (
|
||||||
@@ -339,87 +346,65 @@ const ServerDashboard = (props) => {
|
|||||||
</Button>
|
</Button>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{user_data.flatMap((e, i) => {
|
{servers.map(([user, server], i) => {
|
||||||
let userServers = Object.values({
|
server.name = server.name || "";
|
||||||
"": e.server,
|
return (
|
||||||
...(e.servers || {}),
|
<tr key={i + "row"} className="user-row">
|
||||||
});
|
<td data-testid="user-row-name">{user.name}</td>
|
||||||
return userServers.map((server) => {
|
<td data-testid="user-row-admin">
|
||||||
server = { name: "", ...server };
|
{user.admin ? "admin" : ""}
|
||||||
return (
|
</td>
|
||||||
<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>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<td data-testid="user-row-server">
|
<td data-testid="user-row-server">
|
||||||
{server.name ? (
|
{server.name ? (
|
||||||
<p class="text-secondary">{server.name}</p>
|
<p class="text-secondary">{server.name}</p>
|
||||||
) : (
|
) : (
|
||||||
<p style={{ color: "lightgrey" }}>[MAIN]</p>
|
<p style={{ color: "lightgrey" }}>[MAIN]</p>
|
||||||
)}
|
)}
|
||||||
</td>
|
</td>
|
||||||
<td data-testid="user-row-last-activity">
|
<td data-testid="user-row-last-activity">
|
||||||
{server.last_activity
|
{server.last_activity
|
||||||
? timeSince(server.last_activity)
|
? timeSince(server.last_activity)
|
||||||
: "Never"}
|
: "Never"}
|
||||||
</td>
|
</td>
|
||||||
<td data-testid="user-row-server-activity">
|
<td data-testid="user-row-server-activity">
|
||||||
{server.started ? (
|
{server.started ? (
|
||||||
// Stop Single-user server
|
// Stop Single-user server
|
||||||
<>
|
<>
|
||||||
<StopServerButton
|
<StopServerButton
|
||||||
serverName={server.name}
|
serverName={server.name}
|
||||||
userName={e.name}
|
userName={user.name}
|
||||||
/>
|
/>
|
||||||
<AccessServerButton
|
<AccessServerButton
|
||||||
serverName={server.name}
|
serverName={server.name}
|
||||||
userName={e.name}
|
userName={user.name}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
// Start Single-user server
|
// Start Single-user server
|
||||||
<>
|
<>
|
||||||
<StartServerButton
|
<StartServerButton
|
||||||
serverName={server.name}
|
serverName={server.name}
|
||||||
userName={e.name}
|
userName={user.name}
|
||||||
/>
|
/>
|
||||||
<a
|
<a
|
||||||
href={`/spawn/${e.name}${
|
href={`/spawn/${user.name}${
|
||||||
server.name && "/" + server.name
|
server.name && "/" + server.name
|
||||||
}`}
|
}`}
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
className="btn btn-secondary btn-xs"
|
||||||
|
style={{ marginRight: 20 }}
|
||||||
>
|
>
|
||||||
<button
|
Spawn Page
|
||||||
className="btn btn-secondary btn-xs"
|
</button>
|
||||||
style={{ marginRight: 20 }}
|
</a>
|
||||||
>
|
</>
|
||||||
Spawn Page
|
)}
|
||||||
</button>
|
</td>
|
||||||
</a>
|
<EditUserCell user={user} />
|
||||||
</>
|
</tr>
|
||||||
)}
|
);
|
||||||
</td>
|
|
||||||
<EditUserCell
|
|
||||||
user={e}
|
|
||||||
numServers={userServers.length}
|
|
||||||
serverName={server.name}
|
|
||||||
/>
|
|
||||||
</tr>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
})}
|
})}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
# 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.
|
||||||
# version_info updated by running `tbump`
|
# version_info updated by running `tbump`
|
||||||
version_info = (2, 2, 0, "", "")
|
version_info = (2, 2, 2, "", "")
|
||||||
|
|
||||||
# pep 440 version: no dot before beta/rc, but before .dev
|
# pep 440 version: no dot before beta/rc, but before .dev
|
||||||
# 0.1.0rc1
|
# 0.1.0rc1
|
||||||
|
@@ -526,10 +526,16 @@ class BaseHandler(RequestHandler):
|
|||||||
path=url_path_join(self.base_url, 'services'),
|
path=url_path_join(self.base_url, 'services'),
|
||||||
**kwargs,
|
**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(
|
self.clear_cookie(
|
||||||
'_xsrf',
|
'_xsrf',
|
||||||
**self.settings.get('xsrf_cookie_kwargs', {}),
|
**clear_xsrf_cookie_kwargs,
|
||||||
)
|
)
|
||||||
# Reset _jupyterhub_user
|
# Reset _jupyterhub_user
|
||||||
self._jupyterhub_user = None
|
self._jupyterhub_user = None
|
||||||
|
@@ -195,8 +195,7 @@ class Spawner(LoggingConfigurable):
|
|||||||
# always check that we're in sync with orm_spawner
|
# always check that we're in sync with orm_spawner
|
||||||
if not self.orm_spawner:
|
if not self.orm_spawner:
|
||||||
# no ORM spawner, nothing to check
|
# no ORM spawner, nothing to check
|
||||||
self._server = None
|
return self._server
|
||||||
return None
|
|
||||||
|
|
||||||
orm_server = self.orm_spawner.server
|
orm_server = self.orm_spawner.server
|
||||||
|
|
||||||
@@ -227,6 +226,10 @@ class Spawner(LoggingConfigurable):
|
|||||||
if server.orm_server is None:
|
if server.orm_server is None:
|
||||||
self.log.warning(f"No ORM server for {self._log_name}")
|
self.log.warning(f"No ORM server for {self._log_name}")
|
||||||
self.orm_spawner.server = server.orm_server
|
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
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
|
@@ -529,3 +529,10 @@ def test_spawner_server(db):
|
|||||||
spawner.server = None
|
spawner.server = None
|
||||||
db.commit()
|
db.commit()
|
||||||
assert spawner.orm_spawner.server is None
|
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"
|
github_url = "https://github.com/jupyterhub/jupyterhub"
|
||||||
|
|
||||||
[tool.tbump.version]
|
[tool.tbump.version]
|
||||||
current = "2.2.0"
|
current = "2.2.2"
|
||||||
|
|
||||||
# Example of a semver regexp.
|
# Example of a semver regexp.
|
||||||
# Make sure this matches current_version before
|
# 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