ConfigLMM 0.4.0 → 0.5.0

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 (227) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +34 -0
  3. data/CNAME +1 -0
  4. data/Examples/.lmm.state.yaml +159 -0
  5. data/Examples/ConfigLMM.mm.yaml +32 -0
  6. data/Examples/Implemented.mm.yaml +252 -4
  7. data/Examples/SmallBusiness.mm.yaml +492 -0
  8. data/Plugins/Apps/Answer/answer.lmm.rb +165 -0
  9. data/Plugins/Apps/Answer/answer@.service +40 -0
  10. data/Plugins/Apps/ArchiSteamFarm/ArchiSteamFarm.conf.erb +0 -3
  11. data/Plugins/Apps/ArchiSteamFarm/ArchiSteamFarm.lmm.rb +0 -1
  12. data/Plugins/Apps/Authentik/Authentik-ProxyOutpost.container +7 -1
  13. data/Plugins/Apps/Authentik/Authentik-Server.container +6 -1
  14. data/Plugins/Apps/Authentik/Authentik-Worker.container +6 -1
  15. data/Plugins/Apps/Authentik/Authentik.conf.erb +12 -7
  16. data/Plugins/Apps/Authentik/Authentik.lmm.rb +226 -61
  17. data/Plugins/Apps/BookStack/BookStack.conf.erb +0 -3
  18. data/Plugins/Apps/BookStack/BookStack.container +5 -0
  19. data/Plugins/Apps/BookStack/BookStack.lmm.rb +14 -3
  20. data/Plugins/Apps/Cassandra/Cassandra.lmm.rb +9 -19
  21. data/Plugins/Apps/ClickHouse/ClickHouse.container +28 -0
  22. data/Plugins/Apps/ClickHouse/ClickHouse.lmm.rb +113 -0
  23. data/Plugins/Apps/ClickHouse/Config/listen.yaml +2 -0
  24. data/Plugins/Apps/ClickHouse/Config/logger.yaml +8 -0
  25. data/Plugins/Apps/ClickHouse/Config/zookeepers.yaml +5 -0
  26. data/Plugins/Apps/ClickHouse/Connection.rb +96 -0
  27. data/Plugins/Apps/Discourse/Discourse-Sidekiq.container +5 -0
  28. data/Plugins/Apps/Discourse/Discourse.conf.erb +1 -4
  29. data/Plugins/Apps/Discourse/Discourse.container +4 -0
  30. data/Plugins/Apps/Discourse/Discourse.lmm.rb +116 -55
  31. data/Plugins/Apps/Dovecot/Dovecot.lmm.rb +74 -62
  32. data/Plugins/Apps/ERPNext/ERPNext-Frontend.container +6 -1
  33. data/Plugins/Apps/ERPNext/ERPNext-Queue.container +5 -0
  34. data/Plugins/Apps/ERPNext/ERPNext-Scheduler.container +5 -0
  35. data/Plugins/Apps/ERPNext/ERPNext-Websocket.container +6 -1
  36. data/Plugins/Apps/ERPNext/ERPNext.container +6 -1
  37. data/Plugins/Apps/ERPNext/ERPNext.lmm.rb +138 -127
  38. data/Plugins/Apps/GitLab/GitLab.container +6 -0
  39. data/Plugins/Apps/GitLab/GitLab.lmm.rb +43 -49
  40. data/Plugins/Apps/Homepage/Homepage.conf.erb +86 -0
  41. data/Plugins/Apps/Homepage/Homepage.container +19 -0
  42. data/Plugins/Apps/Homepage/Homepage.lmm.rb +54 -0
  43. data/Plugins/Apps/IPFS/IPFS.conf.erb +0 -3
  44. data/Plugins/Apps/IPFS/IPFS.lmm.rb +0 -1
  45. data/Plugins/Apps/InfluxDB/InfluxDB.conf.erb +0 -3
  46. data/Plugins/Apps/InfluxDB/InfluxDB.lmm.rb +0 -1
  47. data/Plugins/Apps/Jackett/Jackett.conf.erb +0 -3
  48. data/Plugins/Apps/Jackett/Jackett.lmm.rb +0 -1
  49. data/Plugins/Apps/Jellyfin/Jellyfin.conf.erb +0 -3
  50. data/Plugins/Apps/Jellyfin/Jellyfin.lmm.rb +0 -1
  51. data/Plugins/Apps/LetsEncrypt/LetsEncrypt.lmm.rb +49 -28
  52. data/Plugins/Apps/LibreTranslate/LibreTranslate.container +21 -0
  53. data/Plugins/Apps/LibreTranslate/LibreTranslate.lmm.rb +34 -0
  54. data/Plugins/Apps/Lobsters/Containerfile +81 -0
  55. data/Plugins/Apps/Lobsters/Lobsters-Tasks.container +26 -0
  56. data/Plugins/Apps/Lobsters/Lobsters.conf.erb +99 -0
  57. data/Plugins/Apps/Lobsters/Lobsters.container +27 -0
  58. data/Plugins/Apps/Lobsters/Lobsters.lmm.rb +196 -0
  59. data/Plugins/Apps/Lobsters/crontab +3 -0
  60. data/Plugins/Apps/Lobsters/database.yml +26 -0
  61. data/Plugins/Apps/Lobsters/entrypoint.sh +30 -0
  62. data/Plugins/Apps/Lobsters/generateCredentials.rb +19 -0
  63. data/Plugins/Apps/Lobsters/lobsters-cron.sh +25 -0
  64. data/Plugins/Apps/Lobsters/lobsters-daily.sh +23 -0
  65. data/Plugins/Apps/Lobsters/puma.rb +49 -0
  66. data/Plugins/Apps/MariaDB/Connection.rb +55 -0
  67. data/Plugins/Apps/MariaDB/MariaDB.lmm.rb +60 -53
  68. data/Plugins/Apps/Mastodon/Mastodon-Sidekiq.container +22 -0
  69. data/Plugins/Apps/Mastodon/Mastodon-Streaming.container +20 -0
  70. data/Plugins/Apps/Mastodon/Mastodon.conf.erb +34 -45
  71. data/Plugins/Apps/Mastodon/Mastodon.container +28 -0
  72. data/Plugins/Apps/Mastodon/Mastodon.lmm.rb +240 -5
  73. data/Plugins/Apps/Mastodon/configlmm.rake +30 -0
  74. data/Plugins/Apps/Mastodon/entrypoint.sh +16 -0
  75. data/Plugins/Apps/Matrix/Element.container +5 -0
  76. data/Plugins/Apps/Matrix/Matrix.conf.erb +2 -8
  77. data/Plugins/Apps/Matrix/Matrix.lmm.rb +100 -71
  78. data/Plugins/Apps/Matrix/Synapse.container +5 -0
  79. data/Plugins/Apps/Netdata/Netdata.conf.erb +0 -3
  80. data/Plugins/Apps/Netdata/Netdata.lmm.rb +0 -1
  81. data/Plugins/Apps/Nextcloud/Nextcloud.conf.erb +3 -4
  82. data/Plugins/Apps/Nextcloud/Nextcloud.lmm.rb +150 -68
  83. data/Plugins/Apps/Nextcloud/autoconfig.php +13 -0
  84. data/Plugins/Apps/Nextcloud/config.php +10 -1
  85. data/Plugins/Apps/Nextcloud/nextcloudcron.service +8 -0
  86. data/Plugins/Apps/Nextcloud/nextcloudcron.timer +10 -0
  87. data/Plugins/Apps/Nginx/Connection.rb +93 -0
  88. data/Plugins/Apps/Nginx/conf.d/configlmm.conf +50 -9
  89. data/Plugins/Apps/Nginx/conf.d/languages.conf +21 -0
  90. data/Plugins/Apps/Nginx/config-lmm/errors.conf +25 -20
  91. data/Plugins/Apps/Nginx/config-lmm/gateway-errors.conf +20 -0
  92. data/Plugins/Apps/Nginx/config-lmm/proxy.conf +1 -1
  93. data/Plugins/Apps/Nginx/main.conf.erb +7 -3
  94. data/Plugins/Apps/Nginx/nginx.conf +2 -2
  95. data/Plugins/Apps/Nginx/nginx.lmm.rb +99 -81
  96. data/Plugins/Apps/Nginx/proxy.conf.erb +11 -3
  97. data/Plugins/Apps/Odoo/Odoo.conf.erb +0 -3
  98. data/Plugins/Apps/Odoo/Odoo.container +5 -0
  99. data/Plugins/Apps/Odoo/Odoo.lmm.rb +4 -5
  100. data/Plugins/Apps/Ollama/Ollama.container +26 -0
  101. data/Plugins/Apps/Ollama/Ollama.lmm.rb +73 -0
  102. data/Plugins/Apps/OpenTelemetry/Config/config.yaml +704 -0
  103. data/Plugins/Apps/OpenTelemetry/OpenTelemetry.lmm.rb +154 -0
  104. data/Plugins/Apps/OpenVidu/Ingress.container +5 -0
  105. data/Plugins/Apps/OpenVidu/OpenVidu.conf.erb +0 -3
  106. data/Plugins/Apps/OpenVidu/OpenVidu.container +5 -0
  107. data/Plugins/Apps/OpenVidu/OpenVidu.lmm.rb +7 -3
  108. data/Plugins/Apps/OpenVidu/OpenViduCall.conf.erb +0 -3
  109. data/Plugins/Apps/OpenVidu/OpenViduCall.container +5 -0
  110. data/Plugins/Apps/PHP-FPM/Connection.rb +91 -0
  111. data/Plugins/Apps/PHP-FPM/PHP-FPM.lmm.rb +31 -4
  112. data/Plugins/Apps/Peppermint/Peppermint.conf.erb +2 -5
  113. data/Plugins/Apps/Peppermint/Peppermint.container +5 -0
  114. data/Plugins/Apps/Peppermint/Peppermint.lmm.rb +29 -33
  115. data/Plugins/Apps/Perplexica/Perplexica.container +25 -0
  116. data/Plugins/Apps/Perplexica/Perplexica.lmm.rb +92 -0
  117. data/Plugins/Apps/Perplexica/config.toml +26 -0
  118. data/Plugins/Apps/Podman/Connection.rb +24 -0
  119. data/Plugins/Apps/Podman/Podman.lmm.rb +80 -0
  120. data/Plugins/Apps/Podman/storage.conf +6 -0
  121. data/Plugins/Apps/Postfix/Postfix.lmm.rb +242 -164
  122. data/Plugins/Apps/PostgreSQL/Connection.rb +97 -0
  123. data/Plugins/Apps/PostgreSQL/PostgreSQL.lmm.rb +184 -148
  124. data/Plugins/Apps/Pterodactyl/Pterodactyl.conf.erb +0 -3
  125. data/Plugins/Apps/Pterodactyl/Pterodactyl.lmm.rb +0 -2
  126. data/Plugins/Apps/Pterodactyl/Wings.conf.erb +0 -3
  127. data/Plugins/Apps/RVM/RVM.lmm.rb +57 -0
  128. data/Plugins/Apps/Roundcube/Roundcube.conf.erb +0 -3
  129. data/Plugins/Apps/Roundcube/Roundcube.lmm.rb +15 -19
  130. data/Plugins/Apps/SSH/SSH.lmm.rb +9 -15
  131. data/Plugins/Apps/SearXNG/SearXNG.container +22 -0
  132. data/Plugins/Apps/SearXNG/SearXNG.lmm.rb +79 -0
  133. data/Plugins/Apps/SearXNG/limiter.toml +40 -0
  134. data/Plugins/Apps/SearXNG/settings.yml +2 -0
  135. data/Plugins/Apps/SigNoz/Config/alerts.yml +11 -0
  136. data/Plugins/Apps/SigNoz/Config/otel-collector-config.yaml +110 -0
  137. data/Plugins/Apps/SigNoz/Config/otel-collector-opamp-config.yaml +1 -0
  138. data/Plugins/Apps/SigNoz/Config/prometheus.yml +18 -0
  139. data/Plugins/Apps/SigNoz/SigNoz-Collector.container +23 -0
  140. data/Plugins/Apps/SigNoz/SigNoz-Migrator.container +17 -0
  141. data/Plugins/Apps/SigNoz/SigNoz.conf.erb +61 -0
  142. data/Plugins/Apps/SigNoz/SigNoz.container +26 -0
  143. data/Plugins/Apps/SigNoz/SigNoz.lmm.rb +319 -0
  144. data/Plugins/Apps/Solr/log4j2.xml +89 -0
  145. data/Plugins/Apps/Solr/solr.lmm.rb +82 -0
  146. data/Plugins/Apps/Sunshine/Sunshine.conf.erb +0 -3
  147. data/Plugins/Apps/Sunshine/Sunshine.lmm.rb +0 -1
  148. data/Plugins/Apps/Tunnel/tunnel.lmm.rb +33 -37
  149. data/Plugins/Apps/UVdesk/UVdesk.conf.erb +0 -3
  150. data/Plugins/Apps/Umami/Umami.container +19 -0
  151. data/Plugins/Apps/Umami/Umami.lmm.rb +108 -0
  152. data/Plugins/Apps/Valkey/Valkey.lmm.rb +54 -42
  153. data/Plugins/Apps/Vaultwarden/Vaultwarden.conf.erb +9 -6
  154. data/Plugins/Apps/Vaultwarden/Vaultwarden.container +7 -1
  155. data/Plugins/Apps/Vaultwarden/Vaultwarden.lmm.rb +64 -29
  156. data/Plugins/Apps/Wiki.js/Wiki.js.conf.erb +1 -4
  157. data/Plugins/Apps/Wiki.js/Wiki.js.container +5 -0
  158. data/Plugins/Apps/Wiki.js/Wiki.js.lmm.rb +31 -37
  159. data/Plugins/Apps/YaCy/YaCy.conf.erb +93 -0
  160. data/Plugins/Apps/YaCy/YaCy.container +21 -0
  161. data/Plugins/Apps/YaCy/YaCy.lmm.rb +160 -0
  162. data/Plugins/Apps/ZooKeeper/ZooKeeper.container +24 -0
  163. data/Plugins/Apps/ZooKeeper/ZooKeeper.lmm.rb +68 -0
  164. data/Plugins/Apps/bitmagnet/bitmagnet.conf.erb +0 -3
  165. data/Plugins/Apps/bitmagnet/bitmagnet.lmm.rb +0 -1
  166. data/Plugins/Apps/gollum/gollum.conf.erb +2 -4
  167. data/Plugins/Apps/gollum/gollum.container +6 -0
  168. data/Plugins/Apps/gollum/gollum.lmm.rb +51 -50
  169. data/Plugins/Apps/llama.cpp/llama.cpp.container +28 -0
  170. data/Plugins/Apps/llama.cpp/llama.cpp.lmm.rb +90 -0
  171. data/Plugins/Apps/vLLM/vLLM.container +32 -0
  172. data/Plugins/Apps/vLLM/vLLM.lmm.rb +89 -0
  173. data/Plugins/OS/General/Utils.lmm.rb +26 -0
  174. data/Plugins/OS/Linux/Connection.rb +472 -0
  175. data/Plugins/OS/Linux/Debian/preseed.cfg.erb +25 -6
  176. data/Plugins/OS/Linux/Flavours.yaml +13 -0
  177. data/Plugins/OS/Linux/Grub/grub.cfg +10 -0
  178. data/Plugins/OS/Linux/HTTP.rb +32 -0
  179. data/Plugins/OS/Linux/Linux.lmm.rb +533 -187
  180. data/Plugins/OS/Linux/Packages.yaml +20 -1
  181. data/Plugins/OS/Linux/Services.yaml +8 -0
  182. data/Plugins/OS/Linux/Shell.rb +70 -0
  183. data/Plugins/OS/Linux/Syslinux/default +8 -0
  184. data/Plugins/OS/Linux/WireGuard/WireGuard.lmm.rb +83 -59
  185. data/Plugins/OS/Linux/WireGuard/wg0.conf.erb +3 -0
  186. data/Plugins/OS/Linux/openSUSE/autoinst.xml.erb +29 -3
  187. data/Plugins/OS/Linux/systemd/systemd.lmm.rb +13 -11
  188. data/Plugins/OS/Routers/Aruba/ArubaInstant.lmm.rb +6 -5
  189. data/Plugins/Platforms/GitHub.lmm.rb +73 -28
  190. data/Plugins/Platforms/GoDaddy/GoDaddy.lmm.rb +9 -6
  191. data/Plugins/Platforms/Proxmox/Proxmox.lmm.rb +402 -0
  192. data/Plugins/Platforms/Proxmox/XTerm.rb +321 -0
  193. data/Plugins/Platforms/libvirt/libvirt.lmm.rb +38 -13
  194. data/Plugins/Platforms/porkbun.lmm.rb +12 -2
  195. data/Plugins/Platforms/porkbun_spec.rb +2 -2
  196. data/Plugins/Services/DNS/AmberBit.lmm.rb +1 -1
  197. data/Plugins/Services/DNS/ArubaItDNS.lmm.rb +1 -1
  198. data/Plugins/Services/DNS/NICLV.lmm.rb +1 -1
  199. data/Plugins/Services/DNS/PowerDNS.lmm.rb +70 -68
  200. data/Plugins/Services/DNS/tonic.lmm.rb +22 -12
  201. data/lib/ConfigLMM/Framework/plugins/dns.rb +4 -3
  202. data/lib/ConfigLMM/Framework/plugins/linuxApp.rb +145 -184
  203. data/lib/ConfigLMM/Framework/plugins/nginxApp.rb +34 -17
  204. data/lib/ConfigLMM/Framework/plugins/plugin.rb +53 -181
  205. data/lib/ConfigLMM/Framework/plugins/store.rb +4 -4
  206. data/lib/ConfigLMM/Framework/variables.rb +75 -0
  207. data/lib/ConfigLMM/Framework.rb +1 -0
  208. data/lib/ConfigLMM/cli.rb +12 -6
  209. data/lib/ConfigLMM/commands/configsCommand.rb +37 -6
  210. data/lib/ConfigLMM/commands/diff.rb +33 -9
  211. data/lib/ConfigLMM/context.rb +22 -3
  212. data/lib/ConfigLMM/io/configList.rb +82 -6
  213. data/lib/ConfigLMM/io/connection.rb +143 -0
  214. data/lib/ConfigLMM/io/dhcp.rb +330 -0
  215. data/lib/ConfigLMM/io/http.rb +78 -0
  216. data/lib/ConfigLMM/io/local.rb +207 -0
  217. data/lib/ConfigLMM/io/pxe.rb +92 -0
  218. data/lib/ConfigLMM/io/ssh.rb +156 -0
  219. data/lib/ConfigLMM/io/tftp.rb +105 -0
  220. data/lib/ConfigLMM/io.rb +2 -0
  221. data/lib/ConfigLMM/secrets/envStore.rb +39 -0
  222. data/lib/ConfigLMM/secrets/fileStore.rb +43 -0
  223. data/lib/ConfigLMM/state.rb +2 -1
  224. data/lib/ConfigLMM/version.rb +2 -1
  225. data/lib/ConfigLMM.rb +1 -0
  226. data/{Examples → scripts}/configlmmAuth.sh +7 -5
  227. metadata +205 -8
