Added backend docstring as helptext

This commit is contained in:
Marc Aymerich 2015-04-23 19:46:23 +00:00
parent 1a78317028
commit eebaee1097
29 changed files with 293 additions and 116 deletions

View File

@ -286,3 +286,6 @@ https://code.djangoproject.com/ticket/24576
# Amend lines???
# Add icon on select contact view
# Determine the difference between data serializer used for validation and used for the rest API!
# Make PluginApiView that fills metadata and other stuff like modeladmin plugin support

View File

@ -1,6 +1,9 @@
import copy
from django.forms import widgets
from django.utils.translation import ugettext_lazy as _
from rest_framework import serializers
from rest_framework.utils import model_meta
from ..core.validators import validate_password
@ -10,32 +13,47 @@ class SetPasswordSerializer(serializers.Serializer):
style={'widget': widgets.PasswordInput}, validators=[validate_password])
#class HyperlinkedModelSerializerOptions(serializers.HyperlinkedModelSerializerOptions):
# def __init__(self, meta):
# super(HyperlinkedModelSerializerOptions, self).__init__(meta)
# self.postonly_fields = getattr(meta, 'postonly_fields', ())
class HyperlinkedModelSerializer(serializers.HyperlinkedModelSerializer):
""" support for postonly_fields, fields whose value can only be set on post """
# _options_class = HyperlinkedModelSerializerOptions
def validate(self, attrs):
""" calls model.clean() """
attrs = super(HyperlinkedModelSerializer, self).validate(attrs)
instance = self.Meta.model(**attrs)
validated_data = dict(attrs)
ModelClass = self.Meta.model
# Remove many-to-many relationships from validated_data.
info = model_meta.get_field_info(ModelClass)
for field_name, relation_info in info.relations.items():
if relation_info.to_many and (field_name in validated_data):
validated_data.pop(field_name)
if self.instance:
# on update: Merge provided fields with instance field
instance = copy.deepcopy(self.instance)
for key, value in validated_data.items():
setattr(instance, key, value)
else:
instance = ModelClass(**validated_data)
instance.clean()
return attrs
# TODO raise validationError instead of silently removing fields
def update(self, instance, validated_data):
""" removes postonly_fields from attrs when not posting """
def post_only_cleanning(self, instance, validated_data):
""" removes postonly_fields from attrs """
model_attrs = dict(**validated_data)
if instance is not None:
for attr, value in validated_data.items():
if attr in self.Meta.postonly_fields:
model_attrs.pop(attr)
return model_attrs
def update(self, instance, validated_data):
""" removes postonly_fields from attrs when not posting """
model_attrs = self.post_only_cleanning(instance, validated_data)
return super(HyperlinkedModelSerializer, self).update(instance, model_attrs)
def partial_update(self, instance, validated_data):
""" removes postonly_fields from attrs when not posting """
model_attrs = self.post_only_cleanning(instance, validated_data)
return super(HyperlinkedModelSerializer, self).partial_update(instance, model_attrs)
class SetPasswordHyperlinkedSerializer(HyperlinkedModelSerializer):

View File

@ -8,13 +8,13 @@ from .serializers import DatabaseSerializer, DatabaseUserSerializer
class DatabaseViewSet(LogApiMixin, AccountApiMixin, viewsets.ModelViewSet):
queryset = Database.objects.all()
queryset = Database.objects.prefetch_related('users').all()
serializer_class = DatabaseSerializer
filter_fields = ('name',)
class DatabaseUserViewSet(LogApiMixin, AccountApiMixin, SetPasswordApiMixin, viewsets.ModelViewSet):
queryset = DatabaseUser.objects.all()
queryset = DatabaseUser.objects.prefetch_related('databases').all()
serializer_class = DatabaseUserSerializer
filter_fields = ('username',)

View File

