diff --git a/TODO.md b/TODO.md index 7f20be38..0178dca8 100644 --- a/TODO.md +++ b/TODO.md @@ -424,3 +424,6 @@ serailzer self.instance on create. # check certificate: websites directive ssl + domains search on miscellaneous + + +# IF modsecurity... and Merge websites locations diff --git a/orchestra/contrib/orchestration/forms.py b/orchestra/contrib/orchestration/forms.py new file mode 100644 index 00000000..a6f253c2 --- /dev/null +++ b/orchestra/contrib/orchestration/forms.py @@ -0,0 +1,14 @@ +from django import forms +from orchestra.forms.widgets import SpanWidget +from orchestra.forms.widgets import paddingCheckboxSelectMultiple + + +class RouteForm(forms.ModelForm): + def __init__(self, *args, **kwargs): + super(RouteForm, self).__init__(*args, **kwargs) + if self.instance: + self.fields['backend'].widget = SpanWidget() + self.fields['backend'].required = False + self.fields['async_actions'].widget = paddingCheckboxSelectMultiple(45) + actions = self.instance.backend_class.actions + self.fields['async_actions'].choices = ((action, action) for action in actions) diff --git a/orchestra/contrib/orchestration/models.py b/orchestra/contrib/orchestration/models.py index 1e1f3644..350f4965 100644 --- a/orchestra/contrib/orchestration/models.py +++ b/orchestra/contrib/orchestration/models.py @@ -211,7 +211,7 @@ class Route(models.Model): bool(self.matches(obj)) except Exception as exception: name = type(exception).__name__ - raise ValidationError(': '.join((name, exception))) + raise ValidationError(': '.join((name, str(exception)))) def action_is_async(self, action): return action in self.async_actions diff --git a/orchestra/contrib/saas/backends/dokuwikimu.py b/orchestra/contrib/saas/backends/dokuwikimu.py index 245e73c4..20f92d44 100644 --- a/orchestra/contrib/saas/backends/dokuwikimu.py +++ b/orchestra/contrib/saas/backends/dokuwikimu.py @@ -1,8 +1,11 @@ +import crypt import os +import textwrap from django.utils.translation import ugettext_lazy as _ -from orchestra.contrib.orchestration import ServiceController, replace +from orchestra.contrib.orchestration import ServiceController +from orchestra.utils.python import random_ascii from .. import settings @@ -11,27 +14,53 @@ class DokuWikiMuBackend(ServiceController): """ Creates a DokuWiki site on a DokuWiki multisite installation. """ + name = 'dokuwiki' verbose_name = _("DokuWiki multisite") - model = 'webapps.WebApp' - doc_settings = (settings, - ('SAAS_DOKUWIKI_TEMPLATE_PATH', 'SAAS_DOKUWIKI_FARM_PATH') - ) + model = 'saas.SaaS' + default_route_match = "saas.service == 'dokuwiki'" + doc_settings = (settings, ( + 'SAAS_DOKUWIKI_TEMPLATE_PATH', + 'SAAS_DOKUWIKI_FARM_PATH', + 'SAAS_DOKUWIKI_USER', + 'SAAS_DOKUWIKI_GROUP', + )) - def save(self, webapp): - context = self.get_context(webapp) - self.append("mkdir %(app_path)" % context) - self.append("tar xfz %(template)s -C %(app_path)s" % context) - self.append("chown -R www-data %(app_path)s" % context) - # TODO move dokuwiki to user directory + def save(self, saas): + context = self.get_context(saas) + self.append(textwrap.dedent(""" + if [[ ! -e %(app_path)s ]]; then + mkdir %(app_path)s + tar xfz %(template)s -C %(app_path)s + chown -R %(user)s:%(group)s %(app_path)s + fi""") % context + ) + if context['password']: + self.append(textwrap.dedent("""\ + if [[ $(grep '^admin:' %(users_path)s) ]]; then + sed -i 's#^admin:.*$#admin:%(password)s:admin:%(email)s:admin,user#' %(users_path)s + else + echo 'admin:%(password)s:admin:%(email)s:admin,user' >> %(users_path)s + fi""") % context + ) - def delete(self, webapp): - context = self.get_context(webapp) + def delete(self, saas): + context = self.get_context(saas) self.append("rm -fr %(app_path)s" % context) - def get_context(self, webapp): - context = super(DokuWikiMuBackend, self).get_context(webapp) + def get_context(self, saas): + context = super(DokuWikiMuBackend, self).get_context(saas) context.update({ 'template': settings.SAAS_DOKUWIKI_TEMPLATE_PATH, - 'app_path': os.path.join(settings.SAAS_DOKUWIKI_FARM_PATH, webapp.name) + 'farm_path': settings.SAAS_DOKUWIKI_FARM_PATH, + 'app_path': os.path.join(settings.SAAS_DOKUWIKI_FARM_PATH, saas.get_site_domain()), + 'user': settings.SAAS_DOKUWIKI_USER, + 'group': settings.SAAS_DOKUWIKI_GROUP, + 'email': saas.account.email, }) - return replace(context, "'", '"') + password = getattr(saas, 'password', None) + salt = random_ascii(8) + context.update({ + 'password': crypt.crypt(password, '$1$'+salt) if password else None, + 'users_path': os.path.join(context['app_path'], 'conf/users.auth.php'), + }) + return context diff --git a/orchestra/contrib/saas/backends/drupalmu.py b/orchestra/contrib/saas/backends/drupalmu.py index 574f8c94..53ea7699 100644 --- a/orchestra/contrib/saas/backends/drupalmu.py +++ b/orchestra/contrib/saas/backends/drupalmu.py @@ -13,7 +13,8 @@ class DrupalMuBackend(ServiceController): Creates a Drupal site on a Drupal multisite installation """ verbose_name = _("Drupal multisite") - model = 'webapps.WebApp' + model = 'saas.SaaS' + default_route_match = "saas.service == 'drupal'" doc_settings = (settings, ('SAAS_DRUPAL_SITES_PATH',) ) diff --git a/orchestra/contrib/saas/backends/wordpressmu.py b/orchestra/contrib/saas/backends/wordpressmu.py index e2fdf7d5..24daae1b 100644 --- a/orchestra/contrib/saas/backends/wordpressmu.py +++ b/orchestra/contrib/saas/backends/wordpressmu.py @@ -13,8 +13,8 @@ class WordpressMuBackend(ServiceController): Creates a wordpress site on a WordPress MultiSite installation. """ verbose_name = _("Wordpress multisite") - model = 'webapps.WebApp' - default_route_match = "webapp.type == 'wordpress-mu'" + model = 'saas.SaaS' + default_route_match = "saas.service == 'wordpress'" doc_settings = (settings, ('SAAS_WORDPRESS_ADMIN_PASSWORD', 'SAAS_WORDPRESS_BASE_URL') ) diff --git a/orchestra/contrib/saas/services/dokuwiki.py b/orchestra/contrib/saas/services/dokuwiki.py index a89eeb46..7917508a 100644 --- a/orchestra/contrib/saas/services/dokuwiki.py +++ b/orchestra/contrib/saas/services/dokuwiki.py @@ -2,5 +2,11 @@ from .options import SoftwareService class DokuWikiService(SoftwareService): + name = 'dokuwiki' verbose_name = "Dowkuwiki" icon = 'orchestra/icons/apps/Dokuwiki.png' + + @property + def site_base_domain(self): + from .. import settings + return settings.SAAS_DOKUWIKI_BASE_DOMAIN diff --git a/orchestra/contrib/saas/services/drupal.py b/orchestra/contrib/saas/services/drupal.py index 285a4e6b..b2e6c5f5 100644 --- a/orchestra/contrib/saas/services/drupal.py +++ b/orchestra/contrib/saas/services/drupal.py @@ -2,5 +2,6 @@ from .options import SoftwareService class DrupalService(SoftwareService): + name = 'drupal' verbose_name = "Drupal" icon = 'orchestra/icons/apps/Drupal.png' diff --git a/orchestra/contrib/saas/services/options.py b/orchestra/contrib/saas/services/options.py index 2ce24ecb..3024905f 100644 --- a/orchestra/contrib/saas/services/options.py +++ b/orchestra/contrib/saas/services/options.py @@ -56,7 +56,7 @@ class SoftwareServiceForm(PluginDataForm): else: site_link = '<site_name>.%s' % self.plugin.site_base_domain self.fields['site_url'].widget.display = site_link - self.fields['name'].label = _("Username") + self.fields['name'].label = _("Site name") if self.plugin.site_base_domain else _("Username") def clean_password2(self): if not self.is_change: diff --git a/orchestra/contrib/saas/services/wordpress.py b/orchestra/contrib/saas/services/wordpress.py index 58078ac5..afca5222 100644 --- a/orchestra/contrib/saas/services/wordpress.py +++ b/orchestra/contrib/saas/services/wordpress.py @@ -7,10 +7,6 @@ from .options import SoftwareService, SoftwareServiceForm class WordPressForm(SoftwareServiceForm): email = forms.EmailField(label=_("Email"), widget=forms.TextInput(attrs={'size':'40'})) - - def __init__(self, *args, **kwargs): - super(WordPressForm, self).__init__(*args, **kwargs) - self.fields['name'].label = _("Site name") class WordPressDataSerializer(serializers.Serializer): @@ -18,9 +14,14 @@ class WordPressDataSerializer(serializers.Serializer): class WordPressService(SoftwareService): + name = 'wordpress' verbose_name = "WordPress" form = WordPressForm serializer = WordPressDataSerializer icon = 'orchestra/icons/apps/WordPress.png' - site_base_domain = 'blogs.orchestra.lan' change_readonly_fileds = ('email',) + + @property + def site_base_domain(self): + from .. import settings + return settings.SAAS_WORDPRESS_BASE_DOMAIN diff --git a/orchestra/contrib/saas/settings.py b/orchestra/contrib/saas/settings.py index 81a062b5..fd0599c2 100644 --- a/orchestra/contrib/saas/settings.py +++ b/orchestra/contrib/saas/settings.py @@ -32,6 +32,11 @@ SAAS_WORDPRESS_BASE_URL = Setting('SAAS_WORDPRESS_BASE_URL', ) +SAAS_WORDPRESS_BASE_DOMAIN = Setting('SAAS_WORDPRESS_BASE_DOMAIN', + 'blogs.{}'.format(ORCHESTRA_BASE_DOMAIN), +) + + SAAS_DOKUWIKI_TEMPLATE_PATH = Setting('SAAS_DOKUWIKI_TEMPLATE_PATH', '/home/httpd/htdocs/wikifarm/template.tar.gz' ) @@ -42,9 +47,32 @@ SAAS_DOKUWIKI_FARM_PATH = Setting('WEBSITES_DOKUWIKI_FARM_PATH', ) +SAAS_DOKUWIKI_BASE_DOMAIN = Setting('SAAS_DOKUWIKI_BASE_DOMAIN', + 'dokuwiki.{}'.format(ORCHESTRA_BASE_DOMAIN), +) + + +SAAS_DOKUWIKI_TEMPLATE_PATH = Setting('SAAS_DOKUWIKI_TEMPLATE_PATH', + '/var/www/wikifarm/template.tar.gz', +) + +SAAS_DOKUWIKI_FARM_PATH = Setting('SAAS_DOKUWIKI_FARM_PATH', + '/var/www/wikifarm/farm' +) + + +SAAS_DOKUWIKI_USER = Setting('SAAS_DOKUWIKI_USER', + 'orchestra' +) + + +SAAS_DOKUWIKI_GROUP = Setting('SAAS_DOKUWIKI_GROUP', + 'orchestra' +) + + SAAS_DRUPAL_SITES_PATH = Setting('WEBSITES_DRUPAL_SITES_PATH', '/home/httpd/htdocs/drupal-mu/sites/%(site_name)s', - )