@@ -1,110 +1,138 @@
1
1
 
2
2
  require_relative '../../OS/Linux/Linux.lmm.rb'
3
+ require_relative 'Connection'
3
4
 
4
5
  module ConfigLMM
5
6
  module LMM
6
7
  class PostgreSQL < Framework::LinuxApp
7
8
  PACKAGE_NAME = 'PostgreSQL'
8
- SERVICE_NAME = 'postgresql'
9
+ SERVICE_NAME = :postgresql
9
10
  USER_NAME = 'postgres'
11
+ PORT = '5432'
10
12
 
11
13
  HBA_FILE = 'data/pg_hba.conf'
12
14
  CONFIG_FILE = 'data/postgresql.conf'
13
15
 
14
16
  def actionPostgreSQLDeploy(id, target, activeState, context, options)
15
17
  target['Deploy'] = !!(target['ListenAll'] || target['Listen'] || target['Settings']) unless target.key?('Deploy')
16
- activeState['Deploy'] = target['Deploy']
17
- activeState['Users'] = target['Users']
18
- activeState['Databases'] = target['Databases']
19
- activeState['Publications'] = target['Publications']
20
- activeState['Subscriptions'] = target['Subscriptions']
21
-
22
- if target['Deploy']
23
- self.ensurePackage(PACKAGE_NAME, target['Location'])
24
- self.ensureServiceAutoStart(SERVICE_NAME, target['Location'])
25
- self.startService(SERVICE_NAME, target['Location'])
26
- end
27
-
28
- if target['Location'] && target['Location'] != '@me'
29
- uri = Addressable::URI.parse(target['Location'])
30
- raise Framework::PluginProcessError.new("#{id}: Unknown Protocol: #{uri.scheme}!") if uri.scheme != 'ssh'
31
18
 
