Improved performance of webapps and websites change lists
This commit is contained in:
parent
50ff252be7
commit
4301d76011
|
@ -11,6 +11,7 @@ Orchestra is a Django-based framework for building web hosting control panels.
|
||||||
|
|
||||||
Motivation
|
Motivation
|
||||||
----------
|
----------
|
||||||
|
|
||||||
There are a lot of widely used open source hosting control panels, however, none of them seems apropiate when you already have an existing service infrastructure or simply you want your services to run on a particular architecture.
|
There are a lot of widely used open source hosting control panels, however, none of them seems apropiate when you already have an existing service infrastructure or simply you want your services to run on a particular architecture.
|
||||||
|
|
||||||
The goal of this project is to provide the tools for easily build a fully featured control panel that is not tied to any particular service architecture.
|
The goal of this project is to provide the tools for easily build a fully featured control panel that is not tied to any particular service architecture.
|
||||||
|
@ -33,9 +34,9 @@ Overview
|
||||||
Fast Deployment Setup
|
Fast Deployment Setup
|
||||||
---------------------
|
---------------------
|
||||||
|
|
||||||
This deployment is **not suitable for production** but more than enough for checking out this project. Checkout the steps for other deployments:
|
This deployment is **not suitable for production** but more than enough for checking out this project. For other deployments checkout these links:
|
||||||
* [development](INSTALLDEV.md)
|
* [Development](INSTALLDEV.md)
|
||||||
* [production](INSTALL.md)
|
* [Production](INSTALL.md)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Create and activate a Python virtualenv
|
# Create and activate a Python virtualenv
|
||||||
|
|
|
@ -50,13 +50,15 @@ class WebAppOptionInline(admin.TabularInline):
|
||||||
|
|
||||||
|
|
||||||
class WebAppAdmin(SelectPluginAdminMixin, AccountAdminMixin, ExtendedModelAdmin):
|
class WebAppAdmin(SelectPluginAdminMixin, AccountAdminMixin, ExtendedModelAdmin):
|
||||||
list_display = ('name', 'display_type', 'display_detail', 'display_websites', 'account_link')
|
list_display = (
|
||||||
|
'name', 'display_type', 'display_detail', 'display_websites', 'account_link'
|
||||||
|
)
|
||||||
list_filter = ('type', HasWebsiteListFilter, PHPVersionListFilter)
|
list_filter = ('type', HasWebsiteListFilter, PHPVersionListFilter)
|
||||||
inlines = [WebAppOptionInline]
|
inlines = [WebAppOptionInline]
|
||||||
readonly_fields = ('account_link', )
|
readonly_fields = ('account_link', )
|
||||||
change_readonly_fields = ('name', 'type', 'display_websites')
|
change_readonly_fields = ('name', 'type', 'display_websites')
|
||||||
search_fields = ('name', 'account__username', 'data', 'website__domains__name')
|
search_fields = ('name', 'account__username', 'data', 'website__domains__name')
|
||||||
list_prefetch_related = ('content_set__website',)
|
list_prefetch_related = ('content_set__website', 'content_set__website__domains')
|
||||||
plugin = AppType
|
plugin = AppType
|
||||||
plugin_field = 'type'
|
plugin_field = 'type'
|
||||||
plugin_title = _("Web application type")
|
plugin_title = _("Web application type")
|
||||||
|
@ -67,7 +69,8 @@ class WebAppAdmin(SelectPluginAdminMixin, AccountAdminMixin, ExtendedModelAdmin)
|
||||||
def display_websites(self, webapp):
|
def display_websites(self, webapp):
|
||||||
websites = []
|
websites = []
|
||||||
for content in webapp.content_set.all():
|
for content in webapp.content_set.all():
|
||||||
site_link = get_on_site_link(content.get_absolute_url())
|
site_url = content.get_absolute_url()
|
||||||
|
site_link = get_on_site_link(site_url)
|
||||||
website = content.website
|
website = content.website
|
||||||
admin_url = change_url(website)
|
admin_url = change_url(website)
|
||||||
name = "%s on %s" % (website.name, content.path)
|
name = "%s on %s" % (website.name, content.path)
|
||||||
|
|
|
@ -55,7 +55,8 @@ class WebAppServiceMixin(object):
|
||||||
self.append("rm -fr %(app_path)s" % context)
|
self.append("rm -fr %(app_path)s" % context)
|
||||||
|
|
||||||
def get_context(self, webapp):
|
def get_context(self, webapp):
|
||||||
context = {
|
context = webapp.type_instance.get_directive_context()
|
||||||
|
context.update({
|
||||||
'user': webapp.get_username(),
|
'user': webapp.get_username(),
|
||||||
'group': webapp.get_groupname(),
|
'group': webapp.get_groupname(),
|
||||||
'app_name': webapp.name,
|
'app_name': webapp.name,
|
||||||
|
@ -64,7 +65,7 @@ class WebAppServiceMixin(object):
|
||||||
'banner': self.get_banner(),
|
'banner': self.get_banner(),
|
||||||
'under_construction_path': settings.WEBAPPS_UNDER_CONSTRUCTION_PATH,
|
'under_construction_path': settings.WEBAPPS_UNDER_CONSTRUCTION_PATH,
|
||||||
'is_mounted': webapp.content_set.exists(),
|
'is_mounted': webapp.content_set.exists(),
|
||||||
}
|
})
|
||||||
context['deleted_app_path'] = settings.WEBAPPS_MOVE_ON_DELETE_PATH % context
|
context['deleted_app_path'] = settings.WEBAPPS_MOVE_ON_DELETE_PATH % context
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
|
@ -167,6 +167,7 @@ class PHPBackend(WebAppServiceMixin, ServiceController):
|
||||||
echo "$state" | grep -v ' RESTART$' || is_last=1
|
echo "$state" | grep -v ' RESTART$' || is_last=1
|
||||||
}
|
}
|
||||||
if [[ $is_last -eq 1 ]]; then
|
if [[ $is_last -eq 1 ]]; then
|
||||||
|
echo "Last backend to run, update: $UPDATED_APACHE, state: '$state'"
|
||||||
if [[ $UPDATED_APACHE -eq 1 || "$state" =~ .*RESTART$ ]]; then
|
if [[ $UPDATED_APACHE -eq 1 || "$state" =~ .*RESTART$ ]]; then
|
||||||
if service apache2 status > /dev/null; then
|
if service apache2 status > /dev/null; then
|
||||||
service apache2 reload
|
service apache2 reload
|
||||||
|
@ -280,10 +281,8 @@ class PHPBackend(WebAppServiceMixin, ServiceController):
|
||||||
return context
|
return context
|
||||||
|
|
||||||
def get_context(self, webapp):
|
def get_context(self, webapp):
|
||||||
context = super(PHPBackend, self).get_context(webapp)
|
context = super().get_context(webapp)
|
||||||
context.update({
|
context.update({
|
||||||
'php_version': webapp.type_instance.get_php_version(),
|
|
||||||
'php_version_number': webapp.type_instance.get_php_version_number(),
|
|
||||||
'max_requests': settings.WEBAPPS_PHP_MAX_REQUESTS,
|
'max_requests': settings.WEBAPPS_PHP_MAX_REQUESTS,
|
||||||
})
|
})
|
||||||
self.update_fpm_context(webapp, context)
|
self.update_fpm_context(webapp, context)
|
||||||
|
|
|
@ -4,8 +4,8 @@ from orchestra.settings import ORCHESTRA_BASE_DOMAIN
|
||||||
from .. import webapps
|
from .. import webapps
|
||||||
|
|
||||||
|
|
||||||
_names = ('home', 'user', 'group', 'app_type', 'app_name', 'app_type', 'app_id')
|
_names = ('home', 'user', 'user_id', 'group', 'app_type', 'app_name', 'app_type', 'app_id', 'account_id')
|
||||||
_php_names = _names + ('php_version', 'php_version_number',)
|
_php_names = _names + ('php_version', 'php_version_number', 'php_version_int')
|
||||||
_python_names = _names + ('python_version', 'python_version_number',)
|
_python_names = _names + ('python_version', 'python_version_number',)
|
||||||
|
|
||||||
|
|
||||||
|
@ -17,8 +17,11 @@ WEBAPPS_BASE_DIR = Setting('WEBAPPS_BASE_DIR',
|
||||||
|
|
||||||
|
|
||||||
WEBAPPS_FPM_LISTEN = Setting('WEBAPPS_FPM_LISTEN',
|
WEBAPPS_FPM_LISTEN = Setting('WEBAPPS_FPM_LISTEN',
|
||||||
'/opt/php/5.4/socks/%(user)s-%(app_name)s.sock',
|
'127.0.0.1:5%(app_id)04d',
|
||||||
help_text=("TCP socket example: <tt>127.0.0.1:9%(app_id)03d</tt><br>"
|
help_text=("TCP socket example: <tt>127.0.0.1:5%(app_id)04d</tt><br>"
|
||||||
|
"UDS example: <tt>/var/lib/php/sockets/%(user)s-%(app_name)s.sock</tt><br>"
|
||||||
|
"Merged TCP example: <tt>127.0.0.1:%(php_version_int)02d%(account_id)03d</tt></br>"
|
||||||
|
"Merged UDS example: <tt>/var/lib/php/sockets/%(user)s-%(php_version)s.sock</tt></br>"
|
||||||
"Available fromat names: <tt>{}</tt>").format(', '.join(_php_names)),
|
"Available fromat names: <tt>{}</tt>").format(', '.join(_php_names)),
|
||||||
validators=[Setting.string_format_validator(_php_names)],
|
validators=[Setting.string_format_validator(_php_names)],
|
||||||
)
|
)
|
||||||
|
|
|
@ -85,6 +85,8 @@ class AppType(plugins.Plugin, metaclass=plugins.PluginMount):
|
||||||
return {
|
return {
|
||||||
'app_id': self.instance.id,
|
'app_id': self.instance.id,
|
||||||
'app_name': self.instance.name,
|
'app_name': self.instance.name,
|
||||||
'user': self.instance.account.username,
|
'user': self.instance.get_username(),
|
||||||
|
'user_id': self.instance.account.main_systemuser_id,
|
||||||
'home': self.instance.account.main_systemuser.get_home(),
|
'home': self.instance.account.main_systemuser.get_home(),
|
||||||
|
'account_id': self.instance.account_id,
|
||||||
}
|
}
|
||||||
|
|
|
@ -121,7 +121,6 @@ class PHPApp(AppType):
|
||||||
init_vars['post_max_size'] = post_max_size
|
init_vars['post_max_size'] = post_max_size
|
||||||
if upload_max_filesize_value > post_max_size_value:
|
if upload_max_filesize_value > post_max_size_value:
|
||||||
init_vars['post_max_size'] = upload_max_filesize
|
init_vars['post_max_size'] = upload_max_filesize
|
||||||
print(init_vars)
|
|
||||||
return init_vars
|
return init_vars
|
||||||
|
|
||||||
def get_directive_context(self):
|
def get_directive_context(self):
|
||||||
|
@ -129,6 +128,7 @@ class PHPApp(AppType):
|
||||||
context.update({
|
context.update({
|
||||||
'php_version': self.get_php_version(),
|
'php_version': self.get_php_version(),
|
||||||
'php_version_number': self.get_php_version_number(),
|
'php_version_number': self.get_php_version_number(),
|
||||||
|
'php_version_int': int(self.get_php_version_number().replace('.', '')),
|
||||||
})
|
})
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ from orchestra.admin.utils import admin_link, change_url
|
||||||
from orchestra.contrib.accounts.actions import list_accounts
|
from orchestra.contrib.accounts.actions import list_accounts
|
||||||
from orchestra.contrib.accounts.admin import AccountAdminMixin, SelectAccountAdminMixin
|
from orchestra.contrib.accounts.admin import AccountAdminMixin, SelectAccountAdminMixin
|
||||||
from orchestra.forms.widgets import DynamicHelpTextSelect
|
from orchestra.forms.widgets import DynamicHelpTextSelect
|
||||||
|
from orchestra.utils.html import get_on_site_link
|
||||||
|
|
||||||
from .directives import SiteDirective
|
from .directives import SiteDirective
|
||||||
from .forms import WebsiteAdminForm, WebsiteDirectiveInlineFormSet
|
from .forms import WebsiteAdminForm, WebsiteDirectiveInlineFormSet
|
||||||
|
@ -84,10 +85,16 @@ class WebsiteAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
|
||||||
def display_webapps(self, website):
|
def display_webapps(self, website):
|
||||||
webapps = []
|
webapps = []
|
||||||
for content in website.content_set.all():
|
for content in website.content_set.all():
|
||||||
|
site_link = get_on_site_link(content.get_absolute_url())
|
||||||
webapp = content.webapp
|
webapp = content.webapp
|
||||||
|
detail = webapp.get_type_display()
|
||||||
|
try:
|
||||||
|
detail += ' ' + webapp.type_instance.get_detail()
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
url = change_url(webapp)
|
url = change_url(webapp)
|
||||||
name = "%s on %s" % (webapp.name, content.path or '/')
|
name = "%s on %s" % (webapp.name, content.path or '/')
|
||||||
webapps.append('<a href="%s">%s</a>' % (url, name))
|
webapps.append('<a href="%s" title="%s">%s %s</a>' % (url, detail, name, site_link))
|
||||||
return '<br>'.join(webapps)
|
return '<br>'.join(webapps)
|
||||||
display_webapps.allow_tags = True
|
display_webapps.allow_tags = True
|
||||||
display_webapps.short_description = _("Web apps")
|
display_webapps.short_description = _("Web apps")
|
||||||
|
|
|
@ -160,6 +160,7 @@ class Apache2Backend(ServiceController):
|
||||||
echo "$state" | grep -v ' RESTART$' || is_last=1
|
echo "$state" | grep -v ' RESTART$' || is_last=1
|
||||||
}
|
}
|
||||||
if [[ $is_last -eq 1 ]]; then
|
if [[ $is_last -eq 1 ]]; then
|
||||||
|
echo "Last backend to run, update: $UPDATED_APACHE, state: '$state'"
|
||||||
if [[ $UPDATED_APACHE -eq 1 || "$state" =~ .*RESTART$ ]]; then
|
if [[ $UPDATED_APACHE -eq 1 || "$state" =~ .*RESTART$ ]]; then
|
||||||
if service apache2 status > /dev/null; then
|
if service apache2 status > /dev/null; then
|
||||||
service apache2 reload
|
service apache2 reload
|
||||||
|
@ -218,6 +219,7 @@ class Apache2Backend(ServiceController):
|
||||||
# UNIX socket
|
# UNIX socket
|
||||||
target = 'unix:%(socket)s|fcgi://127.0.0.1%(app_path)s/'
|
target = 'unix:%(socket)s|fcgi://127.0.0.1%(app_path)s/'
|
||||||
if context['location']:
|
if context['location']:
|
||||||
|
# FIXME unix sockets do not support $1
|
||||||
target = 'unix:%(socket)s|fcgi://127.0.0.1%(app_path)s/$1'
|
target = 'unix:%(socket)s|fcgi://127.0.0.1%(app_path)s/$1'
|
||||||
context.update({
|
context.update({
|
||||||
'app_path': os.path.normpath(app_path),
|
'app_path': os.path.normpath(app_path),
|
||||||
|
|
|
@ -83,8 +83,11 @@ class Website(models.Model):
|
||||||
return directives
|
return directives
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
domain = self.domains.first()
|
try:
|
||||||
if domain:
|
domain = self.domains.all()[0]
|
||||||
|
except IndexError:
|
||||||
|
return
|
||||||
|
else:
|
||||||
return '%s://%s' % (self.get_protocol(), domain)
|
return '%s://%s' % (self.get_protocol(), domain)
|
||||||
|
|
||||||
def get_user(self):
|
def get_user(self):
|
||||||
|
@ -113,7 +116,7 @@ class WebsiteDirective(models.Model):
|
||||||
website = models.ForeignKey(Website, verbose_name=_("web site"),
|
website = models.ForeignKey(Website, verbose_name=_("web site"),
|
||||||
related_name='directives')
|
related_name='directives')
|
||||||
name = models.CharField(_("name"), max_length=128,
|
name = models.CharField(_("name"), max_length=128,
|
||||||
choices=SiteDirective.get_choices())
|
choices=SiteDirective.get_choices())
|
||||||
value = models.CharField(_("value"), max_length=256)
|
value = models.CharField(_("value"), max_length=256)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
@ -157,6 +160,9 @@ class Content(models.Model):
|
||||||
self.path = '/'
|
self.path = '/'
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
domain = self.website.domains.first()
|
try:
|
||||||
if domain:
|
domain = self.website.domains.all()[0]
|
||||||
|
except IndexError:
|
||||||
|
return
|
||||||
|
else:
|
||||||
return '%s://%s%s' % (self.website.get_protocol(), domain, self.path)
|
return '%s://%s%s' % (self.website.get_protocol(), domain, self.path)
|
||||||
|
|
|
@ -29,7 +29,7 @@ def html_to_pdf(html, pagination=False):
|
||||||
|
|
||||||
def get_on_site_link(url):
|
def get_on_site_link(url):
|
||||||
context = {
|
context = {
|
||||||
'title': _("View on site"),
|
'title': _("View on site %s") % url,
|
||||||
'url': url,
|
'url': url,
|
||||||
'image': '<img src="%s"></img>' % static('orchestra/images/view-on-site.png'),
|
'image': '<img src="%s"></img>' % static('orchestra/images/view-on-site.png'),
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue