summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJean-Baptiste Jaillet <jbjaillet@entrouvert.com>2017-03-20 18:10:41 (GMT)
committerJean-Baptiste Jaillet <jbjaillet@entrouvert.com>2017-03-31 10:34:41 (GMT)
commit1e1ee079bd78fec76c26caf26b94e9ea632b5470 (patch)
tree267c26bd73436f154d6c74e37655ae6bbb68e666
parent5c37a4a6bc8567230f94e4f873c983844fa3a943 (diff)
downloadhobo-1e1ee079bd78fec76c26caf26b94e9ea632b5470.zip
hobo-1e1ee079bd78fec76c26caf26b94e9ea632b5470.tar.gz
hobo-1e1ee079bd78fec76c26caf26b94e9ea632b5470.tar.bz2
multitenant: add delete_tenant command (#15513)
-rw-r--r--hobo/multitenant/management/commands/delete_tenant.py29
-rw-r--r--hobo/multitenant/models.py14
-rw-r--r--tests_multitenant/conftest.py3
-rw-r--r--tests_multitenant/test_tenant_command.py24
4 files changed, 67 insertions, 3 deletions
diff --git a/hobo/multitenant/management/commands/delete_tenant.py b/hobo/multitenant/management/commands/delete_tenant.py
new file mode 100644
index 0000000..4d3096d
--- /dev/null
+++ b/hobo/multitenant/management/commands/delete_tenant.py
@@ -0,0 +1,29 @@
+import sys
+from optparse import make_option
+
+from django.core.management.base import CommandError, BaseCommand
+from hobo.multitenant.middleware import TenantMiddleware
+
+
+class Command(BaseCommand):
+ help = "Delete tenant(s) by hostname(s)"
+ args = ['...']
+ option_list = BaseCommand.option_list + (
+ make_option('--force-drop', action='store_true', default=False,
+ help='If you want the schema to be deleted from database'),
+ )
+
+ def handle(self, *args, **options):
+
+ if not args:
+ raise CommandError("you must give at least one tenant hostname")
+
+ # if - is given on the command line, get list of hostnames from stdin
+ if '-' in args:
+ args = list(args)
+ args.remove('-')
+ args.extend([x.strip() for x in sys.stdin.readlines()])
+ for hostname in args:
+ tenant = TenantMiddleware.get_tenant_by_hostname(hostname)
+ tenant.delete(force_drop=options['force_drop'])
+
diff --git a/hobo/multitenant/models.py b/hobo/multitenant/models.py
index 2fa97c8..34d0994 100644
--- a/hobo/multitenant/models.py
+++ b/hobo/multitenant/models.py
@@ -1,9 +1,11 @@
import os
from urlparse import urljoin
import json
+from shutil import rmtree
from django.conf import settings
from django.db import connection
+from django.utils import timezone
from tenant_schemas.utils import get_public_schema_name
from tenant_schemas.models import TenantMixin
@@ -64,9 +66,17 @@ class Tenant(TenantMixin):
raise Exception("Can't delete tenant outside it's own schema or "
"the public schema. Current schema is %s."
% connection.schema_name)
-
- os.rename(self.get_directory(), self.get_directory() + '.invalid')
+ if force_drop:
+ rmtree(self.get_directory())
+ else:
+ deletion_date = timezone.now().strftime('%Y%m%d_%H%M%S_%f')
+ os.rename(self.get_directory(), self.get_directory() + '.removed_%s.invalid' % deletion_date)
if schema_exists(self.schema_name) and (self.auto_drop_schema or force_drop):
cursor = connection.cursor()
cursor.execute('DROP SCHEMA %s CASCADE' % self.schema_name)
+
+ if schema_exists(self.schema_name) and (not self.auto_drop_schema and not force_drop):
+ cursor = connection.cursor()
+ schema_new_name = 'removed_%s_%s' % (deletion_date, self.schema_name)
+ cursor.execute('ALTER SCHEMA %s RENAME TO %s' % (self.schema_name, schema_new_name[:63]))
diff --git a/tests_multitenant/conftest.py b/tests_multitenant/conftest.py
index ca70a4c..77b326f 100644
--- a/tests_multitenant/conftest.py
+++ b/tests_multitenant/conftest.py
@@ -54,8 +54,9 @@ def tenants(transactional_db, request, settings):
tenants = [make_tenant('tenant1.example.net'), make_tenant('tenant2.example.net')]
def fin():
from django.db import connection
+ from hobo.multitenant.middleware import TenantMiddleware
connection.set_schema_to_public()
- for t in tenants:
+ for t in TenantMiddleware.get_tenants():
t.delete(True)
shutil.rmtree(base)
request.addfinalizer(fin)
diff --git a/tests_multitenant/test_tenant_command.py b/tests_multitenant/test_tenant_command.py
index 8bac572..bd7b473 100644
--- a/tests_multitenant/test_tenant_command.py
+++ b/tests_multitenant/test_tenant_command.py
@@ -1,5 +1,6 @@
import pytest
import mock
+import os
pytestmark = pytest.mark.django_db
@@ -29,3 +30,26 @@ def test_one_tenant(handle, tenants, tenant_in_call=None):
assert handle.call_count == 1
assert len(handle.side_effect.tenants) == 1
assert handle.side_effect.tenants[0].domain_url == 'tenant2.example.net'
+
+def test_delete_tenant(tenants):
+ from django.core.management import execute_from_command_line
+ from hobo.multitenant.middleware import TenantMiddleware
+ base = os.path.dirname(tenants[0].get_directory())
+ if any('removed' in d for d in os.listdir(base)):
+ assert False
+ def get_schemas():
+ from django.db import connection
+ cursor = connection.cursor()
+ cursor.execute('select schema_name from information_schema.schemata')
+ return [x[0] for x in cursor.fetchall()]
+ if any('removed' in x for x in get_schemas()):
+ assert False
+ all_tenants = list(TenantMiddleware.get_tenants())
+ assert len(all_tenants) == 2
+ execute_from_command_line(['manage.py', 'delete_tenant', 'tenant2.example.net'])
+ if not any('removed' in d for d in os.listdir(base)):
+ assert False
+ if not any('removed' in x for x in get_schemas()):
+ assert False
+ all_tenants = list(TenantMiddleware.get_tenants())
+ assert len(all_tenants) == 1