From e30a211d2dea8bb48b8f6bc83460980b3d85a8f9 Mon Sep 17 00:00:00 2001 From: Alexander Tiunov Date: Fri, 2 Dec 2016 22:38:36 +0300 Subject: [PATCH 1/2] limit for running users --- everware/spawner.py | 22 +++++++++++++++++++--- everware/user_spawn_handler.py | 12 ++++++++++++ 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/everware/spawner.py b/everware/spawner.py index 12bb877..63e6f43 100755 --- a/everware/spawner.py +++ b/everware/spawner.py @@ -18,6 +18,7 @@ import ssl import json import os +import sys from .image_handler import ImageHandler from .git_processor import GitMixin @@ -29,6 +30,10 @@ class CustomDockerSpawner(DockerSpawner, GitMixin, EmailNotificator): + max_users_running = Integer( + config=True + ) + def __init__(self, **kwargs): self._user_log = [] self._is_failed = False @@ -144,7 +149,7 @@ def options_from_form(self, formdata): def form_repo_url(self): """Repository URL as submitted by the user.""" return self.user_options.get('repo_url', '') - + @property def container_name(self): return "{}-{}".format(self.container_prefix, @@ -283,6 +288,12 @@ def remove_old_container(self): except APIError as e: self.log.info("Can't erase container %s due to %s" % (self.container_name, e)) + def are_too_many_users(self): + if not hasattr(self, 'max_users_running'): + return False + running_users = self.user_options.get('running_users', -1) + self.log.info('{} running_users'.format(running_users)) + return running_users >= self.max_users_running @gen.coroutine def start(self, image=None): @@ -292,6 +303,8 @@ def start(self, image=None): self._is_building = True self._is_empty = False try: + if self.are_too_many_users(): + raise Exception('Sorry, there are too many users') f = self.build_image() image_name = yield gen.with_timeout( timedelta(seconds=self.start_timeout), @@ -327,7 +340,10 @@ def start(self, image=None): message = "Container doesn't have jupyter-singleuser inside" elif 'Cannot locate specified Dockerfile' in message: message = "Your repo doesn't include Dockerfile" - self._add_to_log('Something went wrong during building. Error: %s' % message) + if message.startswith('Sorry'): + self._add_to_log(message) + else: + self._add_to_log('Something went wrong during building. Error: %s' % message) yield self.notify_about_fail(message) raise e finally: @@ -379,7 +395,7 @@ def stop(self, now=False): "Removing container %s (id: %s)", self.container_name, self.container_id[:7]) # remove the container, as well as any associated volumes - yield self.docker('remove_container', self.container_id, v=True) + yield self.docker('remove_container', self.container_id, v=True, force=True) self.clear_state() diff --git a/everware/user_spawn_handler.py b/everware/user_spawn_handler.py index 0e84d0a..9c5c127 100755 --- a/everware/user_spawn_handler.py +++ b/everware/user_spawn_handler.py @@ -6,6 +6,14 @@ class SpawnHandler(default_handlers.SpawnHandler): + @gen.coroutine + def count_running_users(self): + running_users = 0 + for user_id, user in self.users.items(): + if user.running: + running_users += 1 + return running_users + def _render_form(self, message=''): user = self.get_current_user() metrica = MetricaIdsMixin() @@ -22,9 +30,13 @@ def _render_form(self, message=''): @gen.coroutine def _spawn(self, user, form_options): + running_users = yield self.count_running_users() self.redirect('/user/%s' % user.name) try: options = user.spawner.options_from_form(form_options) + options.update({ + 'running_users': running_users + }) yield self.spawn_single_user(user, options=options) # if user set another access token (for example he logged with github # and clones from bitbucket) From 37599d363f330620742a78d5c417901c4904c055 Mon Sep 17 00:00:00 2001 From: Alexander Tiunov Date: Fri, 2 Dec 2016 22:52:09 +0300 Subject: [PATCH 2/2] added param to config --- etc/base_config.py | 1 + 1 file changed, 1 insertion(+) diff --git a/etc/base_config.py b/etc/base_config.py index 3c418bf..b4a7a32 100644 --- a/etc/base_config.py +++ b/etc/base_config.py @@ -10,6 +10,7 @@ c.Spawner.debug = True c.Spawner.start_timeout = 1000 c.Spawner.http_timeout = 60 +c.Spawner.max_users_running = 60 c.Spawner.remove_containers = True c.Spawner.tls_assert_hostname = False c.Spawner.use_docker_client_env = True