From 525d38750ea6a122d92ce7526f3cb01d45dd03dd Mon Sep 17 00:00:00 2001 From: Marc Aymerich Date: Sun, 12 Apr 2015 18:18:10 +0000 Subject: [PATCH] Only reload apache only when strictly necessary --- TODO.md | 12 +++++- orchestra/contrib/orchestration/manager.py | 39 ++++++++++--------- orchestra/contrib/resources/actions.py | 6 +-- orchestra/contrib/resources/backends.py | 2 +- orchestra/contrib/resources/tasks.py | 7 ++-- orchestra/contrib/webapps/backends/php.py | 17 ++++---- orchestra/contrib/webapps/options.py | 2 +- orchestra/templates/admin/orchestra/menu.html | 2 +- 8 files changed, 48 insertions(+), 39 deletions(-) diff --git a/TODO.md b/TODO.md index 0833b8f1..0815b9bd 100644 --- a/TODO.md +++ b/TODO.md @@ -286,6 +286,14 @@ https://code.djangoproject.com/ticket/24576 # Change crons, create cron for deleted webapps and users * UNIFY PHP FPM settings name # virtualhost name name-account? -# php version update should trigger webiste upgrade (wrapper name/fpm config for apache), public root and other config also needs apache to execute * add a delay to changes on the webserver apache to no overwelm it with backend executions? -# Delete webapps deletes wrapper that may be used for other sites, maybe merging webapps is a bad idea after all? +* replace unique_name by natural_key? +* do not require contact or create default +* send signals for backend triggers +* monitor resources with multiple backends not possible to identify the correct last execution, allow to specify backends only once or change backend.model = 'resources.MonitorData' +* force ignore slack billing period overridig when billing +* fpm reload starts new pools? +* more processes for webmail, or use fpm pool +* rename resource.monitors to resource.backends ? + +* abstract model classes enabling overriding? diff --git a/orchestra/contrib/orchestration/manager.py b/orchestra/contrib/orchestration/manager.py index 18c737f6..991e823b 100644 --- a/orchestra/contrib/orchestration/manager.py +++ b/orchestra/contrib/orchestration/manager.py @@ -142,27 +142,28 @@ def collect(instance, action, **kwargs): operations = kwargs.get('operations', set()) route_cache = kwargs.get('route_cache', {}) for backend_cls in ServiceBackend.get_backends(): - # Check if there exists a related instance to be executed for this backend + # Check if there exists a related instance to be executed for this backend and action instances = [] - if backend_cls.is_main(instance): - instances = [(instance, action)] - else: - candidate = backend_cls.get_related(instance) - if candidate: - if candidate.__class__.__name__ == 'ManyRelatedManager': - if 'pk_set' in kwargs: - # m2m_changed signal - candidates = kwargs['model'].objects.filter(pk__in=kwargs['pk_set']) + if action in backend_cls.actions: + if backend_cls.is_main(instance): + instances = [(instance, action)] + else: + candidate = backend_cls.get_related(instance) + if candidate: + if candidate.__class__.__name__ == 'ManyRelatedManager': + if 'pk_set' in kwargs: + # m2m_changed signal + candidates = kwargs['model'].objects.filter(pk__in=kwargs['pk_set']) + else: + candidates = candidate.all() else: - candidates = candidate.all() - else: - candidates = [candidate] - for candidate in candidates: - # Check if a delete for candidate is in operations - delete_mock = Operation(backend_cls, candidate, Operation.DELETE) - if delete_mock not in operations: - # related objects with backend.model trigger save() - instances.append((candidate, Operation.SAVE)) + candidates = [candidate] + for candidate in candidates: + # Check if a delete for candidate is in operations + delete_mock = Operation(backend_cls, candidate, Operation.DELETE) + if delete_mock not in operations: + # related objects with backend.model trigger save() + instances.append((candidate, Operation.SAVE)) for selected, iaction in instances: # Maintain consistent state of operations based on save/delete behaviour # Prevent creating a deleted selected by deleting existing saves diff --git a/orchestra/contrib/resources/actions.py b/orchestra/contrib/resources/actions.py index 829da240..e7117340 100644 --- a/orchestra/contrib/resources/actions.py +++ b/orchestra/contrib/resources/actions.py @@ -10,11 +10,9 @@ def run_monitor(modeladmin, request, queryset): async = modeladmin.model.monitor.__defaults__[0] logs = set() for resource in queryset: - results = resource.monitor() + rlogs = resource.monitor() if not async: - for result in results: - if hasattr(result, 'log'): - logs.add(str(result.log.pk)) + logs = logs.union(set([str(rlog.pk) for rlog in rlogs])) modeladmin.log_change(request, resource, _("Run monitors")) if async: num = len(queryset) diff --git a/orchestra/contrib/resources/backends.py b/orchestra/contrib/resources/backends.py index 6da2c768..db8c4325 100644 --- a/orchestra/contrib/resources/backends.py +++ b/orchestra/contrib/resources/backends.py @@ -42,7 +42,7 @@ class ServiceMonitor(ServiceBackend): from .models import MonitorData try: return MonitorData.objects.filter(content_type=self.content_type, - object_id=object_id).latest() + monitor=type(self).get_name(), object_id=object_id).latest() except MonitorData.DoesNotExist: return None diff --git a/orchestra/contrib/resources/tasks.py b/orchestra/contrib/resources/tasks.py index bb1cde0c..431f49bc 100644 --- a/orchestra/contrib/resources/tasks.py +++ b/orchestra/contrib/resources/tasks.py @@ -12,7 +12,7 @@ def monitor(resource_id, ids=None, async=True): resource = Resource.objects.get(pk=resource_id) resource_model = resource.content_type.model_class() - operations = [] + logs = [] # Execute monitors for monitor_name in resource.monitors: backend = ServiceMonitor.get_backend(monitor_name) @@ -28,10 +28,9 @@ def monitor(resource_id, ids=None, async=True): monitorings = [] for obj in model.objects.filter(**kwargs): op = Operation(backend, obj, Operation.MONITOR) - operations.append(op) monitorings.append(op) # TODO async=True only when running with celery - Operation.execute(monitorings, async=async) + logs += Operation.execute(monitorings, async=async) kwargs = {'id__in': ids} if ids else {} # Update used resources and trigger resource exceeded and revovery @@ -50,4 +49,4 @@ def monitor(resource_id, ids=None, async=True): op = Operation(backend, obj, Operation.RECOVERY) triggers.append(op) Operation.execute(triggers) - return operations + return logs diff --git a/orchestra/contrib/webapps/backends/php.py b/orchestra/contrib/webapps/backends/php.py index 3898b2fe..9b0c5234 100644 --- a/orchestra/contrib/webapps/backends/php.py +++ b/orchestra/contrib/webapps/backends/php.py @@ -33,7 +33,7 @@ class PHPBackend(WebAppServiceMixin, ServiceController): echo -e "${fpm_config}" | diff -N -I'^\s*;;' %(fpm_path)s - } || { echo -e "${fpm_config}" > %(fpm_path)s - UPDATEDFPM=1 + UPDATED_FPM=1 } """) % context ) @@ -46,7 +46,10 @@ class PHPBackend(WebAppServiceMixin, ServiceController): echo -e "${wrapper}" | diff -N -I'^\s*#' %(wrapper_path)s - } || { echo -e "${wrapper}" > %(wrapper_path)s - [[ ${UPDATED_APACHE} -eq 0 ]] && UPDATED_APACHE=%(is_mounted)i + if [[ %(is_mounted)i -eq 1 ]]; then + # Reload fcgid wrapper + pkill -SIGHUP -U %(user)s "^%(php_binary)s$" || true + fi } """) % context ) @@ -93,15 +96,14 @@ class PHPBackend(WebAppServiceMixin, ServiceController): def commit(self): self.append(textwrap.dedent(""" - if [[ $UPDATEDFPM == 1 ]]; then + if [[ $UPDATED_FPM -eq 1 ]]; then service php5-fpm reload - service php5-fpm start fi # Coordinate apache restart with apache backend locked=1 state="$(grep -v 'PHPBackend' /dev/shm/restart.apache2)" || locked=0 echo -n "$state" > /dev/shm/restart.apache2 - if [[ $UPDATED_APACHE == 1 ]]; then + if [[ $UPDATED_APACHE -eq 1 ]]; then if [[ $locked == 0 ]]; then service apache2 reload else @@ -151,18 +153,19 @@ class PHPBackend(WebAppServiceMixin, ServiceController): init_vars = [ "-d %s='%s'" % (k, v.replace("'", '"')) for k,v in init_vars.items() ] init_vars = ' \\\n '.join(init_vars) context.update({ - 'php_binary': os.path.normpath(settings.WEBAPPS_PHP_CGI_BINARY_PATH % context), + 'php_binary_path': os.path.normpath(settings.WEBAPPS_PHP_CGI_BINARY_PATH % context), 'php_rc': os.path.normpath(settings.WEBAPPS_PHP_CGI_RC_DIR % context), 'php_ini_scan': os.path.normpath(settings.WEBAPPS_PHP_CGI_INI_SCAN_DIR % context), 'php_init_vars': init_vars, }) + context['php_binary'] = os.path.basename(context['php_binary_path']) return textwrap.dedent("""\ #!/bin/sh # %(banner)s export PHPRC=%(php_rc)s export PHP_INI_SCAN_DIR=%(php_ini_scan)s export PHP_FCGI_MAX_REQUESTS=%(max_requests)s - exec %(php_binary)s %(php_init_vars)s""") % context + exec %(php_binary_path)s %(php_init_vars)s""") % context def get_fcgid_cmd_options(self, webapp, context): maps = { diff --git a/orchestra/contrib/webapps/options.py b/orchestra/contrib/webapps/options.py index d90cf0bf..a6f52b1f 100644 --- a/orchestra/contrib/webapps/options.py +++ b/orchestra/contrib/webapps/options.py @@ -88,7 +88,7 @@ class Processes(AppOption): # FPM pm.max_children verbose_name = _("Number of processes") help_text = _("Maximum number of children that can be alive at the same time (a number between 0 and 9).") - regex = r'^[0-9]$' + regex = r'^[0-9]{1,2}$' group = AppOption.PROCESS diff --git a/orchestra/templates/admin/orchestra/menu.html b/orchestra/templates/admin/orchestra/menu.html index bb8d91bf..e1e63f52 100644 --- a/orchestra/templates/admin/orchestra/menu.html +++ b/orchestra/templates/admin/orchestra/menu.html @@ -49,7 +49,7 @@

Pangea Hosting Management 0.0.1a1

{% for item in menu.children %}{% admin_tools_render_menu_item item forloop.counter %}{% endfor %} {% trans 'Welcome' %}, - {% url 'admin:users_user_change' user.pk as user_change_url %} + {% url 'admin:accounts_account_change' user.pk as user_change_url %} {% filter force_escape %}{% firstof user.get_short_name user.username %}{% endfilter %}. Change password / Log out