Merge pull request #597 from modoboa/automx-replacement
Replaced automx by Modoboa autoconfig service
This commit is contained in:
@@ -44,7 +44,6 @@ The following components are installed by the installer:
|
|||||||
* Postfix
|
* Postfix
|
||||||
* Dovecot
|
* Dovecot
|
||||||
* Amavis (with SpamAssassin and ClamAV) or Rspamd
|
* Amavis (with SpamAssassin and ClamAV) or Rspamd
|
||||||
* automx (autoconfiguration service)
|
|
||||||
* OpenDKIM
|
* OpenDKIM
|
||||||
* Radicale (CalDAV and CardDAV server)
|
* Radicale (CalDAV and CardDAV server)
|
||||||
|
|
||||||
|
|||||||
@@ -222,35 +222,6 @@ ConfigDictTemplate = [
|
|||||||
},
|
},
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "automx",
|
|
||||||
"values": [
|
|
||||||
{
|
|
||||||
"option": "enabled",
|
|
||||||
"default": "true",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"option": "user",
|
|
||||||
"default": "automx",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"option": "config_dir",
|
|
||||||
"default": "/etc",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"option": "home_dir",
|
|
||||||
"default": "/srv/automx",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"option": "venv_path",
|
|
||||||
"default": "%(home_dir)s/env",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"option": "instance_path",
|
|
||||||
"default": "%(home_dir)s/instance",
|
|
||||||
},
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "rspamd",
|
"name": "rspamd",
|
||||||
"if": ["antispam.enabled=true", "antispam.type=rspamd"],
|
"if": ["antispam.enabled=true", "antispam.type=rspamd"],
|
||||||
|
|||||||
@@ -1,101 +0,0 @@
|
|||||||
"""Automx related tasks."""
|
|
||||||
|
|
||||||
import os
|
|
||||||
import pwd
|
|
||||||
import shutil
|
|
||||||
import stat
|
|
||||||
|
|
||||||
from .. import python
|
|
||||||
from .. import system
|
|
||||||
from .. import utils
|
|
||||||
|
|
||||||
from . import base
|
|
||||||
|
|
||||||
|
|
||||||
class Automx(base.Installer):
|
|
||||||
"""Automx installation."""
|
|
||||||
|
|
||||||
appname = "automx"
|
|
||||||
config_files = ["automx.conf"]
|
|
||||||
no_daemon = True
|
|
||||||
packages = {
|
|
||||||
"deb": ["memcached", "unzip"],
|
|
||||||
"rpm": ["memcached", "unzip"]
|
|
||||||
}
|
|
||||||
with_user = True
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
"""Get configuration."""
|
|
||||||
super(Automx, self).__init__(*args, **kwargs)
|
|
||||||
self.venv_path = self.config.get("automx", "venv_path")
|
|
||||||
self.instance_path = self.config.get("automx", "instance_path")
|
|
||||||
|
|
||||||
def get_template_context(self):
|
|
||||||
"""Additional variables."""
|
|
||||||
context = super(Automx, self).get_template_context()
|
|
||||||
sql_dsn = "{}://{}:{}@{}:{}/{}".format(
|
|
||||||
"postgresql" if self.dbengine == "postgres" else self.dbengine,
|
|
||||||
self.config.get("modoboa", "dbuser"),
|
|
||||||
self.config.get("modoboa", "dbpassword"),
|
|
||||||
self.dbhost,
|
|
||||||
self.dbport,
|
|
||||||
self.config.get("modoboa", "dbname"))
|
|
||||||
if self.db_driver == "pgsql":
|
|
||||||
sql_query = (
|
|
||||||
"SELECT first_name || ' ' || last_name AS display_name, email"
|
|
||||||
", SPLIT_PART(email, '@', 2) AS domain "
|
|
||||||
"FROM core_user WHERE email='%s' AND is_active;")
|
|
||||||
else:
|
|
||||||
sql_query = (
|
|
||||||
"SELECT concat(first_name, ' ', last_name) AS display_name, "
|
|
||||||
"email, SUBSTRING_INDEX(email, '@', -1) AS domain "
|
|
||||||
"FROM core_user WHERE email='%s' AND is_active=1;"
|
|
||||||
)
|
|
||||||
context.update({"sql_dsn": sql_dsn, "sql_query": sql_query})
|
|
||||||
return context
|
|
||||||
|
|
||||||
def _setup_venv(self):
|
|
||||||
"""Prepare a python virtualenv."""
|
|
||||||
python.setup_virtualenv(self.venv_path, sudo_user=self.user)
|
|
||||||
packages = [
|
|
||||||
"future", "lxml", "ipaddress", "sqlalchemy < 2.0", "python-memcached",
|
|
||||||
"python-dateutil", "configparser"
|
|
||||||
]
|
|
||||||
if self.dbengine == "postgres":
|
|
||||||
packages.append("psycopg2-binary")
|
|
||||||
else:
|
|
||||||
packages.append("mysqlclient")
|
|
||||||
python.install_packages(packages, self.venv_path, sudo_user=self.user)
|
|
||||||
target = "{}/master.zip".format(self.home_dir)
|
|
||||||
if os.path.exists(target):
|
|
||||||
os.unlink(target)
|
|
||||||
utils.exec_cmd(
|
|
||||||
"wget https://github.com/sys4/automx/archive/master.zip",
|
|
||||||
sudo_user=self.user, cwd=self.home_dir)
|
|
||||||
self.repo_dir = "{}/automx-master".format(self.home_dir)
|
|
||||||
if os.path.exists(self.repo_dir):
|
|
||||||
shutil.rmtree(self.repo_dir)
|
|
||||||
utils.exec_cmd(
|
|
||||||
"unzip master.zip", sudo_user=self.user, cwd=self.home_dir)
|
|
||||||
utils.exec_cmd(
|
|
||||||
"{} setup.py install".format(
|
|
||||||
python.get_path("python", self.venv_path)),
|
|
||||||
cwd=self.repo_dir)
|
|
||||||
|
|
||||||
def _deploy_instance(self):
|
|
||||||
"""Copy files to instance dir."""
|
|
||||||
if not os.path.exists(self.instance_path):
|
|
||||||
pw = pwd.getpwnam(self.user)
|
|
||||||
mode = (
|
|
||||||
stat.S_IRWXU | stat.S_IRGRP | stat.S_IXGRP |
|
|
||||||
stat.S_IROTH | stat.S_IXOTH)
|
|
||||||
utils.mkdir(self.instance_path, mode, pw[2], pw[3])
|
|
||||||
path = "{}/src/automx_wsgi.py".format(self.repo_dir)
|
|
||||||
utils.exec_cmd("cp {} {}".format(path, self.instance_path),
|
|
||||||
sudo_user=self.user, cwd=self.home_dir)
|
|
||||||
|
|
||||||
def post_run(self):
|
|
||||||
"""Additional tasks."""
|
|
||||||
self._setup_venv()
|
|
||||||
self._deploy_instance()
|
|
||||||
system.enable_and_start_service("memcached")
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
[automx]
|
|
||||||
provider = %domain
|
|
||||||
domains = *
|
|
||||||
|
|
||||||
#debug=yes
|
|
||||||
#logfile = /srv/automx/automx.log
|
|
||||||
|
|
||||||
# Protect against DoS
|
|
||||||
memcache = 127.0.0.1:11211
|
|
||||||
memcache_ttl = 600
|
|
||||||
client_error_limit = 20
|
|
||||||
rate_limit_exception_networks = 127.0.0.0/8, ::1/128
|
|
||||||
|
|
||||||
[global]
|
|
||||||
backend = sql
|
|
||||||
action = settings
|
|
||||||
account_type = email
|
|
||||||
host = %sql_dsn
|
|
||||||
query = %sql_query
|
|
||||||
result_attrs = display_name, email
|
|
||||||
|
|
||||||
display_name = ${display_name}
|
|
||||||
|
|
||||||
smtp = yes
|
|
||||||
smtp_server = %hostname
|
|
||||||
smtp_port = 587
|
|
||||||
smtp_encryption = starttls
|
|
||||||
smtp_auth = plaintext
|
|
||||||
smtp_auth_identity = ${email}
|
|
||||||
smtp_refresh_ttl = 6
|
|
||||||
smtp_default = yes
|
|
||||||
|
|
||||||
imap = yes
|
|
||||||
imap_server = %hostname
|
|
||||||
imap_port = 143
|
|
||||||
imap_encryption = starttls
|
|
||||||
imap_auth = plaintext
|
|
||||||
imap_auth_identity = ${email}
|
|
||||||
imap_refresh_ttl = 6
|
|
||||||
@@ -1,18 +1,14 @@
|
|||||||
upstream automx {
|
|
||||||
server unix:%uwsgi_socket_path fail_timeout=0;
|
|
||||||
}
|
|
||||||
|
|
||||||
server {
|
server {
|
||||||
listen 80;
|
listen 80;
|
||||||
listen [::]:80;
|
listen [::]:80;
|
||||||
server_name %hostname;
|
server_name %hostname;
|
||||||
root /srv/automx/instance;
|
root %app_instance_path;
|
||||||
|
|
||||||
access_log /var/log/nginx/%{hostname}-access.log;
|
access_log /var/log/nginx/%{hostname}-access.log;
|
||||||
error_log /var/log/nginx/%{hostname}-error.log;
|
error_log /var/log/nginx/%{hostname}-error.log;
|
||||||
|
|
||||||
location /mail/config-v1.1.xml {
|
location ~ ^/(mail/config-v1.1.xml|mobileconfig) {
|
||||||
include uwsgi_params;
|
include uwsgi_params;
|
||||||
uwsgi_pass automx;
|
uwsgi_pass modoboa;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
[uwsgi]
|
|
||||||
uid = %app_user
|
|
||||||
gid = %app_user
|
|
||||||
plugins = %uwsgi_plugin
|
|
||||||
home = %app_venv_path
|
|
||||||
chdir = %app_instance_path
|
|
||||||
module = automx_wsgi
|
|
||||||
master = true
|
|
||||||
vhost = true
|
|
||||||
harakiri = 60
|
|
||||||
processes = %nb_processes
|
|
||||||
socket = %uwsgi_socket_path
|
|
||||||
chmod-socket = 660
|
|
||||||
vacuum = true
|
|
||||||
@@ -59,20 +59,11 @@ class Nginx(base.Installer):
|
|||||||
def post_run(self):
|
def post_run(self):
|
||||||
"""Additionnal tasks."""
|
"""Additionnal tasks."""
|
||||||
extra_modoboa_config = ""
|
extra_modoboa_config = ""
|
||||||
if self.config.getboolean("automx", "enabled"):
|
|
||||||
hostname = "autoconfig.{}".format(
|
hostname = "autoconfig.{}".format(
|
||||||
self.config.get("general", "domain"))
|
self.config.get("general", "domain"))
|
||||||
self._setup_config("automx", hostname)
|
self._setup_config("autoconfig", hostname)
|
||||||
extra_modoboa_config = """
|
|
||||||
location ~* ^/autodiscover/autodiscover.xml {
|
|
||||||
include uwsgi_params;
|
|
||||||
uwsgi_pass automx;
|
|
||||||
}
|
|
||||||
location /mobileconfig {
|
|
||||||
include uwsgi_params;
|
|
||||||
uwsgi_pass automx;
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
if self.config.get("radicale", "enabled"):
|
if self.config.get("radicale", "enabled"):
|
||||||
extra_modoboa_config += """
|
extra_modoboa_config += """
|
||||||
location /radicale/ {
|
location /radicale/ {
|
||||||
|
|||||||
@@ -83,24 +83,9 @@ class Uwsgi(base.Installer):
|
|||||||
utils.exec_cmd(
|
utils.exec_cmd(
|
||||||
"perl -pi -e '{}' /etc/uwsgi.ini".format(pattern))
|
"perl -pi -e '{}' /etc/uwsgi.ini".format(pattern))
|
||||||
|
|
||||||
def _setup_automx_config(self):
|
|
||||||
"""Custom automx configuration."""
|
|
||||||
dst = self._setup_config("automx")
|
|
||||||
if package.backend.FORMAT == "deb":
|
|
||||||
self._enable_config_debian(dst)
|
|
||||||
else:
|
|
||||||
system.add_user_to_group(
|
|
||||||
"uwsgi", self.config.get("automx", "user"))
|
|
||||||
pattern = (
|
|
||||||
"s/emperor-tyrant = true/emperor-tyrant = false/")
|
|
||||||
utils.exec_cmd(
|
|
||||||
"perl -pi -e '{}' /etc/uwsgi.ini".format(pattern))
|
|
||||||
|
|
||||||
def post_run(self):
|
def post_run(self):
|
||||||
"""Additionnal tasks."""
|
"""Additionnal tasks."""
|
||||||
self._setup_modoboa_config()
|
self._setup_modoboa_config()
|
||||||
if self.config.getboolean("automx", "enabled"):
|
|
||||||
self._setup_automx_config()
|
|
||||||
|
|
||||||
def restart_daemon(self):
|
def restart_daemon(self):
|
||||||
"""Restart daemon process."""
|
"""Restart daemon process."""
|
||||||
|
|||||||
1
run.py
1
run.py
@@ -22,7 +22,6 @@ from modoboa_installer import disclaimers
|
|||||||
PRIMARY_APPS = [
|
PRIMARY_APPS = [
|
||||||
"fail2ban",
|
"fail2ban",
|
||||||
"modoboa",
|
"modoboa",
|
||||||
"automx",
|
|
||||||
"radicale",
|
"radicale",
|
||||||
"uwsgi",
|
"uwsgi",
|
||||||
"nginx",
|
"nginx",
|
||||||
|
|||||||
2
tests.py
2
tests.py
@@ -126,7 +126,7 @@ class ConfigFileTestCase(unittest.TestCase):
|
|||||||
"example.test"])
|
"example.test"])
|
||||||
self.assertTrue(os.path.exists(self.cfgfile))
|
self.assertTrue(os.path.exists(self.cfgfile))
|
||||||
self.assertIn(
|
self.assertIn(
|
||||||
"fail2ban modoboa automx amavis clamav dovecot nginx "
|
"fail2ban modoboa amavis clamav dovecot nginx "
|
||||||
"postfix postwhite spamassassin uwsgi radicale opendkim",
|
"postfix postwhite spamassassin uwsgi radicale opendkim",
|
||||||
out.getvalue()
|
out.getvalue()
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user