32
- self.class.sshStart(uri) do |ssh|
33
- if target['Deploy']
34
- self.updateSettingsOverSSH(target, ssh, options)
35
- self.class.sshExec!(ssh, "su --login #{USER_NAME} --command 'pg_ctl reload'")
19
+ withConnection(target['Location'], target) do |connection|
20
+ Linux.withConnection(connection) do |linuxConnection|
21
+ self.class.withConnection({}, linuxConnection) do |postgres|
22
+ if target['Deploy']
23
+ linuxConnection.ensurePackage(PACKAGE_NAME, options)
24
+ linuxConnection.ensureServiceAutoStart(SERVICE_NAME, options)
25
+
26
+ # So that OpenTelemetry can read logs
27
+ linuxConnection.createDirs(options, '/var/log/postgresql')
28
+ linuxConnection.exec("chown postgres:postgres /var/log/postgresql", false, options)
29
+ linuxConnection.exec("chmod 750 /var/log/postgresql", false, options)
30
+
31
+ replicate(target, linuxConnection, postgres, context, options)
32
+ linuxConnection.startService(SERVICE_NAME, options)
33
+
34
+ updateSettings(target, linuxConnection, postgres, options)
35
+
36
+ if activeState['Status'] == State::STATUS_DEPLOYED
37
+ linuxConnection.withUserShell(USER_NAME) do |shellConnection|
38
+ shellConnection.exec("pg_ctl reload -D #{postgres.pgsqlDir}data", false, options)
39
+ end
40
+ else
41
+ # Restart only on first deploy
42
+ linuxConnection.restartService(SERVICE_NAME, options)
43
+ end
44
+ end
45
+
46
+ createUsers(target, postgres, context, options)
47
+ createDatabases(target, postgres, context, options)
48
+ createPublications(target, postgres, context, options)
49
+ createSubscriptions(target, postgres, context, options)
36
50
  end
37
- self.class.createUsersOverSSH(target, ssh)
38
- self.class.createDatabasesOverSSH(target, ssh)
39
- self.class.createPublicationsOverSSH(target, ssh)
40
- self.class.createSubscriptionsOverSSH(target, ssh)
41
- end
42
- else
43
- if target['Deploy']
44
- `pg_ctl reload`
45
51
  end
46
52
  end
47
-
48
- activeState['Status'] = State::STATUS_DEPLOYED
49
53
  end
50
54
 
51
55
  def cleanup(configs, state, context, options)
52
- cleanupType(:PostgreSQL, configs, state, context, options) do |item, id, state, context, options, ssh|
53
- if item['Deploy']
54
- Framework::LinuxApp.stopService(SERVICE_NAME, ssh, options[:dry])
55
- Framework::LinuxApp.disableService(SERVICE_NAME, ssh, options[:dry])
56
- Framework::LinuxApp.removePackage(PACKAGE_NAME, ssh, options[:dry])
57
-
58
- state.item(id)['Status'] = State::STATUS_DELETED unless options[:dry]
59
-
60
- if options[:destroy]
61
- Framework::LinuxApp.deleteUserAndGroup(USER_NAME, ssh, options[:dry])
62
-
63
- state.item(id)['Status'] = State::STATUS_DESTROYED unless options[:dry]
56
+ cleanupType(:PostgreSQL, configs, state, context, options) do |item, id, state, context, options, connection|
57
+ withConnection(item['Config']['Location'], item['Config']) do |connection|
58
+ Linux.withConnection(connection) do |linuxConnection|
59
+ if item['Deploy']
60
+ linuxConnection.stopService(SERVICE_NAME, options)
61
+ linuxConnection.disableService(SERVICE_NAME, options)
62
+ linuxConnection.removePackage(PACKAGE_NAME, options)
63
+
64
+ state.item(id)['Status'] = State::STATUS_DELETED unless options[:dry]
65
+
66
+ if options[:destroy]
67
+ linuxConnection.deleteUserAndGroup(USER_NAME, options)
68
+
69
+ state.item(id)['Status'] = State::STATUS_DESTROYED unless options[:dry]
70
+ end
71
+ end
64
72
  end
