smartmachine 1.2.3 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. checksums.yaml +4 -4
  2. data/lib/smart_machine/apps/app.rb +1 -0
  3. data/lib/smart_machine/buildpackers/buildpacker.rb +2 -2
  4. data/lib/smart_machine/commands/grid.rb +8 -0
  5. data/lib/smart_machine/commands/grid_commands/emailer.rb +107 -0
  6. data/lib/smart_machine/commands/grid_commands/roundcube.rb +107 -0
  7. data/lib/smart_machine/configuration.rb +35 -2
  8. data/lib/smart_machine/credentials.rb +10 -0
  9. data/lib/smart_machine/engine.rb +7 -1
  10. data/lib/smart_machine/grids/adminer.rb +1 -0
  11. data/lib/smart_machine/grids/certbot.rb +1 -0
  12. data/lib/smart_machine/grids/emailer/imapsync.rb +7 -0
  13. data/lib/smart_machine/grids/emailer.rb +188 -0
  14. data/lib/smart_machine/grids/haproxy.rb +1 -0
  15. data/lib/smart_machine/grids/mariadb.rb +1 -0
  16. data/lib/smart_machine/grids/postgresql.rb +1 -0
  17. data/lib/smart_machine/grids/roundcube/.keep +0 -0
  18. data/lib/smart_machine/grids/roundcube.rb +184 -0
  19. data/lib/smart_machine/machine.rb +7 -0
  20. data/lib/smart_machine/syncer.rb +10 -0
  21. data/lib/smart_machine/templates/dotsmartmachine/config/emailer/docker/command.rb +50 -0
  22. data/lib/smart_machine/templates/dotsmartmachine/config/emailer/docker/entrypoint.rb +196 -0
  23. data/lib/smart_machine/templates/dotsmartmachine/config/emailer/docker/logtailer.rb +75 -0
  24. data/lib/smart_machine/templates/dotsmartmachine/config/emailer/etc/dovecot/conf.d/10-auth.conf +132 -0
  25. data/lib/smart_machine/templates/dotsmartmachine/config/emailer/etc/dovecot/conf.d/10-mail.conf +427 -0
  26. data/lib/smart_machine/templates/dotsmartmachine/config/emailer/etc/dovecot/conf.d/10-master.conf +153 -0
  27. data/lib/smart_machine/templates/dotsmartmachine/config/emailer/etc/dovecot/conf.d/10-ssl.conf +87 -0
  28. data/lib/smart_machine/templates/dotsmartmachine/config/emailer/etc/dovecot/conf.d/15-mailboxes.conf +94 -0
  29. data/lib/smart_machine/templates/dotsmartmachine/config/emailer/etc/dovecot/conf.d/20-imap.conf +102 -0
  30. data/lib/smart_machine/templates/dotsmartmachine/config/emailer/etc/dovecot/conf.d/20-lmtp.conf +43 -0
  31. data/lib/smart_machine/templates/dotsmartmachine/config/emailer/etc/dovecot/conf.d/90-quota.conf +114 -0
  32. data/lib/smart_machine/templates/dotsmartmachine/config/emailer/etc/dovecot/conf.d/90-sieve.conf +229 -0
  33. data/lib/smart_machine/templates/dotsmartmachine/config/emailer/etc/dovecot/dovecot-sql.conf.ext +163 -0
  34. data/lib/smart_machine/templates/dotsmartmachine/config/emailer/etc/dovecot/sieve/learn-ham.sh +2 -0
  35. data/lib/smart_machine/templates/dotsmartmachine/config/emailer/etc/dovecot/sieve/learn-ham.sieve +5 -0
  36. data/lib/smart_machine/templates/dotsmartmachine/config/emailer/etc/dovecot/sieve/learn-spam.sh +2 -0
  37. data/lib/smart_machine/templates/dotsmartmachine/config/emailer/etc/dovecot/sieve/learn-spam.sieve +2 -0
  38. data/lib/smart_machine/templates/dotsmartmachine/config/emailer/etc/dovecot/sieve-after/spam-to-folder.sieve +6 -0
  39. data/lib/smart_machine/templates/dotsmartmachine/config/emailer/etc/haproxy/haproxy.cfg +58 -0
  40. data/lib/smart_machine/templates/dotsmartmachine/config/emailer/etc/monit/conf.d/services.cfg +70 -0
  41. data/lib/smart_machine/templates/dotsmartmachine/config/emailer/etc/monit/monitrc +344 -0
  42. data/lib/smart_machine/templates/dotsmartmachine/config/emailer/etc/opendkim.conf +71 -0
  43. data/lib/smart_machine/templates/dotsmartmachine/config/emailer/etc/postfix/main.cf +128 -0
  44. data/lib/smart_machine/templates/dotsmartmachine/config/emailer/etc/postfix/master.cf +149 -0
  45. data/lib/smart_machine/templates/dotsmartmachine/config/emailer/etc/postfix/mysql-sender-login-maps.cf +7 -0
  46. data/lib/smart_machine/templates/dotsmartmachine/config/emailer/etc/postfix/mysql-virtual-alias-domains.cf +7 -0
  47. data/lib/smart_machine/templates/dotsmartmachine/config/emailer/etc/postfix/mysql-virtual-alias-maps-domains.cf +7 -0
  48. data/lib/smart_machine/templates/dotsmartmachine/config/emailer/etc/postfix/mysql-virtual-alias-maps-masters.cf +7 -0
  49. data/lib/smart_machine/templates/dotsmartmachine/config/emailer/etc/postfix/mysql-virtual-alias-maps-users.cf +7 -0
  50. data/lib/smart_machine/templates/dotsmartmachine/config/emailer/etc/postfix/mysql-virtual-alias-maps-userstothemselves.cf +7 -0
  51. data/lib/smart_machine/templates/dotsmartmachine/config/emailer/etc/postfix/mysql-virtual-mailbox-domains.cf +7 -0
  52. data/lib/smart_machine/templates/dotsmartmachine/config/emailer/etc/postfix/mysql-virtual-mailbox-maps.cf +7 -0
  53. data/lib/smart_machine/templates/dotsmartmachine/config/emailer/etc/postfix-policyd-spf-python/policyd-spf.conf +12 -0
  54. data/lib/smart_machine/templates/dotsmartmachine/config/emailer/etc/spamassassin/local.cf +124 -0
  55. data/lib/smart_machine/templates/dotsmartmachine/config/emailer/usr/local/bin/quota-warning.sh +22 -0
  56. data/lib/smart_machine/templates/dotsmartmachine/config/emailer.yml +37 -0
  57. data/lib/smart_machine/templates/dotsmartmachine/config/engine.yml +2 -0
  58. data/lib/smart_machine/templates/dotsmartmachine/config/roundcube/docker/custom-docker-entrypoint.sh +185 -0
  59. data/lib/smart_machine/templates/dotsmartmachine/config/roundcube/docker/entrypoint.rb +58 -0
  60. data/lib/smart_machine/templates/dotsmartmachine/config/roundcube/etc/apache2/sites-available/000-default.conf +36 -0
  61. data/lib/smart_machine/templates/dotsmartmachine/config/roundcube/usr/local/etc/php/conf.d/zzz_roundcube-custom.ini +4 -0
  62. data/lib/smart_machine/templates/dotsmartmachine/config/roundcube/var/roundcube/config/config.custom.inc.php +25 -0
  63. data/lib/smart_machine/templates/dotsmartmachine/config/roundcube/var/www/html/plugins/password/config.inc.php +523 -0
  64. data/lib/smart_machine/templates/dotsmartmachine/config/roundcube.yml +49 -0
  65. data/lib/smart_machine/templates/dotsmartmachine/config/users.yml +1 -1
  66. data/lib/smart_machine/version.rb +2 -2
  67. data/lib/smart_machine.rb +2 -0
  68. metadata +89 -8
