from the sqlalchemy docs
checks if a connection is valid via `SELECT 1` prior to using it.
Since we have long-running connections, this helps us survive database restarts, disconnects, etc.
in order to use sqlalchemy's expire_on_commit=False optimization,
we need to make sure that objects are kept up to date.
This means we cannot rely on ForeignKey ondelete/onupdate behavior,
we must use sqlalchemy's local relationship cascades
The main key here is that we must use relationships to set foreign-key relations,
e.g. APIToken.user = user instead of APIToken.user_id = user.id.
It also means that we cannot use passive_deletes,
which allows sqlalchemy to defer to the database's more efficient ON DELETE behavior.
This makes deletions more expensive in particular,
but should improve db performance overall.
- set ONDELETE='set null' on spawner->server relation (fixes error when deleting servers that stopped)
- set `spawner.server = None`, which is not triggered when deleting orm_spawner.server
user-provided tokens are added in exactly one place,
so switch default handling of tokens to generated=True
and explicitly distrust user tokens.
Add JupyterHub.trust_user_provided_tokens flag so that users can avoid the extra hashing
if they know they are providing good keys.
fail with informative error if version mismatches
Since we weren't always tagging before,
we have to handle no tag being present:
- database empty (use latest because we are about to create everything anew)
- if 'spawners' is present, assume 0.8.dev
- if 'services' is present, assume 0.7.x
- else: assume base revision when we started tracking this stuff
privy is used for encryption
- db only has blob column, no knowledge of encryption
- add CryptKeeper for handling encryption
- use privy for encryption, so we have fewer choices to make
- storing/loading encrypted auth_state runs in a ThreadPool
- MultFernet allows key rotation via `AUTH_STATE_KEY=secret2;secret1;secret0`
- Failure to decrypt results in cleared state
- Attempting to set auth_state without encryption is a hard failure
- Absent encryption, auth_state will always be None