65
- else
66
- # TODO
67
73
  end
68
74
  end
69
75
  end
70
76
 
71
- def updateListenLocal(target)
72
- dir = pgsqlDir(self.class.distroID)
73
- if target['ListenAll']
74
- `sed -i 's|^host all all 127.0.0.1/32 ident|host all all 0.0.0.0/0 scram-sha-256|' #{dir + HBA_FILE}`
75
- updateLocalFile(dir + CONFIG_FILE, options) do |configLines|
76
- configLines << "listen_addresses = '*'\n"
77
+ def replicate(target, linuxConnection, postgres, context, options)
78
+ if target['Replicate']
79
+ if !linuxConnection.filePresent?(postgres.pgsqlDir + "data")
80
+ linuxConnection.withUserShell(USER_NAME) do |shellConnection|
81
+ connection = Framework::Variables.stringEval(target['Replicate']['Connection'], context)
82
+ extra = ''
83
+ if target['Replicate']['Slot']
84
+ extra = "--create-slot --slot=#{target['Replicate']['Slot'].downcase}"
85
+ end
86
+ shellConnection.exec("pg_basebackup --dbname=#{connection.shellescape} --write-recovery-conf #{extra} --pgdata #{postgres.pgsqlDir}data", false, options)
87
+ end
77
88
  end
78
- else
79
- `sed -i 's|^host all all 127.0.0.1/32 ident|host all all 127.0.0.1/32 scram-sha-256|' #{dir + HBA_FILE}`
80
89
  end
81
90
  end
82
91
 
83
- def updateSettingsOverSSH(target, ssh, options)
84
- dir = nil
92
+ def updateSettings(target, linuxConnection, postgres, options)
85
93
  settingLines = []
86
94
  hbaLines = []
87
95
  if target['ListenAll']
88
96
  cmd = "sed -i 's|^host all all 127.0.0.1/32 ident|host all all 0.0.0.0/0 scram-sha-256|'"
89
- dir = updateConfigOverSSH(ssh, cmd)
97
+ postgres.connection.exec(cmd + ' ' + postgres.pgsqlDir + HBA_FILE, false, options)
90
98
  settingLines << "listen_addresses = '*'\n"
91
- Framework::LinuxApp.firewallAddPortOverSSH('5432/tcp', ssh)
99
+ postgres.connection.firewallAddPort('5432/tcp', options)
92
100
  elsif target['Listen'] && !target['Listen'].empty?
93
101
  cmd = "sed -i 's|^host all all 127.0.0.1/32 ident|host all all 127.0.0.1/32 scram-sha-256|'"
94
- dir = updateConfigOverSSH(ssh, cmd)
102
+ postgres.connection.exec(cmd + ' ' + postgres.pgsqlDir + HBA_FILE, false, options)
95
103
 
96
104
  ips = target['Listen'].map { |addr| addr.split('/').first }.join(',')
97
105
  settingLines << "listen_addresses = '#{ips}'\n"
98
106
 
99
107
  target['Listen'].each do |addr|
100
108
  if addr != 'localhost' && !addr.start_with?('127.0.0.1') && !addr.start_with?('::1')
109
+ addr += '/0' if addr == '0.0.0.0'
110
+ addr += '/32' if addr =~ /^\d+\.\d+\.\d+\.\d+$/
101
111
  hbaLines << "host all all #{addr} scram-sha-256\n"
102
112
  end
103
113
  end
104
114
  else
105
115
  cmd = "sed -i 's|^host all all 127.0.0.1/32 ident|host all all 127.0.0.1/32 scram-sha-256|'"
106
- dir = updateConfigOverSSH(ssh, cmd)
116
+ postgres.connection.exec(cmd + ' ' + postgres.pgsqlDir + HBA_FILE, false, options)
117
+ end
118
+ if target['AllowReplication']
119
+ addresses = target['AllowReplication']
120
+ addresses = [addresses] unless addresses.is_a?(Array)
121
+ addresses.each do |addr|
122
+ addr += '/0' if addr == '0.0.0.0'
123
+ addr += '/32' if addr =~ /^\d+\.\d+\.\d+\.\d+$/
124
+ hbaLines << "host replication all #{addr} scram-sha-256\n"
125
+ end
107
126
  end
127
+ postgres.connection.exec('sed -i "s|^log_destination|#log_destination|" ' + postgres.pgsqlDir + CONFIG_FILE, false, options)
128
+ postgres.connection.exec('sed -i "s|^logging_collector|#logging_collector|" ' + postgres.pgsqlDir + CONFIG_FILE, false, options)
129
+ postgres.connection.exec('sed -i "s|^log_directory|#log_directory|" ' + postgres.pgsqlDir + CONFIG_FILE, false, options)
130
+ postgres.connection.exec('sed -i "s|^log_file_mode|#log_file_mode|" ' + postgres.pgsqlDir + CONFIG_FILE, false, options)
131
+ settingLines << "log_destination = 'jsonlog'\n"
132
+ settingLines << "logging_collector = on\n"
133
+ settingLines << "log_directory = '/var/log/postgresql'\n"
134
+ settingLines << "log_file_mode = 0640\n"
135
+
108
136
  #if !target['Publications'].to_h.empty?
109
137
  # target['Settings'] ||= {}
110
138
  # target['Settings']['wal_level'] = 'logical'
@@ -113,41 +141,39 @@ module ConfigLMM
113
141
  settingLines << "#{name} = #{value}\n"
114
142
  end
115
143
  if !hbaLines.empty?
116
- updateRemoteFile(ssh, dir + HBA_FILE, options, false) do |configLines|
144
+ postgres.connection.updateFile(postgres.pgsqlDir + HBA_FILE, options, false) do |configLines|
117
145
  configLines += hbaLines
118
146
  end
119
147
  end
120
148
  if !settingLines.empty?
121
- updateRemoteFile(ssh, dir + CONFIG_FILE, options, false) do |configLines|
149
+ postgres.connection.updateFile(postgres.pgsqlDir + CONFIG_FILE, options, false) do |configLines|
122
150
  configLines += settingLines
123
151
  end
124
152
  end
125
153
  end
126
154
 
