From 9dc24c0995f36218346a90b8fdb94a4f0088e8fe Mon Sep 17 00:00:00 2001 From: Min RK Date: Wed, 21 Mar 2018 14:24:25 +0100 Subject: [PATCH] add user.created, spawner.started - alembic revision - in user/spawner models --- .../versions/56cc5a70207e_token_tracking.py | 2 - .../versions/99a28a4418e1_user_created.py | 47 +++++++++++++++++++ jupyterhub/apihandlers/base.py | 8 +++- jupyterhub/orm.py | 1 + jupyterhub/user.py | 4 ++ 5 files changed, 59 insertions(+), 3 deletions(-) create mode 100644 jupyterhub/alembic/versions/99a28a4418e1_user_created.py diff --git a/jupyterhub/alembic/versions/56cc5a70207e_token_tracking.py b/jupyterhub/alembic/versions/56cc5a70207e_token_tracking.py index 3bba1c4c..9550ee89 100644 --- a/jupyterhub/alembic/versions/56cc5a70207e_token_tracking.py +++ b/jupyterhub/alembic/versions/56cc5a70207e_token_tracking.py @@ -18,7 +18,6 @@ import sqlalchemy as sa def upgrade(): tables = op.get_bind().engine.table_names() - op.add_column('users', sa.Column('created', sa.DateTime(), nullable=True)) op.add_column('api_tokens', sa.Column('created', sa.DateTime(), nullable=True)) op.add_column('api_tokens', sa.Column('last_activity', sa.DateTime(), nullable=True)) op.add_column('api_tokens', sa.Column('note', sa.Unicode(length=1023), nullable=True)) @@ -32,7 +31,6 @@ def upgrade(): def downgrade(): op.drop_constraint(None, 'oauth_codes', type_='foreignkey') op.drop_constraint(None, 'oauth_access_tokens', type_='foreignkey') - op.add_column('users', 'created') op.drop_column('oauth_access_tokens', 'last_activity') op.drop_column('oauth_access_tokens', 'created') op.drop_column('api_tokens', 'note') diff --git a/jupyterhub/alembic/versions/99a28a4418e1_user_created.py b/jupyterhub/alembic/versions/99a28a4418e1_user_created.py new file mode 100644 index 00000000..b0c6732d --- /dev/null +++ b/jupyterhub/alembic/versions/99a28a4418e1_user_created.py @@ -0,0 +1,47 @@ +"""user.created and spawner.started + +Revision ID: 99a28a4418e1 +Revises: 56cc5a70207e +Create Date: 2018-03-21 14:27:17.466841 + +""" + +# revision identifiers, used by Alembic. +revision = '99a28a4418e1' +down_revision = '56cc5a70207e' +branch_labels = None +depends_on = None + + +from alembic import op +import sqlalchemy as sa + +from datetime import datetime + +def upgrade(): + op.add_column('users', sa.Column('created', sa.DateTime, nullable=True)) + c = op.get_bind() + # fill created date with current time + now = datetime.utcnow() + c.execute(""" + UPDATE users + SET created='%s' + """ % (now,) + ) + + tables = c.engine.table_names() + + if 'spawners' in tables: + op.add_column('spawners', sa.Column('started', sa.DateTime, nullable=True)) + # fill started value with now for running servers + c.execute(""" + UPDATE spawners + SET started='%s' + WHERE server_id NOT NULL + """ % (now,) + ) + + +def downgrade(): + op.drop_column('users', 'created') + op.drop_column('spawners', 'started') diff --git a/jupyterhub/apihandlers/base.py b/jupyterhub/apihandlers/base.py index 329d6eb7..9193da24 100644 --- a/jupyterhub/apihandlers/base.py +++ b/jupyterhub/apihandlers/base.py @@ -112,10 +112,15 @@ class APIHandler(BaseHandler): 'groups': [ g.name for g in user.groups ], 'server': user.url if user.running else None, 'pending': None, + 'created': isoformat(user.created), 'last_activity': last_activity, + 'started': None, } if '' in user.spawners: - model['pending'] = user.spawners[''].pending or None + spawner = user.spawners[''] + model['pending'] = spawner.pending or None + if spawner.active and spawner.started: + model['started'] = isoformat(spawner.started) if self.allow_named_servers: servers = model['servers'] = {} @@ -127,6 +132,7 @@ class APIHandler(BaseHandler): servers[name] = s = { 'name': name, 'last_activity': last_activity, + 'started': isoformat(spawner.orm_spawner.started), } if spawner.pending: s['pending'] = spawner.pending diff --git a/jupyterhub/orm.py b/jupyterhub/orm.py index 745ff637..dc98c4b8 100644 --- a/jupyterhub/orm.py +++ b/jupyterhub/orm.py @@ -183,6 +183,7 @@ class Spawner(Base): state = Column(JSONDict) name = Column(Unicode(255)) + started = Column(DateTime) last_activity = Column(DateTime, nullable=True) diff --git a/jupyterhub/user.py b/jupyterhub/user.py index 681ba8ce..c8c4ae5f 100644 --- a/jupyterhub/user.py +++ b/jupyterhub/user.py @@ -380,6 +380,8 @@ class User: await maybe_future(authenticator.pre_spawn_start(self, spawner)) spawner._start_pending = True + spawner.started = datetime.utcnow() + db.commit() # wait for spawner.start to return try: # run optional preparation work to bootstrap the notebook @@ -527,6 +529,8 @@ class User: self.db.delete(orm_token) self.db.commit() finally: + spawner.started = None + self.db.commit() # trigger post-spawner hook on authenticator auth = spawner.authenticator try: