mirror of
https://github.com/jupyterhub/jupyterhub.git
synced 2025-10-12 20:43:02 +00:00
indicate that REST API timestamps are UTC
use iso8601 Z suffix for UTC timestamps use dateutil to parse dates from proxy, as well even though CHP uses iso8601 UTC timestamps, we no longer assume CHP, so use more general parsing in our db we are stuck with naïve datetime objects, so use those internally. But ensure we put 'Z' on timestamps we ship externally
This commit is contained in:
@@ -8,7 +8,7 @@ import json
|
||||
from urllib.parse import quote
|
||||
|
||||
from oauth2.web.tornado import OAuth2Handler
|
||||
from tornado import web, gen
|
||||
from tornado import web
|
||||
|
||||
from .. import orm
|
||||
from ..user import User
|
||||
|
@@ -10,7 +10,7 @@ from tornado import web
|
||||
|
||||
from .. import orm
|
||||
from ..handlers import BaseHandler
|
||||
from ..utils import url_path_join
|
||||
from ..utils import isoformat, url_path_join
|
||||
|
||||
class APIHandler(BaseHandler):
|
||||
|
||||
@@ -103,7 +103,7 @@ class APIHandler(BaseHandler):
|
||||
last_activity = user.last_activity
|
||||
# don't call isoformat if last_activity is None
|
||||
if last_activity:
|
||||
last_activity = last_activity.isoformat()
|
||||
last_activity = isoformat(last_activity)
|
||||
|
||||
model = {
|
||||
'kind': 'user',
|
||||
@@ -122,7 +122,7 @@ class APIHandler(BaseHandler):
|
||||
for name, spawner in user.spawners.items():
|
||||
last_activity = spawner.orm_spawner.last_activity
|
||||
if last_activity:
|
||||
last_activity = last_activity.isoformat()
|
||||
last_activity = isoformat(last_activity)
|
||||
if spawner.ready:
|
||||
servers[name] = s = {
|
||||
'name': name,
|
||||
|
@@ -8,7 +8,7 @@ import asyncio
|
||||
import atexit
|
||||
import binascii
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
from datetime import datetime
|
||||
from datetime import datetime, timezone
|
||||
from getpass import getuser
|
||||
import logging
|
||||
from operator import itemgetter
|
||||
@@ -22,8 +22,8 @@ from urllib.parse import urlparse
|
||||
if sys.version_info[:2] < (3, 3):
|
||||
raise ValueError("Python < 3.3 not supported: %s" % sys.version)
|
||||
|
||||
from dateutil.parser import parse as parse_date
|
||||
from jinja2 import Environment, FileSystemLoader, PrefixLoader, ChoiceLoader
|
||||
|
||||
from sqlalchemy.exc import OperationalError
|
||||
|
||||
from tornado.httpclient import AsyncHTTPClient
|
||||
@@ -50,7 +50,7 @@ from .services.service import Service
|
||||
|
||||
from . import crypto
|
||||
from . import dbutil, orm
|
||||
from .user import User, UserDict
|
||||
from .user import UserDict
|
||||
from .oauth.store import make_provider
|
||||
from ._data import DATA_FILES_PATH
|
||||
from .log import CoroutineLogFormatter, log_request
|
||||
@@ -59,7 +59,6 @@ from .traitlets import URLPrefix, Command
|
||||
from .utils import (
|
||||
maybe_future,
|
||||
url_path_join,
|
||||
ISO8601_ms, ISO8601_s,
|
||||
print_stacks, print_ps_info,
|
||||
)
|
||||
# classes for config
|
||||
@@ -1581,10 +1580,11 @@ class JupyterHub(Application):
|
||||
if spawner is None:
|
||||
self.log.warning("Found no spawner for route: %s", route)
|
||||
continue
|
||||
try:
|
||||
dt = datetime.strptime(route_data['last_activity'], ISO8601_ms)
|
||||
except Exception:
|
||||
dt = datetime.strptime(route_data['last_activity'], ISO8601_s)
|
||||
dt = parse_date(route_data['last_activity'])
|
||||
if dt.tzinfo:
|
||||
# strip timezone info to naïve UTC datetime
|
||||
dt = dt.astimezone(timezone.utc).replace(tzinfo=None)
|
||||
|
||||
if user.last_activity:
|
||||
user.last_activity = max(user.last_activity, dt)
|
||||
else:
|
||||
|
@@ -26,7 +26,7 @@ from ..spawner import LocalProcessSpawner
|
||||
from ..utils import maybe_future, url_path_join
|
||||
from ..metrics import (
|
||||
SERVER_SPAWN_DURATION_SECONDS, ServerSpawnStatus,
|
||||
PROXY_ADD_DURATION_SECONDS, ProxyAddStatus
|
||||
PROXY_ADD_DURATION_SECONDS, ProxyAddStatus,
|
||||
)
|
||||
|
||||
# pattern for the authentication token header
|
||||
|
@@ -10,7 +10,6 @@ from oauth2.error import ClientNotFoundError
|
||||
from sqlalchemy import inspect
|
||||
from tornado import gen
|
||||
from tornado.log import app_log
|
||||
from traitlets import HasTraits, Any, Dict, default
|
||||
|
||||
from .utils import maybe_future, url_path_join
|
||||
|
||||
|
@@ -6,6 +6,7 @@
|
||||
import asyncio
|
||||
from binascii import b2a_hex
|
||||
import concurrent.futures
|
||||
from datetime import datetime, timezone
|
||||
import random
|
||||
import errno
|
||||
import hashlib
|
||||
@@ -15,7 +16,6 @@ import os
|
||||
import socket
|
||||
import sys
|
||||
import threading
|
||||
from threading import Thread
|
||||
import uuid
|
||||
import warnings
|
||||
|
||||
@@ -39,6 +39,16 @@ ISO8601_ms = '%Y-%m-%dT%H:%M:%S.%fZ'
|
||||
ISO8601_s = '%Y-%m-%dT%H:%M:%SZ'
|
||||
|
||||
|
||||
def isoformat(dt):
|
||||
"""Render a datetime object as an ISO 8601 UTC timestamp
|
||||
|
||||
Naïve datetime objects are assumed to be UTC
|
||||
"""
|
||||
if dt.tzinfo:
|
||||
dt = dt.astimezone(timezone.utc).replace(tzinfo=None)
|
||||
return dt.isoformat() + 'Z'
|
||||
|
||||
|
||||
def can_connect(ip, port):
|
||||
"""Check if we can connect to an ip:port.
|
||||
|
||||
|
@@ -4,6 +4,7 @@ tornado>=4.1
|
||||
jinja2
|
||||
pamela
|
||||
python-oauth2>=1.0
|
||||
python-dateutil
|
||||
SQLAlchemy>=1.1
|
||||
requests
|
||||
prometheus_client>=0.0.21
|
||||
|
Reference in New Issue
Block a user