From ad251d5e42d1da42d3beadb09dfca6a5fba43c67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20P=C3=A9ters?= Date: Thu, 15 Nov 2018 11:44:52 +0100 Subject: [PATCH] multitenant: don't abort --all-tenants on first failing tenant (#28039) --- .../management/commands/tenant_command.py | 47 +++++++++++++++++-- 1 file changed, 44 insertions(+), 3 deletions(-) diff --git a/hobo/multitenant/management/commands/tenant_command.py b/hobo/multitenant/management/commands/tenant_command.py index 8f0ff33..3a58e7d 100644 --- a/hobo/multitenant/management/commands/tenant_command.py +++ b/hobo/multitenant/management/commands/tenant_command.py @@ -6,15 +6,50 @@ # Home-page: http://github.com/bcarneiro/django-tenant-schemas import argparse +import sys from django.conf import settings -from django.core.management.base import BaseCommand, CommandError +from django.core.exceptions import ImproperlyConfigured +from django.core.management.base import (BaseCommand, CommandError, + SystemCheckError, handle_default_options) from django.core.management import call_command, get_commands, load_command_class -from django.db import connection +from django.db import connection, connections from hobo.multitenant.management.commands import InteractiveTenantOption from hobo.multitenant.middleware import TenantMiddleware +def run_command_from_argv(command, argv): + # copied/adapted from Django run_from_argv + command._called_from_command_line = True + parser = command.create_parser(argv[0], argv[1]) + + options = parser.parse_args(argv[2:]) + cmd_options = vars(options) + # Move positional args out of options to mimic legacy optparse + args = cmd_options.pop('args', ()) + handle_default_options(options) + try: + command.execute(*args, **cmd_options) + except Exception as e: + if options.traceback: + raise + + # SystemCheckError takes care of its own formatting. + if isinstance(e, SystemCheckError): + command.stderr.write(str(e), lambda x: x) + else: + command.stderr.write('%s: %s: %s' % ( + connection.get_tenant(), e.__class__.__name__, e)) + return e + finally: + try: + connections.close_all() + except ImproperlyConfigured: + # Ignore if connections aren't setup at this point (e.g. no + # configured settings). + pass + + class Command(InteractiveTenantOption, BaseCommand): help = "Wrapper around django commands for use with an individual tenant" args = '' @@ -64,11 +99,17 @@ class Command(InteractiveTenantOption, BaseCommand): return if args_namespace.all_tenants: + errors = [] for tenant in TenantMiddleware.get_tenants(): if args_verbosity.verbosity > 1: print(u'* Running command on tenant %s' % tenant.domain_url) connection.set_tenant(tenant) - klass.run_from_argv(args) + error = run_command_from_argv(klass, args) + if error: + errors.append(error) + if errors: + self.stderr.write('Command failed on multiple tenants') + sys.exit(1) else: tenant = self.get_tenant_from_options_or_interactive(domain=args_namespace.domain_name) connection.set_tenant(tenant) -- 2.19.1