mirror of
https://github.com/Mailu/Mailu.git
synced 2025-01-26 03:52:50 +02:00
Resolve HOST_* to *_ADDRESS only if *_ADDRESS is not already set
This commit is contained in:
parent
1f0b45e47b
commit
de2f166bd1
@ -60,7 +60,9 @@ DEFAULT_CONFIG = {
|
|||||||
'HOST_SMTP': 'smtp',
|
'HOST_SMTP': 'smtp',
|
||||||
'HOST_AUTHSMTP': 'smtp',
|
'HOST_AUTHSMTP': 'smtp',
|
||||||
'HOST_ADMIN': 'admin',
|
'HOST_ADMIN': 'admin',
|
||||||
|
'ANTISPAM': 'none',
|
||||||
'HOST_ANTISPAM': 'antispam:11334',
|
'HOST_ANTISPAM': 'antispam:11334',
|
||||||
|
'WEBMAIL': 'none',
|
||||||
'HOST_WEBMAIL': 'webmail',
|
'HOST_WEBMAIL': 'webmail',
|
||||||
'HOST_WEBDAV': 'webdav:5232',
|
'HOST_WEBDAV': 'webdav:5232',
|
||||||
'HOST_REDIS': 'redis',
|
'HOST_REDIS': 'redis',
|
||||||
@ -79,18 +81,26 @@ class ConfigManager(dict):
|
|||||||
'mysql': 'mysql://{DB_USER}:{DB_PW}@{DB_HOST}/{DB_NAME}'
|
'mysql': 'mysql://{DB_USER}:{DB_PW}@{DB_HOST}/{DB_NAME}'
|
||||||
}
|
}
|
||||||
|
|
||||||
HOSTS = ('IMAP', 'POP3', 'AUTHSMTP', 'SMTP', 'REDIS')
|
|
||||||
OPTIONAL_HOSTS = ('WEBMAIL', 'ANTISPAM')
|
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.config = dict()
|
self.config = dict()
|
||||||
|
|
||||||
def resolve_host(self):
|
def get_host_address(self, name):
|
||||||
optional = [item for item in self.OPTIONAL_HOSTS if item in self.config and self.config[item] != "none"]
|
# if MYSERVICE_ADDRESS is defined, use this
|
||||||
for item in list(self.HOSTS) + optional:
|
if '{}_ADDRESS'.format(name) in os.environ:
|
||||||
host = 'HOST_' + item
|
return os.environ.get('{}_ADDRESS'.format(name))
|
||||||
address = item + '_ADDRESS'
|
# otherwise use the host name and resolve it
|
||||||
self.config[address] = system.resolve_address(self.config[host])
|
return system.resolve_address(self.config['HOST_{}'.format(name)])
|
||||||
|
|
||||||
|
def resolve_hosts(self):
|
||||||
|
self.config["IMAP_ADDRESS"] = self.get_host_address("IMAP")
|
||||||
|
self.config["POP3_ADDRESS"] = self.get_host_address("POP3")
|
||||||
|
self.config["AUTHSMTP_ADDRESS"] = self.get_host_address("AUTHSMTP")
|
||||||
|
self.config["SMTP_ADDRESS"] = self.get_host_address("SMTP")
|
||||||
|
self.config["REDIS_ADDRESS"] = self.get_host_address("REDIS")
|
||||||
|
if self.config["WEBMAIL"] != "none":
|
||||||
|
self.config["WEBMAIL_ADDRESS"] = self.get_host_address("WEBMAIL")
|
||||||
|
if self.config["ANTISPAM"] != "none":
|
||||||
|
self.config["ANTISPAM_ADDRESS"] = self.get_host_address("ANTISPAM")
|
||||||
|
|
||||||
def __coerce_value(self, value):
|
def __coerce_value(self, value):
|
||||||
if isinstance(value, str) and value.lower() in ('true','yes'):
|
if isinstance(value, str) and value.lower() in ('true','yes'):
|
||||||
@ -106,7 +116,7 @@ class ConfigManager(dict):
|
|||||||
key: self.__coerce_value(os.environ.get(key, value))
|
key: self.__coerce_value(os.environ.get(key, value))
|
||||||
for key, value in DEFAULT_CONFIG.items()
|
for key, value in DEFAULT_CONFIG.items()
|
||||||
})
|
})
|
||||||
self.resolve_host()
|
self.resolve_hosts()
|
||||||
|
|
||||||
# automatically set the sqlalchemy string
|
# automatically set the sqlalchemy string
|
||||||
if self.config['DB_FLAVOR']:
|
if self.config['DB_FLAVOR']:
|
||||||
|
@ -3,6 +3,9 @@ from flask import current_app as app
|
|||||||
|
|
||||||
import re
|
import re
|
||||||
import urllib
|
import urllib
|
||||||
|
import ipaddress
|
||||||
|
import socket
|
||||||
|
import tenacity
|
||||||
|
|
||||||
|
|
||||||
SUPPORTED_AUTH_METHODS = ["none", "plain"]
|
SUPPORTED_AUTH_METHODS = ["none", "plain"]
|
||||||
@ -88,4 +91,18 @@ def get_server(protocol, authenticated=False):
|
|||||||
hostname, port = extract_host_port(app.config['AUTHSMTP_ADDRESS'], 10025)
|
hostname, port = extract_host_port(app.config['AUTHSMTP_ADDRESS'], 10025)
|
||||||
else:
|
else:
|
||||||
hostname, port = extract_host_port(app.config['SMTP_ADDRESS'], 25)
|
hostname, port = extract_host_port(app.config['SMTP_ADDRESS'], 25)
|
||||||
|
try:
|
||||||
|
# test if hostname is already resolved to an ip adddress
|
||||||
|
ipaddress.ip_address(hostname)
|
||||||
|
except:
|
||||||
|
# hostname is not an ip address - so we need to resolve it
|
||||||
|
hostname = resolve_hostname(hostname)
|
||||||
return hostname, port
|
return hostname, port
|
||||||
|
|
||||||
|
@tenacity.retry(stop=tenacity.stop_after_attempt(100),
|
||||||
|
wait=tenacity.wait_random(min=2, max=5))
|
||||||
|
def resolve_hostname(hostname):
|
||||||
|
""" This function uses system DNS to resolve a hostname.
|
||||||
|
It is capable of retrying in case the host is not immediately available
|
||||||
|
"""
|
||||||
|
return socket.gethostbyname(hostname)
|
||||||
|
@ -5,7 +5,7 @@ RUN apk add --no-cache \
|
|||||||
&& pip3 install --upgrade pip
|
&& pip3 install --upgrade pip
|
||||||
|
|
||||||
# Shared layer between nginx, dovecot, postfix, postgresql, rspamd, unbound, rainloop, roundcube
|
# Shared layer between nginx, dovecot, postfix, postgresql, rspamd, unbound, rainloop, roundcube
|
||||||
RUN pip3 install socrate
|
RUN pip3 install socrate==0.2.0
|
||||||
|
|
||||||
# Shared layer between dovecot and postfix
|
# Shared layer between dovecot and postfix
|
||||||
RUN pip3 install "podop>0.2.5"
|
RUN pip3 install "podop>0.2.5"
|
||||||
|
@ -21,12 +21,13 @@ def start_podop():
|
|||||||
])
|
])
|
||||||
|
|
||||||
# Actual startup script
|
# Actual startup script
|
||||||
os.environ["FRONT_ADDRESS"] = system.resolve_address(os.environ.get("HOST_FRONT", "front"))
|
|
||||||
os.environ["REDIS_ADDRESS"] = system.resolve_address(os.environ.get("HOST_REDIS", "redis"))
|
os.environ["FRONT_ADDRESS"] = system.get_host_address_from_environment("FRONT", "front")
|
||||||
os.environ["ADMIN_ADDRESS"] = system.resolve_address(os.environ.get("HOST_ADMIN", "admin"))
|
os.environ["REDIS_ADDRESS"] = system.get_host_address_from_environment("REDIS", "redis")
|
||||||
os.environ["ANTISPAM_ADDRESS"] = system.resolve_address(os.environ.get("HOST_ANTISPAM", "antispam:11334"))
|
os.environ["ADMIN_ADDRESS"] = system.get_host_address_from_environment("ADMIN", "admin")
|
||||||
|
os.environ["ANTISPAM_ADDRESS"] = system.get_host_address_from_environment("ANTISPAM", "antispam:11334")
|
||||||
if os.environ["WEBMAIL"] != "none":
|
if os.environ["WEBMAIL"] != "none":
|
||||||
os.environ["WEBMAIL_ADDRESS"] = system.resolve_address(os.environ.get("HOST_WEBMAIL", "webmail"))
|
os.environ["WEBMAIL_ADDRESS"] = system.get_host_address_from_environment("WEBMAIL", "webmail")
|
||||||
|
|
||||||
for dovecot_file in glob.glob("/conf/*.conf"):
|
for dovecot_file in glob.glob("/conf/*.conf"):
|
||||||
conf.jinja(dovecot_file, os.environ, os.path.join("/etc/dovecot", os.path.basename(dovecot_file)))
|
conf.jinja(dovecot_file, os.environ, os.path.join("/etc/dovecot", os.path.basename(dovecot_file)))
|
||||||
|
@ -5,7 +5,7 @@ RUN apk add --no-cache \
|
|||||||
&& pip3 install --upgrade pip
|
&& pip3 install --upgrade pip
|
||||||
|
|
||||||
# Shared layer between nginx, dovecot, postfix, postgresql, rspamd, unbound, rainloop, roundcube
|
# Shared layer between nginx, dovecot, postfix, postgresql, rspamd, unbound, rainloop, roundcube
|
||||||
RUN pip3 install socrate
|
RUN pip3 install socrate==0.2.0
|
||||||
|
|
||||||
# Image specific layers under this line
|
# Image specific layers under this line
|
||||||
RUN apk add --no-cache certbot nginx nginx-mod-mail openssl curl \
|
RUN apk add --no-cache certbot nginx nginx-mod-mail openssl curl \
|
||||||
|
@ -14,12 +14,12 @@ with open("/etc/resolv.conf") as handle:
|
|||||||
content = handle.read().split()
|
content = handle.read().split()
|
||||||
args["RESOLVER"] = content[content.index("nameserver") + 1]
|
args["RESOLVER"] = content[content.index("nameserver") + 1]
|
||||||
|
|
||||||
args["ADMIN_ADDRESS"] = system.resolve_address(args.get("HOST_ADMIN", "admin"))
|
args["ADMIN_ADDRESS"] = system.get_host_address_from_environment("ADMIN", "admin")
|
||||||
args["ANTISPAM_ADDRESS"] = system.resolve_address(args.get("HOST_ANTISPAM", "antispam:11334"))
|
args["ANTISPAM_ADDRESS"] = system.get_host_address_from_environment("ANTISPAM", "antispam:11334")
|
||||||
if args["WEBMAIL"] != "none":
|
if args["WEBMAIL"] != "none":
|
||||||
args["WEBMAIL_ADDRESS"] = system.resolve_address(args.get("HOST_WEBMAIL", "webmail"))
|
args["WEBMAIL_ADDRESS"] = system.get_host_address_from_environment("WEBMAIL", "webmail")
|
||||||
if args["WEBDAV"] != "none":
|
if args["WEBDAV"] != "none":
|
||||||
args["WEBDAV_ADDRESS"] = system.resolve_address(args.get("HOST_WEBDAV", "webdav:5232"))
|
args["WEBDAV_ADDRESS"] = system.get_host_address_from_environment("WEBDAV", "webdav:5232")
|
||||||
|
|
||||||
# TLS configuration
|
# TLS configuration
|
||||||
cert_name = os.getenv("TLS_CERT_FILENAME", default="cert.pem")
|
cert_name = os.getenv("TLS_CERT_FILENAME", default="cert.pem")
|
||||||
|
@ -5,7 +5,7 @@ RUN apk add --no-cache \
|
|||||||
&& pip3 install --upgrade pip
|
&& pip3 install --upgrade pip
|
||||||
|
|
||||||
# Shared layer between nginx, dovecot, postfix, postgresql, rspamd, unbound, rainloop, roundcube
|
# Shared layer between nginx, dovecot, postfix, postgresql, rspamd, unbound, rainloop, roundcube
|
||||||
RUN pip3 install socrate
|
RUN pip3 install socrate==0.2.0
|
||||||
|
|
||||||
# Shared layer between dovecot and postfix
|
# Shared layer between dovecot and postfix
|
||||||
RUN pip3 install "podop>0.2.5"
|
RUN pip3 install "podop>0.2.5"
|
||||||
|
@ -26,10 +26,10 @@ def start_podop():
|
|||||||
])
|
])
|
||||||
|
|
||||||
# Actual startup script
|
# Actual startup script
|
||||||
os.environ["FRONT_ADDRESS"] = system.resolve_address(os.environ.get("HOST_FRONT", "front"))
|
os.environ["FRONT_ADDRESS"] = system.get_host_address_from_environment("FRONT", "front")
|
||||||
os.environ["ADMIN_ADDRESS"] = system.resolve_address(os.environ.get("HOST_ADMIN", "admin"))
|
os.environ["ADMIN_ADDRESS"] = system.get_host_address_from_environment("ADMIN", "admin")
|
||||||
os.environ["ANTISPAM_ADDRESS"] = system.resolve_address(os.environ.get("HOST_ANTISPAM", "antispam:11332"))
|
os.environ["ANTISPAM_ADDRESS"] = system.get_host_address_from_environment("ANTISPAM", "antispam:11332")
|
||||||
os.environ["LMTP_ADDRESS"] = system.resolve_address(os.environ.get("HOST_LMTP", "imap:2525"))
|
os.environ["LMTP_ADDRESS"] = system.get_host_address_from_environment("LMTP", "imap:2525")
|
||||||
|
|
||||||
for postfix_file in glob.glob("/conf/*.cf"):
|
for postfix_file in glob.glob("/conf/*.cf"):
|
||||||
conf.jinja(postfix_file, os.environ, os.path.join("/etc/postfix", os.path.basename(postfix_file)))
|
conf.jinja(postfix_file, os.environ, os.path.join("/etc/postfix", os.path.basename(postfix_file)))
|
||||||
|
@ -151,11 +151,13 @@ optional port number. Those variables are:
|
|||||||
- ``HOST_WEBMAIL``: the container that is running the webmail (default: ``webmail``)
|
- ``HOST_WEBMAIL``: the container that is running the webmail (default: ``webmail``)
|
||||||
- ``HOST_WEBDAV``: the container that is running the webdav server (default: ``webdav:5232``)
|
- ``HOST_WEBDAV``: the container that is running the webdav server (default: ``webdav:5232``)
|
||||||
- ``HOST_REDIS``: the container that is running the redis daemon (default: ``redis``)
|
- ``HOST_REDIS``: the container that is running the redis daemon (default: ``redis``)
|
||||||
|
- ``HOST_WEBMAIL``: the container that is running the webmail (default: ``webmail``)
|
||||||
|
|
||||||
|
The startup scripts will resolve HOST_* to their IP addresses and store the result in *_ADDRESS for further use.
|
||||||
|
|
||||||
|
Alternatively, *_ADDRESS can directly be set. In this case, the values of *_ADDRESS is kept and not
|
||||||
|
resolved. This can be used to rely on DNS based service discovery with changing services IP addresses.
|
||||||
|
When using *_ADDRESS, the hostnames must be full-qualified hostnames. Otherwise nginx will not be able to
|
||||||
|
resolve the hostnames.
|
||||||
|
|
||||||
Additional variables are used to locate other containers without dialing a
|
|
||||||
specific port number. It is used to either whitelist connection from these
|
|
||||||
addresses or connect to containers on the docker network:
|
|
||||||
|
|
||||||
- ``FRONT_ADDRESS``: the nginx container address (default: ``front``)
|
|
||||||
- ``WEBMAIL_ADDRESS``: the webmail container address (default: ``webmail``)
|
|
||||||
- ``IMAP_ADDRESS``: the webmail container address (default: ``webmail``)
|
|
||||||
|
@ -5,7 +5,7 @@ RUN apk add --no-cache \
|
|||||||
&& pip3 install --upgrade pip
|
&& pip3 install --upgrade pip
|
||||||
|
|
||||||
# Shared layer between nginx, dovecot, postfix, postgresql, rspamd, unbound, rainloop, roundcube
|
# Shared layer between nginx, dovecot, postfix, postgresql, rspamd, unbound, rainloop, roundcube
|
||||||
RUN pip3 install socrate
|
RUN pip3 install socrate==0.2.0
|
||||||
|
|
||||||
# Image specific layers under this line
|
# Image specific layers under this line
|
||||||
RUN apk add --no-cache rspamd rspamd-controller rspamd-proxy rspamd-fuzzy ca-certificates curl
|
RUN apk add --no-cache rspamd rspamd-controller rspamd-proxy rspamd-fuzzy ca-certificates curl
|
||||||
|
@ -10,11 +10,11 @@ log.basicConfig(stream=sys.stderr, level=os.environ.get("LOG_LEVEL", "WARNING"))
|
|||||||
|
|
||||||
# Actual startup script
|
# Actual startup script
|
||||||
|
|
||||||
os.environ["FRONT_ADDRESS"] = system.resolve_address(os.environ.get("HOST_FRONT", "front"))
|
os.environ["FRONT_ADDRESS"] = system.get_host_address_from_environment("FRONT", "front")
|
||||||
os.environ["REDIS_ADDRESS"] = system.resolve_address(os.environ.get("HOST_REDIS", "redis"))
|
os.environ["REDIS_ADDRESS"] = system.get_host_address_from_environment("REDIS", "redis")
|
||||||
|
|
||||||
if os.environ.get("ANTIVIRUS") == 'clamav':
|
if os.environ.get("ANTIVIRUS") == 'clamav':
|
||||||
os.environ["ANTIVIRUS_ADDRESS"] = system.resolve_address(os.environ.get("HOST_ANTIVIRUS", "antivirus:3310"))
|
os.environ["ANTIVIRUS_ADDRESS"] = system.get_host_address_from_environment("ANTIVIRUS", "antivirus:3310")
|
||||||
|
|
||||||
for rspamd_file in glob.glob("/conf/*"):
|
for rspamd_file in glob.glob("/conf/*"):
|
||||||
conf.jinja(rspamd_file, os.environ, os.path.join("/etc/rspamd/local.d", os.path.basename(rspamd_file)))
|
conf.jinja(rspamd_file, os.environ, os.path.join("/etc/rspamd/local.d", os.path.basename(rspamd_file)))
|
||||||
|
1
towncrier/newsfragments/1113.feature
Normal file
1
towncrier/newsfragments/1113.feature
Normal file
@ -0,0 +1 @@
|
|||||||
|
Resolve hosts to IPs if only HOST_* is set. If *_ADDRESS is set, leave it unresolved.
|
Loading…
x
Reference in New Issue
Block a user