127
- def self.createUsersOverSSH(target, ssh)
155
+ def createUsers(target, postgres, context, options)
128
156
  target['Users'].to_a.each do |user, info|
129
- self.sshExec!(ssh, "su --login #{USER_NAME} --command 'createuser #{user}'", true)
130
- if !info['Password'].to_s.empty?
131
- password = self.loadVariable(info['Password'], target).to_s
132
- if !password.empty?
133
- sql = "ALTER USER #{user} WITH PASSWORD '#{password}'"
134
- self.executeSQL(sql, nil, ssh)
135
- end
157
+ password = info['Password'].to_s
158
+ if !password.empty?
159
+ password = Framework::Variables.parse(info['Password'], context).to_s
136
160
  end
137
- if info['Replication'] && info['Replication'] != 'no'
138
- self.executeSQL("ALTER USER #{user} REPLICATION", nil, ssh)
139
- self.executeSQL("GRANT pg_read_all_data TO #{user}", nil, ssh)
161
+ postgres.createUser(user, password, options)
162
+
163
+ if info['Replication']
164
+ postgres.grantReplication(user)
140
165
  end
141
166
  end
142
167
  end
143
168
 
144
- def self.createDatabasesOverSSH(target, ssh)
169
+ def createDatabases(target, postgres, context, options)
145
170
  target['Databases'].to_a.each do |db, info|
146
- self.sshExec!(ssh, "su --login #{USER_NAME} --command 'createdb #{db}'", true)
171
+ owner = info['Owner'] ? info['Owner'] : nil
172
+ postgres.createDB(db, owner, options)
147
173
  end
148
174
  end
149
175
 
150
- def self.createPublicationsOverSSH(target, ssh)
176
+ def createPublications(target, postgres, context, options)
151
177
  return if target['Publications'].to_h.empty?
152
178
 
153
179
  target['Publications'].each do |name, data|
@@ -156,139 +182,149 @@ module ConfigLMM
156
182
  # TODO
157
183
  elsif data['Tables'] == 'All'
158
184
  sql = "CREATE PUBLICATION #{name} FOR ALL TABLES"
159
- self.executeSQL(sql, data['Database'], ssh, true)
185
+ postgres.exec(sql, data['Database'], true, [], options)
160
186
  else
161
187
  raise "Invalid Tables field: #{data['Tables']}"
162
188
  end
163
189
  end
164
190
  end
165
191
 
166
- def self.createSubscriptionsOverSSH(target, ssh)
192
+ def createSubscriptions(target, postgres, context, options)
167
193
  return if target['Subscriptions'].to_h.empty?
168
194
 
169
195
  target['Subscriptions'].each do |name, data|
170
196
  data['Database'] = name unless data['Database']
171
197
  data['Publication'] = name unless data['Publication']
172
- connection = self.loadVariable(data['Connection'], target).to_s
198
+ connection = Framework::Variables.stringEval(data['Connection'], context)
173
199
 
174
200
  authParams = '--host=' + connection.match('host=([^ ]+)')[1]
175
201
  authParams += ' --username=' + connection.match('user=([^ ]+)')[1]
176
202
  password = connection.match('password=([^ ]+)')[1]
177
203
 
178
- self.importRemoteSchemaOverSSH(name, data['Database'], password, authParams, ssh)
204
+ importRemoteSchema(name, data['Database'], password, authParams, postgres, options)
179
205
 
180
206
  sql = "CREATE SUBSCRIPTION #{name} CONNECTION '#{connection}' PUBLICATION #{data['Publication']}"
181
- self.executeSQL(sql, data['Database'], ssh, true)
207
+ message = postgres.exec(sql, data['Database'], true, [], options)
208
+ # 'ERROR: subscription "$NAME" already exists' - is fine
209
+ # but other errors aren't like ERROR: could not create replication slot "$NAME": ERROR: replication slot "$NAME" already exists
210
+ if message.include?('ERROR') && !(message.include?('subscription') && message.include?('already exists'))
211
+ raise message
212
+ end
182
213
  end
183
214
  end
184
215
 
185
- def self.importRemoteSchemaOverSSH(sourceDB, targetDB, password, authParams, ssh)
186
- self.sshExec!(ssh, "su --login #{USER_NAME} --command 'createdb #{targetDB}'", true)
187
- cmd = " su --login #{USER_NAME} --command 'PGPASSWORD=#{password} pg_dump --schema-only --no-owner --dbname=#{sourceDB} #{authParams} | psql --dbname=#{targetDB}'"
188
- self.sshExec!(ssh, cmd)
216
+ def importRemoteSchema(sourceDB, targetDB, password, authParams, postgres, options)
217
+ postgres.createDB(targetDB, nil, options)
218
+ postgres.connection.exec(" PGPASSWORD=#{password} pg_dump --schema-only --no-owner --dbname=#{sourceDB} #{authParams} | psql --dbname=#{targetDB}", false, { **options, hide: true })
189
219
  end
190
220
 
191
- def self.updateOwner(db, owner, ssh)
192
- sql = "SELECT tablename FROM pg_tables WHERE NOT schemaname IN ('pg_catalog', 'information_schema')"
193
- tables = self.executeSQL(sql, db, ssh, false, ['--csv', '--tuples-only']).strip.lines
194
- tables.each do |table|
195
- self.executeSQL("ALTER TABLE public.#{table} OWNER TO #{owner};", db, ssh)
196
- end
197
-
198
- sql = "SELECT sequence_name FROM information_schema.sequences WHERE NOT sequence_schema IN ('pg_catalog', 'information_schema')"
199
- sequences = self.executeSQL(sql, db, ssh, false, ['--csv', '--tuples-only']).strip.lines
200
- sequences.each do |sequence|
201
- self.executeSQL("ALTER SEQUENCE public.#{sequence} OWNER TO #{owner};", db, ssh)
202
- end
221
+ def self.defaults(settings)
222
+ settings['HostName'] = 'localhost' unless settings['HostName']
223
+ settings['Port'] = PORT unless settings['Port']
224
+ end
203
225
 
