From 2c0395802c72fd534123d87a0c98a3b9903e1acf Mon Sep 17 00:00:00 2001 From: Stefano Borini Date: Tue, 25 Apr 2017 14:52:27 +0100 Subject: [PATCH 1/6] Adding Stats resource --- remoteappmanager/webapi/admin/stats.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 remoteappmanager/webapi/admin/stats.py diff --git a/remoteappmanager/webapi/admin/stats.py b/remoteappmanager/webapi/admin/stats.py new file mode 100644 index 000000000..e69de29bb From d2cec27d311253c6c49e0f4c9db13c7fbc321401 Mon Sep 17 00:00:00 2001 From: Stefano Borini Date: Wed, 26 Apr 2017 16:28:18 +0100 Subject: [PATCH 2/6] Added Stats --- remoteappmanager/admin_application.py | 3 +- remoteappmanager/webapi/admin/__init__.py | 1 + remoteappmanager/webapi/admin/stats.py | 32 ++++++++++++++ .../webapi/admin/tests/test_stats.py | 42 +++++++++++++++++++ 4 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 remoteappmanager/webapi/admin/tests/test_stats.py diff --git a/remoteappmanager/admin_application.py b/remoteappmanager/admin_application.py index 2753dd502..b881093f8 100644 --- a/remoteappmanager/admin_application.py +++ b/remoteappmanager/admin_application.py @@ -18,7 +18,8 @@ def _webapi_resources(self): return [admin.ContainerHandler, admin.ApplicationHandler, admin.UserHandler, - admin.AccountingHandler] + admin.AccountingHandler, + admin.StatsHandler] def _web_handlers(self): base_urlpath = self.command_line_config.base_urlpath diff --git a/remoteappmanager/webapi/admin/__init__.py b/remoteappmanager/webapi/admin/__init__.py index fa0d7934e..b38ac6051 100644 --- a/remoteappmanager/webapi/admin/__init__.py +++ b/remoteappmanager/webapi/admin/__init__.py @@ -2,3 +2,4 @@ from .application import ApplicationHandler # noqa from .user import UserHandler # noqa from .accounting import AccountingHandler # noqa +from .stats import StatsHandler # noqa diff --git a/remoteappmanager/webapi/admin/stats.py b/remoteappmanager/webapi/admin/stats.py index e69de29bb..fccc5fad1 100644 --- a/remoteappmanager/webapi/admin/stats.py +++ b/remoteappmanager/webapi/admin/stats.py @@ -0,0 +1,32 @@ +from tornado import gen + +from tornadowebapi.traitlets import Unicode, Int +from tornadowebapi.singleton_resource import SingletonResource +from tornadowebapi.resource_handler import ResourceHandler + +from remoteappmanager.webapi.decorators import authenticated + + +class Stats(SingletonResource): + realm = Unicode(allow_empty=False, strip=True) + num_total_users = Int() + num_active_users = Int() + num_images = Int() + num_running_containers = Int() + + +class StatsHandler(ResourceHandler): + resource_class = Stats + + @gen.coroutine + @authenticated + def retrieve(self, resource, **kwargs): + app = self.application + manager = self.application.container_manager + containers = (yield manager.find_containers()) + + resource.realm = app.file_config.docker_realm + resource.num_total_users = len(app.db.list_users()) + resource.num_active_users = len(set([c.user for c in containers])) + resource.num_images = len(app.db.list_applications()) + resource.num_running_containers = len(containers) diff --git a/remoteappmanager/webapi/admin/tests/test_stats.py b/remoteappmanager/webapi/admin/tests/test_stats.py new file mode 100644 index 000000000..99a31a9b8 --- /dev/null +++ b/remoteappmanager/webapi/admin/tests/test_stats.py @@ -0,0 +1,42 @@ +from tornadowebapi.authenticator import NullAuthenticator +from tornadowebapi.http import httpstatus + +from remoteappmanager.tests.webapi_test_case import WebAPITestCase +from remoteappmanager.tests.mocking import dummy + + +class TestStats(WebAPITestCase): + def get_app(self): + app = dummy.create_admin_application() + app.hub.verify_token.return_value = { + 'pending': None, + 'name': app.settings['user'], + 'admin': False, + 'server': app.settings['base_urlpath']} + return app + + def test_get(self): + code, data = self.get("/user/johndoe/api/v1/stats/") + self.assertEqual(code, httpstatus.OK) + self.assertEqual(data, { + 'num_active_users': 1, + 'num_images': 2, + 'num_running_containers': 1, + 'num_total_users': 1, + 'realm': 'remoteexec'}) + + def cookie_auth_token(self): + return "jupyter-hub-token-johndoe=johndoe" + + +class TestContainerNoUser(WebAPITestCase): + def get_app(self): + app = dummy.create_admin_application() + app.registry.authenticator = NullAuthenticator + return app + + def test_get_no_user(self): + self.get("/user/johndoe/api/v1/stats/", httpstatus.NOT_FOUND) + + def cookie_auth_token(self): + return "jupyter-hub-token-johndoe=johndoe" From c06d7e6ffafd3847105900870f20be9d7220143c Mon Sep 17 00:00:00 2001 From: Stefano Borini Date: Wed, 26 Apr 2017 16:30:42 +0100 Subject: [PATCH 3/6] Flake --- remoteappmanager/webapi/admin/tests/test_stats.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/remoteappmanager/webapi/admin/tests/test_stats.py b/remoteappmanager/webapi/admin/tests/test_stats.py index 99a31a9b8..8bb9a645e 100644 --- a/remoteappmanager/webapi/admin/tests/test_stats.py +++ b/remoteappmanager/webapi/admin/tests/test_stats.py @@ -20,10 +20,10 @@ def test_get(self): self.assertEqual(code, httpstatus.OK) self.assertEqual(data, { 'num_active_users': 1, - 'num_images': 2, - 'num_running_containers': 1, - 'num_total_users': 1, - 'realm': 'remoteexec'}) + 'num_images': 2, + 'num_running_containers': 1, + 'num_total_users': 1, + 'realm': 'remoteexec'}) def cookie_auth_token(self): return "jupyter-hub-token-johndoe=johndoe" From e3218720502aeda6f8c5b8d48a89eae5eb327938 Mon Sep 17 00:00:00 2001 From: Stefano Borini Date: Wed, 26 Apr 2017 23:11:41 +0100 Subject: [PATCH 4/6] docs --- remoteappmanager/webapi/admin/stats.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/remoteappmanager/webapi/admin/stats.py b/remoteappmanager/webapi/admin/stats.py index fccc5fad1..dfc68d7fd 100644 --- a/remoteappmanager/webapi/admin/stats.py +++ b/remoteappmanager/webapi/admin/stats.py @@ -8,14 +8,20 @@ class Stats(SingletonResource): + #: The current realm of the application realm = Unicode(allow_empty=False, strip=True) + #: Total number of users on the system num_total_users = Int() + #: Total number of users currently running at least one container num_active_users = Int() - num_images = Int() + #: Total number of available applications. + num_application = Int() + #: Total number of running containers. num_running_containers = Int() class StatsHandler(ResourceHandler): + """Provides statistics about the service.""" resource_class = Stats @gen.coroutine @@ -28,5 +34,5 @@ def retrieve(self, resource, **kwargs): resource.realm = app.file_config.docker_realm resource.num_total_users = len(app.db.list_users()) resource.num_active_users = len(set([c.user for c in containers])) - resource.num_images = len(app.db.list_applications()) + resource.num_applications = len(app.db.list_applications()) resource.num_running_containers = len(containers) From 17a45f76fafd618a98dcbb0800e45265a1a959f3 Mon Sep 17 00:00:00 2001 From: Stefano Borini Date: Wed, 26 Apr 2017 23:23:47 +0100 Subject: [PATCH 5/6] typo --- remoteappmanager/webapi/admin/stats.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/remoteappmanager/webapi/admin/stats.py b/remoteappmanager/webapi/admin/stats.py index dfc68d7fd..f9d9c5745 100644 --- a/remoteappmanager/webapi/admin/stats.py +++ b/remoteappmanager/webapi/admin/stats.py @@ -15,7 +15,7 @@ class Stats(SingletonResource): #: Total number of users currently running at least one container num_active_users = Int() #: Total number of available applications. - num_application = Int() + num_applications = Int() #: Total number of running containers. num_running_containers = Int() From cc3dd8da940cb2a1e9e1b6d16f8337630e8d7c7e Mon Sep 17 00:00:00 2001 From: Stefano Borini Date: Wed, 26 Apr 2017 23:33:24 +0100 Subject: [PATCH 6/6] changed test --- remoteappmanager/webapi/admin/tests/test_stats.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/remoteappmanager/webapi/admin/tests/test_stats.py b/remoteappmanager/webapi/admin/tests/test_stats.py index 8bb9a645e..fd0c10799 100644 --- a/remoteappmanager/webapi/admin/tests/test_stats.py +++ b/remoteappmanager/webapi/admin/tests/test_stats.py @@ -20,7 +20,7 @@ def test_get(self): self.assertEqual(code, httpstatus.OK) self.assertEqual(data, { 'num_active_users': 1, - 'num_images': 2, + 'num_applications': 2, 'num_running_containers': 1, 'num_total_users': 1, 'realm': 'remoteexec'})