ESBORRANY - DRAFT - BORRADOR
+A related website will be automatically configured if needed.', verbose_name='custom URL'), + ), + migrations.AlterField( + model_name='saas', + name='name', + field=models.CharField(help_text='Required. 64 characters or fewer. Letters, digits and ./- only.', max_length=64, validators=[orchestra.core.validators.validate_hostname], verbose_name='Name'), + ), + migrations.AlterField( + model_name='saas', + name='service', + field=models.CharField(choices=[('bscw', 'BSCW'), ('dokuwiki', 'Dowkuwiki'), ('drupal', 'Drupal'), ('gitlab', 'GitLab'), ('moodle', 'Moodle'), ('wordpress', 'WordPress'), ('nextcloud', 'nextCloud'), ('owncloud', 'ownCloud'), ('phplist', 'phpList')], max_length=32, verbose_name='service'), + ), + ] diff --git a/orchestra/contrib/saas/models.py b/orchestra/contrib/saas/models.py index b5b4e23e..ee1423b1 100644 --- a/orchestra/contrib/saas/models.py +++ b/orchestra/contrib/saas/models.py @@ -70,7 +70,7 @@ class SaaS(models.Model): self.save(update_fields=('is_active',)) def enable(self): - self.is_active = False + self.is_active = True self.save(update_fields=('is_active',)) def clean(self): diff --git a/orchestra/contrib/saas/services/helpers.py b/orchestra/contrib/saas/services/helpers.py index 03ed1e20..bf081995 100644 --- a/orchestra/contrib/saas/services/helpers.py +++ b/orchestra/contrib/saas/services/helpers.py @@ -6,6 +6,7 @@ from django.utils.translation import ugettext_lazy as _ from orchestra.contrib.websites.models import Website, WebsiteDirective, Content from orchestra.contrib.websites.validators import validate_domain_protocol +from orchestra.contrib.orchestration.models import Server from orchestra.utils.python import AttrDict @@ -54,7 +55,9 @@ def clean_custom_url(saas): (url.netloc, account, domain.account), }) # Create new website for custom_url - website = Website(name=url.netloc, protocol=protocol, account=account) + # Changed by daniel: hardcode target_server to web.pangea.lan, consider putting it into settings.py + tgt_server = Server.objects.get(name='web.pangea.lan') + website = Website(name=url.netloc, protocol=protocol, account=account, target_server=tgt_server) full_clean(website) try: validate_domain_protocol(website, domain, protocol) @@ -110,7 +113,8 @@ def create_or_update_directive(saas): Domain = Website.domains.field.rel.to domain = Domain.objects.get(name=url.netloc) # Create new website for custom_url - website = Website(name=url.netloc, protocol=protocol, account=account) + tgt_server = Server.objects.get(name='web.pangea.lan') + website = Website(name=url.netloc, protocol=protocol, account=account, target_server=tgt_server) website.save() website.domains.add(domain) # get or create directive diff --git a/orchestra/contrib/services/migrations/0006_auto_20170528_2005.py b/orchestra/contrib/services/migrations/0006_auto_20170528_2005.py new file mode 100644 index 00000000..1f59952b --- /dev/null +++ b/orchestra/contrib/services/migrations/0006_auto_20170528_2005.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.5 on 2017-05-28 18:05 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('services', '0005_auto_20160427_1531'), + ] + + operations = [ + migrations.AlterField( + model_name='service', + name='rate_algorithm', + field=models.CharField(choices=[('orchestra.contrib.plans.ratings.best_price', 'Best price'), ('orchestra.contrib.plans.ratings.step_price', 'Step price'), ('orchestra.contrib.plans.ratings.match_price', 'Match price')], default='orchestra.contrib.plans.ratings.step_price', help_text='Algorithm used to interprete the rating table.
Best price: Produces the best possible price given all active rating lines (those with quantity lower or equal to the metric).
Step price: All rates with a quantity lower or equal than the metric are applied. Nominal price will be used when initial block is missing.
Match price: Only the rate with a) inmediate inferior metric and b) lower price is applied. Nominal price will be used when initial block is missing.', max_length=64, verbose_name='rate algorithm'), + ), + ] diff --git a/orchestra/contrib/services/migrations/0007_auto_20170528_2011.py b/orchestra/contrib/services/migrations/0007_auto_20170528_2011.py new file mode 100644 index 00000000..d11e961a --- /dev/null +++ b/orchestra/contrib/services/migrations/0007_auto_20170528_2011.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.5 on 2017-05-28 18:11 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('services', '0006_auto_20170528_2005'), + ] + + operations = [ + migrations.AlterField( + model_name='service', + name='rate_algorithm', + field=models.CharField(choices=[('orchestra.contrib.plans.ratings.step_price', 'Step price'), ('orchestra.contrib.plans.ratings.best_price', 'Best price'), ('orchestra.contrib.plans.ratings.match_price', 'Match price')], default='orchestra.contrib.plans.ratings.step_price', help_text='Algorithm used to interprete the rating table.
Step price: All rates with a quantity lower or equal than the metric are applied. Nominal price will be used when initial block is missing.
Best price: Produces the best possible price given all active rating lines (those with quantity lower or equal to the metric).
Match price: Only the rate with a) inmediate inferior metric and b) lower price is applied. Nominal price will be used when initial block is missing.', max_length=64, verbose_name='rate algorithm'), + ), + ] diff --git a/orchestra/contrib/services/migrations/0008_auto_20170625_1813.py b/orchestra/contrib/services/migrations/0008_auto_20170625_1813.py new file mode 100644 index 00000000..a00a05e7 --- /dev/null +++ b/orchestra/contrib/services/migrations/0008_auto_20170625_1813.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.5 on 2017-06-25 16:13 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('services', '0007_auto_20170528_2011'), + ] + + operations = [ + migrations.AlterField( + model_name='service', + name='rate_algorithm', + field=models.CharField(choices=[('orchestra.contrib.plans.ratings.best_price', 'Best price'), ('orchestra.contrib.plans.ratings.step_price', 'Step price'), ('orchestra.contrib.plans.ratings.match_price', 'Match price')], default='orchestra.contrib.plans.ratings.step_price', help_text='Algorithm used to interprete the rating table.
Best price: Produces the best possible price given all active rating lines (those with quantity lower or equal to the metric).
Step price: All rates with a quantity lower or equal than the metric are applied. Nominal price will be used when initial block is missing.
Match price: Only the rate with a) inmediate inferior metric and b) lower price is applied. Nominal price will be used when initial block is missing.', max_length=64, verbose_name='rate algorithm'), + ), + ] diff --git a/orchestra/contrib/services/migrations/0009_auto_20170625_1840.py b/orchestra/contrib/services/migrations/0009_auto_20170625_1840.py new file mode 100644 index 00000000..29eb3d52 --- /dev/null +++ b/orchestra/contrib/services/migrations/0009_auto_20170625_1840.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.5 on 2017-06-25 16:40 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('services', '0008_auto_20170625_1813'), + ] + + operations = [ + migrations.AlterField( + model_name='service', + name='rate_algorithm', + field=models.CharField(choices=[('orchestra.contrib.plans.ratings.match_price', 'Match price'), ('orchestra.contrib.plans.ratings.best_price', 'Best price'), ('orchestra.contrib.plans.ratings.step_price', 'Step price')], default='orchestra.contrib.plans.ratings.step_price', help_text='Algorithm used to interprete the rating table.
Match price: Only the rate with a) inmediate inferior metric and b) lower price is applied. Nominal price will be used when initial block is missing.
Best price: Produces the best possible price given all active rating lines (those with quantity lower or equal to the metric).
Step price: All rates with a quantity lower or equal than the metric are applied. Nominal price will be used when initial block is missing.', max_length=64, verbose_name='rate algorithm'), + ), + ] diff --git a/orchestra/contrib/services/migrations/0010_auto_20170625_1840.py b/orchestra/contrib/services/migrations/0010_auto_20170625_1840.py new file mode 100644 index 00000000..f59f304d --- /dev/null +++ b/orchestra/contrib/services/migrations/0010_auto_20170625_1840.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.5 on 2017-06-25 16:40 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('services', '0009_auto_20170625_1840'), + ] + + operations = [ + migrations.AlterField( + model_name='service', + name='rate_algorithm', + field=models.CharField(choices=[('orchestra.contrib.plans.ratings.best_price', 'Best price'), ('orchestra.contrib.plans.ratings.match_price', 'Match price'), ('orchestra.contrib.plans.ratings.step_price', 'Step price')], default='orchestra.contrib.plans.ratings.step_price', help_text='Algorithm used to interprete the rating table.
Best price: Produces the best possible price given all active rating lines (those with quantity lower or equal to the metric).
Match price: Only the rate with a) inmediate inferior metric and b) lower price is applied. Nominal price will be used when initial block is missing.
Step price: All rates with a quantity lower or equal than the metric are applied. Nominal price will be used when initial block is missing.', max_length=64, verbose_name='rate algorithm'), + ), + ] diff --git a/orchestra/contrib/services/migrations/0011_auto_20170625_1840.py b/orchestra/contrib/services/migrations/0011_auto_20170625_1840.py new file mode 100644 index 00000000..6018a17e --- /dev/null +++ b/orchestra/contrib/services/migrations/0011_auto_20170625_1840.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.5 on 2017-06-25 16:40 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('services', '0010_auto_20170625_1840'), + ] + + operations = [ + migrations.AlterField( + model_name='service', + name='rate_algorithm', + field=models.CharField(choices=[('orchestra.contrib.plans.ratings.match_price', 'Match price'), ('orchestra.contrib.plans.ratings.best_price', 'Best price'), ('orchestra.contrib.plans.ratings.step_price', 'Step price')], default='orchestra.contrib.plans.ratings.step_price', help_text='Algorithm used to interprete the rating table.
Match price: Only the rate with a) inmediate inferior metric and b) lower price is applied. Nominal price will be used when initial block is missing.
Best price: Produces the best possible price given all active rating lines (those with quantity lower or equal to the metric).
Step price: All rates with a quantity lower or equal than the metric are applied. Nominal price will be used when initial block is missing.', max_length=64, verbose_name='rate algorithm'), + ), + ] diff --git a/orchestra/contrib/services/migrations/0012_auto_20170625_1841.py b/orchestra/contrib/services/migrations/0012_auto_20170625_1841.py new file mode 100644 index 00000000..e4cd2468 --- /dev/null +++ b/orchestra/contrib/services/migrations/0012_auto_20170625_1841.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.5 on 2017-06-25 16:41 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('services', '0011_auto_20170625_1840'), + ] + + operations = [ + migrations.AlterField( + model_name='service', + name='rate_algorithm', + field=models.CharField(choices=[('orchestra.contrib.plans.ratings.best_price', 'Best price'), ('orchestra.contrib.plans.ratings.step_price', 'Step price'), ('orchestra.contrib.plans.ratings.match_price', 'Match price')], default='orchestra.contrib.plans.ratings.step_price', help_text='Algorithm used to interprete the rating table.
Best price: Produces the best possible price given all active rating lines (those with quantity lower or equal to the metric).
Step price: All rates with a quantity lower or equal than the metric are applied. Nominal price will be used when initial block is missing.
Match price: Only the rate with a) inmediate inferior metric and b) lower price is applied. Nominal price will be used when initial block is missing.', max_length=64, verbose_name='rate algorithm'), + ), + ] diff --git a/orchestra/contrib/services/migrations/0013_auto_20190805_1134.py b/orchestra/contrib/services/migrations/0013_auto_20190805_1134.py new file mode 100644 index 00000000..e568b4d5 --- /dev/null +++ b/orchestra/contrib/services/migrations/0013_auto_20190805_1134.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.5 on 2019-08-05 09:34 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('services', '0012_auto_20170625_1841'), + ] + + operations = [ + migrations.AlterField( + model_name='service', + name='rate_algorithm', + field=models.CharField(choices=[('orchestra.contrib.plans.ratings.match_price', 'Match price'), ('orchestra.contrib.plans.ratings.best_price', 'Best price'), ('orchestra.contrib.plans.ratings.step_price', 'Step price')], default='orchestra.contrib.plans.ratings.step_price', help_text='Algorithm used to interprete the rating table.
Match price: Only the rate with a) inmediate inferior metric and b) lower price is applied. Nominal price will be used when initial block is missing.
Best price: Produces the best possible price given all active rating lines (those with quantity lower or equal to the metric).
Step price: All rates with a quantity lower or equal than the metric are applied. Nominal price will be used when initial block is missing.', max_length=64, verbose_name='rate algorithm'), + ), + ] diff --git a/orchestra/contrib/services/migrations/0014_auto_20200204_1218.py b/orchestra/contrib/services/migrations/0014_auto_20200204_1218.py new file mode 100644 index 00000000..057b1955 --- /dev/null +++ b/orchestra/contrib/services/migrations/0014_auto_20200204_1218.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.5 on 2020-02-04 11:18 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('services', '0013_auto_20190805_1134'), + ] + + operations = [ + migrations.AlterField( + model_name='service', + name='rate_algorithm', + field=models.CharField(choices=[('orchestra.contrib.plans.ratings.best_price', 'Best price'), ('orchestra.contrib.plans.ratings.match_price', 'Match price'), ('orchestra.contrib.plans.ratings.step_price', 'Step price')], default='orchestra.contrib.plans.ratings.step_price', help_text='Algorithm used to interprete the rating table.
Best price: Produces the best possible price given all active rating lines (those with quantity lower or equal to the metric).
Match price: Only the rate with a) inmediate inferior metric and b) lower price is applied. Nominal price will be used when initial block is missing.
Step price: All rates with a quantity lower or equal than the metric are applied. Nominal price will be used when initial block is missing.', max_length=64, verbose_name='rate algorithm'), + ), + ] diff --git a/orchestra/contrib/systemusers/backends.py b/orchestra/contrib/systemusers/backends.py index f8b9f875..22dde957 100644 --- a/orchestra/contrib/systemusers/backends.py +++ b/orchestra/contrib/systemusers/backends.py @@ -28,6 +28,14 @@ class UNIXUserController(ServiceController): context = self.get_context(user) if not context['user']: return + if not user.active: + self.append(textwrap.dedent(""" + #Just disable that user, if it exists + if id %(user)s ; then + usermod %(user)s --password '%(password)s' + fi + """) % context) + return # TODO userd add will fail if %(user)s group already exists self.append(textwrap.dedent(""" # Update/create user state for %(user)s @@ -61,7 +69,8 @@ class UNIXUserController(ServiceController): if context['home'] != context['base_home']: self.append(textwrap.dedent("""\ # Set extra permissions: %(user)s home is inside %(mainuser)s home - if mount | grep "^$(df %(home)s|grep '^/'|cut -d' ' -f1)\s" | grep acl > /dev/null; then + if true; then +# if mount | grep "^$(df %(home)s|grep '^/'|cut -d' ' -f1)\s" | grep acl > /dev/null; then # Account group as the owner chown %(mainuser)s:%(mainuser)s '%(home)s' chmod g+s '%(home)s' diff --git a/orchestra/contrib/systemusers/migrations/0003_auto_20170528_2011.py b/orchestra/contrib/systemusers/migrations/0003_auto_20170528_2011.py new file mode 100644 index 00000000..0556f593 --- /dev/null +++ b/orchestra/contrib/systemusers/migrations/0003_auto_20170528_2011.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.5 on 2017-05-28 18:11 +from __future__ import unicode_literals + +from django.db import migrations, models +import orchestra.core.validators + + +class Migration(migrations.Migration): + + dependencies = [ + ('systemusers', '0002_auto_20150429_1413'), + ] + + operations = [ + migrations.AlterField( + model_name='systemuser', + name='shell', + field=models.CharField(choices=[('/dev/null', 'No shell, FTP only'), ('/bin/rssh', 'No shell, SFTP/RSYNC only'), ('/usr/bin/git-shell', 'No shell, GIT only'), ('/bin/bash', '/bin/bash')], default='/dev/null', max_length=32, verbose_name='shell'), + ), + migrations.AlterField( + model_name='systemuser', + name='username', + field=models.CharField(help_text='Required. 32 characters or fewer. Letters, digits and ./-/_ only.', max_length=32, unique=True, validators=[orchestra.core.validators.validate_username], verbose_name='username'), + ), + ] diff --git a/orchestra/contrib/systemusers/models.py b/orchestra/contrib/systemusers/models.py index ebd15def..de60a698 100644 --- a/orchestra/contrib/systemusers/models.py +++ b/orchestra/contrib/systemusers/models.py @@ -88,7 +88,7 @@ class SystemUser(models.Model): self.save(update_fields=('is_active',)) def enable(self): - self.is_active = False + self.is_active = True self.save(update_fields=('is_active',)) def get_description(self): diff --git a/orchestra/contrib/vps/migrations/0004_auto_20170528_2005.py b/orchestra/contrib/vps/migrations/0004_auto_20170528_2005.py new file mode 100644 index 00000000..ff91cc96 --- /dev/null +++ b/orchestra/contrib/vps/migrations/0004_auto_20170528_2005.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.5 on 2017-05-28 18:05 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('vps', '0003_vps_is_active'), + ] + + operations = [ + migrations.AlterField( + model_name='vps', + name='template', + field=models.CharField(choices=[('debian7', 'Debian 7 - Wheezy'), ('placeholder', 'LXC placeholder')], default='placeholder', help_text='Initial template.', max_length=64, verbose_name='template'), + ), + migrations.AlterField( + model_name='vps', + name='type', + field=models.CharField(choices=[('openvz', 'OpenVZ container'), ('lxc', 'LXC container')], default='lxc', max_length=64, verbose_name='type'), + ), + ] diff --git a/orchestra/contrib/webapps/backends/php.py b/orchestra/contrib/webapps/backends/php.py index ef549325..d0383beb 100644 --- a/orchestra/contrib/webapps/backends/php.py +++ b/orchestra/contrib/webapps/backends/php.py @@ -32,6 +32,7 @@ class PHPController(WebAppServiceMixin, ServiceController): )) def save(self, webapp): + self.delete_old_config(webapp) context = self.get_context(webapp) self.create_webapp_dir(context) if webapp.type_instance.is_fpm: @@ -40,11 +41,32 @@ class PHPController(WebAppServiceMixin, ServiceController): self.save_fcgid(webapp, context) else: raise TypeError("Unknown PHP execution type") - self.append("# Clean non-used PHP FCGID wrappers and FPM pools") - self.delete_fcgid(webapp, context, preserve=True) - self.delete_fpm(webapp, context, preserve=True) +# LEGACY CLEANUP FUNCTIONS. TODO REMOVE WHEN SURE NOT NEEDED. +# self.delete_fcgid(webapp, context, preserve=True) +# self.delete_fpm(webapp, context, preserve=True) self.set_under_construction(context) - + + def delete_config(self,webapp): + context = self.get_context(webapp) + to_delete = [] + if webapp.type_instance.is_fpm: + to_delete.append(settings.WEBAPPS_PHPFPM_POOL_PATH % context) + to_delete.append(settings.WEBAPPS_FPM_LISTEN % context) + elif webapp.type_instance.is_fcgid: + to_delete.append(settings.WEBAPPS_FCGID_WRAPPER_PATH % context) + to_delete.append(settings.WEBAPPS_FCGID_CMD_OPTIONS_PATH % context) + for item in to_delete: + self.append('rm -f "{}"'.format(item)) + + def delete_old_config(self,webapp): + # Check if we loaded the old version of the webapp. If so, we're updating + # rather than creating, so we must make sure the old config files are removed. + if hasattr(webapp, '_old_self'): + self.append("# Clean old configuration files") + self.delete_config(webapp._old_self) + else: + self.append("# No old config files to delete") + def save_fpm(self, webapp, context): self.append(textwrap.dedent(""" # Generate FPM configuration @@ -99,10 +121,11 @@ class PHPController(WebAppServiceMixin, ServiceController): def delete(self, webapp): context = self.get_context(webapp) - if webapp.type_instance.is_fpm: - self.delete_fpm(webapp, context) - elif webapp.type_instance.is_fcgid: - self.delete_fcgid(webapp, context) + self.delete_old_config(webapp) +# if webapp.type_instance.is_fpm: +# self.delete_fpm(webapp, context) +# elif webapp.type_instance.is_fcgid: +# self.delete_fcgid(webapp, context) self.delete_webapp_dir(context) def has_sibilings(self, webapp, context): @@ -205,7 +228,7 @@ class PHPController(WebAppServiceMixin, ServiceController): context['fpm_listen'] = webapp.type_instance.FPM_LISTEN % context fpm_config = Template(textwrap.dedent("""\ ;; {{ banner }} - [{{ user }}-{{app_id}}] + [{{ user }}-{{app_name}}] user = {{ user }} group = {{ group }} diff --git a/orchestra/contrib/webapps/migrations/0002_auto_20170528_2011.py b/orchestra/contrib/webapps/migrations/0002_auto_20170528_2011.py new file mode 100644 index 00000000..18300cad --- /dev/null +++ b/orchestra/contrib/webapps/migrations/0002_auto_20170528_2011.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.5 on 2017-05-28 18:11 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('webapps', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='webapp', + name='type', + field=models.CharField(choices=[('moodle-php', 'Moodle'), ('php', 'PHP'), ('python', 'Python'), ('static', 'Static'), ('symbolic-link', 'Symbolic link'), ('webalizer', 'Webalizer'), ('wordpress-php', 'WordPress')], max_length=32, verbose_name='type'), + ), + migrations.AlterField( + model_name='webappoption', + name='name', + field=models.CharField(choices=[(None, '-------'), ('FileSystem', [('public-root', 'Public root')]), ('Process', [('timeout', 'Process timeout'), ('processes', 'Number of processes')]), ('PHP', [('enable_functions', 'Enable functions'), ('disable_functions', 'Disable functions'), ('allow_url_include', 'Allow URL include'), ('allow_url_fopen', 'Allow URL fopen'), ('auto_append_file', 'Auto append file'), ('auto_prepend_file', 'Auto prepend file'), ('date.timezone', 'date.timezone'), ('default_socket_timeout', 'Default socket timeout'), ('display_errors', 'Display errors'), ('extension', 'Extension'), ('include_path', 'Include path'), ('magic_quotes_gpc', 'Magic quotes GPC'), ('magic_quotes_runtime', 'Magic quotes runtime'), ('magic_quotes_sybase', 'Magic quotes sybase'), ('max_input_time', 'Max input time'), ('max_input_vars', 'Max input vars'), ('memory_limit', 'Memory limit'), ('mysql.connect_timeout', 'Mysql connect timeout'), ('output_buffering', 'Output buffering'), ('register_globals', 'Register globals'), ('post_max_size', 'Post max size'), ('sendmail_path', 'Sendmail path'), ('session.bug_compat_warn', 'Session bug compat warning'), ('session.auto_start', 'Session auto start'), ('safe_mode', 'Safe mode'), ('suhosin.post.max_vars', 'Suhosin POST max vars'), ('suhosin.get.max_vars', 'Suhosin GET max vars'), ('suhosin.request.max_vars', 'Suhosin request max vars'), ('suhosin.session.encrypt', 'Suhosin session encrypt'), ('suhosin.simulation', 'Suhosin simulation'), ('suhosin.executor.include.whitelist', 'Suhosin executor include whitelist'), ('upload_max_filesize', 'Upload max filesize'), ('upload_tmp_dir', 'Upload tmp dir'), ('zend_extension', 'Zend extension')])], max_length=128, verbose_name='name'), + ), + ] diff --git a/orchestra/contrib/webapps/migrations/0003_webapp_target_server.py b/orchestra/contrib/webapps/migrations/0003_webapp_target_server.py new file mode 100644 index 00000000..4bddb317 --- /dev/null +++ b/orchestra/contrib/webapps/migrations/0003_webapp_target_server.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.5 on 2017-07-04 08:49 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('orchestration', '0007_auto_20170528_2011'), + ('webapps', '0002_auto_20170528_2011'), + ] + + operations = [ + migrations.AddField( + model_name='webapp', + name='target_server', + field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, related_name='webapps', to='orchestration.Server', verbose_name='Target Server'), + preserve_default=False, + ), + ] diff --git a/orchestra/contrib/webapps/migrations/0004_webapp_comments.py b/orchestra/contrib/webapps/migrations/0004_webapp_comments.py new file mode 100644 index 00000000..25ad65d7 --- /dev/null +++ b/orchestra/contrib/webapps/migrations/0004_webapp_comments.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.5 on 2020-02-04 11:17 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('webapps', '0003_webapp_target_server'), + ] + + operations = [ + migrations.AddField( + model_name='webapp', + name='comments', + field=models.TextField(default=''), + preserve_default=False, + ), + ] diff --git a/orchestra/contrib/webapps/migrations/0005_auto_20200204_1218.py b/orchestra/contrib/webapps/migrations/0005_auto_20200204_1218.py new file mode 100644 index 00000000..80b315f7 --- /dev/null +++ b/orchestra/contrib/webapps/migrations/0005_auto_20200204_1218.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.5 on 2020-02-04 11:18 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('webapps', '0004_webapp_comments'), + ] + + operations = [ + migrations.AlterField( + model_name='webapp', + name='comments', + field=models.TextField(default=''), + ), + ] diff --git a/orchestra/contrib/webapps/models.py b/orchestra/contrib/webapps/models.py index d3fd7121..2180e01b 100644 --- a/orchestra/contrib/webapps/models.py +++ b/orchestra/contrib/webapps/models.py @@ -25,6 +25,7 @@ class WebApp(models.Model): help_text=_("Extra information dependent of each service.")) target_server = models.ForeignKey('orchestration.Server', verbose_name=_("Target Server"), related_name='webapps') + comments = models.TextField(default="", blank=True) # CMS webapps usually need a database and dbuser, with these virtual fields we tell the ORM to delete them databases = VirtualDatabaseRelation('databases.Database') diff --git a/orchestra/contrib/webapps/options.py b/orchestra/contrib/webapps/options.py index 79bd2802..dad0ec87 100644 --- a/orchestra/contrib/webapps/options.py +++ b/orchestra/contrib/webapps/options.py @@ -102,8 +102,8 @@ class Processes(AppOption): # FCGID MaxProcesses # FPM pm.max_children verbose_name = _("Number of processes") - help_text = _("Maximum number of children that can be alive at the same time (a number between 0 and 9).") - regex = r'^[0-9]{1,2}$' + help_text = _("Maximum number of children that can be alive at the same time (a number between 0 and 99).") + regex = r'^[0-9]{1,3}$' group = AppOption.PROCESS diff --git a/orchestra/contrib/webapps/serializers.py b/orchestra/contrib/webapps/serializers.py index cd9f657a..abfe9dc6 100644 --- a/orchestra/contrib/webapps/serializers.py +++ b/orchestra/contrib/webapps/serializers.py @@ -30,7 +30,7 @@ class WebAppSerializer(AccountSerializerMixin, HyperlinkedModelSerializer): class Meta: model = WebApp - fields = ('url', 'id', 'name', 'type', 'options', 'data') + fields = ('url', 'id', 'name', 'type', 'options', 'data',) postonly_fields = ('name', 'type') def __init__(self, *args, **kwargs): diff --git a/orchestra/contrib/webapps/signals.py b/orchestra/contrib/webapps/signals.py index ff849139..9bffd7d5 100644 --- a/orchestra/contrib/webapps/signals.py +++ b/orchestra/contrib/webapps/signals.py @@ -3,19 +3,22 @@ from django.dispatch import receiver from .models import WebApp - # Admin bulk deletion doesn't call model.delete() # So, signals are used instead of model method overriding @receiver(pre_save, sender=WebApp, dispatch_uid='webapps.type.save') def type_save(sender, *args, **kwargs): instance = kwargs['instance'] + # Since a webapp might need to cleanup its old config files, the data + # from the OLD VERSION of the webapp is needed. + if instance.pk: + instance._old_self = type(instance).objects.get(id=instance.pk) instance.type_instance.save() - @receiver(pre_delete, sender=WebApp, dispatch_uid='webapps.type.delete') def type_delete(sender, *args, **kwargs): instance = kwargs['instance'] + instance._old_self = type(instance).objects.get(id=instance.pk) try: instance.type_instance.delete() except KeyError: diff --git a/orchestra/contrib/websites/admin.py b/orchestra/contrib/websites/admin.py index 5b0dd106..e447683a 100644 --- a/orchestra/contrib/websites/admin.py +++ b/orchestra/contrib/websites/admin.py @@ -69,7 +69,7 @@ class WebsiteAdmin(SelectAccountAdminMixin, ExtendedModelAdmin): fieldsets = ( (None, { 'classes': ('extrapretty',), - 'fields': ('account_link', 'name', 'protocol', 'target_server', 'domains', 'is_active'), + 'fields': ('account_link', 'name', 'protocol', 'target_server', 'domains', 'is_active', 'comments'), }), ) form = WebsiteAdminForm diff --git a/orchestra/contrib/websites/backends/apache.py b/orchestra/contrib/websites/backends/apache.py index c6a11092..2cee8c4e 100644 --- a/orchestra/contrib/websites/backends/apache.py +++ b/orchestra/contrib/websites/backends/apache.py @@ -233,10 +233,12 @@ class Apache2Controller(ServiceController): 'socket': socket, }) directives = textwrap.dedent(""" -