204
- sql = "SELECT table_name FROM information_schema.views WHERE NOT table_schema IN ('pg_catalog', 'information_schema')"
205
- views = self.executeSQL(sql, db, ssh, false, ['--csv', '--tuples-only']).strip.lines
206
- views.each do |view|
207
- self.executeSQL("ALTER VIEW public.#{view} OWNER TO #{owner};", db, ssh)
226
+ def self.withConnection(settings, linuxConnection)
227
+ if settings.nil? || settings['HostName'].nil? || settings['HostName'] == 'localhost' || settings['HostName'].start_with?('/')
228
+ settings ||= {}
229
+ settings = settings.dup
230
+ settings.delete('HostName')
231
+ settings.delete('Port')
232
+ linuxConnection.withUserShell(USER_NAME) do |shellConnection|
233
+ yield(PostgreSQLConnection.new(shellConnection, settings))
234
+ end
235
+ else
236
+ IO::Connection.tunnel("ssh://#{settings['HostName']}/", {}, {}, linuxConnection.prompt, linuxConnection.logger) do |connection|
237
+ Linux.withConnection(connection) do |linuxConnection|
238
+ linuxConnection.withUserShell(USER_NAME) do |shellConnection|
239
+ yield(PostgreSQLConnection.new(shellConnection, settings))
240
+ end
241
+ end
242
+ end
208
243
  end
209
244
  end
210
245
 
211
- def updateConfigOverSSH(ssh, cmd)
212
- dir = ''
213
- distroID = self.class.distroID(ssh)
214
- dir = pgsqlDir(distroID)
215
- self.class.sshExec!(ssh, cmd + ' ' + dir + HBA_FILE)
216
- dir
246
+ # DEPRECATED
247
+ def self.createRemoteUserAndDB(settings, user, password, connection)
248
+ self.executeRemotely(settings, connection) do |connection|
249
+ self.createUserAndDB(user, password, connection)
250
+ end
217
251
  end
218
252
 
253
+ # DEPRECATED
219
254
  def self.createRemoteUserAndDBOverSSH(settings, user, password, ssh)
220
- self.executeRemotely(settings, ssh) do |ssh|
221
- self.createUserAndDBOverSSH(user, password, ssh)
255
+ self.executeRemotely(settings, ssh) do |connection|
256
+ self.createUserAndDBOverSSH(user, password, connection)
222
257
  end
223
258
  end
224
259
 
225
- def self.dropUserAndDB(settings, user, ssh, dry)
226
- self.executeRemotely(settings, ssh) do |ssh|
227
- self.exec("su --login #{USER_NAME} --command 'dropdb #{user}'", ssh, true, dry)
228
- self.exec("su --login #{USER_NAME} --command 'dropuser #{user}'", ssh, true, dry)
260
+ # DEPRECATED
261
+ def self.dropUserAndDB(settings, user, connection, dry)
262
+ self.executeRemotely(settings, connection) do |connection|
263
+ connection.exec("su --login #{USER_NAME} --command 'dropdb #{user}'", true, dry)
264
+ connection.exec("su --login #{USER_NAME} --command 'dropuser #{user}'", true, dry)
229
265
  end
230
266
  end
231
267
 
232
- def self.createExtensions(settings, db, extensions, ssh)
233
- self.executeRemotely(settings, ssh) do |ssh|
268
+ # DEPRECATED
269
+ def self.createExtensions(settings, db, extensions, connectionOrSSH)
270
+ self.executeRemotely(settings, ssh) do |connection|
234
271
  extensions.each do |extension|
235
- self.executeSQL("CREATE EXTENSION #{extension}", db, ssh, true)
272
+ self.executeSQL("CREATE EXTENSION #{extension}", db, connection, true)
236
273
  end
237
274
  end
238
275
  end
239
276
 
240
- def self.executeRemotely(settings, ssh = nil)
241
- settings['HostName'] = 'localhost' unless settings['HostName']
277
+ # DEPRECATED
278
+ def self.executeRemotely(settings, connectionOrSSH = nil)
279
+ prompt = TTY::Prompt.new
280
+ logger = TTY::Logger.new
281
+ self.defaults(settings)
242
282
  if settings['HostName'] == 'localhost'
243
- yield(ssh)
283
+ connection = connectionOrSSH
284
+ if connectionOrSSH.nil?
285
+ connection = IO::Connection.new(:Local, IO::Local.new(prompt, logger), prompt, logger)
286
+ elsif !connectionOrSSH.is_a?(IO::Connection)
287
+ connection = IO::Connection.new(:SSH, IO::SSH.new(prompt, logger, connectionOrSSH), prompt, logger)
288
+ end
289
+ yield(connection)
244
290
  else
245
291
  self.sshStart("ssh://#{settings['HostName']}/") do |ssh|
246
- yield(ssh)
292
+ yield(IO::Connection.new(:SSH, IO::SSH.new(prompt, logger, ssh), prompt, logger))
247
293
  end
248
294
  end
249
295
  end
250
296
 
251
- def self.createUserAndDBOverSSH(user, password, ssh)
252
- self.sshExec!(ssh, "su --login #{USER_NAME} --command 'createuser #{user}'", true)
253
- self.sshExec!(ssh, "su --login #{USER_NAME} --command 'createdb --owner=#{user} #{user}'", true)
254
- if password
255
- sql = "ALTER USER #{user} WITH PASSWORD '#{password}'"
256
- self.executeSQL(sql, nil, ssh)
257
- end
297
+ # DEPRECATED
298
+ def self.createUserAndDB(user, password, connection)
299
+ self.createUserAndDBOverSSH(user, password, connection)
258
300
  end
259
301
 
260
- def self.importSQL(owner, db, sqlFile, ssh = nil)
261
- if ssh
262
- self.sshExec!(ssh, "echo \"SET ROLE '#{owner}';\" > /tmp/postgres_import.sql")
263
- self.sshExec!(ssh, "cat #{sqlFile} >> /tmp/postgres_import.sql")
264
- cmd = "su --login #{USER_NAME} --command 'psql #{db} < /tmp/postgres_import.sql'"
265
- self.sshExec!(ssh, cmd)
302
+ # DEPRECATED
303
+ def self.createUserAndDBOverSSH(user, password, connectionOrSSH)
304
+ if connectionOrSSH.is_a?(IO::Connection)
305
+ connectionOrSSH.exec("su --login #{USER_NAME} --command 'createuser #{user}'", true)
306
+ connectionOrSSH.exec("su --login #{USER_NAME} --command 'createdb --locale=C --template=template0 --owner=#{user} #{user}'", true)
266
307
  else
