ConfigLMM 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +31 -0
- data/Examples/Implemented.mm.yaml +75 -1
- data/Plugins/Apps/Authentik/Authentik-Server.container +18 -0
- data/Plugins/Apps/Authentik/Authentik-Worker.container +17 -0
- data/Plugins/Apps/Authentik/Authentik.conf.erb +35 -0
- data/Plugins/Apps/Authentik/Authentik.lmm.rb +73 -0
- data/Plugins/Apps/Cassandra/Cassandra.lmm.rb +41 -0
- data/Plugins/Apps/Dovecot/Dovecot.lmm.rb +148 -0
- data/Plugins/Apps/GitLab/GitLab.conf.erb +26 -0
- data/Plugins/Apps/GitLab/GitLab.container +17 -0
- data/Plugins/Apps/GitLab/GitLab.lmm.rb +75 -0
- data/Plugins/Apps/Nextcloud/Nextcloud.conf.erb +48 -10
- data/Plugins/Apps/Nextcloud/Nextcloud.lmm.rb +59 -2
- data/Plugins/Apps/Nextcloud/config.php +18 -0
- data/Plugins/Apps/Nginx/conf.d/configlmm.conf +62 -0
- data/Plugins/Apps/Nginx/config-lmm/errors.conf +1 -1
- data/Plugins/Apps/Nginx/main.conf.erb +31 -0
- data/Plugins/Apps/Nginx/nginx.conf +3 -68
- data/Plugins/Apps/Nginx/nginx.lmm.rb +71 -14
- data/Plugins/Apps/Odoo/Odoo.conf.erb +30 -13
- data/Plugins/Apps/Odoo/Odoo.container +17 -0
- data/Plugins/Apps/Odoo/Odoo.lmm.rb +62 -2
- data/Plugins/Apps/Odoo/odoo.conf +37 -0
- data/Plugins/Apps/PHP-FPM/PHP-FPM.lmm.rb +95 -0
- data/Plugins/Apps/Peppermint/Peppermint.conf.erb +64 -0
- data/Plugins/Apps/Peppermint/Peppermint.container +14 -0
- data/Plugins/Apps/Peppermint/Peppermint.lmm.rb +58 -0
- data/Plugins/Apps/Postfix/Postfix.lmm.rb +139 -31
- data/Plugins/Apps/Postfix/smtpd.conf +3 -0
- data/Plugins/Apps/PostgreSQL/PostgreSQL.lmm.rb +172 -23
- data/Plugins/Apps/SSH/SSH.lmm.rb +51 -0
- data/Plugins/Apps/UVdesk/UVdesk.conf.erb +52 -0
- data/Plugins/Apps/UVdesk/UVdesk.lmm.rb +85 -0
- data/Plugins/Apps/Valkey/Valkey.lmm.rb +2 -1
- data/Plugins/Apps/Vaultwarden/Vaultwarden.conf.erb +35 -18
- data/Plugins/Apps/Vaultwarden/Vaultwarden.container +16 -0
- data/Plugins/Apps/Vaultwarden/Vaultwarden.lmm.rb +42 -3
- data/Plugins/Apps/gollum/gollum.conf.erb +45 -18
- data/Plugins/Apps/gollum/gollum.container +12 -0
- data/Plugins/Apps/gollum/gollum.lmm.rb +39 -10
- data/Plugins/OS/Linux/Distributions.yaml +10 -0
- data/Plugins/OS/Linux/Linux.lmm.rb +145 -12
- data/Plugins/OS/Linux/Packages.yaml +42 -4
- data/Plugins/OS/Linux/WireGuard/WireGuard.lmm.rb +108 -0
- data/Plugins/OS/Linux/WireGuard/wg0.conf.erb +15 -0
- data/Plugins/OS/Linux/systemd/systemd.lmm.rb +28 -0
- data/Plugins/OS/Linux/systemd/user-0.slice +9 -0
- data/Plugins/OS/Linux/systemd/user@.service.d/delegate.conf +3 -0
- data/Plugins/Platforms/GoDaddy/GoDaddy.lmm.rb +6 -2
- data/Plugins/Services/DNS/PowerDNS.lmm.rb +69 -6
- data/README.md +6 -0
- data/bootstrap.sh +54 -0
- data/lib/ConfigLMM/Framework/plugins/dns.rb +1 -2
- data/lib/ConfigLMM/Framework/plugins/linuxApp.rb +157 -35
- data/lib/ConfigLMM/Framework/plugins/nginxApp.rb +24 -6
- data/lib/ConfigLMM/Framework/plugins/plugin.rb +52 -12
- data/lib/ConfigLMM/version.rb +1 -1
- metadata +31 -3
- data/Plugins/Apps/Nginx/main.conf +0 -30
@@ -3,6 +3,9 @@ module ConfigLMM
|
|
3
3
|
module LMM
|
4
4
|
class Odoo < Framework::NginxApp
|
5
5
|
|
6
|
+
USER = 'odoo'
|
7
|
+
HOME_DIR = '/var/lib/odoo'
|
8
|
+
|
6
9
|
def actionOdooBuild(id, target, state, context, options)
|
7
10
|
writeNginxConfig(__dir__, 'Odoo', id, target, state, context, options)
|
8
11
|
end
|
@@ -12,12 +15,69 @@ module ConfigLMM
|
|
12
15
|
end
|
13
16
|
|
14
17
|
def actionOdooDeploy(id, target, activeState, context, options)
|
15
|
-
|
16
|
-
|
18
|
+
target['Database'] ||= {}
|
19
|
+
if target['Location'] && target['Location'] != '@me'
|
20
|
+
uri = Addressable::URI.parse(target['Location'])
|
21
|
+
raise Framework::PluginProcessError.new("#{id}: Unknown Protocol: #{uri.scheme}!") if uri.scheme != 'ssh'
|
22
|
+
|
23
|
+
self.class.sshStart(uri) do |ssh|
|
24
|
+
|
25
|
+
if !target.key?('Proxy') || target['Proxy'] != 'only'
|
26
|
+
dbPassword = self.configurePostgreSQL(target['Database'], ssh)
|
27
|
+
distroInfo = Framework::LinuxApp.currentDistroInfo(ssh)
|
28
|
+
Framework::LinuxApp.configurePodmanServiceOverSSH(USER, HOME_DIR, 'Odoo', distroInfo, ssh)
|
29
|
+
self.class.sshExec!(ssh, "su --login #{USER} --shell /bin/sh --command 'mkdir -p ~/config'")
|
30
|
+
self.class.sshExec!(ssh, "su --login #{USER} --shell /bin/sh --command 'mkdir -p ~/data'")
|
31
|
+
self.class.sshExec!(ssh, "su --login #{USER} --shell /bin/sh --command 'mkdir -p ~/addons'")
|
32
|
+
|
33
|
+
path = Framework::LinuxApp::SYSTEMD_CONTAINERS_PATH.gsub('~', HOME_DIR)
|
34
|
+
dbHost = '10.0.2.2'
|
35
|
+
dbHost = target['Database']['HostName'] if target['Database']['HostName']
|
36
|
+
|
37
|
+
self.class.sshExec!(ssh, " echo 'HOST=#{dbHost}' > #{path}/Odoo.env")
|
38
|
+
self.class.sshExec!(ssh, " echo 'USER=#{USER}' >> #{path}/Odoo.env")
|
39
|
+
self.class.sshExec!(ssh, " echo 'PASSWORD=#{dbPassword}' >> #{path}/Odoo.env")
|
40
|
+
self.class.sshExec!(ssh, "chown #{USER}:#{USER} #{path}/Odoo.env")
|
41
|
+
self.class.sshExec!(ssh, "chmod 600 #{path}/Odoo.env")
|
42
|
+
|
43
|
+
ssh.scp.upload!(__dir__ + '/Odoo.container', path)
|
44
|
+
ssh.scp.upload!(__dir__ + '/odoo.conf', HOME_DIR + '/config/')
|
45
|
+
self.class.sshExec!(ssh, "chown #{USER}:#{USER} #{HOME_DIR}/config/odoo.conf")
|
46
|
+
self.class.sshExec!(ssh, "systemctl --user --machine=#{USER}@ daemon-reload")
|
47
|
+
self.class.sshExec!(ssh, "systemctl --user --machine=#{USER}@ start Odoo")
|
48
|
+
end
|
49
|
+
|
50
|
+
if !target.key?('Proxy') || target['Proxy'] == true || target['Proxy'] == 'only'
|
51
|
+
raise Framework::PluginProcessError.new('Domain field must be set!') unless target['Domain']
|
52
|
+
|
53
|
+
Framework::LinuxApp.ensurePackages([NGINX_PACKAGE], ssh)
|
54
|
+
Framework::LinuxApp.ensureServiceAutoStartOverSSH(NGINX_PACKAGE, ssh)
|
55
|
+
self.class.prepareNginxConfig(target, ssh)
|
56
|
+
self.writeNginxConfig(__dir__, 'Odoo', id, target, state, context, options)
|
57
|
+
self.deployNginxConfig(id, target, activeState, context, options)
|
58
|
+
Framework::LinuxApp.startServiceOverSSH(NGINX_PACKAGE, ssh)
|
59
|
+
end
|
60
|
+
|
61
|
+
Framework::LinuxApp.firewallAddPortOverSSH('8069/tcp', uri)
|
62
|
+
end
|
63
|
+
else
|
64
|
+
if !target.key?('Proxy') || target['Proxy'] == true || target['Proxy'] == 'only'
|
65
|
+
deployNginxConfig(id, target, activeState, context, options)
|
66
|
+
end
|
17
67
|
activeState['Location'] = '@me'
|
18
68
|
end
|
19
69
|
end
|
20
70
|
|
71
|
+
def configurePostgreSQL(settings, ssh)
|
72
|
+
user = USER
|
73
|
+
password = SecureRandom.alphanumeric(20)
|
74
|
+
PostgreSQL.executeRemotelyOverSSH(settings, ssh) do |ssh|
|
75
|
+
self.class.sshExec!(ssh, "su --login #{PostgreSQL::USER_NAME} --command 'createuser --createdb #{user}'", true)
|
76
|
+
PostgreSQL.executeSQL("ALTER USER #{user} WITH PASSWORD '#{password}'", nil, ssh)
|
77
|
+
end
|
78
|
+
password
|
79
|
+
end
|
80
|
+
|
21
81
|
end
|
22
82
|
end
|
23
83
|
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
[options]
|
2
|
+
addons_path = /mnt/extra-addons
|
3
|
+
data_dir = /var/lib/odoo
|
4
|
+
; admin_passwd = admin
|
5
|
+
; csv_internal_sep = ,
|
6
|
+
; db_maxconn = 64
|
7
|
+
; db_name = False
|
8
|
+
; db_template = template1
|
9
|
+
; dbfilter = .*
|
10
|
+
; debug_mode = False
|
11
|
+
; email_from = False
|
12
|
+
; limit_memory_hard = 2684354560
|
13
|
+
; limit_memory_soft = 2147483648
|
14
|
+
; limit_request = 8192
|
15
|
+
; limit_time_cpu = 60
|
16
|
+
; limit_time_real = 120
|
17
|
+
list_db = False
|
18
|
+
; log_db = False
|
19
|
+
; log_handler = [':INFO']
|
20
|
+
; log_level = info
|
21
|
+
; logfile = None
|
22
|
+
; longpolling_port = 8072
|
23
|
+
; max_cron_threads = 2
|
24
|
+
; osv_memory_age_limit = 1.0
|
25
|
+
; osv_memory_count_limit = False
|
26
|
+
; smtp_password = False
|
27
|
+
; smtp_port = 25
|
28
|
+
; smtp_server = localhost
|
29
|
+
; smtp_ssl = False
|
30
|
+
; smtp_user = False
|
31
|
+
; workers = 0
|
32
|
+
; xmlrpc = True
|
33
|
+
; xmlrpc_interface =
|
34
|
+
; xmlrpc_port = 8069
|
35
|
+
; xmlrpcs = True
|
36
|
+
; xmlrpcs_interface =
|
37
|
+
; xmlrpcs_port = 8071
|
@@ -0,0 +1,95 @@
|
|
1
|
+
|
2
|
+
module ConfigLMM
|
3
|
+
module LMM
|
4
|
+
class PHP_FPM < Framework::LinuxApp
|
5
|
+
|
6
|
+
PHPFPM_PACKAGE = 'PHP-FPM'
|
7
|
+
PHPFPM_SERVICE = 'php-fpm'
|
8
|
+
|
9
|
+
def self.writeConfig(name, target, distroInfo, configLines)
|
10
|
+
target['PHP-FPM'] ||= {}
|
11
|
+
|
12
|
+
configLines << "[#{name}]\n"
|
13
|
+
configLines << "user = #{target['User']}\n"
|
14
|
+
configLines << "group = #{target['User']}\n"
|
15
|
+
if target['Listen']
|
16
|
+
configLines << "listen = #{target['Listen']}\n"
|
17
|
+
else
|
18
|
+
configLines << "listen = /run/php-fpm/#{name}.sock\n"
|
19
|
+
configLines << "listen.owner = #{target['User']}\n"
|
20
|
+
group = 'http'
|
21
|
+
group = 'nginx' if distroInfo['Name'] == 'openSUSE Leap'
|
22
|
+
configLines << "listen.group = #{group}\n"
|
23
|
+
end
|
24
|
+
configLines << "pm = dynamic\n"
|
25
|
+
configLines << "pm.max_children = 5\n"
|
26
|
+
configLines << "pm.min_spare_servers = 1\n"
|
27
|
+
configLines << "pm.max_spare_servers = 3\n"
|
28
|
+
configLines << "pm.start_servers = 2\n"
|
29
|
+
configLines << "access.log = /var/log/php/$pool.access.log\n"
|
30
|
+
if target['PHP-FPM']['chdir']
|
31
|
+
configLines << "chdir = #{target['PHP-FPM']['chdir']}\n"
|
32
|
+
else
|
33
|
+
configLines << "chdir = #{self.webappsDir(distroInfo)}$pool\n"
|
34
|
+
end
|
35
|
+
configLines << "php_admin_value[error_log] = /var/log/php/$pool.errors.log\n"
|
36
|
+
configLines << "php_admin_flag[log_errors] = on\n"
|
37
|
+
configLines << "php_admin_value[memory_limit] = 1G\n"
|
38
|
+
configLines << "php_admin_value[mail.log] = /var/log/php/$pool.mail.log\n"
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.phpConfig(distroInfo)
|
42
|
+
if distroInfo['Name'] == 'openSUSE Leap'
|
43
|
+
'/etc/php8/fpm/php.ini'
|
44
|
+
else
|
45
|
+
'/etc/php/php.ini'
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.peclInstallOverSSH(name, ssh)
|
50
|
+
self.sshExec!(ssh, "printf \"\\n\" | pecl install #{name}", true)
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.enableExtensionOverSSH(name, distroInfo, ssh)
|
54
|
+
phpFile = self.phpConfig(distroInfo)
|
55
|
+
if self.remoteFileContains?(phpFile, "extension=#{name}", ssh)
|
56
|
+
self.sshExec!(ssh, "sed -i 's|^;extension=#{name}|extension=#{name}|' #{phpFile}")
|
57
|
+
else
|
58
|
+
self.sshExec!(ssh, "sed -i 's|extension=zip|extension=zip\\nextension=#{name}|' #{phpFile}")
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.configFileDir(distroInfo)
|
63
|
+
if distroInfo['Name'] == 'openSUSE Leap'
|
64
|
+
'/etc/php8/fpm/'
|
65
|
+
else
|
66
|
+
'/etc/php/'
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def self.configDir(distroInfo)
|
71
|
+
if distroInfo['Name'] == 'openSUSE Leap'
|
72
|
+
'/etc/php8/fpm/php-fpm.d/'
|
73
|
+
else
|
74
|
+
'/etc/php/php-fpm.d/'
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def self.webappsDir(distroInfo)
|
79
|
+
if distroInfo['Name'] == 'openSUSE Leap'
|
80
|
+
'/srv/www/htdocs/'
|
81
|
+
else
|
82
|
+
'/usr/share/webapps/'
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def self.fixConfigFileOverSSH(distroInfo, ssh)
|
87
|
+
dir = self.configFileDir(distroInfo)
|
88
|
+
if !self.remoteFilePresent?(dir + 'php-fpm.conf', ssh)
|
89
|
+
self.sshExec!(ssh, "cp #{dir}php-fpm.conf.default #{dir}php-fpm.conf")
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
|
2
|
+
server {
|
3
|
+
listen 80;
|
4
|
+
listen [::]:80;
|
5
|
+
server_name peppermint.example.com;
|
6
|
+
add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always;
|
7
|
+
|
8
|
+
<% if !config['TLS'] %>
|
9
|
+
listen <%= config['Port'] %>;
|
10
|
+
listen [::]:<%= config['Port'] %>;
|
11
|
+
<% else %>
|
12
|
+
<% if config['NginxVersion'] >= 1.25 %>
|
13
|
+
listen <%= config['Port'] %> ssl;
|
14
|
+
listen [::]:<%= config['Port'] %> ssl;
|
15
|
+
http2 on;
|
16
|
+
http3 on;
|
17
|
+
quic_retry on;
|
18
|
+
add_header Alt-Svc 'h3=":<%= config['Port'] %>"; ma=86400';
|
19
|
+
<% else %>
|
20
|
+
listen <%= config['Port'] %> ssl http2;
|
21
|
+
listen [::]:<%= config['Port'] %> ssl http2;
|
22
|
+
<% end %>
|
23
|
+
|
24
|
+
include config-lmm/ssl.conf;
|
25
|
+
<% end %>
|
26
|
+
|
27
|
+
server_name <%= config['Domain'] %>;
|
28
|
+
|
29
|
+
access_log /var/log/nginx/peppermint.access.log;
|
30
|
+
error_log /var/log/nginx/peppermint.error.log;
|
31
|
+
|
32
|
+
include config-lmm/errors.conf;
|
33
|
+
include config-lmm/security.conf;
|
34
|
+
|
35
|
+
client_max_body_size 10M;
|
36
|
+
|
37
|
+
location / {
|
38
|
+
<% if config['Server'] %>
|
39
|
+
proxy_pass <%= config['Server'] %>;
|
40
|
+
<% else %>
|
41
|
+
proxy_pass http://127.0.0.1:13000;
|
42
|
+
<% end %>
|
43
|
+
|
44
|
+
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503;
|
45
|
+
|
46
|
+
include config-lmm/proxy.conf;
|
47
|
+
proxy_redirect off;
|
48
|
+
proxy_read_timeout 5m;
|
49
|
+
}
|
50
|
+
|
51
|
+
location /api/ {
|
52
|
+
<% if config['Server'] %>
|
53
|
+
proxy_pass <%= config['Server'] %>;
|
54
|
+
<% else %>
|
55
|
+
proxy_pass http://127.0.0.1:15003/;
|
56
|
+
<% end %>
|
57
|
+
|
58
|
+
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503;
|
59
|
+
|
60
|
+
include config-lmm/proxy.conf;
|
61
|
+
proxy_redirect off;
|
62
|
+
proxy_read_timeout 5m;
|
63
|
+
}
|
64
|
+
}
|
@@ -0,0 +1,14 @@
|
|
1
|
+
|
2
|
+
[Unit]
|
3
|
+
Description=Peppermint Ticket Management container
|
4
|
+
After=local-fs.target
|
5
|
+
|
6
|
+
[Container]
|
7
|
+
Image=pepperlabs/peppermint:latest
|
8
|
+
EnvironmentFile=/var/lib/peppermint/.config/containers/systemd/Peppermint.env
|
9
|
+
Network=slirp4netns:allow_host_loopback=true
|
10
|
+
PublishPort=127.0.0.1:13000:3000
|
11
|
+
PublishPort=127.0.0.1:15003:5003
|
12
|
+
|
13
|
+
[Install]
|
14
|
+
WantedBy=multi-user.target default.target
|
@@ -0,0 +1,58 @@
|
|
1
|
+
|
2
|
+
module ConfigLMM
|
3
|
+
module LMM
|
4
|
+
class Peppermint < Framework::NginxApp
|
5
|
+
|
6
|
+
USER = 'peppermint'
|
7
|
+
HOME_DIR = '/var/lib/peppermint'
|
8
|
+
HOST_IP = '10.0.2.2'
|
9
|
+
|
10
|
+
def actionPeppermintDeploy(id, target, activeState, context, options)
|
11
|
+
raise Framework::PluginProcessError.new('Domain field must be set!') unless target['Domain']
|
12
|
+
|
13
|
+
target['Database'] ||= {}
|
14
|
+
if target['Location'] && target['Location'] != '@me'
|
15
|
+
uri = Addressable::URI.parse(target['Location'])
|
16
|
+
raise Framework::PluginProcessError.new("#{id}: Unknown Protocol: #{uri.scheme}!") if uri.scheme != 'ssh'
|
17
|
+
|
18
|
+
self.class.sshStart(uri) do |ssh|
|
19
|
+
|
20
|
+
dbPassword = self.configurePostgreSQL(target['Database'], ssh)
|
21
|
+
distroInfo = Framework::LinuxApp.currentDistroInfo(ssh)
|
22
|
+
Framework::LinuxApp.configurePodmanServiceOverSSH(USER, HOME_DIR, 'Peppermint Ticket Management', distroInfo, ssh)
|
23
|
+
|
24
|
+
path = Framework::LinuxApp::SYSTEMD_CONTAINERS_PATH.gsub('~', HOME_DIR)
|
25
|
+
self.class.sshExec!(ssh, " echo 'DB_HOST=#{HOST_IP}' > #{path}/Peppermint.env")
|
26
|
+
self.class.sshExec!(ssh, " echo 'DB_USERNAME=#{USER}' >> #{path}/Peppermint.env")
|
27
|
+
self.class.sshExec!(ssh, " echo 'DB_PASSWORD=#{dbPassword}' >> #{path}/Peppermint.env")
|
28
|
+
self.class.sshExec!(ssh, " echo 'SECRET=#{SecureRandom.urlsafe_base64(60)}' >> #{path}/Peppermint.env")
|
29
|
+
self.class.sshExec!(ssh, " echo 'API_URL=https://#{target['Domain']}/api' >> #{path}/Peppermint.env")
|
30
|
+
self.class.sshExec!(ssh, "chown #{USER}:#{USER} #{path}/Peppermint.env")
|
31
|
+
self.class.sshExec!(ssh, "chmod 600 #{path}/Peppermint.env")
|
32
|
+
|
33
|
+
ssh.scp.upload!(__dir__ + '/Peppermint.container', path)
|
34
|
+
self.class.sshExec!(ssh, "systemctl --user --machine=#{USER}@ daemon-reload")
|
35
|
+
self.class.sshExec!(ssh, "systemctl --user --machine=#{USER}@ start Peppermint")
|
36
|
+
|
37
|
+
Framework::LinuxApp.ensurePackages([NGINX_PACKAGE], ssh)
|
38
|
+
Framework::LinuxApp.ensureServiceAutoStartOverSSH(NGINX_PACKAGE, ssh)
|
39
|
+
self.class.prepareNginxConfig(target, ssh)
|
40
|
+
self.writeNginxConfig(__dir__, 'Peppermint', id, target, state, context, options)
|
41
|
+
self.deployNginxConfig(id, target, activeState, context, options)
|
42
|
+
Framework::LinuxApp.startServiceOverSSH(NGINX_PACKAGE, ssh)
|
43
|
+
end
|
44
|
+
else
|
45
|
+
# TODO
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def configurePostgreSQL(settings, ssh)
|
50
|
+
password = SecureRandom.alphanumeric(20)
|
51
|
+
PostgreSQL.createRemoteUserAndDBOverSSH(settings, USER, password, ssh)
|
52
|
+
password
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
@@ -4,12 +4,12 @@ module ConfigLMM
|
|
4
4
|
class Postfix < Framework::Plugin
|
5
5
|
PACKAGE_NAME = 'Postfix'
|
6
6
|
SERVICE_NAME = 'postfix'
|
7
|
-
MASTER_FILE = '
|
8
|
-
MAIN_FILE = '
|
9
|
-
TRANSPORT_FILE = '
|
7
|
+
MASTER_FILE = 'master.cf'
|
8
|
+
MAIN_FILE = 'main.cf'
|
9
|
+
TRANSPORT_FILE = 'transport'
|
10
10
|
|
11
11
|
def actionPostfixDeploy(id, target, activeState, context, options)
|
12
|
-
plugins[:Linux].
|
12
|
+
plugins[:Linux].ensurePackages([PACKAGE_NAME, 'CyrusSASL'], target['Location'])
|
13
13
|
plugins[:Linux].ensureServiceAutoStart(SERVICE_NAME, target['Location'])
|
14
14
|
|
15
15
|
deploySettings(target, target['Location'], options)
|
@@ -18,54 +18,162 @@ module ConfigLMM
|
|
18
18
|
end
|
19
19
|
|
20
20
|
def deploySettings(target, location, options)
|
21
|
+
postfixDirName = 'postfix'
|
22
|
+
postfixDirName = 'postfix-' + target['Instance'] if target['Instance']
|
23
|
+
postfixDir = '/etc/' + postfixDirName + '/'
|
21
24
|
if location && location != '@me'
|
22
|
-
if target['AlternativePort']
|
23
|
-
updateRemoteFile(location, MASTER_FILE, options, true) do |fileLines|
|
24
|
-
fileLines << "#{target['AlternativePort']} inet n - n - - smtpd\n"
|
25
|
-
end
|
26
|
-
end
|
27
25
|
self.class.sshStart(location) do |ssh|
|
28
|
-
|
29
|
-
|
30
|
-
|
26
|
+
if target['Instance']
|
27
|
+
self.class.sshExec!(ssh, "postmulti -e init")
|
28
|
+
self.class.sshExec!(ssh, "postmulti -I #{postfixDirName} -e create", true)
|
29
|
+
self.class.sshExec!(ssh, "sed -i 's|^master_service_disable|#master_service_disable|' #{postfixDir + MAIN_FILE}")
|
30
|
+
end
|
31
|
+
self.class.sshExec!(ssh, "sed -i 's|^tlsmgr|#tlsmgr|' #{postfixDir + MASTER_FILE}")
|
32
|
+
if target.key?('SMTP')
|
33
|
+
if !target['SMTP'] || target['SMTP'] == 'unix'
|
34
|
+
self.class.sshExec!(ssh, "sed -i 's|^smtp|#smtp|' #{postfixDir + MASTER_FILE}")
|
35
|
+
end
|
36
|
+
end
|
37
|
+
updateRemoteFile(ssh, postfixDir + MASTER_FILE, options, true) do |fileLines|
|
38
|
+
if target['AlternativePort']
|
39
|
+
fileLines << "#{target['AlternativePort']} inet n - n - - smtpd\n"
|
40
|
+
fileLines << "tlsmgr unix - - n 1000? 1 tlsmgr\n"
|
41
|
+
else
|
42
|
+
if !target.key?('Submission') || (target.key?('Submission') && target['Submission'])
|
43
|
+
fileLines << "submissions inet n - n - - smtpd\n"
|
44
|
+
fileLines << " -o syslog_name=postfix/submissions\n"
|
45
|
+
fileLines << " -o smtpd_tls_wrappermode=yes\n"
|
46
|
+
fileLines << " -o smtpd_tls_security_level=encrypt\n"
|
47
|
+
fileLines << " -o smtpd_sasl_auth_enable=yes\n"
|
48
|
+
fileLines << " -o cleanup_service_name=header_cleanup\n"
|
49
|
+
fileLines << "header_cleanup unix n - - - 0 cleanup\n"
|
50
|
+
fileLines << " -o header_checks=regexp:/etc/postfix/header_cleanup\n"
|
51
|
+
|
52
|
+
self.class.sshExec!(ssh, "echo '/^Received:/ IGNORE' > /etc/postfix/header_cleanup")
|
53
|
+
self.class.sshExec!(ssh, "echo '/^User-Agent:/ IGNORE' >> /etc/postfix/header_cleanup")
|
54
|
+
end
|
55
|
+
fileLines << "tlsmgr unix - - n 1000? 1 tlsmgr\n"
|
56
|
+
if target['SMTP'] == 'unix'
|
57
|
+
fileLines << "smtp unix - - n - - smtp\n"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
fileLines
|
61
|
+
end
|
62
|
+
|
63
|
+
domain = target['Domain']
|
64
|
+
domain = self.class.sshExec!(ssh, "hostname --fqdn").strip unless domain
|
65
|
+
command = "sed -i 's|^myhostname = .*|myhostname = #{domain}|' #{postfixDir + MAIN_FILE}"
|
31
66
|
self.class.sshExec!(ssh, command)
|
32
|
-
|
33
|
-
|
67
|
+
command = "sed -i 's|^#myhostname = virtual.domain.tld|myhostname = #{domain}|' #{postfixDir + MAIN_FILE}"
|
68
|
+
self.class.sshExec!(ssh, command)
|
69
|
+
|
70
|
+
# Fix config bug
|
71
|
+
command = "sed -i 's|^alias_maps = :/etc/aliases|alias_maps = lmdb:/etc/aliases|' #{postfixDir + MAIN_FILE}"
|
72
|
+
self.class.sshExec!(ssh, command)
|
73
|
+
command = "sed -i 's|^canonical_maps = :/etc/postfix/canonical|canonical_maps = lmdb:/etc/postfix/canonical|' #{postfixDir + MAIN_FILE}"
|
74
|
+
self.class.sshExec!(ssh, command)
|
75
|
+
command = "sed -i 's|^relocated_maps = :/etc/postfix/relocated|relocated_maps = lmdb:/etc/postfix/relocated|' #{postfixDir + MAIN_FILE}"
|
76
|
+
self.class.sshExec!(ssh, command)
|
77
|
+
command = "sed -i 's|^sender_canonical_maps = :/etc/postfix/sender_canonical|sender_canonical_maps = lmdb:/etc/postfix/sender_canonical|' #{postfixDir + MAIN_FILE}"
|
78
|
+
self.class.sshExec!(ssh, command)
|
79
|
+
command = "sed -i 's|^transport_maps = :/etc/postfix/transport|transport_maps = lmdb:/etc/postfix/transport|' #{postfixDir + MAIN_FILE}"
|
80
|
+
self.class.sshExec!(ssh, command)
|
81
|
+
command = "sed -i 's|^smtpd_sender_restrictions = :/etc/postfix/access|smtpd_sender_restrictions = lmdb:/etc/postfix/access|' #{postfixDir + MAIN_FILE}"
|
82
|
+
self.class.sshExec!(ssh, command)
|
83
|
+
command = "sed -i 's|^virtual_alias_maps = :/etc/postfix/virtual|virtual_alias_maps = lmdb:/etc/postfix/virtual|' #{postfixDir + MAIN_FILE}"
|
84
|
+
self.class.sshExec!(ssh, command)
|
85
|
+
command = "sed -i 's|^relay_domains = $mydestination :/etc/postfix/relay|relay_domains = $mydestination lmdb:/etc/postfix/relay|' #{postfixDir + MAIN_FILE}"
|
86
|
+
self.class.sshExec!(ssh, command)
|
87
|
+
command = "sed -i 's|^relay_recipient_maps = :/etc/postfix/relay_recipients|relay_recipient_maps = lmdb:/etc/postfix/relay_recipients|' #{postfixDir + MAIN_FILE}"
|
88
|
+
self.class.sshExec!(ssh, command)
|
89
|
+
command = "sed -i 's|^virtual_mailbox_maps =.*|virtual_mailbox_maps = lmdb:/etc/postfix/mailboxes|' #{postfixDir + MAIN_FILE}"
|
90
|
+
self.class.sshExec!(ssh, command)
|
91
|
+
|
92
|
+
|
93
|
+
if target['AlternativePort']
|
94
|
+
self.class.sshExec!(ssh, "firewall-cmd -q --add-port='#{target['AlternativePort']}/tcp'")
|
95
|
+
self.class.sshExec!(ssh, "firewall-cmd -q --permanent --add-port='#{target['AlternativePort']}/tcp'")
|
96
|
+
else
|
97
|
+
self.class.sshExec!(ssh, "firewall-cmd -q --add-service='smtp'")
|
98
|
+
self.class.sshExec!(ssh, "firewall-cmd -q --permanent --add-service='smtp'")
|
99
|
+
end
|
100
|
+
self.class.sshExec!(ssh, "firewall-cmd -q --add-service='smtps'")
|
101
|
+
self.class.sshExec!(ssh, "firewall-cmd -q --permanent --add-service='smtps'")
|
102
|
+
|
103
|
+
ssh.scp.upload!(__dir__ + '/smtpd.conf', '/etc/sasl2/smtpd.conf')
|
104
|
+
self.class.sshExec!(ssh, "touch /etc/sasldb2")
|
105
|
+
self.class.sshExec!(ssh, "chown postfix:postfix /etc/sasldb2")
|
106
|
+
self.class.sshExec!(ssh, "touch #{postfixDir}access")
|
107
|
+
self.class.sshExec!(ssh, "postmap #{postfixDir}access")
|
108
|
+
self.class.sshExec!(ssh, "touch #{postfixDir}sender_login")
|
109
|
+
self.class.sshExec!(ssh, "postmap #{postfixDir}sender_login")
|
110
|
+
|
111
|
+
certDir = Framework::LinuxApp.createCertificateOverSSH(ssh)
|
112
|
+
target['Settings'] ||= []
|
113
|
+
target['Settings']['smtpd_sender_login_maps'] = "lmdb:#{postfixDir}sender_login" unless target['Settings']['smtpd_sender_login_maps']
|
114
|
+
target['Settings']['smtpd_sender_restrictions'] = "reject_sender_login_mismatch, lmdb:#{postfixDir}access" unless target['Settings']['smtpd_sender_restrictions']
|
115
|
+
target['Settings']['smtp_tls_security_level'] = 'may' unless target['Settings']['smtp_tls_security_level']
|
116
|
+
target['Settings']['smtpd_tls_mandatory_protocols'] = '>=TLSv1.2' unless target['Settings']['smtpd_tls_mandatory_protocols']
|
117
|
+
target['Settings']['smtpd_tls_auth_only'] = 'yes' unless target['Settings']['smtpd_tls_auth_only']
|
118
|
+
target['Settings']['smtpd_tls_security_level'] = 'may' unless target['Settings']['smtpd_tls_security_level']
|
119
|
+
target['Settings']['smtpd_tls_cert_file'] = certDir + 'fullchain.pem' unless target['Settings']['smtpd_tls_cert_file']
|
120
|
+
target['Settings']['smtpd_tls_key_file'] = certDir + 'privkey.pem' unless target['Settings']['smtpd_tls_key_file']
|
121
|
+
target['Settings']['tls_preempt_cipherlist'] = 'yes' unless target['Settings']['tls_preempt_cipherlist']
|
122
|
+
target['Settings']['tls_ssl_options'] = 'NO_RENEGOTIATION' unless target['Settings']['tls_ssl_options']
|
123
|
+
|
124
|
+
|
34
125
|
target['Settings'].each do |name, value|
|
35
|
-
|
36
|
-
|
37
|
-
|
126
|
+
command = "sed -i 's|^#{name} =.*|##{name} = #{value}|' #{postfixDir + MAIN_FILE}"
|
127
|
+
self.class.sshExec!(ssh, command)
|
128
|
+
end
|
129
|
+
updateRemoteFile(ssh, postfixDir + MAIN_FILE, options) do |fileLines|
|
130
|
+
target['Settings'].each do |name, value|
|
131
|
+
value = 'yes' if value == true
|
132
|
+
value = 'no' if value == false
|
133
|
+
fileLines << "#{name} = #{value}\n"
|
38
134
|
end
|
135
|
+
fileLines
|
39
136
|
end
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
hostname = '[' + hostname + ']'
|
45
|
-
line = '* smtp:' + hostname
|
46
|
-
line += ':' + port if port
|
47
|
-
fileLines << line + "\n"
|
137
|
+
|
138
|
+
if target['ForwardDovecot']
|
139
|
+
command = "sed -i 's|^#virtual_transport =.*|virtual_transport = lmtp:unix:/run/dovecot/lmtp|' #{postfixDir + MAIN_FILE}"
|
140
|
+
self.class.sshExec!(ssh, command)
|
48
141
|
end
|
49
|
-
|
50
|
-
|
142
|
+
|
143
|
+
if target['ForwardAll']
|
144
|
+
command = "sed -i 's|^transport_maps =.*|transport_maps = lmdb:#{postfixDir}transport|' #{postfixDir + MAIN_FILE}"
|
145
|
+
self.class.sshExec!(ssh, command)
|
146
|
+
updateRemoteFile(ssh, postfixDir + TRANSPORT_FILE, options, true) do |fileLines|
|
147
|
+
hostname, port = target['ForwardAll'].split(':')
|
148
|
+
hostname = '[' + hostname + ']'
|
149
|
+
line = '* smtp:' + hostname
|
150
|
+
line += ':' + port if port
|
151
|
+
fileLines << line + "\n"
|
152
|
+
end
|
153
|
+
self.class.sshExec!(ssh, "postmap #{postfixDir + TRANSPORT_FILE}")
|
154
|
+
end
|
155
|
+
|
156
|
+
if target['Instance']
|
157
|
+
self.class.sshExec!(ssh, "postmulti -i #{postfixDirName} -e enable")
|
158
|
+
self.class.sshExec!(ssh, "postmulti -i #{postfixDirName} -p start", true)
|
51
159
|
end
|
52
160
|
end
|
53
161
|
else
|
54
162
|
if target['AlternativePort']
|
55
|
-
updateLocalFile(MASTER_FILE, options, true) do |fileLines|
|
163
|
+
updateLocalFile(postfixDir + MASTER_FILE, options, true) do |fileLines|
|
56
164
|
fileLines << "#{target['AlternativePort']} inet n - n - - smtpd\n"
|
57
165
|
end
|
58
166
|
end
|
59
167
|
if target['Settings']
|
60
168
|
target['Settings'].each do |name, value|
|
61
|
-
`sed -i 's|^#{name} =.*|#{name} = #{value}|' #{MAIN_FILE}`
|
169
|
+
`sed -i 's|^#{name} =.*|#{name} = #{value}|' #{postfixDir + MAIN_FILE}`
|
62
170
|
end
|
63
171
|
end
|
64
172
|
if target['ForwardAll']
|
65
|
-
updateLocalFile(TRANSPORT_FILE, options, true) do |fileLines|
|
173
|
+
updateLocalFile(postfixDir + TRANSPORT_FILE, options, true) do |fileLines|
|
66
174
|
fileLines << '* smtp:[' + target['ForwardAll'] + "]\n"
|
67
175
|
end
|
68
|
-
`postmap #{TRANSPORT_FILE}`
|
176
|
+
`postmap #{postfixDir + TRANSPORT_FILE}`
|
69
177
|
end
|
70
178
|
end
|
71
179
|
end
|