@ -9,6 +9,12 @@ from . import settings
class MySQLBackend(ServiceController):
"""
Simple backend for creating MySQL databases using `CREATE DATABASE` statement.
DATABASES_DEFAULT_HOST = %s
"""
format_docstring = (settings.DATABASES_DEFAULT_HOST,)
verbose_name = "MySQL database"
model = 'databases.Database'
default_route_match = "database.type == 'mysql'"
@ -54,6 +60,11 @@ class MySQLBackend(ServiceController):
class MySQLUserBackend(ServiceController):
"""
Simple backend for creating MySQL users using `CREATE USER` statement.
DATABASES_DEFAULT_HOST = %s
""" % settings.DATABASES_DEFAULT_HOST
verbose_name = "MySQL user"
model = 'databases.DatabaseUser'
default_route_match = "databaseuser.type == 'mysql'"
@ -93,6 +104,10 @@ class MySQLUserBackend(ServiceController):
class MysqlDisk(ServiceMonitor):
"""
du -bs <database_path>
Implements triggers for resource limit exceeded and recovery, disabling insert and create privileges.
"""
model = 'databases.Database'
verbose_name = _("MySQL disk")

View File

@ -11,6 +11,18 @@ from . import settings
class Bind9MasterDomainBackend(ServiceController):
"""
Bind9 zone and config generation.
It auto-discovers slave Bind9 servers based on your routing configuration or you can use DOMAINS_SLAVES to explicitly configure the slaves.
DOMAINS_SLAVES = %s
DOMAINS_MASTERS_PATH = '%s'
"""
format_docstring = (
str(settings.DOMAINS_SLAVES),
settings.DOMAINS_MASTERS_PATH,
)
verbose_name = _("Bind9 master domain")
model = 'domains.Domain'
related_models = (
@ -121,6 +133,12 @@ class Bind9MasterDomainBackend(ServiceController):
class Bind9SlaveDomainBackend(Bind9MasterDomainBackend):
"""
Generate the configuartion for slave servers
It auto-discover the master server based on your routing configuration or you can use DOMAINS_MASTERS to explicitly configure the master.
DOMAINS_MASTERS = %s
""" % str(settings.DOMAINS_MASTERS)
verbose_name = _("Bind9 slave domain")
related_models = (
('domains.Domain', 'origin'),

View File

@ -10,6 +10,19 @@ from .models import List
class MailmanBackend(ServiceController):
"""
Mailman backend based on `newlist`, it handles custom domains.
LISTS_VIRTUAL_ALIAS_PATH = '%s'
LISTS_VIRTUAL_ALIAS_DOMAINS_PATH = '%s'
LISTS_DEFAULT_DOMAIN = '%s'
LISTS_MAILMAN_ROOT_DIR = '%s'
"""
format_docstring = (
settings.LISTS_VIRTUAL_ALIAS_PATH,
settings.LISTS_VIRTUAL_ALIAS_DOMAINS_PATH,
settings.LISTS_DEFAULT_DOMAIN,
settings.LISTS_MAILMAN_ROOT_DIR,
)
verbose_name = "Mailman"
model = 'lists.List'
addresses = [
@ -149,75 +162,15 @@ class MailmanBackend(ServiceController):
return replace(context, "'", '"')
class MailmanTrafficBash(ServiceMonitor):
model = 'lists.List'
resource = ServiceMonitor.TRAFFIC
verbose_name = _("Mailman traffic (Bash)")
def prepare(self):
super(MailmanTraffic, self).prepare()
context = {
'mailman_log': '%s{,.1}' % settings.LISTS_MAILMAN_POST_LOG_PATH,
'current_date': self.current_date.strftime("%Y-%m-%d %H:%M:%S %Z"),
}
self.append(textwrap.dedent("""\
function monitor () {
OBJECT_ID=$1
# Dates convertions are done server-side because of timezone discrepancies
INI_DATE=$(date "+%%Y%%m%%d%%H%%M%%S" -d "$2")
END_DATE=$(date '+%%Y%%m%%d%%H%%M%%S' -d '%(current_date)s')
LIST_NAME="$3"
MAILMAN_LOG=%(mailman_log)s
SUBSCRIBERS=$(list_members ${LIST_NAME} | wc -l)
{
{ grep " post to ${LIST_NAME} " ${MAILMAN_LOG} || echo '\\r'; } \\
| awk -v ini="${INI_DATE}" -v end="${END_DATE}" -v subs="${SUBSCRIBERS}" '
BEGIN {
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"
} {
# Mar 01 08:29:02 2015
month = months[$1]
day = $2
year = $4
split($3, time, ":")
line_date = year month day time[1] time[2] time[3]
if ( line_date > ini && line_date < end)
sum += substr($11, 6, length($11)-6)
} END {
print sum * subs
}' || [[ $? == 1 ]] && true
} | xargs echo ${OBJECT_ID}
}""") % context)
def monitor(self, mail_list):
context = self.get_context(mail_list)
self.append(
'monitor %(object_id)i "%(last_date)s" "%(list_name)s"' % context
)
def get_context(self, mail_list):
context = {
'list_name': mail_list.name,
'object_id': mail_list.pk,
'last_date': self.get_last_date(mail_list.pk).strftime("%Y-%m-%d %H:%M:%S %Z"),
}
return replace(context, "'", '"')
class MailmanTraffic(ServiceMonitor):
"""
Parses mailman log file looking for email size and multiples it by `list_members` count.
LISTS_MAILMAN_POST_LOG_PATH = '%s'
"""
format_docstring = (
settings.LISTS_MAILMAN_POST_LOG_PATH,
)
model = 'lists.List'
resource = ServiceMonitor.TRAFFIC
verbose_name = _("Mailman traffic")
@ -235,13 +188,13 @@ class MailmanTraffic(ServiceMonitor):
import sys
from datetime import datetime
from dateutil import tz
def to_local_timezone(date, tzlocal=tz.tzlocal()):
date = datetime.strptime(date, '%Y-%m-%d %H:%M:%S %Z')
date = date.replace(tzinfo=tz.tzutc())
date = date.astimezone(tzlocal)
return date
postlogs = {postlogs}
# Use local timezone
end_date = to_local_timezone('{current_date}')
@ -261,13 +214,13 @@ class MailmanTraffic(ServiceMonitor):
'Nov': '11',
'Dec': '12',
}}
def prepare(object_id, list_name, ini_date):
global lists
ini_date = to_local_timezone(ini_date)
ini_date = int(ini_date.strftime('%Y%m%d%H%M%S'))
lists[list_name] = [ini_date, object_id, 0]
def monitor(lists, end_date, months, postlogs):
for postlog in postlogs:
try:
@ -318,6 +271,9 @@ class MailmanTraffic(ServiceMonitor):
class MailmanSubscribers(ServiceMonitor):
"""
Monitors number of list subscribers via `list_members`
"""
model = 'lists.List'
verbose_name = _("Mailman subscribers")

View File

@ -8,13 +8,12 @@ from .serializers import AddressSerializer, MailboxSerializer
class AddressViewSet(LogApiMixin, AccountApiMixin, viewsets.ModelViewSet):
queryset = Address.objects.all()
queryset = Address.objects.select_related('domain').prefetch_related('mailboxes').all()
serializer_class = AddressSerializer
class MailboxViewSet(LogApiMixin, SetPasswordApiMixin, AccountApiMixin, viewsets.ModelViewSet):
queryset = Mailbox.objects.all()
queryset = Mailbox.objects.prefetch_related('addresses__domain').all()
serializer_class = MailboxSerializer

View File

@ -20,6 +20,10 @@ logger = logging.getLogger(__name__)
class UNIXUserMaildirBackend(ServiceController):
"""
Assumes that all system users on this servers all mail accounts.
If you want to have system users AND mailboxes on the same server you should consider using virtual mailboxes
"""
verbose_name = _("UNIX maildir user")
model = 'mailboxes.Mailbox'
@ -74,6 +78,9 @@ class UNIXUserMaildirBackend(ServiceController):
class DovecotPostfixPasswdVirtualUserBackend(ServiceController):
"""
WARNING: This backends is not fully implemented
"""
verbose_name = _("Dovecot-Postfix virtualuser")
model = 'mailboxes.Mailbox'
# TODO related_models = ('resources__content_type') ?? needed for updating disk usage from resource.data
@ -176,6 +183,17 @@ class DovecotPostfixPasswdVirtualUserBackend(ServiceController):
class PostfixAddressBackend(ServiceController):
"""
Addresses based on Postfix virtual alias domains.
<tt>MAILBOXES_LOCAL_DOMAIN = '%s'
MAILBOXES_VIRTUAL_ALIAS_DOMAINS_PATH = '%s'
MAILBOXES_VIRTUAL_ALIAS_MAPS_PATH = '%s'</tt>
"""
format_docstring = (
settings.MAILBOXES_LOCAL_DOMAIN,
settings.MAILBOXES_VIRTUAL_ALIAS_DOMAINS_PATH,
settings.MAILBOXES_VIRTUAL_ALIAS_MAPS_PATH,
)
verbose_name = _("Postfix address")
model = 'mailboxes.Address'
related_models = (
@ -267,6 +285,9 @@ class PostfixAddressBackend(ServiceController):
class AutoresponseBackend(ServiceController):
"""
WARNING: not implemented
"""
verbose_name = _("Mail autoresponse")
model = 'mailboxes.Autoresponse'
@ -274,9 +295,13 @@ class AutoresponseBackend(ServiceController):
class DovecotMaildirDisk(ServiceMonitor):
"""
Maildir disk usage based on Dovecot maildirsize file
http://wiki2.dovecot.org/Quota/Maildir
MAILBOXES_MAILDIRSIZE_PATH = '%s'
"""
format_docstring = (
settings.MAILBOXES_MAILDIRSIZE_PATH,
)
model = 'mailboxes.Mailbox'
resource = ServiceMonitor.DISK
verbose_name = _("Dovecot Maildir size")
@ -304,9 +329,13 @@ class DovecotMaildirDisk(ServiceMonitor):
class PostfixMailscannerTraffic(ServiceMonitor):
"""
A high-performance log parser
Reads the mail.log file only once, for all users
A high-performance log parser.
Reads the mail.log file only once, for all users.
MAILBOXES_MAIL_LOG_PATH = '%s'
"""
format_docstring = (
settings.MAILBOXES_MAIL_LOG_PATH,
)
model = 'mailboxes.Mailbox'
resource = ServiceMonitor.TRAFFIC
verbose_name = _("Postfix-Mailscanner traffic")
@ -460,8 +489,3 @@ class PostfixMailscannerTraffic(ServiceMonitor):
'last_date': self.get_last_date(mailbox.pk).strftime("%Y-%m-%d %H:%M:%S %Z"),
}
return replace(context, "'", '"')

View File

@ -25,10 +25,10 @@ class RelatedAddressSerializer(AccountSerializerMixin, serializers.HyperlinkedMo
class Meta:
model = Address
fields = ('url', 'name', 'domain', 'forward')
def from_native(self, data, files=None):
queryset = self.opts.model.objects.filter(account=self.account)
return get_object_or_404(queryset, name=data['name'])
#
# def from_native(self, data, files=None):
# queryset = self.opts.model.objects.filter(account=self.account)
# return get_object_or_404(queryset, name=data['name'])
class MailboxSerializer(AccountSerializerMixin, SetPasswordHyperlinkedSerializer):

View File

@ -25,9 +25,7 @@ class Operation():
self.backend = backend
# instance should maintain any dynamic attribute until backend execution
# deep copy is prefered over copy otherwise objects will share same atributes (queryset cache)
print('aa', getattr(instance, 'password', 'NOOOO'), id(instance))
self.instance = copy.deepcopy(instance)
print('aa', getattr(self.instance, 'password', 'NOOOO'), id(self.instance))
self.action = action
self.servers = servers

View File

@ -6,7 +6,7 @@ from django.utils.translation import ugettext_lazy as _
from orchestra.admin.html import monospace_format
from orchestra.admin.utils import admin_link, admin_date, admin_colored
from . import settings
from . import settings, helpers
from .backends import ServiceBackend
from .models import Server, Route, BackendLog, BackendOperation
from .widgets import RouteBackendSelect
@ -31,10 +31,7 @@ class RouteAdmin(admin.ModelAdmin):
list_filter = ('host', 'is_active', 'backend')
ordering = ('backend',)
BACKEND_HELP_TEXT = {
backend: "This backend operates over '%s'" % ServiceBackend.get_backend(backend).model
for backend, __ in ServiceBackend.get_choices()
}
BACKEND_HELP_TEXT = helpers.get_backends_help_text(ServiceBackend.get_backends())
DEFAULT_MATCH = {
backend.get_name(): backend.default_route_match for backend in ServiceBackend.get_backends()
}

View File

@ -45,6 +45,7 @@ class ServiceBackend(plugins.Plugin, metaclass=ServiceMount):
default_route_match = 'True'
# Force the backend manager to block in multiple backend executions executing them synchronously
block = False
format_docstring = ()
def __str__(self):
return type(self).__name__

View File

@ -1,3 +1,5 @@
import textwrap
from django.contrib import messages
from django.core.mail import mail_admins
from django.core.urlresolvers import reverse
@ -6,6 +8,36 @@ from django.utils.safestring import mark_safe
from django.utils.translation import ungettext, ugettext_lazy as _
def get_backends_help_text(backends):
help_texts = {}
for backend in backends:
context = {
'model': backend.model,
'related_models': str(backend.related_models),
'script_executable': backend.script_executable,
'script_method': str(backend.script_method),
'function_method': str(backend.script_method),
'actions': ', '.join(backend.actions),
}
help_text = textwrap.dedent("""
- Model: '%(model)s'<br>
- Related models: %(related_models)s<br>
- Script executable: %(script_executable)s<br>
- Script method: %(script_method)s<br>
- Function method: %(function_method)s<br>
- Actions: %(actions)s<br>"""
) % context
docstring = backend.__doc__
if docstring:
try:
docstring = (docstring % backend.format_docstring).strip().splitlines()
except TypeError as e:
raise TypeError(str(backend) + str(e))
help_text += '<br>' + '<br>'.join(docstring)
help_texts[backend.get_name()] = help_text
return help_texts
def send_report(method, args, log):
server = args[0]
backend = method.__self__.__class__.__name__

View File

@ -32,5 +32,5 @@ ORCHESTRATION_DISABLE_EXECUTION = getattr(settings, 'ORCHESTRATION_DISABLE_EXECU
ORCHESTRATION_BACKEND_CLEANUP_DELTA = getattr(settings, 'ORCHESTRATION_BACKEND_CLEANUP_DELTA',
timedelta(days=40)
timedelta(days=15)
)

View File

@ -10,6 +10,16 @@ from . import settings
class UNIXUserBackend(ServiceController):
"""
Basic UNIX system user/group support based on `useradd`, `usermod`, `userdel` and `groupdel`.
<tt>SYSTEMUSERS_DEFAULT_GROUP_MEMBERS = '%s'
SYSTEMUSERS_MOVE_ON_DELETE_PATH = '%s'</tt>
"""
format_docstring = (
settings.SYSTEMUSERS_DEFAULT_GROUP_MEMBERS,
settings.SYSTEMUSERS_MOVE_ON_DELETE_PATH,
)
verbose_name = _("UNIX user")
model = 'systemusers.SystemUser'
actions = ('save', 'delete', 'grant_permission')
@ -84,6 +94,9 @@ class UNIXUserBackend(ServiceController):
class UNIXUserDisk(ServiceMonitor):
"""
`du -bs <home>`
"""
model = 'systemusers.SystemUser'
resource = ServiceMonitor.DISK
verbose_name = _('UNIX user disk')
@ -109,6 +122,14 @@ class UNIXUserDisk(ServiceMonitor):
class Exim4Traffic(ServiceMonitor):
"""
Exim4 mainlog parser for mails sent on the webserver by system users (e.g. via PHP mail())
SYSTEMUSERS_MAIL_LOG_PATH = '%s'
"""
format_docstring = (
settings.SYSTEMUSERS_MAIL_LOG_PATH,
)
model = 'systemusers.SystemUser'
resource = ServiceMonitor.TRAFFIC
verbose_name = _("Exim4 traffic")
@ -188,6 +209,13 @@ class Exim4Traffic(ServiceMonitor):
class VsFTPdTraffic(ServiceMonitor):
"""
vsFTPd log parser.
SYSTEMUSERS_FTP_LOG_PATH = '%s'
"""
format_docstring = (
settings.SYSTEMUSERS_FTP_LOG_PATH,
)
model = 'systemusers.SystemUser'
resource = ServiceMonitor.TRAFFIC
verbose_name = _('VsFTPd traffic')
@ -279,4 +307,3 @@ class VsFTPdTraffic(ServiceMonitor):
'username': user.username,
}
return replace(context, "'", '"')

View File

@ -3,6 +3,9 @@ from orchestra.contrib.resources import ServiceMonitor
class OpenVZTraffic(ServiceMonitor):
"""
WARNING: Not fully implemeted
"""
model = 'vps.VPS'
resource = ServiceMonitor.TRAFFIC

View File

@ -5,11 +5,13 @@ from orchestra.contrib.accounts.api import AccountApiMixin
from . import settings
from .models import WebApp
from .options import AppOption
from .serializers import WebAppSerializer
from .types import AppType
class WebAppViewSet(LogApiMixin, AccountApiMixin, viewsets.ModelViewSet):
queryset = WebApp.objects.all()
queryset = WebApp.objects.prefetch_related('options').all()
serializer_class = WebAppSerializer
filter_fields = ('name',)
@ -22,6 +24,31 @@ class WebAppViewSet(LogApiMixin, AccountApiMixin, viewsets.ModelViewSet):
metadata.data['settings'] = {
name.lower(): getattr(settings, name, None) for name in names
}
# AppTypes
meta = self.metadata_class()
app_types = {}
for app_type in AppType.get_plugins():
if app_type.serializer:
data = meta.get_serializer_info(app_type.serializer())
else:
data = {}
options = []
for group, option in app_type.get_options():
options += [opt.name for opt in option]
app_types[app_type.get_name()] = {
'data': data,
'options': options,
}
metadata.data['actions']['types'] = app_types
# Options
options = {}
for option in AppOption.get_plugins():
options[option.get_name()] = {
'verbose_name': option.get_verbose_name(),
'help_text': option.help_text,
'group': option.group,
}
metadata.data['actions']['options'] = options
return metadata

View File

@ -11,6 +11,29 @@ from .. import settings
class PHPBackend(WebAppServiceMixin, ServiceController):
"""
PHP support for apache-mod-fcgid and php-fpm.
It handles switching between these two PHP process management systemes.
WEBAPPS_MERGE_PHP_WEBAPPS = %s
WEBAPPS_FPM_DEFAULT_MAX_CHILDREN = %s
WEBAPPS_PHP_CGI_BINARY_PATH = '%s'
WEBAPPS_PHP_CGI_RC_DIR = '%s'
WEBAPPS_PHP_CGI_INI_SCAN_DIR = '%s'
WEBAPPS_FCGID_CMD_OPTIONS_PATH = '%s'
WEBAPPS_PHPFPM_POOL_PATH = '%s'
WEBAPPS_PHP_MAX_REQUESTS = %s
"""
format_docstring = (
settings.WEBAPPS_MERGE_PHP_WEBAPPS,
settings.WEBAPPS_FPM_DEFAULT_MAX_CHILDREN,
settings.WEBAPPS_PHP_CGI_BINARY_PATH,
settings.WEBAPPS_PHP_CGI_RC_DIR,
settings.WEBAPPS_PHP_CGI_INI_SCAN_DIR,
settings.WEBAPPS_FCGID_CMD_OPTIONS_PATH,
settings.WEBAPPS_PHPFPM_POOL_PATH,
settings.WEBAPPS_PHP_MAX_REQUESTS,
)
verbose_name = _("PHP FPM/FCGID")
default_route_match = "webapp.type.endswith('php')"
MERGE = settings.WEBAPPS_MERGE_PHP_WEBAPPS

View File

@ -13,9 +13,19 @@ from .. import settings
class uWSGIPythonBackend(WebAppServiceMixin, ServiceController):
"""
Emperor mode
http://uwsgi-docs.readthedocs.org/en/latest/Emperor.html
WEBAPPS_UWSGI_BASE_DIR = '%s'
WEBAPPS_PYTHON_MAX_REQUESTS = %s
WEBAPPS_PYTHON_DEFAULT_MAX_WORKERS = %s
WEBAPPS_PYTHON_DEFAULT_TIMEOUT = %s
"""
format_docstring = (
settings.WEBAPPS_UWSGI_BASE_DIR,
settings.WEBAPPS_PYTHON_MAX_REQUESTS,
settings.WEBAPPS_PYTHON_DEFAULT_MAX_WORKERS,
settings.WEBAPPS_PYTHON_DEFAULT_TIMEOUT,
)
verbose_name = _("Python uWSGI")
default_route_match = "webapp.type.endswith('python')"

View File

@ -6,6 +6,10 @@ from . import WebAppServiceMixin
class StaticBackend(WebAppServiceMixin, ServiceController):
"""
Static web pages.
Only creates the webapp dir and leaves the web server the decision to execute CGIs or not.
"""
verbose_name = _("Static")
default_route_match = "webapp.type == 'static'"

View File

@ -8,6 +8,10 @@ from .php import PHPBackend
class SymbolicLinkBackend(PHPBackend, ServiceController):
"""
Same as PHPBackend but allows you to have the webapps on a directory diferent than the webapps dir.
"""
format_docstring = ()
verbose_name = _("Symbolic link webapp")
model = 'webapps.WebApp'
default_route_match = "webapp.type == 'symbolic-link'"

View File

@ -7,7 +7,9 @@ from . import WebAppServiceMixin
# TODO DEPRECATE
class WebalizerAppBackend(WebAppServiceMixin, ServiceController):
""" Needed for cleaning up webalizer main folder when webapp deleteion withou related contents """
"""
Needed for cleaning up webalizer main folder when webapp deleteion withou related contents
"""
verbose_name = _("Webalizer App")
default_route_match = "webapp.type == 'webalizer'"

View File

@ -11,6 +11,14 @@ from . import WebAppServiceMixin
# Based on https://github.com/mtomic/wordpress-install/blob/master/wpinstall.php
class WordPressBackend(WebAppServiceMixin, ServiceController):
"""
Installs the latest version of WordPress available on www.wordpress.org
It fully configures the wp-config.php (keys included) and sets up the database with initial admin password.
WEBAPPS_DEFAULT_MYSQL_DATABASE_HOST = '%s'
"""
format_docstring = (
settings.WEBAPPS_DEFAULT_MYSQL_DATABASE_HOST,
)
verbose_name = _("Wordpress")
model = 'webapps.WebApp'
default_route_match = "webapp.type == 'wordpress-php'"

View File

@ -35,7 +35,7 @@ class WebAppSerializer(AccountSerializerMixin, HyperlinkedModelSerializer):
def update(self, instance, validated_data):
options_data = validated_data.pop('options')
instance = super(WebAppSerializer, self).update(validated_data)
instance = super(WebAppSerializer, self).update(instance, validated_data)
existing = {}
for obj in instance.options.all():
existing[obj.name] = obj

View File

@ -114,6 +114,11 @@ WEBAPPS_UWSGI_SOCKET = getattr(settings, 'WEBAPPS_UWSGI_SOCKET',
)
WEBAPPS_UWSGI_BASE_DIR = getattr(settings, 'WEBAPPS_UWSGI_BASE_DIR',
'/etc/uwsgi/'
)
WEBAPPS_PYTHON_MAX_REQUESTS = getattr(settings, 'WEBAPPS_PYTHON_MAX_REQUESTS',
500
)

View File

@ -9,7 +9,7 @@ from .serializers import WebsiteSerializer
class WebsiteViewSet(LogApiMixin, AccountApiMixin, viewsets.ModelViewSet):
queryset = Website.objects.all()
queryset = Website.objects.prefetch_related('domains', 'content_set__webapp', 'directives').all()
serializer_class = WebsiteSerializer
filter_fields = ('name',)

View File

@ -40,7 +40,7 @@ class Apache2Backend(ServiceController):
extra_conf = sorted(extra_conf, key=lambda a: len(a[0]), reverse=True)
context['extra_conf'] = '\n'.join([conf for location, conf in extra_conf])
return Template(textwrap.dedent("""\
<VirtualHost {% for ip in ips %}{{ ip }}:{{ port }} {% endfor %}>
<VirtualHost{% for ip in ips %} {{ ip }}:{{ port }}{% endfor %}>
IncludeOptional /etc/apache2/site[s]-override/{{ site_unique_name }}.con[f]
ServerName {{ server_name }}\
{% if server_alias %}
@ -59,7 +59,7 @@ class Apache2Backend(ServiceController):
def render_redirect_https(self, context):
context['port'] = self.HTTP_PORT
return Template(textwrap.dedent("""
<VirtualHost {% for ip in ips %}{{ ip }}:{{ port }} {% endfor %}>
<VirtualHost{% for ip in ips %} {{ ip }}:{{ port }}{% endfor %}>
ServerName {{ server_name }}\
{% if server_alias %}
ServerAlias {{ server_alias|join:' ' }}{% endif %}\

View File

@ -9,6 +9,9 @@ from .. import settings
class WebalizerBackend(ServiceController):
"""
Creates webalizer conf file for each time a webalizer webapp is mounted on a website.
"""
verbose_name = _("Webalizer Content")
model = 'websites.Content'
default_route_match = "content.webapp.type == 'webalizer'"

View File

@ -82,7 +82,7 @@ class WebsiteSerializer(AccountSerializerMixin, HyperlinkedModelSerializer):
def update(self, instance, validated_data):
options_data = validated_data.pop('options')
instance = super(WebsiteSerializer, self).update(validated_data)
instance = super(WebsiteSerializer, self).update(instance, validated_data)
existing = {}
for obj in instance.options.all():
existing[obj.name] = obj