Optimized save model operations with update_fields kwarg
This commit is contained in:
parent
5ed8773acc
commit
774422a41b
2
TODO.md
2
TODO.md
|
@ -138,3 +138,5 @@ Remember that, as always with QuerySets, any subsequent chained methods which im
|
||||||
|
|
||||||
|
|
||||||
* Redirect junk emails and delete every 30 days?
|
* Redirect junk emails and delete every 30 days?
|
||||||
|
|
||||||
|
* Complitely decouples scripts execution, billing, service definition
|
||||||
|
|
|
@ -0,0 +1,121 @@
|
||||||
|
import textwrap
|
||||||
|
|
||||||
|
from django.utils import timezone
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
from orchestra.apps.orchestration import ServiceController
|
||||||
|
from orchestra.apps.resources import ServiceMonitor
|
||||||
|
|
||||||
|
from . import settings
|
||||||
|
|
||||||
|
# TODO create a base backend for SystemUsers!
|
||||||
|
|
||||||
|
class MainUserBackend(ServiceController):
|
||||||
|
verbose_name = _("Main user")
|
||||||
|
model = 'accounts.Account'
|
||||||
|
ignore_fields = ['last_login']
|
||||||
|
|
||||||
|
def save(self, user):
|
||||||
|
context = self.get_context(user)
|
||||||
|
self.append(textwrap.dedent("""
|
||||||
|
if [[ $( id %(username)s ) ]]; then
|
||||||
|
usermod --password '%(password)s' %(username)s
|
||||||
|
else
|
||||||
|
useradd %(username)s --password '%(password)s' --shell %(shell)s
|
||||||
|
fi
|
||||||
|
mkdir -p %(home)s
|
||||||
|
chown %(username)s.%(username)s %(home)s""" % context
|
||||||
|
))
|
||||||
|
|
||||||
|
def delete(self, user):
|
||||||
|
context = self.get_context(user)
|
||||||
|
self.append("{ sleep 2 && killall -u %(username)s -s KILL; } &" % context)
|
||||||
|
self.append("killall -u %(username)s" % context)
|
||||||
|
self.append("userdel %(username)s" % context)
|
||||||
|
|
||||||
|
def get_context(self, user):
|
||||||
|
context = {
|
||||||
|
'username': user.username,
|
||||||
|
'password': user.password if user.is_active else '*%s' % user.password,
|
||||||
|
'shell': getattr(user, 'shell', settings.ACCOUNTS_DEFAULT_SHELL)
|
||||||
|
}
|
||||||
|
context['home'] = settings.ACCOUNTS_HOME % context
|
||||||
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
class MainUserDisk(ServiceMonitor):
|
||||||
|
model = 'accounts.Account'
|
||||||
|
resource = ServiceMonitor.DISK
|
||||||
|
verbose_name = _('Main user disk')
|
||||||
|
|
||||||
|
def monitor(self, user):
|
||||||
|
context = self.get_context(user)
|
||||||
|
self.append("du -s %(home)s | xargs echo %(object_id)s" % context)
|
||||||
|
|
||||||
|
def get_context(self, user):
|
||||||
|
context = SystemUserBackend().get_context(user)
|
||||||
|
context['object_id'] = user.pk
|
||||||
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
class MainFTPTraffic(ServiceMonitor):
|
||||||
|
model = 'accounts.Account'
|
||||||
|
resource = ServiceMonitor.TRAFFIC
|
||||||
|
verbose_name = _('Main FTP traffic')
|
||||||
|
|
||||||
|
def prepare(self):
|
||||||
|
current_date = timezone.localtime(self.current_date)
|
||||||
|
current_date = current_date.strftime("%Y%m%d%H%M%S")
|
||||||
|
self.append(textwrap.dedent("""
|
||||||
|
function monitor () {
|
||||||
|
OBJECT_ID=$1
|
||||||
|
INI_DATE=$2
|
||||||
|
USERNAME="$3"
|
||||||
|
LOG_FILE="$4"
|
||||||
|
grep "UPLOAD\|DOWNLOAD" "${LOG_FILE}" \\
|
||||||
|
| grep " \\[${USERNAME}\\] " \\
|
||||||
|
| awk -v ini="${INI_DATE}" '
|
||||||
|
BEGIN {
|
||||||
|
end = "%s"
|
||||||
|
sum = 0
|
||||||
|
months["Jan"] = "01"
|
||||||
|
months["Feb"] = "02"
|
||||||
|
months["Mar"] = "03"
|
||||||
|
months["Apr"] = "04"
|
||||||
|
months["May"] = "05"
|
||||||
|
months["Jun"] = "06"
|
||||||
|
months["Jul"] = "07"
|
||||||
|
months["Aug"] = "08"
|
||||||
|
months["Sep"] = "09"
|
||||||
|
months["Oct"] = "10"
|
||||||
|
months["Nov"] = "11"
|
||||||
|
months["Dec"] = "12"
|
||||||
|
} {
|
||||||
|
# log: Fri Jul 11 13:23:17 2014
|
||||||
|
split($4, t, ":")
|
||||||
|
# line_date = year month day hour minute second
|
||||||
|
line_date = $5 months[$2] $3 t[1] t[2] t[3]
|
||||||
|
if ( line_date > ini && line_date < end)
|
||||||
|
split($0, l, "\\", ")
|
||||||
|
split(l[3], b, " ")
|
||||||
|
sum += b[1]
|
||||||
|
} END {
|
||||||
|
print sum
|
||||||
|
}
|
||||||
|
' | xargs echo ${OBJECT_ID}
|
||||||
|
}""" % current_date))
|
||||||
|
|
||||||
|
def monitor(self, user):
|
||||||
|
context = self.get_context(user)
|
||||||
|
self.append(
|
||||||
|
'monitor %(object_id)i %(last_date)s "%(username)s" "%(log_file)s"' % context)
|
||||||
|
|
||||||
|
def get_context(self, user):
|
||||||
|
last_date = timezone.localtime(self.get_last_date(user.pk))
|
||||||
|
return {
|
||||||
|
'log_file': settings.ACCOUNTS_FTP_LOG_PATH,
|
||||||
|
'last_date': last_date.strftime("%Y%m%d%H%M%S"),
|
||||||
|
'object_id': user.pk,
|
||||||
|
'username': user.username,
|
||||||
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@ class AccountCreationForm(auth.forms.UserCreationForm):
|
||||||
|
|
||||||
|
|
||||||
class AccountChangeForm(forms.ModelForm):
|
class AccountChangeForm(forms.ModelForm):
|
||||||
username = forms.CharField()
|
username = forms.CharField(required=False)
|
||||||
password = auth.forms.ReadOnlyPasswordHashField(label=_("Password"),
|
password = auth.forms.ReadOnlyPasswordHashField(label=_("Password"),
|
||||||
help_text=_("Raw passwords are not stored, so there is no way to see "
|
help_text=_("Raw passwords are not stored, so there is no way to see "
|
||||||
"this user's password, but you can change the password "
|
"this user's password, but you can change the password "
|
||||||
|
@ -33,7 +33,8 @@ class AccountChangeForm(forms.ModelForm):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(AccountChangeForm, self).__init__(*args, **kwargs)
|
super(AccountChangeForm, self).__init__(*args, **kwargs)
|
||||||
account = kwargs.get('instance')
|
account = kwargs.get('instance')
|
||||||
self.fields['username'].widget = ReadOnlyWidget(account.username)
|
username = '<b style="font-size:small">%s</b>' % account.username
|
||||||
|
self.fields['username'].widget = ReadOnlyWidget(username)
|
||||||
self.fields['password'].initial = account.password
|
self.fields['password'].initial = account.password
|
||||||
|
|
||||||
def clean_password(self):
|
def clean_password(self):
|
||||||
|
|
|
@ -68,8 +68,7 @@ class Account(auth.AbstractBaseUser):
|
||||||
def send_email(self, template, context, contacts=[], attachments=[], html=None):
|
def send_email(self, template, context, contacts=[], attachments=[], html=None):
|
||||||
contacts = self.contacts.filter(email_usages=contacts)
|
contacts = self.contacts.filter(email_usages=contacts)
|
||||||
email_to = contacts.values_list('email', flat=True)
|
email_to = contacts.values_list('email', flat=True)
|
||||||
send_email_template(template, context, email_to, html=html,
|
send_email_template(template, context, email_to, html=html, attachments=attachments)
|
||||||
attachments=attachments)
|
|
||||||
|
|
||||||
def get_full_name(self):
|
def get_full_name(self):
|
||||||
full_name = '%s %s' % (self.first_name, self.last_name)
|
full_name = '%s %s' % (self.first_name, self.last_name)
|
||||||
|
|
|
@ -22,3 +22,12 @@ ACCOUNTS_DEFAULT_LANGUAGE = getattr(settings, 'ACCOUNTS_DEFAULT_LANGUAGE', 'en')
|
||||||
|
|
||||||
|
|
||||||
ACCOUNTS_MAIN_PK = getattr(settings, 'ACCOUNTS_MAIN_PK', 1)
|
ACCOUNTS_MAIN_PK = getattr(settings, 'ACCOUNTS_MAIN_PK', 1)
|
||||||
|
|
||||||
|
|
||||||
|
ACCOUNTS_HOME = getattr(settings, 'ACCOUNTS_HOME', '/home/%(username)s')
|
||||||
|
|
||||||
|
|
||||||
|
ACCOUNTS_FTP_LOG_PATH = getattr(settings, 'ACCOUNTS_FTP_LOG_PATH', '/var/log/vsftpd.log')
|
||||||
|
|
||||||
|
|
||||||
|
ACCOUNTS_DEFAULT_SHELL = getattr(settings, 'ACCOUNTS_DEFAULT_SHELL', '/bin/false')
|
||||||
|
|
|
@ -156,7 +156,7 @@ class Bill(models.Model):
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
self.is_sent = True
|
self.is_sent = True
|
||||||
self.save()
|
self.save(update_fields=['is_sent'])
|
||||||
|
|
||||||
def render(self, payment=False):
|
def render(self, payment=False):
|
||||||
if payment is False:
|
if payment is False:
|
||||||
|
@ -281,7 +281,7 @@ class BillLine(models.Model):
|
||||||
super(BillLine, self).save(*args, **kwargs)
|
super(BillLine, self).save(*args, **kwargs)
|
||||||
if self.bill.is_open:
|
if self.bill.is_open:
|
||||||
self.bill.total = self.bill.get_total()
|
self.bill.total = self.bill.get_total()
|
||||||
self.bill.save()
|
self.bill.save(update_fields=['total'])
|
||||||
|
|
||||||
|
|
||||||
class BillSubline(models.Model):
|
class BillSubline(models.Model):
|
||||||
|
@ -306,7 +306,7 @@ class BillSubline(models.Model):
|
||||||
super(BillSubline, self).save(*args, **kwargs)
|
super(BillSubline, self).save(*args, **kwargs)
|
||||||
if self.line.bill.is_open:
|
if self.line.bill.is_open:
|
||||||
self.line.bill.total = self.line.bill.get_total()
|
self.line.bill.total = self.line.bill.get_total()
|
||||||
self.line.bill.save()
|
self.line.bill.save(update_fields=['total'])
|
||||||
|
|
||||||
|
|
||||||
accounts.register(Bill)
|
accounts.register(Bill)
|
||||||
|
|
|
@ -58,7 +58,7 @@ class Domain(models.Model):
|
||||||
serial = str(self.serial)[:8] + '%.2d' % num
|
serial = str(self.serial)[:8] + '%.2d' % num
|
||||||
serial = int(serial)
|
serial = int(serial)
|
||||||
self.serial = serial
|
self.serial = serial
|
||||||
self.save()
|
self.save(update_fields=['serial'])
|
||||||
|
|
||||||
def render_records(self):
|
def render_records(self):
|
||||||
types = {}
|
types = {}
|
||||||
|
@ -128,7 +128,7 @@ class Domain(models.Model):
|
||||||
domains = Domain.objects.exclude(pk=self.pk)
|
domains = Domain.objects.exclude(pk=self.pk)
|
||||||
for domain in domains.filter(name__endswith=self.name):
|
for domain in domains.filter(name__endswith=self.name):
|
||||||
domain.top = self
|
domain.top = self
|
||||||
domain.save()
|
domain.save(update_fields=['top'])
|
||||||
self.get_subdomains().update(account=self.account)
|
self.get_subdomains().update(account=self.account)
|
||||||
|
|
||||||
def get_top(self):
|
def get_top(self):
|
||||||
|
|
|
@ -122,6 +122,6 @@ def set_default_queue(modeladmin, request, queryset):
|
||||||
Queue.objects.filter(default=True).update(default=False)
|
Queue.objects.filter(default=True).update(default=False)
|
||||||
queue = queryset.get()
|
queue = queryset.get()
|
||||||
queue.default = True
|
queue.default = True
|
||||||
queue.save()
|
queue.save(update_fields=['default'])
|
||||||
modeladmin.log_change(request, queue, _("Chosen as default."))
|
modeladmin.log_change(request, queue, _("Chosen as default."))
|
||||||
messages.info(request, _("Chosen '%s' as default queue.") % queue)
|
messages.info(request, _("Chosen '%s' as default queue.") % queue)
|
||||||
|
|
|
@ -135,19 +135,19 @@ class Ticket(models.Model):
|
||||||
|
|
||||||
def reject(self):
|
def reject(self):
|
||||||
self.state = Ticket.REJECTED
|
self.state = Ticket.REJECTED
|
||||||
self.save()
|
self.save(update_fields=['state'])
|
||||||
|
|
||||||
def resolve(self):
|
def resolve(self):
|
||||||
self.state = Ticket.RESOLVED
|
self.state = Ticket.RESOLVED
|
||||||
self.save()
|
self.save(update_fields=['state'])
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
self.state = Ticket.CLOSED
|
self.state = Ticket.CLOSED
|
||||||
self.save()
|
self.save(update_fields=['state'])
|
||||||
|
|
||||||
def take(self, user):
|
def take(self, user):
|
||||||
self.owner = user
|
self.owner = user
|
||||||
self.save()
|
self.save(update_fields=['state'])
|
||||||
|
|
||||||
|
|
||||||
class Message(models.Model):
|
class Message(models.Model):
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import textwrap
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
@ -18,14 +19,13 @@ class MailSystemUserBackend(ServiceController):
|
||||||
DEFAULT_GROUP = 'postfix'
|
DEFAULT_GROUP = 'postfix'
|
||||||
|
|
||||||
def create_user(self, context):
|
def create_user(self, context):
|
||||||
self.append(
|
self.append(textwrap("""
|
||||||
"if [[ $( id %(username)s ) ]]; then \n"
|
if [[ $( id %(username)s ) ]]; then
|
||||||
" usermod -p '%(password)s' %(username)s \n"
|
usermod -p '%(password)s' %(username)s
|
||||||
"else \n"
|
else
|
||||||
" useradd %(username)s --password '%(password)s' \\\n"
|
useradd %(username)s --password '%(password)s' --shell /dev/null
|
||||||
" --shell /dev/null \n"
|
fi""" % context
|
||||||
"fi" % context
|
))
|
||||||
)
|
|
||||||
self.append("mkdir -p %(home)s" % context)
|
self.append("mkdir -p %(home)s" % context)
|
||||||
self.append("chown %(username)s.%(group)s %(home)s" % context)
|
self.append("chown %(username)s.%(group)s %(home)s" % context)
|
||||||
|
|
||||||
|
@ -51,12 +51,12 @@ class MailSystemUserBackend(ServiceController):
|
||||||
'quota': mailbox.resources.disk.allocated*1000*1000,
|
'quota': mailbox.resources.disk.allocated*1000*1000,
|
||||||
})
|
})
|
||||||
self.append("mkdir -p %(maildir_path)s" % context)
|
self.append("mkdir -p %(maildir_path)s" % context)
|
||||||
self.append(
|
self.append(textwrap("""
|
||||||
"sed -i '1s/.*/%(quota)s,S/' %(maildirsize_path)s || {"
|
sed -i '1s/.*/%(quota)s,S/' %(maildirsize_path)s || {
|
||||||
" echo '%(quota)s,S' > %(maildirsize_path)s && "
|
echo '%(quota)s,S' > %(maildirsize_path)s &&
|
||||||
" chown %(username)s %(maildirsize_path)s;"
|
chown %(username)s %(maildirsize_path)s;
|
||||||
"}" % context
|
}""" % context
|
||||||
)
|
))
|
||||||
|
|
||||||
def save(self, mailbox):
|
def save(self, mailbox):
|
||||||
context = self.get_context(mailbox)
|
context = self.get_context(mailbox)
|
||||||
|
@ -98,26 +98,26 @@ class PostfixAddressBackend(ServiceController):
|
||||||
self.append('sed -i "s/^%(domain)s//" %(virtdomains)s' % context)
|
self.append('sed -i "s/^%(domain)s//" %(virtdomains)s' % context)
|
||||||
|
|
||||||
def update_virtusertable(self, context):
|
def update_virtusertable(self, context):
|
||||||
self.append(
|
self.append(textwrap("""
|
||||||
'LINE="%(email)s\t%(destination)s"\n'
|
LINE="%(email)s\t%(destination)s"
|
||||||
'if [[ ! $(grep "^%(email)s\s" %(virtusertable)s) ]]; then\n'
|
if [[ ! $(grep "^%(email)s\s" %(virtusertable)s) ]]; then
|
||||||
' echo "$LINE" >> %(virtusertable)s\n'
|
echo "$LINE" >> %(virtusertable)s
|
||||||
' UPDATED=1\n'
|
UPDATED=1
|
||||||
'else\n'
|
else
|
||||||
' if [[ ! $(grep "^${LINE}$" %(virtusertable)s) ]]; then\n'
|
if [[ ! $(grep "^${LINE}$" %(virtusertable)s) ]]; then
|
||||||
' sed -i "s/^%(email)s\s.*$/${LINE}/" %(virtusertable)s\n'
|
sed -i "s/^%(email)s\s.*$/${LINE}/" %(virtusertable)s
|
||||||
' UPDATED=1\n'
|
UPDATED=1
|
||||||
' fi\n'
|
fi
|
||||||
'fi' % context
|
fi""" % context
|
||||||
)
|
))
|
||||||
|
|
||||||
def exclude_virtusertable(self, context):
|
def exclude_virtusertable(self, context):
|
||||||
self.append(
|
self.append(textwrap("""
|
||||||
'if [[ $(grep "^%(email)s\s") ]]; then\n'
|
if [[ $(grep "^%(email)s\s") ]]; then
|
||||||
' sed -i "s/^%(email)s\s.*$//" %(virtusertable)s\n'
|
sed -i "s/^%(email)s\s.*$//" %(virtusertable)s
|
||||||
' UPDATED=1\n'
|
UPDATED=1
|
||||||
'fi'
|
fi"""
|
||||||
)
|
))
|
||||||
|
|
||||||
def save(self, address):
|
def save(self, address):
|
||||||
context = self.get_context(address)
|
context = self.get_context(address)
|
||||||
|
@ -131,10 +131,12 @@ class PostfixAddressBackend(ServiceController):
|
||||||
|
|
||||||
def commit(self):
|
def commit(self):
|
||||||
context = self.get_context_files()
|
context = self.get_context_files()
|
||||||
self.append('[[ $UPDATED == 1 ]] && { '
|
self.append(textwrap("""
|
||||||
'postmap %(virtdomains)s;'
|
[[ $UPDATED == 1 ]] && {
|
||||||
'postmap %(virtusertable)s;'
|
postmap %(virtdomains)s
|
||||||
'}' % context)
|
postmap %(virtusertable)s
|
||||||
|
}""" % context
|
||||||
|
))
|
||||||
|
|
||||||
def get_context_files(self):
|
def get_context_files(self):
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -16,7 +16,7 @@ def BashSSH(backend, log, server, cmds):
|
||||||
script = '\n'.join(['set -e', 'set -o pipefail'] + cmds + ['exit 0'])
|
script = '\n'.join(['set -e', 'set -o pipefail'] + cmds + ['exit 0'])
|
||||||
script = script.replace('\r', '')
|
script = script.replace('\r', '')
|
||||||
log.script = script
|
log.script = script
|
||||||
log.save()
|
log.save(update_fields=['script'])
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Avoid "Argument list too long" on large scripts by genereting a file
|
# Avoid "Argument list too long" on large scripts by genereting a file
|
||||||
|
@ -34,7 +34,7 @@ def BashSSH(backend, log, server, cmds):
|
||||||
key_filename=settings.ORCHESTRATION_SSH_KEY_PATH)
|
key_filename=settings.ORCHESTRATION_SSH_KEY_PATH)
|
||||||
except socket.error:
|
except socket.error:
|
||||||
log.state = BackendLog.TIMEOUT
|
log.state = BackendLog.TIMEOUT
|
||||||
log.save()
|
log.save(update_fields=['state'])
|
||||||
return
|
return
|
||||||
transport = ssh.get_transport()
|
transport = ssh.get_transport()
|
||||||
channel = transport.open_session()
|
channel = transport.open_session()
|
||||||
|
@ -66,7 +66,7 @@ def BashSSH(backend, log, server, cmds):
|
||||||
log.stdout += channel.recv(1024)
|
log.stdout += channel.recv(1024)
|
||||||
if channel.recv_stderr_ready():
|
if channel.recv_stderr_ready():
|
||||||
log.stderr += channel.recv_stderr(1024)
|
log.stderr += channel.recv_stderr(1024)
|
||||||
log.save()
|
log.save(update_fields=['stdout', 'stderr'])
|
||||||
if channel.exit_status_ready():
|
if channel.exit_status_ready():
|
||||||
break
|
break
|
||||||
log.exit_code = exit_code = channel.recv_exit_status()
|
log.exit_code = exit_code = channel.recv_exit_status()
|
||||||
|
@ -85,7 +85,7 @@ def Python(backend, log, server, cmds):
|
||||||
script = [ str(cmd.func.func_name) + str(cmd.args) for cmd in cmds ]
|
script = [ str(cmd.func.func_name) + str(cmd.args) for cmd in cmds ]
|
||||||
script = json.dumps(script, indent=4).replace('"', '')
|
script = json.dumps(script, indent=4).replace('"', '')
|
||||||
log.script = '\n'.join([log.script, script])
|
log.script = '\n'.join([log.script, script])
|
||||||
log.save()
|
log.save(update_fields=['script'])
|
||||||
stdout = ''
|
stdout = ''
|
||||||
try:
|
try:
|
||||||
for cmd in cmds:
|
for cmd in cmds:
|
||||||
|
|
|
@ -162,11 +162,11 @@ class Order(models.Model):
|
||||||
id=self.id, description=description, metric=metric))
|
id=self.id, description=description, metric=metric))
|
||||||
if self.description != description:
|
if self.description != description:
|
||||||
self.description = description
|
self.description = description
|
||||||
self.save()
|
self.save(update_fields=['description'])
|
||||||
|
|
||||||
def cancel(self):
|
def cancel(self):
|
||||||
self.cancelled_on = timezone.now()
|
self.cancelled_on = timezone.now()
|
||||||
self.save()
|
self.save(update_fields=['cancelled_on'])
|
||||||
logger.info("CANCELLED order id: {id}".format(id=self.id))
|
logger.info("CANCELLED order id: {id}".format(id=self.id))
|
||||||
|
|
||||||
def get_metric(self, *args, **kwargs):
|
def get_metric(self, *args, **kwargs):
|
||||||
|
@ -230,7 +230,7 @@ class MetricStorage(models.Model):
|
||||||
cls.objects.create(order=order, value=value, updated_on=now)
|
cls.objects.create(order=order, value=value, updated_on=now)
|
||||||
else:
|
else:
|
||||||
metric.updated_on = now
|
metric.updated_on = now
|
||||||
metric.save()
|
metric.save(update_fields=['updated_on'])
|
||||||
|
|
||||||
|
|
||||||
accounts.register(Order)
|
accounts.register(Order)
|
||||||
|
|
|
@ -178,7 +178,7 @@ class SEPADirectDebit(PaymentMethod):
|
||||||
account = transaction.account
|
account = transaction.account
|
||||||
data = transaction.source.data
|
data = transaction.source.data
|
||||||
transaction.state = transaction.WAITTING_CONFIRMATION
|
transaction.state = transaction.WAITTING_CONFIRMATION
|
||||||
transaction.save()
|
transaction.save(update_fields=['state'])
|
||||||
yield E.DrctDbtTxInf( # Direct Debit Transaction Info
|
yield E.DrctDbtTxInf( # Direct Debit Transaction Info
|
||||||
E.PmtId( # Payment Id
|
E.PmtId( # Payment Id
|
||||||
E.EndToEndId(str(transaction.id)) # Payment Id/End to End
|
E.EndToEndId(str(transaction.id)) # Payment Id/End to End
|
||||||
|
@ -219,7 +219,7 @@ class SEPADirectDebit(PaymentMethod):
|
||||||
account = transaction.account
|
account = transaction.account
|
||||||
data = transaction.source.data
|
data = transaction.source.data
|
||||||
transaction.state = transaction.WAITTING_CONFIRMATION
|
transaction.state = transaction.WAITTING_CONFIRMATION
|
||||||
transaction.save()
|
transaction.save(update_fields=['state'])
|
||||||
yield E.CdtTrfTxInf( # Credit Transfer Transaction Info
|
yield E.CdtTrfTxInf( # Credit Transfer Transaction Info
|
||||||
E.PmtId( # Payment Id
|
E.PmtId( # Payment Id
|
||||||
E.EndToEndId(str(transaction.id)) # Payment Id/End to End
|
E.EndToEndId(str(transaction.id)) # Payment Id/End to End
|
||||||
|
@ -278,7 +278,7 @@ class SEPADirectDebit(PaymentMethod):
|
||||||
sepa = etree.parse(StringIO(etree.tostring(sepa)))
|
sepa = etree.parse(StringIO(etree.tostring(sepa)))
|
||||||
schema.assertValid(sepa)
|
schema.assertValid(sepa)
|
||||||
process.file = file_name
|
process.file = file_name
|
||||||
process.save()
|
process.save(update_fields=['file'])
|
||||||
sepa.write(process.file.path,
|
sepa.write(process.file.path,
|
||||||
pretty_print=True,
|
pretty_print=True,
|
||||||
xml_declaration=True,
|
xml_declaration=True,
|
||||||
|
|
|
@ -119,22 +119,22 @@ class Transaction(models.Model):
|
||||||
def mark_as_processed(self):
|
def mark_as_processed(self):
|
||||||
assert self.state == self.WAITTING_PROCESSING
|
assert self.state == self.WAITTING_PROCESSING
|
||||||
self.state = self.WAITTING_EXECUTION
|
self.state = self.WAITTING_EXECUTION
|
||||||
self.save()
|
self.save(update_fields=['state'])
|
||||||
|
|
||||||
def mark_as_executed(self):
|
def mark_as_executed(self):
|
||||||
assert self.state == self.WAITTING_EXECUTION
|
assert self.state == self.WAITTING_EXECUTION
|
||||||
self.state = self.EXECUTED
|
self.state = self.EXECUTED
|
||||||
self.save()
|
self.save(update_fields=['state'])
|
||||||
|
|
||||||
def mark_as_secured(self):
|
def mark_as_secured(self):
|
||||||
assert self.state == self.EXECUTED
|
assert self.state == self.EXECUTED
|
||||||
self.state = self.SECURED
|
self.state = self.SECURED
|
||||||
self.save()
|
self.save(update_fields=['state'])
|
||||||
|
|
||||||
def mark_as_rejected(self):
|
def mark_as_rejected(self):
|
||||||
assert self.state == self.EXECUTED
|
assert self.state == self.EXECUTED
|
||||||
self.state = self.REJECTED
|
self.state = self.REJECTED
|
||||||
self.save()
|
self.save(update_fields=['state'])
|
||||||
|
|
||||||
|
|
||||||
class TransactionProcess(models.Model):
|
class TransactionProcess(models.Model):
|
||||||
|
@ -169,21 +169,21 @@ class TransactionProcess(models.Model):
|
||||||
self.state = self.EXECUTED
|
self.state = self.EXECUTED
|
||||||
for transaction in self.transactions.all():
|
for transaction in self.transactions.all():
|
||||||
transaction.mark_as_executed()
|
transaction.mark_as_executed()
|
||||||
self.save()
|
self.save(update_fields=['state'])
|
||||||
|
|
||||||
def abort(self):
|
def abort(self):
|
||||||
assert self.state in [self.CREATED, self.EXCECUTED]
|
assert self.state in [self.CREATED, self.EXCECUTED]
|
||||||
self.state = self.ABORTED
|
self.state = self.ABORTED
|
||||||
for transaction in self.transaction.all():
|
for transaction in self.transaction.all():
|
||||||
transaction.mark_as_aborted()
|
transaction.mark_as_aborted()
|
||||||
self.save()
|
self.save(update_fields=['state'])
|
||||||
|
|
||||||
def commit(self):
|
def commit(self):
|
||||||
assert self.state in [self.CREATED, self.EXECUTED]
|
assert self.state in [self.CREATED, self.EXECUTED]
|
||||||
self.state = self.COMMITED
|
self.state = self.COMMITED
|
||||||
for transaction in self.transactions.processing():
|
for transaction in self.transactions.processing():
|
||||||
transaction.mark_as_secured()
|
transaction.mark_as_secured()
|
||||||
self.save()
|
self.save(update_fields=['state'])
|
||||||
|
|
||||||
|
|
||||||
accounts.register(PaymentSource)
|
accounts.register(PaymentSource)
|
||||||
|
|
|
@ -98,7 +98,7 @@ class Resource(models.Model):
|
||||||
task.delete()
|
task.delete()
|
||||||
elif task.crontab != self.crontab:
|
elif task.crontab != self.crontab:
|
||||||
task.crontab = self.crontab
|
task.crontab = self.crontab
|
||||||
task.save()
|
task.save(update_fields=['crontab'])
|
||||||
if created:
|
if created:
|
||||||
# This only work on tests because of multiprocessing used on real deployments
|
# This only work on tests because of multiprocessing used on real deployments
|
||||||
create_resource_relation()
|
create_resource_relation()
|
||||||
|
@ -146,7 +146,7 @@ class ResourceData(models.Model):
|
||||||
current = self.get_used()
|
current = self.get_used()
|
||||||
self.used = current or 0
|
self.used = current or 0
|
||||||
self.updated_at = timezone.now()
|
self.updated_at = timezone.now()
|
||||||
self.save()
|
self.save(update_fields=['used', 'updated_at'])
|
||||||
|
|
||||||
|
|
||||||
class MonitorData(models.Model):
|
class MonitorData(models.Model):
|
||||||
|
|
|
@ -222,7 +222,7 @@ class ServiceHandler(plugins.Plugin):
|
||||||
for order in givers:
|
for order in givers:
|
||||||
if hasattr(order, 'new_billed_until'):
|
if hasattr(order, 'new_billed_until'):
|
||||||
order.billed_until = order.new_billed_until
|
order.billed_until = order.new_billed_until
|
||||||
order.save()
|
order.save(update_fields=['billed_until'])
|
||||||
|
|
||||||
def apply_compensations(self, order, only_beyond=False):
|
def apply_compensations(self, order, only_beyond=False):
|
||||||
dsize = 0
|
dsize = 0
|
||||||
|
@ -481,5 +481,5 @@ class ServiceHandler(plugins.Plugin):
|
||||||
order = line.order
|
order = line.order
|
||||||
order.billed_on = now
|
order.billed_on = now
|
||||||
order.billed_until = getattr(order, 'new_billed_until', order.billed_until)
|
order.billed_until = getattr(order, 'new_billed_until', order.billed_until)
|
||||||
order.save()
|
order.save(update_fields=['billed_on', 'billed_until'])
|
||||||
return lines
|
return lines
|
||||||
|
|
|
@ -3,121 +3,15 @@ import textwrap
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from orchestra.apps.orchestration import ServiceController
|
from orchestra.apps.accounts.backends import MainUserBackend, MainFTPTraffic
|
||||||
from orchestra.apps.resources import ServiceMonitor
|
|
||||||
|
|
||||||
from . import settings
|
|
||||||
|
|
||||||
|
|
||||||
class SystemUserBackend(ServiceController):
|
class SystemUserBackend(MainUserBackend):
|
||||||
verbose_name = _("System User")
|
verbose_name = _("System user")
|
||||||
model = 'users.User'
|
model = 'systemusers.SystemUser'
|
||||||
ignore_fields = ['last_login']
|
ignore_fields = []
|
||||||
|
|
||||||
def save(self, user):
|
|
||||||
context = self.get_context(user)
|
|
||||||
if user.is_main:
|
|
||||||
self.append(textwrap.dedent("""
|
|
||||||
if [[ $( id %(username)s ) ]]; then
|
|
||||||
usermod --password '%(password)s' %(username)s
|
|
||||||
else
|
|
||||||
useradd %(username)s --password '%(password)s' \\
|
|
||||||
--shell /bin/false
|
|
||||||
fi
|
|
||||||
mkdir -p %(home)s
|
|
||||||
chown %(username)s.%(username)s %(home)s""" % context
|
|
||||||
))
|
|
||||||
else:
|
|
||||||
self.delete(user)
|
|
||||||
|
|
||||||
def delete(self, user):
|
|
||||||
context = self.get_context(user)
|
|
||||||
self.append("{ sleep 2 && killall -u %(username)s -s KILL; } &" % context)
|
|
||||||
self.append("killall -u %(username)s" % context)
|
|
||||||
self.append("userdel %(username)s" % context)
|
|
||||||
|
|
||||||
def get_context(self, user):
|
|
||||||
context = {
|
|
||||||
'username': user.username,
|
|
||||||
'password': user.password if user.is_active else '*%s' % user.password,
|
|
||||||
}
|
|
||||||
context['home'] = settings.USERS_SYSTEMUSER_HOME % context
|
|
||||||
return context
|
|
||||||
|
|
||||||
|
|
||||||
class SystemUserDisk(ServiceMonitor):
|
class SystemUserFTPTraffic(MainFTPTraffic):
|
||||||
model = 'users.User'
|
model = 'systemusers.SystemUser'
|
||||||
resource = ServiceMonitor.DISK
|
verbose_name = _('System user FTP traffic')
|
||||||
verbose_name = _('System user disk')
|
|
||||||
|
|
||||||
def monitor(self, user):
|
|
||||||
context = self.get_context(user)
|
|
||||||
self.append("du -s %(home)s | xargs echo %(object_id)s" % context)
|
|
||||||
|
|
||||||
def get_context(self, user):
|
|
||||||
context = SystemUserBackend().get_context(user)
|
|
||||||
context['object_id'] = user.pk
|
|
||||||
return context
|
|
||||||
|
|
||||||
|
|
||||||
class FTPTraffic(ServiceMonitor):
|
|
||||||
model = 'users.User'
|
|
||||||
resource = ServiceMonitor.TRAFFIC
|
|
||||||
verbose_name = _('FTP traffic')
|
|
||||||
|
|
||||||
def prepare(self):
|
|
||||||
current_date = timezone.localtime(self.current_date)
|
|
||||||
current_date = current_date.strftime("%Y%m%d%H%M%S")
|
|
||||||
self.append(textwrap.dedent("""
|
|
||||||
function monitor () {
|
|
||||||
OBJECT_ID=$1
|
|
||||||
INI_DATE=$2
|
|
||||||
USERNAME="$3"
|
|
||||||
LOG_FILE="$4"
|
|
||||||
grep "UPLOAD\|DOWNLOAD" "${LOG_FILE}" \\
|
|
||||||
| grep " \\[${USERNAME}\\] " \\
|
|
||||||
| awk -v ini="${INI_DATE}" '
|
|
||||||
BEGIN {
|
|
||||||
end = "%s"
|
|
||||||
sum = 0
|
|
||||||
months["Jan"] = "01"
|
|
||||||
months["Feb"] = "02"
|
|
||||||
months["Mar"] = "03"
|
|
||||||
months["Apr"] = "04"
|
|
||||||
months["May"] = "05"
|
|
||||||
months["Jun"] = "06"
|
|
||||||
months["Jul"] = "07"
|
|
||||||
months["Aug"] = "08"
|
|
||||||
months["Sep"] = "09"
|
|
||||||
months["Oct"] = "10"
|
|
||||||
months["Nov"] = "11"
|
|
||||||
months["Dec"] = "12"
|
|
||||||
} {
|
|
||||||
# log: Fri Jul 11 13:23:17 2014
|
|
||||||
split($4, t, ":")
|
|
||||||
# line_date = year month day hour minute second
|
|
||||||
line_date = $5 months[$2] $3 t[1] t[2] t[3]
|
|
||||||
if ( line_date > ini && line_date < end)
|
|
||||||
split($0, l, "\\", ")
|
|
||||||
split(l[3], b, " ")
|
|
||||||
sum += b[1]
|
|
||||||
} END {
|
|
||||||
print sum
|
|
||||||
}
|
|
||||||
' | xargs echo ${OBJECT_ID}
|
|
||||||
}""" % current_date))
|
|
||||||
|
|
||||||
def monitor(self, user):
|
|
||||||
context = self.get_context(user)
|
|
||||||
self.append(
|
|
||||||
'monitor %(object_id)i %(last_date)s "%(username)s" "%(log_file)s"' % context)
|
|
||||||
|
|
||||||
def get_context(self, user):
|
|
||||||
last_date = timezone.localtime(self.get_last_date(user.pk))
|
|
||||||
return {
|
|
||||||
'log_file': settings.USERS_FTP_LOG_PATH,
|
|
||||||
'last_date': last_date.strftime("%Y%m%d%H%M%S"),
|
|
||||||
'object_id': user.pk,
|
|
||||||
'username': user.username,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ class SystemUserQuerySet(models.QuerySet):
|
||||||
def create_user(self, username, password='', **kwargs):
|
def create_user(self, username, password='', **kwargs):
|
||||||
user = super(SystemUserQuerySet, self).create(username=username, **kwargs)
|
user = super(SystemUserQuerySet, self).create(username=username, **kwargs)
|
||||||
user.set_password(password)
|
user.set_password(password)
|
||||||
user.save()
|
user.save(update_fields=['password'])
|
||||||
|
|
||||||
|
|
||||||
class SystemUser(models.Model):
|
class SystemUser(models.Model):
|
||||||
|
@ -59,15 +59,6 @@ class SystemUser(models.Model):
|
||||||
def set_password(self, raw_password):
|
def set_password(self, raw_password):
|
||||||
self.password = make_password(raw_password)
|
self.password = make_password(raw_password)
|
||||||
|
|
||||||
def check_password(self, raw_password):
|
|
||||||
"""
|
|
||||||
Returns a boolean of whether the raw_password was correct. Handles
|
|
||||||
hashing formats behind the scenes.
|
|
||||||
"""
|
|
||||||
def setter(raw_password):
|
|
||||||
self.set_password(raw_password)
|
|
||||||
self.save(update_fields=["password"])
|
|
||||||
|
|
||||||
def get_is_active(self):
|
def get_is_active(self):
|
||||||
return self.account.is_active and self.is_active
|
return self.account.is_active and self.is_active
|
||||||
|
|
||||||
|
|
|
@ -3,10 +3,6 @@ from django.conf import settings
|
||||||
from django.utils.translation import ugettext, ugettext_lazy as _
|
from django.utils.translation import ugettext, ugettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
USERS_SYSTEMUSER_HOME = getattr(settings, 'USERES_SYSTEMUSER_HOME', '/home/%(username)s')
|
|
||||||
|
|
||||||
USERS_FTP_LOG_PATH = getattr(settings, 'USERS_FTP_LOG_PATH', '/var/log/vsftpd.log')
|
|
||||||
|
|
||||||
USERS_SHELLS = getattr(settings, 'USERS_SHELLS', (
|
USERS_SHELLS = getattr(settings, 'USERS_SHELLS', (
|
||||||
('/bin/false', _("No shell, FTP only")),
|
('/bin/false', _("No shell, FTP only")),
|
||||||
('/bin/rsync', _("No shell, SFTP/RSYNC only")),
|
('/bin/rsync', _("No shell, SFTP/RSYNC only")),
|
||||||
|
|
Loading…
Reference in New Issue