Refactor userdbs app to use signals
This commit isolates the celery task invocations of the userdbs app into signal handlers. All celery interaction is now asynchronously handled in userdbs.signals.
This commit is contained in:
parent
1649e4592e
commit
c9a9fa11b2
4 changed files with 208 additions and 91 deletions
|
@ -170,7 +170,7 @@ class DatabaseUserAdmin(admin.ModelAdmin):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
actions = super(DatabaseUserAdmin, self).get_actions(request)
|
actions = super(DatabaseUserAdmin, self).get_actions(request)
|
||||||
if 'delete_selected' in actions:
|
if 'delete_selected' in actions: # pragma: no cover
|
||||||
del actions['delete_selected']
|
del actions['delete_selected']
|
||||||
return actions
|
return actions
|
||||||
|
|
||||||
|
@ -250,8 +250,6 @@ class UserDatabaseAdmin(admin.ModelAdmin):
|
||||||
databases
|
databases
|
||||||
|
|
||||||
"""
|
"""
|
||||||
for dbuser in queryset.all():
|
|
||||||
dbuser.delete()
|
|
||||||
for database in queryset.all():
|
for database in queryset.all():
|
||||||
database.delete()
|
database.delete()
|
||||||
perform_delete_selected.short_description = _(
|
perform_delete_selected.short_description = _(
|
||||||
|
@ -270,7 +268,7 @@ class UserDatabaseAdmin(admin.ModelAdmin):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
actions = super(UserDatabaseAdmin, self).get_actions(request)
|
actions = super(UserDatabaseAdmin, self).get_actions(request)
|
||||||
if 'delete_selected' in actions:
|
if 'delete_selected' in actions: # pragma: no cover
|
||||||
del actions['delete_selected']
|
del actions['delete_selected']
|
||||||
return actions
|
return actions
|
||||||
|
|
||||||
|
|
|
@ -16,3 +16,11 @@ class UserdbsAppConfig(AppConfig):
|
||||||
"""
|
"""
|
||||||
name = 'userdbs'
|
name = 'userdbs'
|
||||||
verbose_name = _('Database Users and their Databases')
|
verbose_name = _('Database Users and their Databases')
|
||||||
|
|
||||||
|
def ready(self):
|
||||||
|
"""
|
||||||
|
Takes care of importing the signal handlers of the :py:mod:`userdbs`
|
||||||
|
app.
|
||||||
|
|
||||||
|
"""
|
||||||
|
import userdbs.signals # NOQA
|
||||||
|
|
|
@ -1,33 +1,14 @@
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models, transaction
|
||||||
from django.db import transaction
|
from django.dispatch import Signal
|
||||||
from django.utils.encoding import python_2_unicode_compatible
|
from django.utils.encoding import python_2_unicode_compatible
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
|
|
||||||
from model_utils import Choices
|
from model_utils import Choices
|
||||||
from model_utils.models import TimeStampedModel
|
from model_utils.models import TimeStampedModel
|
||||||
|
|
||||||
from passlib.utils import generate_password
|
|
||||||
|
|
||||||
from osusers.models import User as OsUser
|
from osusers.models import User as OsUser
|
||||||
|
|
||||||
from mysqltasks.tasks import (
|
|
||||||
create_mysql_database,
|
|
||||||
create_mysql_user,
|
|
||||||
delete_mysql_database,
|
|
||||||
delete_mysql_user,
|
|
||||||
set_mysql_userpassword,
|
|
||||||
)
|
|
||||||
from pgsqltasks.tasks import (
|
|
||||||
create_pgsql_database,
|
|
||||||
create_pgsql_user,
|
|
||||||
delete_pgsql_database,
|
|
||||||
delete_pgsql_user,
|
|
||||||
set_pgsql_userpassword,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
DB_TYPES = Choices(
|
DB_TYPES = Choices(
|
||||||
(0, 'pgsql', _('PostgreSQL')),
|
(0, 'pgsql', _('PostgreSQL')),
|
||||||
(1, 'mysql', _('MySQL')),
|
(1, 'mysql', _('MySQL')),
|
||||||
|
@ -37,6 +18,9 @@ Database type choice enumeration.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
password_set = Signal(providing_args=['instance', 'password'])
|
||||||
|
|
||||||
|
|
||||||
class DatabaseUserManager(models.Manager):
|
class DatabaseUserManager(models.Manager):
|
||||||
"""
|
"""
|
||||||
Default Manager for :py:class:`userdbs.models.DatabaseUser`.
|
Default Manager for :py:class:`userdbs.models.DatabaseUser`.
|
||||||
|
@ -93,7 +77,6 @@ class DatabaseUserManager(models.Manager):
|
||||||
db_user = DatabaseUser(
|
db_user = DatabaseUser(
|
||||||
osuser=osuser, db_type=db_type, name=username)
|
osuser=osuser, db_type=db_type, name=username)
|
||||||
if commit:
|
if commit:
|
||||||
db_user.create_in_database(password=password)
|
|
||||||
db_user.save()
|
db_user.save()
|
||||||
return db_user
|
return db_user
|
||||||
|
|
||||||
|
@ -120,34 +103,15 @@ class DatabaseUser(TimeStampedModel, models.Model):
|
||||||
'osuser': self.osuser.username,
|
'osuser': self.osuser.username,
|
||||||
}
|
}
|
||||||
|
|
||||||
def create_in_database(self, password=None):
|
@transaction.atomic
|
||||||
"""
|
|
||||||
Create this user in the target database.
|
|
||||||
|
|
||||||
:param str password: initial password for the database user
|
|
||||||
"""
|
|
||||||
if password is None:
|
|
||||||
password = generate_password()
|
|
||||||
# TODO: send GPG encrypted mail with this information
|
|
||||||
if self.db_type == DB_TYPES.pgsql:
|
|
||||||
create_pgsql_user.delay(self.name, password).get()
|
|
||||||
elif self.db_type == DB_TYPES.mysql:
|
|
||||||
create_mysql_user.delay(self.name, password).get()
|
|
||||||
else:
|
|
||||||
raise ValueError('Unknown database type %d' % self.db_type)
|
|
||||||
|
|
||||||
def set_password(self, password):
|
def set_password(self, password):
|
||||||
"""
|
"""
|
||||||
Set an existing user's password.
|
Set an existing user's password.
|
||||||
|
|
||||||
:param str password: new password for the database user
|
:param str password: new password for the database user
|
||||||
"""
|
"""
|
||||||
if self.db_type == DB_TYPES.pgsql:
|
password_set.send(
|
||||||
set_pgsql_userpassword.delay(self.name, password).get(timeout=5)
|
sender=self.__class__, password=password, instance=self)
|
||||||
elif self.db_type == DB_TYPES.mysql:
|
|
||||||
set_mysql_userpassword.delay(self.name, password).get(timeout=5)
|
|
||||||
else:
|
|
||||||
raise ValueError('Unknown database type %d' % self.db_type)
|
|
||||||
|
|
||||||
@transaction.atomic
|
@transaction.atomic
|
||||||
def delete(self, *args, **kwargs):
|
def delete(self, *args, **kwargs):
|
||||||
|
@ -163,12 +127,6 @@ class DatabaseUser(TimeStampedModel, models.Model):
|
||||||
"""
|
"""
|
||||||
for database in self.userdatabase_set.all():
|
for database in self.userdatabase_set.all():
|
||||||
database.delete()
|
database.delete()
|
||||||
if self.db_type == DB_TYPES.pgsql:
|
|
||||||
delete_pgsql_user.delay(self.name).get(propagate=False, timeout=5)
|
|
||||||
elif self.db_type == DB_TYPES.mysql:
|
|
||||||
delete_mysql_user.delay(self.name).get(propagate=False, timeout=5)
|
|
||||||
else:
|
|
||||||
raise ValueError('Unknown database type %d' % self.db_type)
|
|
||||||
super(DatabaseUser, self).delete(*args, **kwargs)
|
super(DatabaseUser, self).delete(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
@ -236,7 +194,6 @@ class UserDatabaseManager(models.Manager):
|
||||||
db_name = self._get_next_dbname(db_user)
|
db_name = self._get_next_dbname(db_user)
|
||||||
database = UserDatabase(db_user=db_user, db_name=db_name)
|
database = UserDatabase(db_user=db_user, db_name=db_name)
|
||||||
if commit:
|
if commit:
|
||||||
database.create_in_database()
|
|
||||||
database.save()
|
database.save()
|
||||||
return database
|
return database
|
||||||
|
|
||||||
|
@ -260,39 +217,3 @@ class UserDatabase(TimeStampedModel, models.Model):
|
||||||
'db_name': self.db_name,
|
'db_name': self.db_name,
|
||||||
'db_user': self.db_user,
|
'db_user': self.db_user,
|
||||||
}
|
}
|
||||||
|
|
||||||
def create_in_database(self):
|
|
||||||
"""
|
|
||||||
Create this database (schema) in the target database.
|
|
||||||
|
|
||||||
"""
|
|
||||||
# TODO: send GPG encrypted mail with this information
|
|
||||||
if self.db_user.db_type == DB_TYPES.pgsql:
|
|
||||||
create_pgsql_database.delay(self.db_name, self.db_user.name).get()
|
|
||||||
elif self.db_user.db_type == DB_TYPES.mysql:
|
|
||||||
create_mysql_database.delay(self.db_name, self.db_user.name).get()
|
|
||||||
else:
|
|
||||||
raise ValueError('Unknown database type %d' % self.db_type)
|
|
||||||
|
|
||||||
@transaction.atomic
|
|
||||||
def delete(self, *args, **kwargs):
|
|
||||||
"""
|
|
||||||
Delete the database (schema) from the target database and the Django
|
|
||||||
database.
|
|
||||||
|
|
||||||
:param args: positional arguments for
|
|
||||||
:py:meth:`django.db.models.Model.delete`
|
|
||||||
:param kwargs: keyword arguments for
|
|
||||||
:py:meth:`django.db.models.Model.delete`
|
|
||||||
|
|
||||||
"""
|
|
||||||
db_user = self.db_user
|
|
||||||
if db_user.db_type == DB_TYPES.pgsql:
|
|
||||||
delete_pgsql_database.delay(self.db_name).get()
|
|
||||||
elif db_user.db_type == DB_TYPES.mysql:
|
|
||||||
delete_mysql_database.delay(self.db_name, db_user.name).get()
|
|
||||||
else:
|
|
||||||
raise ValueError('Unknown database type %d' % self.db_type)
|
|
||||||
super(UserDatabase, self).delete(*args, **kwargs)
|
|
||||||
if not db_user.userdatabase_set.exists():
|
|
||||||
db_user.delete()
|
|
||||||
|
|
190
gnuviechadmin/userdbs/signals.py
Normal file
190
gnuviechadmin/userdbs/signals.py
Normal file
|
@ -0,0 +1,190 @@
|
||||||
|
"""
|
||||||
|
This module contains the signal handlers of the :py:mod:`userdbs` app.
|
||||||
|
|
||||||
|
"""
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from django.db.models.signals import post_delete, post_save
|
||||||
|
from django.dispatch import receiver
|
||||||
|
from passlib.utils import generate_password
|
||||||
|
|
||||||
|
from mysqltasks.tasks import (create_mysql_database, create_mysql_user,
|
||||||
|
delete_mysql_database, delete_mysql_user,
|
||||||
|
set_mysql_userpassword)
|
||||||
|
from pgsqltasks.tasks import (create_pgsql_database, create_pgsql_user,
|
||||||
|
delete_pgsql_database, delete_pgsql_user,
|
||||||
|
set_pgsql_userpassword)
|
||||||
|
from taskresults.models import TaskResult
|
||||||
|
|
||||||
|
from .models import DB_TYPES, DatabaseUser, UserDatabase, password_set
|
||||||
|
|
||||||
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
@receiver(password_set, sender=DatabaseUser)
|
||||||
|
def handle_dbuser_password_set(sender, instance, password, **kwargs):
|
||||||
|
"""
|
||||||
|
Signal handler triggered by password changes for
|
||||||
|
:py:class:`userdbs.models.DatabaseUser` instances.
|
||||||
|
|
||||||
|
"""
|
||||||
|
if instance.db_type == DB_TYPES.mysql:
|
||||||
|
taskresult = TaskResult.objects.create_task_result(
|
||||||
|
'handle_dbuser_password_set',
|
||||||
|
set_mysql_userpassword.s(instance.name, password),
|
||||||
|
'mysql password change')
|
||||||
|
_LOGGER.info(
|
||||||
|
'MySQL password change has been requested in task %s',
|
||||||
|
taskresult.task_id)
|
||||||
|
elif instance.db_type == DB_TYPES.pgsql:
|
||||||
|
taskresult = TaskResult.objects.create_task_result(
|
||||||
|
'handle_dbuser_password_set',
|
||||||
|
set_pgsql_userpassword.s(instance.name, password),
|
||||||
|
'pgsql password change')
|
||||||
|
_LOGGER.info(
|
||||||
|
'PostgreSQL password change has been requested in task %s',
|
||||||
|
taskresult.task_id)
|
||||||
|
else:
|
||||||
|
_LOGGER.warning(
|
||||||
|
'Password change has been requested for unknown database %s'
|
||||||
|
' the request has been ignored.',
|
||||||
|
instance.db_type)
|
||||||
|
|
||||||
|
|
||||||
|
@receiver(post_save, sender=DatabaseUser)
|
||||||
|
def handle_dbuser_created(sender, instance, created, **kwargs):
|
||||||
|
"""
|
||||||
|
Signal handler triggered after the creation of or updates to
|
||||||
|
:py:class:`userdbs.models.DatabaseUser` instances.
|
||||||
|
|
||||||
|
"""
|
||||||
|
if created:
|
||||||
|
password = kwargs.get('password', generate_password())
|
||||||
|
# TODO: send GPG encrypted mail with this information
|
||||||
|
if instance.db_type == DB_TYPES.mysql:
|
||||||
|
taskresult = TaskResult.objects.create_task_result(
|
||||||
|
'handle_dbuser_created',
|
||||||
|
create_mysql_user.s(instance.name, password),
|
||||||
|
'mysql user creation')
|
||||||
|
_LOGGER.info(
|
||||||
|
'A new MySQL user %s creation has been requested in task %s',
|
||||||
|
instance.name, taskresult.task_id)
|
||||||
|
elif instance.db_type == DB_TYPES.pgsql:
|
||||||
|
taskresult = TaskResult.objects.create_task_result(
|
||||||
|
'handle_dbuser_created',
|
||||||
|
create_pgsql_user.s(instance.name, password),
|
||||||
|
'pgsql user creation')
|
||||||
|
_LOGGER.info(
|
||||||
|
'A new PostgreSQL user %s creation has been requested in task'
|
||||||
|
' %s',
|
||||||
|
instance.name, taskresult.task_id)
|
||||||
|
else:
|
||||||
|
_LOGGER.warning(
|
||||||
|
'created DatabaseUser for unknown database type %s',
|
||||||
|
instance.db_type)
|
||||||
|
_LOGGER.debug(
|
||||||
|
'database user %s has been %s',
|
||||||
|
instance, created and "created" or "updated")
|
||||||
|
|
||||||
|
|
||||||
|
@receiver(post_delete, sender=DatabaseUser)
|
||||||
|
def handle_dbuser_deleted(sender, instance, **kwargs):
|
||||||
|
"""
|
||||||
|
Signal handler triggered after the deletion of
|
||||||
|
:py:class:`userdbs.models.DatabaseUser` instances.
|
||||||
|
|
||||||
|
"""
|
||||||
|
if instance.db_type == DB_TYPES.mysql:
|
||||||
|
taskresult = TaskResult.objects.create_task_result(
|
||||||
|
'handle_dbuser_deleted',
|
||||||
|
delete_mysql_user.s(instance.name),
|
||||||
|
'mysql user deletion')
|
||||||
|
_LOGGER.info(
|
||||||
|
'MySQL user %s deletion has been requested in task %s',
|
||||||
|
instance.name, taskresult.task_id)
|
||||||
|
elif instance.db_type == DB_TYPES.pgsql:
|
||||||
|
taskresult = TaskResult.objects.create_task_result(
|
||||||
|
'handle_dbuser_deleted',
|
||||||
|
delete_pgsql_user.s(instance.name),
|
||||||
|
'pgsql user deletion')
|
||||||
|
_LOGGER.info(
|
||||||
|
'PostgreSQL user %s deletion has been requested in task %s',
|
||||||
|
instance.name, taskresult.task_id)
|
||||||
|
else:
|
||||||
|
_LOGGER.warning(
|
||||||
|
'deleted DatabaseUser %s for unknown database type %s',
|
||||||
|
instance.name, instance.db_type)
|
||||||
|
_LOGGER.debug(
|
||||||
|
'database user %s has been deleted', instance)
|
||||||
|
|
||||||
|
|
||||||
|
@receiver(post_save, sender=UserDatabase)
|
||||||
|
def handle_userdb_created(sender, instance, created, **kwargs):
|
||||||
|
"""
|
||||||
|
Signal handler triggered after the creation of or updates to
|
||||||
|
:py:class:`userdbs.models.UserDatabase` instances.
|
||||||
|
|
||||||
|
"""
|
||||||
|
if created:
|
||||||
|
if instance.db_user.db_type == DB_TYPES.mysql:
|
||||||
|
taskresult = TaskResult.objects.create_task_result(
|
||||||
|
'handle_userdb_created',
|
||||||
|
create_mysql_database.s(
|
||||||
|
instance.db_name, instance.db_user.name),
|
||||||
|
'mysql database creation')
|
||||||
|
_LOGGER.info(
|
||||||
|
'The creation of a new MySQL database %s has been requested in'
|
||||||
|
' task %s',
|
||||||
|
instance.db_name, taskresult.task_id)
|
||||||
|
elif instance.db_user.db_type == DB_TYPES.pgsql:
|
||||||
|
taskresult = TaskResult.objects.create_task_result(
|
||||||
|
'handle_userdb_created',
|
||||||
|
create_pgsql_database.s(
|
||||||
|
instance.db_name, instance.db_user.name),
|
||||||
|
'pgsql database creation')
|
||||||
|
_LOGGER.info(
|
||||||
|
'The creation of a new PostgreSQL database %s has been'
|
||||||
|
' requested in task %s',
|
||||||
|
instance.db_name, taskresult.task_id)
|
||||||
|
else:
|
||||||
|
_LOGGER.warning(
|
||||||
|
'created UserDatabase for unknown database type %s',
|
||||||
|
instance.db_user.db_type)
|
||||||
|
_LOGGER.debug(
|
||||||
|
'database %s has been %s',
|
||||||
|
instance, created and "created" or "updated")
|
||||||
|
|
||||||
|
|
||||||
|
@receiver(post_delete, sender=UserDatabase)
|
||||||
|
def handle_userdb_deleted(sender, instance, **kwargs):
|
||||||
|
"""
|
||||||
|
Signal handler triggered after the deletion of
|
||||||
|
:py:class:`userdbs.models.UserDatabase` instances.
|
||||||
|
|
||||||
|
"""
|
||||||
|
if instance.db_user.db_type == DB_TYPES.mysql:
|
||||||
|
taskresult = TaskResult.objects.create_task_result(
|
||||||
|
'handle_userdb_deleted',
|
||||||
|
delete_mysql_database.s(instance.db_name, instance.db_user.name),
|
||||||
|
'mysql database deletion')
|
||||||
|
_LOGGER.info(
|
||||||
|
'The deletion of MySQL database %s has been requested in task %s',
|
||||||
|
instance.db_name, taskresult.task_id)
|
||||||
|
elif instance.db_user.db_type == DB_TYPES.pgsql:
|
||||||
|
taskresult = TaskResult.objects.create_task_result(
|
||||||
|
'handle_userdb_deleted',
|
||||||
|
delete_pgsql_database.s(instance.db_name),
|
||||||
|
'pgsql database deletion')
|
||||||
|
_LOGGER.info(
|
||||||
|
'The deletion of PostgreSQL database %s has been requested in '
|
||||||
|
' task %s',
|
||||||
|
instance.db_name, taskresult.task_id)
|
||||||
|
else:
|
||||||
|
_LOGGER.warning(
|
||||||
|
'deleted UserDatabase %s of unknown type %s',
|
||||||
|
instance.db_name, instance.db_type)
|
||||||
|
pass
|
||||||
|
_LOGGER.debug(
|
||||||
|
'database %s has been deleted', instance)
|
Loading…
Reference in a new issue