267
- # TODO
308
+ self.sshExec!(connectionOrSSH, "su --login #{USER_NAME} --command 'createuser #{user}'", true)
309
+ self.sshExec!(connectionOrSSH, "su --login #{USER_NAME} --command 'createdb --locale=C --template=template0 --owner=#{user} #{user}'", true)
268
310
  end
269
- end
270
-
271
- def self.executeSQL(sql, db, ssh = nil, allowFailure = false, options = [])
272
- if ssh
273
- db = 'postgres' unless db
274
- cmd = " su --login #{USER_NAME} --command ' psql #{options.join(' ')} --dbname=#{db} --command=\"#{sql.gsub("'", "'\"'\"'")};\"'"
275
- self.sshExec!(ssh, cmd, allowFailure)
276
- else
277
- # TODO
311
+ if password
312
+ sql = "ALTER USER #{user} WITH PASSWORD '#{password}'"
313
+ self.executeSQL(sql, nil, connectionOrSSH)
278
314
  end
279
315
  end
280
316
 
281
- def pgsqlDir(distroID)
282
- if distroID == 'opensuse-leap'
283
- '/var/lib/pgsql/'
284
- elsif distroID == 'arch'
285
- '/var/lib/postgres/'
317
+ # DEPRECATED
318
+ def self.executeSQL(sql, db, connectionOrSSH = nil, allowFailure = false, options = [], dry = false)
319
+ db = 'postgres' unless db
320
+ cmd = " su --login #{USER_NAME} --command ' psql #{options.join(' ')} --dbname=#{db} --command=\"#{sql.gsub("'", "'\"'\"'")};\"'"
321
+ if connectionOrSSH.is_a?(IO::Connection)
322
+ connectionOrSSH.exec(cmd, allowFailure, dry)
286
323
  else
287
- raise Framework::PluginProcessError.new("Unknown Linux Distro: #{distroID}!")
324
+ self.exec(cmd, connectionOrSSH, allowFailure, dry)
288
325
  end
289
326
  end
290
327
 
291
328
  end
292
-
293
329
  end
294
330
  end
@@ -14,9 +14,6 @@ server {
14
14
 
15
15
  server_name <%= config['Domain'] %>;
16
16
 
17
- access_log /var/log/nginx/pterodactyl.access.log;
18
- error_log /var/log/nginx/pterodactyl.error.log;
19
-
20
17
  include config-lmm/private.conf;
21
18
  include config-lmm/errors.conf;
22
19
 
@@ -10,7 +10,6 @@ module ConfigLMM
10
10
  def actionPterodactylDeploy(id, target, activeState, context, options)
11
11
  if !target['Location'] || target['Location'] == '@me'
12
12
  deployNginxConfig(id, target, activeState, context, options)
13
- activeState['Location'] = '@me'
14
13
  end
15
14
  end
16
15
 
@@ -21,7 +20,6 @@ module ConfigLMM
21
20
  def actionWingsDeploy(id, target, activeState, context, options)
22
21
  if !target['Location'] || target['Location'] == '@me'
23
22
  deployNginxConfig(id, target, activeState, context, options)
24
- activeState['Location'] = '@me'
25
23
  end
26
24
  end
27
25
  end
@@ -17,9 +17,6 @@ server {
17
17
 
18
18
  server_name <%= config['Domain'] %>;
19
19
 
20
- access_log /var/log/nginx/wings.access.log;
21
- error_log /var/log/nginx/wings.error.log;
22
-
23
20
  include config-lmm/private.conf;
24
21
  include config-lmm/errors.conf;
25
22
 
@@ -0,0 +1,57 @@
1
+
2
+ module ConfigLMM
3
+ module LMM
4
+ class RVM < Framework::Plugin
5
+
6
+ LATEST_RUBY_VERSION = '3.4.1'
7
+
8
+ def actionRVMDeploy(id, target, activeState, context, options)
9
+ self.withConnection(target['Location'], target) do |connection|
10
+ Linux.withConnection(connection) do |linuxConnection|
11
+ installPackages(linuxConnection, target, options)
12
+ installRVM(linuxConnection, true, target, options)
13
+ if target['User']
14
+ linuxConnection.exec("usermod --append --groups rvm #{target['User']}")
15
+ end
16
+ installGems(linuxConnection, target, options)
17
+ end
18
+ end
19
+ end
20
+
21
+ def installPackages(connection, target, options)
22
+ packages = target['Packages'].to_a
23
+ if !packages.empty?
24
+ connection.ensurePackages(packages, options)
25
+ end
26
+ end
27
+
28
+ def installRVM(connection, installDeps, target, options)
29
+ if !connection.hasBinaries?('rvm', options)
30
+ # Needs dirmngr
31
+ # connection.exec('gpg2 --keyserver hkp://keyserver.ubuntu.com --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB', false, options)
32
+
33
+ connection.exec('curl -sSL https://rvm.io/mpapis.asc | gpg --import -', false, options)
34
+ connection.exec('curl -sSL https://rvm.io/pkuczynski.asc | gpg --import -', false, options)
35
+ extra = ''
36
+ if !installDeps
37
+ extra = ' --autolibs=read-fail'
38
+ end
39
+ connection.exec("curl --silent --show-error --location https://get.rvm.io | bash -s stable --ruby=#{LATEST_RUBY_VERSION}#{extra}", false, options)
40
+ installFishFunction(connection, target, options)
41
+ end
42
+ end
43
+
44
+ def installFishFunction(connection, target, options)
45
+ connection.exec('curl --silent --show-error --location --create-dirs --output /etc/fish/conf.d/rvm.fish https://raw.github.com/lunks/fish-nuggets/master/functions/rvm.fish', false, options)
46
+ connection.fileAppend("/etc/fish/conf.d/rvm.fish", 'rvm default', options)
47
+ end
48
+
49
+ def installGems(connection, target, options)
50
+ gems = target['Gems'].to_a.join(' ')
51
+ if !gems.empty?
52
+ connection.exec("gem install #{gems}", false, options)
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -31,9 +31,6 @@ server
31
31
 
32
32
  server_name <%= config['Domain'] %>;
33
33
 
34
- access_log /var/log/nginx/roundcube.access.log;
35
- error_log /var/log/nginx/roundcube.error.log;
36
-
37
34
  index index.php;
38
35
  root /usr/share/webapps/roundcubemail;
39
36