@@ -0,0 +1,184 @@
1
+ module SmartMachine
2
+ class Grids
3
+ class Roundcube < SmartMachine::Base
4
+ def initialize(name:)
5
+ config = SmartMachine.config.grids.roundcube.dig(name.to_sym)
6
+ raise "roundcube config for #{name} not found." unless config
7
+
8
+ @fqdn = config.dig(:fqdn)
9
+ @image = "smartmachine/roundcube:#{SmartMachine.version}"
10
+ @sysadmin_email = config.dig(:sysadmin_email)
11
+ @networks = config.dig(:networks)
12
+ @database_type = config.dig(:database_type)
13
+ @database_host = config.dig(:database_host)
14
+ @database_port = config.dig(:database_port)
15
+ @database_user = config.dig(:database_user)
16
+ @database_pass = config.dig(:database_pass)
17
+ @database_name = config.dig(:database_name)
18
+ @mail_host = config.dig(:mail_host)
19
+ @mail_port = config.dig(:mail_port)
20
+ @smtp_host = config.dig(:smtp_host)
21
+ @smtp_port = config.dig(:smtp_port)
22
+ @request_path = config.dig(:request_path)
23
+ @plugins = config.dig(:plugins)
24
+ @plugins_password_database_type = config.dig(:plugins_password_database_type)
25
+ @plugins_password_database_host = config.dig(:plugins_password_database_host)
26
+ @plugins_password_database_user = config.dig(:plugins_password_database_user)
27
+ @plugins_password_database_pass = config.dig(:plugins_password_database_pass)
28
+ @plugins_password_database_name = config.dig(:plugins_password_database_name)
29
+ @skin = config.dig(:skin)
30
+ @upload_max_filesize = config.dig(:upload_max_filesize)
31
+ @aspell_dictionaries = config.dig(:aspell_dictionaries)
32
+
33
+ @name = name.to_s
34
+ @home_dir = File.expand_path('~')
35
+ end
36
+
37
+ def installer
38
+ unless system("docker image inspect #{@image}", [:out, :err] => File::NULL)
39
+ puts "-----> Creating image #{@image} ... "
40
+ command = [
41
+ "docker image build -t #{@image}",
42
+ "--build-arg SMARTMACHINE_VERSION=#{SmartMachine.version}",
43
+ "-f- #{SmartMachine.config.gem_dir}/lib/smart_machine/grids/roundcube",
44
+ "<<'EOF'\n#{dockerfile}EOF"
45
+ ]
46
+ if system(command.join(" "), out: File::NULL)
47
+ puts "done"
48
+ else
49
+ raise "Error: Could not install image: #{@image}"
50
+ end
51
+ else
52
+ raise "Error: Image already installed: #{@image}. Please uninstall using 'smartmachine grids roundcube uninstall' and try installing again."
53
+ end
54
+ end
55
+
56
+ def uninstaller
57
+ unless system("docker inspect -f '{{.State.Running}}' '#{@name}'", [:out, :err] => File::NULL)
58
+ if system("docker image inspect #{@image}", [:out, :err] => File::NULL)
59
+ puts "-----> Removing image #{@image} ... "
60
+ if system("docker image rm #{@image}", out: File::NULL)
61
+ puts "done"
62
+ end
63
+ else
64
+ raise "Error: Roundcube already uninstalled. Please install using 'smartmachine grids roundcube install' and try uninstalling again."
65
+ end
66
+ else
67
+ raise "Error: Roundcube is currently running. Please stop the roundcube using 'smartmachine grids roundcube down' and try uninstalling again."
68
+ end
69
+ end
70
+
71
+ def uper
72
+ if system("docker image inspect #{@image}", [:out, :err] => File::NULL)
73
+ FileUtils.mkdir_p("#{@home_dir}/machine/grids/roundcube/#{@name}/backups")
74
+ FileUtils.mkdir_p("#{@home_dir}/machine/grids/roundcube/#{@name}/data/roundcube-temp")
75
+
76
+ # Setting entrypoint permission.
77
+ system("chmod +x #{@home_dir}/machine/config/roundcube/docker/custom-docker-entrypoint.sh")
78
+ system("chmod +x #{@home_dir}/machine/config/roundcube/docker/entrypoint.rb")
79
+
80
+ # Creating & Starting containers
81
+ print "-----> Creating container #{@name} ... "
82
+
83
+ command = [
84
+ "docker create",
85
+ "--name='#{@name}'",
86
+ "--env VIRTUAL_HOST=#{@fqdn}",
87
+ "--env VIRTUAL_PATH='#{@request_path}'",
88
+ "--env LETSENCRYPT_HOST=#{@fqdn}",
89
+ "--env LETSENCRYPT_EMAIL=#{@sysadmin_email}",
90
+ "--env LETSENCRYPT_TEST=false",
91
+ "--env CONTAINER_NAME='#{@name}'",
92
+ "--env FQDN='#{@fqdn}'",
93
+ "--env ROUNDCUBEMAIL_DEFAULT_HOST='#{@mail_host}'",
94
+ "--env ROUNDCUBEMAIL_DEFAULT_PORT='#{@mail_port}'",
95
+ "--env ROUNDCUBEMAIL_SMTP_SERVER='#{@smtp_host}'",
96
+ "--env ROUNDCUBEMAIL_SMTP_PORT='#{@smtp_port}'",
97
+ "--env ROUNDCUBEMAIL_USERNAME_DOMAIN=''",
98
+ "--env ROUNDCUBEMAIL_REQUEST_PATH='#{@request_path}'",
99
+ "--env ROUNDCUBEMAIL_PLUGINS='#{@plugins.join(',')}'",
100
+ "--env ROUNDCUBEMAIL_PLUGINS_PASSWORD_DATABASE_TYPE='#{@plugins_password_database_type}'",
101
+ "--env ROUNDCUBEMAIL_PLUGINS_PASSWORD_DATABASE_HOST='#{@plugins_password_database_host}'",
102
+ "--env ROUNDCUBEMAIL_PLUGINS_PASSWORD_DATABASE_USER='#{@plugins_password_database_user}'",
103
+ "--env ROUNDCUBEMAIL_PLUGINS_PASSWORD_DATABASE_PASS='#{@plugins_password_database_pass}'",
104
+ "--env ROUNDCUBEMAIL_PLUGINS_PASSWORD_DATABASE_NAME='#{@plugins_password_database_name}'",
105
+ "--env ROUNDCUBEMAIL_INSTALL_PLUGINS='1'",
106
+ "--env ROUNDCUBEMAIL_SKIN='#{@skin}'",
107
+ "--env ROUNDCUBEMAIL_UPLOAD_MAX_FILESIZE='#{@upload_max_filesize}'",
108
+ "--env ROUNDCUBEMAIL_SPELLCHECK_URI=''",
109
+ "--env ROUNDCUBEMAIL_ASPELL_DICTS='#{@aspell_dictionaries.join(',')}'",
110
+ "--env ROUNDCUBEMAIL_DB_TYPE='#{@database_type}'",
111
+ "--env ROUNDCUBEMAIL_DB_HOST='#{@database_host}'",
112
+ "--env ROUNDCUBEMAIL_DB_PORT='#{@database_port}'",
113
+ "--env ROUNDCUBEMAIL_DB_USER='#{@database_user}'",
114
+ "--env ROUNDCUBEMAIL_DB_PASSWORD='#{@database_pass}'",
115
+ "--env ROUNDCUBEMAIL_DB_NAME='#{@database_name}'",
116
+ "--volume='#{@home_dir}/smartmachine/config/roundcube:/smartmachine/config/roundcube:ro'",
117
+ "--volume='#{@home_dir}/smartmachine/grids/roundcube/#{@name}/data/roundcube-temp:/tmp/roundcube-temp'",
118
+ "--tmpfs /run/tmpfs",
119
+ "--init",
120
+ "--restart='always'",
121
+ "--network='nginx-network'",
122
+ "#{@image}"
123
+ ]
124
+ if system(command.compact.join(" "), out: File::NULL)
125
+ @networks.each do |network|
126
+ system("docker network connect #{network} #{@name}")
127
+ end
128
+
129
+ puts "done"
130
+ puts "-----> Starting container #{@name} ... "
131
+ if system("docker start #{@name}", out: File::NULL)
132
+ puts "done"
133
+ else
134
+ raise "Error: Could not start container: #{@name}"
135
+ end
136
+ else
137
+ raise "Error: Could not create container: #{@name}"
138
+ end
139
+ else
140
+ raise "Error: Could not find image: #{@image}"
141
+ end
142
+ end
143
+
144
+ def downer
145
+ # Disconnecting networks
146
+ @networks.reverse.each do |network|
147
+ system("docker network disconnect #{network} #{@name}")
148
+ end
149
+
150
+ # Stopping & Removing containers - in reverse order
151
+ print "-----> Stopping container #{@name} ... "
152
+ if system("docker stop '#{@name}'", out: File::NULL)
153
+ puts "done"
154
+ print "-----> Removing container #{@name} ... "
155
+ if system("docker rm '#{@name}'", out: File::NULL)
156
+ puts "done"
157
+ end
158
+ end
159
+ end
160
+
161
+ private
162
+
163
+ def dockerfile
164
+ file = <<~'DOCKERFILE'
165
+ ARG SMARTMACHINE_VERSION
166
+
167
+ FROM roundcube/roundcubemail:1.6.8-apache
168
+ LABEL maintainer="plainsource <plainsource@humanmind.me>"
169
+
170
+ RUN apt-get update && \
171
+ apt-get install -y --no-install-recommends \
172
+ ruby-full build-essential zlib1g-dev \
173
+ dovecot-common && \
174
+ rm -rf /var/lib/apt/lists/*
175
+
176
+ ENTRYPOINT ["/smartmachine/config/roundcube/docker/custom-docker-entrypoint.sh"]
177
+ CMD ["apache2-foreground"]
178
+ DOCKERFILE
179
+
180
+ format(file, "mailname": @mailname)
181
+ end
182
+ end
183
+ end
184
+ end
@@ -77,6 +77,13 @@ module SmartMachine
77
77
  # puts 'You may be prompted to make a menu selection when the Grub package is updated on Ubuntu. If prompted, select keep the local version currently installed.'
78
78
 
79
79
  # dpkg-reconfigure tzdata
80
+ # debconf-set-selections <<EOF
81
+ # tzdata tzdata/Areas select Asia
82
+ # tzdata tzdata/Areas seen true
83
+ # tzdata tzdata/Zones/Asia select Kolkata
84
+ # tzdata tzdata/Zones/Asia seen true
85
+ # EOF
86
+ # dpkg-reconfigure -fnoninteractive tzdata
80
87
  # date
81
88
 
82
89
  # hostnamectl set-hostname SmartMachine.credentials.machine[:name]
@@ -64,6 +64,9 @@ module SmartMachine
64
64
  'grids/elasticsearch',
65
65
  'grids/elasticsearch/***',
66
66
 
67
+ 'grids/emailer',
68
+ 'grids/emailer/***',
69
+
67
70
  'grids/minio',
68
71
  'grids/minio/***',
69
72
 
@@ -103,11 +106,17 @@ module SmartMachine
103
106
  'bin/smartmachine',
104
107
 
105
108
  'config',
109
+ 'config/emailer',
110
+ 'config/emailer/***',
106
111
  'config/mysql',
107
112
  'config/mysql/schedule.rb',
108
113
  'config/phpmyadmin',
109
114
  'config/phpmyadmin/***',
115
+ 'config/roundcube',
116
+ 'config/roundcube/***',
110
117
  'config/credentials.yml.enc',
118
+ 'config/emailer.yml',
119
+ 'config/engine.yml',
111
120
  'config/environment.rb',
112
121
  'config/elasticsearch.yml',
113
122
  'config/minio.yml',
@@ -117,6 +126,7 @@ module SmartMachine
117
126
  'config/phpmyadmin.yml',
118
127
  'config/prereceiver.yml',
119
128
  'config/redis.yml',
129
+ 'config/roundcube.yml',
120
130
  'config/terminal.yml',
121
131
 
122
132
  'grids',
@@ -0,0 +1,50 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ STDOUT.sync = true
5
+
6
+ class Services
7
+ def initialize
8
+ @services = %w(rsyslog haproxy spamassassin spamassassin.update opendkim postfix dovecot)
9
+ end
10
+
11
+ def start
12
+ puts "Starting Services..."
13
+ @services.each { |service| system("monit start #{service}") }
14
+ system("monit")
15
+
16
+ puts "Starting Logtailer..."
17
+ system("/usr/bin/logtailer.rb start")
18
+ end
19
+
20
+ def stop(signo)
21
+ puts "Stopping Logtailer..."
22
+ system("/usr/bin/logtailer.rb stop")
23
+
24
+ puts "Stopping Services... SIGNAL: SIG#{Signal.signame(signo)}."
25
+ system("monit quit")
26
+ sleep(3)
27
+ @services.reverse.each { |service| system("monit stop #{service}") }
28
+
29
+ puts "Flushing Logtailer..."
30
+ system("/usr/bin/logtailer.rb flush")
31
+
32
+ exit
33
+ end
34
+ end
35
+
36
+ trap('SIGINT') do |signo|
37
+ Services.new.stop(signo)
38
+ end
39
+
40
+ trap('SIGTERM') do |signo|
41
+ Services.new.stop(signo)
42
+ end
43
+
44
+ at_exit do
45
+ # Clean up.
46
+ end
47
+
48
+ Services.new.start
49
+
50
+ sleep
@@ -0,0 +1,196 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'fileutils'
5
+ require 'logger'
6
+
7
+ logger = Logger.new(STDOUT)
8
+ STDOUT.sync = true
9
+
10
+ def update_envkeys_in(filepaths, envkeys)
11
+ filepaths.each do |filepath|
12
+ str = File.read(filepath)
13
+ str = str.gsub(/%(?!<)/, '%%')
14
+ str = format(str, envkeys)
15
+ File.open(filepath, "w") { |file| file << str }
16
+ end
17
+ end
18
+
19
+ # initial setup
20
+ unless File.exist?('/run/initial_container_start')
21
+ FileUtils.touch('/run/initial_container_start')
22
+
23
+ # EnvKeys
24
+ envkeys = {
25
+ container_name: ENV.delete('CONTAINER_NAME'),
26
+ fqdn: ENV.delete('FQDN'),
27
+ mailname: ENV.delete('MAILNAME'),
28
+ sysadmin_email: ENV.delete('SYSADMIN_EMAIL'),
29
+ mysql_host: ENV.delete('MYSQL_HOST'),
30
+ mysql_port: ENV.delete('MYSQL_PORT'),
31
+ mysql_user: ENV.delete('MYSQL_USER'),
32
+ mysql_password: ENV.delete('MYSQL_PASSWORD'),
33
+ mysql_database_name: ENV.delete('MYSQL_DATABASE_NAME'),
34
+ monit_smtp_email_name: ENV.delete('MONIT_SMTP_EMAIL_NAME'),
35
+ monit_smtp_email_address: ENV.delete('MONIT_SMTP_EMAIL_ADDRESS'),
36
+ monit_smtp_host: ENV.delete('MONIT_SMTP_HOST'),
37
+ monit_smtp_port: ENV.delete('MONIT_SMTP_PORT'),
38
+ monit_smtp_username: ENV.delete('MONIT_SMTP_USERNAME'),
39
+ monit_smtp_password: ENV.delete('MONIT_SMTP_PASSWORD'),
40
+ oracle_ips_allowed: ENV.delete('ORACLE_IPS_ALLOWED'),
41
+ oracle_deflect_url: ENV.delete('ORACLE_DEFLECT_URL'),
42
+ timezone: `cat /etc/timezone`.chomp
43
+ }
44
+
45
+ # rsyslog
46
+ # imklog module is commented in rsyslog.conf because rsyslog does not
47
+ # have privileges to run it and hence throws error on startup.
48
+ system("sed -i '/imklog/s/^/#/' /etc/rsyslog.conf")
49
+
50
+ # Postfix
51
+ FileUtils.cp '/smartmachine/config/emailer/etc/postfix/main.cf', '/etc/postfix/main.cf'
52
+ FileUtils.cp '/smartmachine/config/emailer/etc/postfix/master.cf', '/etc/postfix/master.cf'
53
+ FileUtils.cp '/smartmachine/config/emailer/etc/postfix/mysql-sender-login-maps.cf', '/etc/postfix/mysql-sender-login-maps.cf'
54
+ FileUtils.cp '/smartmachine/config/emailer/etc/postfix/mysql-virtual-alias-domains.cf', '/etc/postfix/mysql-virtual-alias-domains.cf'
55
+ FileUtils.cp '/smartmachine/config/emailer/etc/postfix/mysql-virtual-alias-maps-domains.cf', '/etc/postfix/mysql-virtual-alias-maps-domains.cf'
56
+ FileUtils.cp '/smartmachine/config/emailer/etc/postfix/mysql-virtual-alias-maps-masters.cf', '/etc/postfix/mysql-virtual-alias-maps-masters.cf'
57
+ FileUtils.cp '/smartmachine/config/emailer/etc/postfix/mysql-virtual-alias-maps-users.cf', '/etc/postfix/mysql-virtual-alias-maps-users.cf'
58
+ FileUtils.cp '/smartmachine/config/emailer/etc/postfix/mysql-virtual-alias-maps-userstothemselves.cf', '/etc/postfix/mysql-virtual-alias-maps-userstothemselves.cf'
59
+ FileUtils.cp '/smartmachine/config/emailer/etc/postfix/mysql-virtual-mailbox-domains.cf', '/etc/postfix/mysql-virtual-mailbox-domains.cf'
60
+ FileUtils.cp '/smartmachine/config/emailer/etc/postfix/mysql-virtual-mailbox-maps.cf', '/etc/postfix/mysql-virtual-mailbox-maps.cf'
61
+ FileUtils.cp '/smartmachine/config/emailer/etc/postfix-policyd-spf-python/policyd-spf.conf', '/etc/postfix-policyd-spf-python/policyd-spf.conf'
62
+ filepaths = [
63
+ '/etc/postfix/main.cf',
64
+ '/etc/postfix/mysql-sender-login-maps.cf',
65
+ '/etc/postfix/mysql-virtual-alias-domains.cf',
66
+ '/etc/postfix/mysql-virtual-alias-maps-domains.cf',
67
+ '/etc/postfix/mysql-virtual-alias-maps-masters.cf',
68
+ '/etc/postfix/mysql-virtual-alias-maps-users.cf',
69
+ '/etc/postfix/mysql-virtual-alias-maps-userstothemselves.cf',
70
+ '/etc/postfix/mysql-virtual-mailbox-domains.cf',
71
+ '/etc/postfix/mysql-virtual-mailbox-maps.cf'
72
+ ]
73
+ update_envkeys_in(filepaths, envkeys)
74
+ system("chgrp postfix /etc/postfix/mysql-*.cf")
75
+ system("chmod -R o-rwx /etc/postfix/mysql-*.cf")
76
+
77
+ # Dovecot
78
+ FileUtils.cp '/smartmachine/config/emailer/etc/dovecot/conf.d/10-auth.conf', '/etc/dovecot/conf.d/10-auth.conf'
79
+ FileUtils.cp '/smartmachine/config/emailer/etc/dovecot/conf.d/10-mail.conf', '/etc/dovecot/conf.d/10-mail.conf'
80
+ FileUtils.cp '/smartmachine/config/emailer/etc/dovecot/conf.d/10-master.conf', '/etc/dovecot/conf.d/10-master.conf'
81
+ FileUtils.cp '/smartmachine/config/emailer/etc/dovecot/conf.d/10-ssl.conf', '/etc/dovecot/conf.d/10-ssl.conf'
82
+ FileUtils.cp '/smartmachine/config/emailer/etc/dovecot/conf.d/15-mailboxes.conf', '/etc/dovecot/conf.d/15-mailboxes.conf'
83
+ FileUtils.cp '/smartmachine/config/emailer/etc/dovecot/conf.d/20-imap.conf', '/etc/dovecot/conf.d/20-imap.conf'
84
+ FileUtils.cp '/smartmachine/config/emailer/etc/dovecot/conf.d/20-lmtp.conf', '/etc/dovecot/conf.d/20-lmtp.conf'
85
+ FileUtils.cp '/smartmachine/config/emailer/etc/dovecot/conf.d/90-quota.conf', '/etc/dovecot/conf.d/90-quota.conf'
86
+ FileUtils.cp '/smartmachine/config/emailer/etc/dovecot/conf.d/90-sieve.conf', '/etc/dovecot/conf.d/90-sieve.conf'
87
+
88
+ FileUtils.mkdir '/etc/dovecot/sieve'
89
+ FileUtils.cp '/smartmachine/config/emailer/etc/dovecot/sieve/learn-ham.sh', '/etc/dovecot/sieve/learn-ham.sh'
90
+ FileUtils.cp '/smartmachine/config/emailer/etc/dovecot/sieve/learn-spam.sh', '/etc/dovecot/sieve/learn-spam.sh'
91
+ FileUtils.cp '/smartmachine/config/emailer/etc/dovecot/sieve/learn-ham.sieve', '/etc/dovecot/sieve/learn-ham.sieve'
92
+ FileUtils.cp '/smartmachine/config/emailer/etc/dovecot/sieve/learn-spam.sieve', '/etc/dovecot/sieve/learn-spam.sieve'
93
+
94
+ FileUtils.mkdir '/etc/dovecot/sieve-after'
95
+ FileUtils.cp '/smartmachine/config/emailer/etc/dovecot/sieve-after/spam-to-folder.sieve', '/etc/dovecot/sieve-after/spam-to-folder.sieve'
96
+
97
+ FileUtils.cp '/smartmachine/config/emailer/etc/dovecot/dovecot-sql.conf.ext', '/etc/dovecot/dovecot-sql.conf.ext'
98
+
99
+ FileUtils.cp '/smartmachine/config/emailer/usr/local/bin/quota-warning.sh', '/usr/local/bin/quota-warning.sh'
100
+
101
+ filepaths = [
102
+ '/etc/dovecot/conf.d/10-ssl.conf',
103
+ '/etc/dovecot/dovecot-sql.conf.ext',
104
+ '/usr/local/bin/quota-warning.sh'
105
+ ]
106
+ update_envkeys_in(filepaths, envkeys)
107
+
108
+ system("groupadd -g 5000 vmail")
109
+ system("useradd -g vmail -u 5000 vmail -d /var/vmail")
110
+ system("chown -R vmail:vmail /var/vmail")
111
+
112
+ system("sievec /etc/dovecot/sieve/learn-ham.sieve")
113
+ system("sievec /etc/dovecot/sieve/learn-spam.sieve")
114
+ system("chmod u=rwx,go= /etc/dovecot/sieve/learn-*.sh")
115
+ system("chown vmail:vmail /etc/dovecot/sieve/learn-*.sh")
116
+ system("chmod u=rw,go= /etc/dovecot/sieve/learn-*.sieve")
117
+ system("chown vmail:vmail /etc/dovecot/sieve/learn-*.sieve")
118
+ system("chmod u=rw,go= /etc/dovecot/sieve/learn-*.svbin")
119
+ system("chown vmail:vmail /etc/dovecot/sieve/learn-*.svbin")
120
+
121
+ system("sievec /etc/dovecot/sieve-after/spam-to-folder.sieve")
122
+ system("chmod u=rw,go= /etc/dovecot/sieve-after/spam-to-folder.sieve")
123
+ system("chown vmail:vmail /etc/dovecot/sieve-after/spam-to-folder.sieve")
124
+ system("chmod u=rw,go= /etc/dovecot/sieve-after/spam-to-folder.svbin")
125
+ system("chown vmail:vmail /etc/dovecot/sieve-after/spam-to-folder.svbin")
126
+
127
+ system("chown root:root /etc/dovecot/dovecot-sql.conf.ext")
128
+ system("chmod go= /etc/dovecot/dovecot-sql.conf.ext")
129
+
130
+ system("chmod +x /usr/local/bin/quota-warning.sh")
131
+
132
+ # Spamassassin
133
+ FileUtils.cp '/smartmachine/config/emailer/etc/spamassassin/local.cf', '/etc/spamassassin/local.cf'
134
+ system("adduser --gecos '' --disabled-login spamd", out: File::NULL)
135
+
136
+ # OpenDKIM
137
+ FileUtils.cp '/smartmachine/config/emailer/etc/opendkim.conf', '/etc/opendkim.conf'
138
+ system("adduser postfix opendkim", out: File::NULL)
139
+ system("chmod u=rw,go=r /etc/opendkim.conf")
140
+ unless File.exists? '/etc/opendkim/key.table'
141
+ FileUtils.mkdir_p '/etc/opendkim/keys'
142
+ FileUtils.touch '/etc/opendkim/key.table'
143
+ FileUtils.touch '/etc/opendkim/signing.table'
144
+ FileUtils.touch '/etc/opendkim/trusted.hosts'
145
+ key_shortname = envkeys[:mailname].gsub(/[^[:alnum:]]/, "")
146
+ raise "Could not create key_shortname from mailname to use in opendkim." if key_shortname.match(/\A[a-zA-Z0-9]*\z/).nil?
147
+ key_selector = Time.now.getlocal('+05:30').strftime("%Y%m")
148
+ raise "Could not create key_selector from Local Time to use in opendkim." if key_selector.match(/\A[0-9]*\z/).nil?
149
+ key_filename = "#{key_shortname}_#{key_selector}"
150
+ IO.write("/etc/opendkim/key.table",
151
+ "#{key_shortname} #{envkeys[:mailname]}:#{key_selector}:/etc/opendkim/keys/#{key_filename}.private\n")
152
+ IO.write("/etc/opendkim/signing.table",
153
+ "*@#{envkeys[:mailname]} #{key_shortname}\n")
154
+ IO.write("/etc/opendkim/trusted.hosts",
155
+ "127.0.0.1\n::1\nlocalhost\n#{envkeys[:fqdn]}\n#{envkeys[:mailname]}\n")
156
+ Dir.chdir("/etc/opendkim/keys") do
157
+ raise "Could not create DKIM keys." unless system("opendkim-genkey -b 2048 -h rsa-sha256 -r -s #{key_selector} -d #{envkeys[:mailname]} -v")
158
+ FileUtils.mv("#{key_selector}.private", "#{key_filename}.private")
159
+ FileUtils.mv("#{key_selector}.txt", "#{key_filename}.txt")
160
+ end
161
+ end
162
+ system("chown -R opendkim:opendkim /etc/opendkim")
163
+ system("chmod -R go-rw /etc/opendkim/keys")
164
+ system("mkdir /var/spool/postfix/opendkim")
165
+ system("chown opendkim:postfix /var/spool/postfix/opendkim")
166
+
167
+ # Haproxy
168
+ FileUtils.mkdir_p '/var/lib/haproxy/dev'
169
+ FileUtils.mkdir_p '/run/haproxy'
170
+ FileUtils.cp '/smartmachine/config/emailer/etc/haproxy/haproxy.cfg', '/etc/haproxy/haproxy.cfg'
171
+ filepaths = [
172
+ '/etc/haproxy/haproxy.cfg'
173
+ ]
174
+ update_envkeys_in(filepaths, envkeys)
175
+
176
+ # Monit
177
+ FileUtils.cp '/smartmachine/config/emailer/etc/monit/monitrc', '/etc/monit/monitrc'
178
+ FileUtils.cp_r '/smartmachine/config/emailer/etc/monit/conf.d/.', '/etc/monit/conf.d'
179
+ filepaths = [
180
+ '/etc/monit/conf.d/services.cfg',
181
+ '/etc/monit/monitrc'
182
+ ]
183
+ update_envkeys_in(filepaths, envkeys)
184
+
185
+ # Logtailer
186
+ FileUtils.cp '/smartmachine/config/emailer/docker/logtailer.rb', '/usr/bin/logtailer.rb'
187
+ system("chmod +x /usr/bin/logtailer.rb")
188
+
189
+ # Command
190
+ FileUtils.cp '/smartmachine/config/emailer/docker/command.rb', '/usr/bin/command.rb'
191
+ system("chmod +x /usr/bin/command.rb")
192
+
193
+ logger.info "Initial setup completed for #{envkeys[:container_name]}."
194
+ end
195
+
196
+ ARGV.empty? ? exec("/usr/bin/command.rb") : exec(*ARGV)
@@ -0,0 +1,75 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ STDOUT.sync = true
5
+
6
+ require 'fileutils'
7
+
8
+ class Logtailer
9
+ def initialize
10
+ @tailers = {
11
+ "/var/log/monit.log" => 1,
12
+ "/var/log/haproxy.log" => 1,
13
+ "/var/log/mail.log" => 1,
14
+ "/home/spamd/spamd.log" => 1
15
+ }
16
+ end
17
+
18
+ def start
19
+ set_start_from_line
20
+
21
+ pids = []
22
+ @tailers.each do |path, start_from_line|
23
+ pid = Process.spawn("tail", "--lines=+#{start_from_line}", "-q", "-F", "#{path}", [:out, :err] => "/proc/1/fd/1")
24
+ Process.detach(pid)
25
+ pids.push(pid)
26
+ end
27
+ IO.write("/run/tmpfs/logtailer.pid", "#{pids.join(' ')}\n")
28
+
29
+ puts "Started Logtailer with PIDs " + `cat /run/tmpfs/logtailer.pid`.chomp + "."
30
+ end
31
+
32
+ def stop
33
+ pids = `cat /run/tmpfs/logtailer.pid`.chomp.split(" ")
34
+ pids.each do |pid|
35
+ system("/bin/kill --signal SIGTERM #{pid}")
36
+ end
37
+ save_start_from_line
38
+
39
+ puts "Stopped Logtailer with PIDs " + `cat /run/tmpfs/logtailer.pid`.chomp + "."
40
+ FileUtils.rm("/run/tmpfs/logtailer.pid")
41
+ end
42
+
43
+ def flush
44
+ set_start_from_line
45
+ @tailers.each do |path, start_from_line|
46
+ system("tail --lines=+#{start_from_line} -q #{path} >> /proc/1/fd/1")
47
+ end
48
+ save_start_from_line
49
+ end
50
+
51
+ private
52
+
53
+ def set_start_from_line
54
+ if File.exist?('/run/logtailer.lines')
55
+ lines = IO.read('/run/logtailer.lines').split("\n")
56
+ lines.each do |line|
57
+ previous_line_no, path = line.split(" ")
58
+ @tailers[path] = previous_line_no.to_i + 1
59
+ end
60
+ end
61
+ end
62
+
63
+ def save_start_from_line
64
+ str = `wc -l #{@tailers.keys.join(' ')} | head --lines=-1`
65
+ IO.write("/run/logtailer.lines", "#{str}")
66
+ end
67
+ end
68
+
69
+ if ARGV[0] == "start"
70
+ Logtailer.new.start
71
+ elsif ARGV[0] == "stop"
72
+ Logtailer.new.stop
73
+ elsif ARGV[0] == "flush"
74
+ Logtailer.new.flush
75
+ end