Clone database connection on manager.execute
This commit is contained in:
parent
c5140ccbae
commit
6fa29a15b8
2
TODO.md
2
TODO.md
|
@ -355,3 +355,5 @@ make django admin taskstate uncollapse fucking traceback, ( if exists ?)
|
||||||
# backend.context and backned.instance provided when an action is called? like forms.cleaned_data: do it on manager.generation(backend.context = backend.get_context()) or in backend.__getattr__ ? also backend.head,tail,content switching on manager.generate()?
|
# backend.context and backned.instance provided when an action is called? like forms.cleaned_data: do it on manager.generation(backend.context = backend.get_context()) or in backend.__getattr__ ? also backend.head,tail,content switching on manager.generate()?
|
||||||
|
|
||||||
# replace return_code by exit_code everywhere
|
# replace return_code by exit_code everywhere
|
||||||
|
|
||||||
|
# plan.rate registry
|
||||||
|
|
|
@ -167,7 +167,11 @@ class ServiceBackend(plugins.Plugin, metaclass=ServiceMount):
|
||||||
run = bool(self.scripts) or (self.force_empty_action_execution or bool(self.content))
|
run = bool(self.scripts) or (self.force_empty_action_execution or bool(self.content))
|
||||||
if not run:
|
if not run:
|
||||||
state = BackendLog.NOTHING
|
state = BackendLog.NOTHING
|
||||||
log = BackendLog.objects.create(backend=self.get_name(), state=state, server=server)
|
using = kwargs.pop('using', None)
|
||||||
|
manager = BackendLog.objects
|
||||||
|
if using:
|
||||||
|
manager = manager.using(using)
|
||||||
|
log = manager.create(backend=self.get_name(), state=state, server=server)
|
||||||
return log
|
return log
|
||||||
|
|
||||||
def execute(self, server, async=False, log=None):
|
def execute(self, server, async=False, log=None):
|
||||||
|
|
|
@ -6,7 +6,7 @@ from functools import partial
|
||||||
|
|
||||||
from django.core.mail import mail_admins
|
from django.core.mail import mail_admins
|
||||||
|
|
||||||
from orchestra.utils.db import close_connection
|
from orchestra.utils import db
|
||||||
from orchestra.utils.python import import_class, OrderedSet
|
from orchestra.utils.python import import_class, OrderedSet
|
||||||
|
|
||||||
from . import settings, Operation
|
from . import settings, Operation
|
||||||
|
@ -31,7 +31,7 @@ def keep_log(execute, log, operations):
|
||||||
send_report(execute, args, log)
|
send_report(execute, args, log)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
trace = traceback.format_exc()
|
trace = traceback.format_exc()
|
||||||
log.state = BackendLog.EXCEPTION
|
log.state = log.EXCEPTION
|
||||||
log.stderr = trace
|
log.stderr = trace
|
||||||
log.save()
|
log.save()
|
||||||
subject = 'EXCEPTION executing backend(s) %s %s' % (str(args), str(kwargs))
|
subject = 'EXCEPTION executing backend(s) %s %s' % (str(args), str(kwargs))
|
||||||
|
@ -122,12 +122,9 @@ def execute(scripts, serialize=False, async=None):
|
||||||
kwargs = {
|
kwargs = {
|
||||||
'async': async,
|
'async': async,
|
||||||
}
|
}
|
||||||
log = backend.create_log(*args, **kwargs)
|
with db.clone(model=BackendLog) as handle:
|
||||||
# TODO Perform this shit outside of the current transaction in a non-hacky way
|
log = backend.create_log(*args, using=handle.target)
|
||||||
#t = threading.Thread(target=backend.create_log, args=args, kwargs=kwargs)
|
log._state.db = handle.origin
|
||||||
#t.start()
|
|
||||||
#log = t.join()
|
|
||||||
# End of hack
|
|
||||||
kwargs['log'] = log
|
kwargs['log'] = log
|
||||||
task = keep_log(backend.execute, log, operations)
|
task = keep_log(backend.execute, log, operations)
|
||||||
logger.debug('%s is going to be executed on %s.' % (backend, route.host))
|
logger.debug('%s is going to be executed on %s.' % (backend, route.host))
|
||||||
|
@ -135,7 +132,7 @@ def execute(scripts, serialize=False, async=None):
|
||||||
# Execute one backend at a time, no need for threads
|
# Execute one backend at a time, no need for threads
|
||||||
task(*args, **kwargs)
|
task(*args, **kwargs)
|
||||||
else:
|
else:
|
||||||
task = close_connection(task)
|
task = db.close_connection(task)
|
||||||
thread = threading.Thread(target=task, args=args, kwargs=kwargs)
|
thread = threading.Thread(target=task, args=args, kwargs=kwargs)
|
||||||
thread.start()
|
thread.start()
|
||||||
if not async:
|
if not async:
|
||||||
|
|
|
@ -28,6 +28,7 @@ def grant_permission(modeladmin, request, queryset):
|
||||||
for user in queryset:
|
for user in queryset:
|
||||||
user.grant_to = to
|
user.grant_to = to
|
||||||
user.grant_ro = ro
|
user.grant_ro = ro
|
||||||
|
# DOn't collect, execute right away for path validation
|
||||||
OperationsMiddleware.collect('grant_permission', instance=user)
|
OperationsMiddleware.collect('grant_permission', instance=user)
|
||||||
context = {
|
context = {
|
||||||
'type': _("read-only") if ro else _("read-write"),
|
'type': _("read-only") if ro else _("read-write"),
|
||||||
|
@ -35,6 +36,7 @@ def grant_permission(modeladmin, request, queryset):
|
||||||
}
|
}
|
||||||
msg = _("Granted %(type)s permissions on %(to)s") % context
|
msg = _("Granted %(type)s permissions on %(to)s") % context
|
||||||
modeladmin.log_change(request, user, msg)
|
modeladmin.log_change(request, user, msg)
|
||||||
|
# TODO feedback message
|
||||||
return
|
return
|
||||||
opts = modeladmin.model._meta
|
opts = modeladmin.model._meta
|
||||||
app_label = opts.app_label
|
app_label = opts.app_label
|
||||||
|
|
|
@ -72,7 +72,7 @@ class UNIXUserBackend(ServiceController):
|
||||||
'to': user.grant_to,
|
'to': user.grant_to,
|
||||||
'ro': user.grant_ro,
|
'ro': user.grant_ro,
|
||||||
})
|
})
|
||||||
if user.ro:
|
if user.grant_ro:
|
||||||
self.append('echo "acl add read permissions for %(user)s to %(to)s"' % context)
|
self.append('echo "acl add read permissions for %(user)s to %(to)s"' % context)
|
||||||
else:
|
else:
|
||||||
self.append('echo "acl add read-write permissions for %(user)s to %(to)s"' % context)
|
self.append('echo "acl add read-write permissions for %(user)s to %(to)s"' % context)
|
||||||
|
|
|
@ -37,7 +37,7 @@
|
||||||
<div class="field-box field-home">
|
<div class="field-box field-home">
|
||||||
{{ form.path_extension.errors }}
|
{{ form.path_extension.errors }}
|
||||||
<label for="{{ form.base_path.id_for_label }}">{{ form.base_path.label }}:</label>
|
<label for="{{ form.base_path.id_for_label }}">{{ form.base_path.label }}:</label>
|
||||||
{{ form.base_path }}
|
{{ form.base_path }}{% for x in ""|ljust:"50" %} {% endfor %}
|
||||||
<p class="help">{{ form.base_path.help_text|safe }}</p>
|
<p class="help">{{ form.base_path.help_text|safe }}</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="field-box field-home">
|
<div class="field-box field-home">
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from django import db
|
from django import db
|
||||||
|
from django.conf import settings as djsettings
|
||||||
|
|
||||||
|
|
||||||
def running_syncdb():
|
def running_syncdb():
|
||||||
|
@ -31,3 +32,31 @@ def close_connection(execute):
|
||||||
finally:
|
finally:
|
||||||
db.connection.close()
|
db.connection.close()
|
||||||
return wrapper
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
|
class clone(object):
|
||||||
|
"""
|
||||||
|
clone database in order to have fresh connections and make queries outside the current transaction
|
||||||
|
|
||||||
|
with db.clone(model=BackendLog) as handle:
|
||||||
|
log = BackendLog.objects.using(handle.target).create()
|
||||||
|
log._state.db = handle.origin
|
||||||
|
|
||||||
|
"""
|
||||||
|
def __init__(self, model=None, origin='', target=''):
|
||||||
|
if model is not None:
|
||||||
|
origin = db.router.db_for_write(model)
|
||||||
|
self.origin = origin or db.DEFAULT_DB_ALIAS
|
||||||
|
self.target = target or 'other_' + origin
|
||||||
|
|
||||||
|
def __enter__(self):
|
||||||
|
djsettings.DATABASES[self.target] = djsettings.DATABASES[self.origin]
|
||||||
|
# Because db.connections.datases is a cached property
|
||||||
|
self.old_connections = db.connections
|
||||||
|
db.connections = db.utils.ConnectionHandler()
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __exit__(self, type, value, traceback):
|
||||||
|
db.connections[self.target].close()
|
||||||
|
djsettings.DATABASES.pop(self.target)
|
||||||
|
db.connections = self.old_connections
|
||||||
|
|
Loading…
Reference in a new issue