ConfigLMM 0.3.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 (250) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +70 -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 +20 -0
  13. data/Plugins/Apps/Authentik/Authentik-Server.container +7 -1
  14. data/Plugins/Apps/Authentik/Authentik-Worker.container +7 -1
  15. data/Plugins/Apps/Authentik/Authentik.conf.erb +18 -6
  16. data/Plugins/Apps/Authentik/Authentik.lmm.rb +232 -45
  17. data/Plugins/Apps/BookStack/BookStack.conf.erb +38 -0
  18. data/Plugins/Apps/BookStack/BookStack.container +20 -0
  19. data/Plugins/Apps/BookStack/BookStack.lmm.rb +91 -0
  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 +22 -0
  28. data/Plugins/Apps/Discourse/Discourse.conf.erb +38 -0
  29. data/Plugins/Apps/Discourse/Discourse.container +21 -0
  30. data/Plugins/Apps/Discourse/Discourse.lmm.rb +156 -0
  31. data/Plugins/Apps/Dovecot/Dovecot.lmm.rb +87 -52
  32. data/Plugins/Apps/ERPNext/ERPNext-Frontend.container +24 -0
  33. data/Plugins/Apps/ERPNext/ERPNext-Queue.container +22 -0
  34. data/Plugins/Apps/ERPNext/ERPNext-Scheduler.container +22 -0
  35. data/Plugins/Apps/ERPNext/ERPNext-Websocket.container +24 -0
  36. data/Plugins/Apps/ERPNext/ERPNext.container +23 -0
  37. data/Plugins/Apps/ERPNext/ERPNext.lmm.rb +204 -0
  38. data/Plugins/Apps/ERPNext/ERPNext.network +12 -0
  39. data/Plugins/Apps/ERPNext/sites/apps.json +10 -0
  40. data/Plugins/Apps/ERPNext/sites/apps.txt +3 -0
  41. data/Plugins/Apps/ERPNext/sites/common_site_config.json +11 -0
  42. data/Plugins/Apps/GitLab/GitLab.container +9 -2
  43. data/Plugins/Apps/GitLab/GitLab.lmm.rb +52 -33
  44. data/Plugins/Apps/Homepage/Homepage.conf.erb +86 -0
  45. data/Plugins/Apps/Homepage/Homepage.container +19 -0
  46. data/Plugins/Apps/Homepage/Homepage.lmm.rb +54 -0
  47. data/Plugins/Apps/IPFS/IPFS.conf.erb +0 -3
  48. data/Plugins/Apps/IPFS/IPFS.lmm.rb +0 -1
  49. data/Plugins/Apps/InfluxDB/InfluxDB.conf.erb +0 -3
  50. data/Plugins/Apps/InfluxDB/InfluxDB.lmm.rb +0 -1
  51. data/Plugins/Apps/Jackett/Jackett.conf.erb +0 -3
  52. data/Plugins/Apps/Jackett/Jackett.lmm.rb +0 -1
  53. data/Plugins/Apps/Jellyfin/Jellyfin.conf.erb +0 -3
  54. data/Plugins/Apps/Jellyfin/Jellyfin.lmm.rb +0 -1
  55. data/Plugins/Apps/LetsEncrypt/LetsEncrypt.lmm.rb +78 -0
  56. data/Plugins/Apps/LetsEncrypt/hooks/dovecot.sh +2 -0
  57. data/Plugins/Apps/LetsEncrypt/hooks/nginx.sh +2 -0
  58. data/Plugins/Apps/LetsEncrypt/hooks/postfix.sh +2 -0
  59. data/Plugins/Apps/LetsEncrypt/renew-certificates.service +7 -0
  60. data/Plugins/Apps/LetsEncrypt/renew-certificates.timer +12 -0
  61. data/Plugins/Apps/LetsEncrypt/rfc2136.ini +11 -0
  62. data/Plugins/Apps/LibreTranslate/LibreTranslate.container +21 -0
  63. data/Plugins/Apps/LibreTranslate/LibreTranslate.lmm.rb +34 -0
  64. data/Plugins/Apps/Lobsters/Containerfile +81 -0
  65. data/Plugins/Apps/Lobsters/Lobsters-Tasks.container +26 -0
  66. data/Plugins/Apps/Lobsters/Lobsters.conf.erb +99 -0
  67. data/Plugins/Apps/Lobsters/Lobsters.container +27 -0
  68. data/Plugins/Apps/Lobsters/Lobsters.lmm.rb +196 -0
  69. data/Plugins/Apps/Lobsters/crontab +3 -0
  70. data/Plugins/Apps/Lobsters/database.yml +26 -0
  71. data/Plugins/Apps/Lobsters/entrypoint.sh +30 -0
  72. data/Plugins/Apps/Lobsters/generateCredentials.rb +19 -0
  73. data/Plugins/Apps/Lobsters/lobsters-cron.sh +25 -0
  74. data/Plugins/Apps/Lobsters/lobsters-daily.sh +23 -0
  75. data/Plugins/Apps/Lobsters/puma.rb +49 -0
  76. data/Plugins/Apps/MariaDB/Connection.rb +55 -0
  77. data/Plugins/Apps/MariaDB/MariaDB.lmm.rb +122 -0
  78. data/Plugins/Apps/Mastodon/Mastodon-Sidekiq.container +22 -0
  79. data/Plugins/Apps/Mastodon/Mastodon-Streaming.container +20 -0
  80. data/Plugins/Apps/Mastodon/Mastodon.conf.erb +34 -45
  81. data/Plugins/Apps/Mastodon/Mastodon.container +28 -0
  82. data/Plugins/Apps/Mastodon/Mastodon.lmm.rb +240 -5
  83. data/Plugins/Apps/Mastodon/configlmm.rake +30 -0
  84. data/Plugins/Apps/Mastodon/entrypoint.sh +16 -0
  85. data/Plugins/Apps/Matrix/Element.container +19 -0
  86. data/Plugins/Apps/Matrix/Matrix.conf.erb +47 -9
  87. data/Plugins/Apps/Matrix/Matrix.lmm.rb +119 -5
  88. data/Plugins/Apps/Matrix/Synapse.container +22 -0
  89. data/Plugins/Apps/Matrix/config.json +50 -0
  90. data/Plugins/Apps/Matrix/homeserver.yaml +70 -0
  91. data/Plugins/Apps/Matrix/log.config +30 -0
  92. data/Plugins/Apps/Netdata/Netdata.conf.erb +0 -3
  93. data/Plugins/Apps/Netdata/Netdata.lmm.rb +0 -1
  94. data/Plugins/Apps/Nextcloud/Nextcloud.conf.erb +3 -4
  95. data/Plugins/Apps/Nextcloud/Nextcloud.lmm.rb +155 -48
  96. data/Plugins/Apps/Nextcloud/autoconfig.php +13 -0
  97. data/Plugins/Apps/Nextcloud/config.php +10 -1
  98. data/Plugins/Apps/Nextcloud/nextcloudcron.service +8 -0
  99. data/Plugins/Apps/Nextcloud/nextcloudcron.timer +10 -0
  100. data/Plugins/Apps/Nginx/Connection.rb +93 -0
  101. data/Plugins/Apps/Nginx/conf.d/configlmm.conf +54 -4
  102. data/Plugins/Apps/Nginx/conf.d/languages.conf +21 -0
  103. data/Plugins/Apps/Nginx/config-lmm/errors.conf +33 -22
  104. data/Plugins/Apps/Nginx/config-lmm/gateway-errors.conf +20 -0
  105. data/Plugins/Apps/Nginx/config-lmm/proxy.conf +6 -2
  106. data/Plugins/Apps/Nginx/main.conf.erb +7 -3
  107. data/Plugins/Apps/Nginx/nginx.conf +2 -2
  108. data/Plugins/Apps/Nginx/nginx.lmm.rb +103 -81
  109. data/Plugins/Apps/Nginx/proxy.conf.erb +24 -6
  110. data/Plugins/Apps/Odoo/Odoo.conf.erb +0 -3
  111. data/Plugins/Apps/Odoo/Odoo.container +7 -1
  112. data/Plugins/Apps/Odoo/Odoo.lmm.rb +4 -5
  113. data/Plugins/Apps/Ollama/Ollama.container +26 -0
  114. data/Plugins/Apps/Ollama/Ollama.lmm.rb +73 -0
  115. data/Plugins/Apps/OpenTelemetry/Config/config.yaml +704 -0
  116. data/Plugins/Apps/OpenTelemetry/OpenTelemetry.lmm.rb +154 -0
  117. data/Plugins/Apps/OpenVidu/Ingress.container +23 -0
  118. data/Plugins/Apps/{GitLab/GitLab.conf.erb → OpenVidu/OpenVidu.conf.erb} +8 -3
  119. data/Plugins/Apps/OpenVidu/OpenVidu.container +21 -0
  120. data/Plugins/Apps/OpenVidu/OpenVidu.lmm.rb +94 -0
  121. data/Plugins/Apps/OpenVidu/OpenViduCall.conf.erb +32 -0
  122. data/Plugins/Apps/OpenVidu/OpenViduCall.container +20 -0
  123. data/Plugins/Apps/OpenVidu/ingress.yaml +10 -0
  124. data/Plugins/Apps/OpenVidu/livekit.yaml +13 -0
  125. data/Plugins/Apps/PHP-FPM/Connection.rb +91 -0
  126. data/Plugins/Apps/PHP-FPM/PHP-FPM.lmm.rb +31 -4
  127. data/Plugins/Apps/Peppermint/Peppermint.conf.erb +2 -9
  128. data/Plugins/Apps/Peppermint/Peppermint.container +7 -1
  129. data/Plugins/Apps/Peppermint/Peppermint.lmm.rb +29 -33
  130. data/Plugins/Apps/Perplexica/Perplexica.container +25 -0
  131. data/Plugins/Apps/Perplexica/Perplexica.lmm.rb +92 -0
  132. data/Plugins/Apps/Perplexica/config.toml +26 -0
  133. data/Plugins/Apps/Podman/Connection.rb +24 -0
  134. data/Plugins/Apps/Podman/Podman.lmm.rb +80 -0
  135. data/Plugins/Apps/Podman/storage.conf +6 -0
  136. data/Plugins/Apps/Postfix/Postfix.lmm.rb +249 -145
  137. data/Plugins/Apps/PostgreSQL/Connection.rb +97 -0
  138. data/Plugins/Apps/PostgreSQL/PostgreSQL.lmm.rb +204 -99
  139. data/Plugins/Apps/Pterodactyl/Pterodactyl.conf.erb +0 -3
  140. data/Plugins/Apps/Pterodactyl/Pterodactyl.lmm.rb +0 -2
  141. data/Plugins/Apps/Pterodactyl/Wings.conf.erb +0 -3
  142. data/Plugins/Apps/RVM/RVM.lmm.rb +57 -0
  143. data/Plugins/Apps/Roundcube/Roundcube.conf.erb +72 -0
  144. data/Plugins/Apps/Roundcube/Roundcube.lmm.rb +141 -0
  145. data/Plugins/Apps/SSH/SSH.lmm.rb +9 -15
  146. data/Plugins/Apps/SearXNG/SearXNG.container +22 -0
  147. data/Plugins/Apps/SearXNG/SearXNG.lmm.rb +79 -0
  148. data/Plugins/Apps/SearXNG/limiter.toml +40 -0
  149. data/Plugins/Apps/SearXNG/settings.yml +2 -0
  150. data/Plugins/Apps/SigNoz/Config/alerts.yml +11 -0
  151. data/Plugins/Apps/SigNoz/Config/otel-collector-config.yaml +110 -0
  152. data/Plugins/Apps/SigNoz/Config/otel-collector-opamp-config.yaml +1 -0
  153. data/Plugins/Apps/SigNoz/Config/prometheus.yml +18 -0
  154. data/Plugins/Apps/SigNoz/SigNoz-Collector.container +23 -0
  155. data/Plugins/Apps/SigNoz/SigNoz-Migrator.container +17 -0
  156. data/Plugins/Apps/SigNoz/SigNoz.conf.erb +61 -0
  157. data/Plugins/Apps/SigNoz/SigNoz.container +26 -0
  158. data/Plugins/Apps/SigNoz/SigNoz.lmm.rb +319 -0
  159. data/Plugins/Apps/Solr/log4j2.xml +89 -0
  160. data/Plugins/Apps/Solr/solr.lmm.rb +82 -0
  161. data/Plugins/Apps/Sunshine/Sunshine.conf.erb +0 -3
  162. data/Plugins/Apps/Sunshine/Sunshine.lmm.rb +0 -1
  163. data/Plugins/Apps/Tunnel/tunnel.lmm.rb +59 -0
  164. data/Plugins/Apps/Tunnel/tunnelTCP.service +9 -0
  165. data/Plugins/Apps/Tunnel/tunnelTCP.socket +9 -0
  166. data/Plugins/Apps/Tunnel/tunnelUDP.service +9 -0
  167. data/Plugins/Apps/Tunnel/tunnelUDP.socket +9 -0
  168. data/Plugins/Apps/UVdesk/UVdesk.conf.erb +0 -3
  169. data/Plugins/Apps/Umami/Umami.container +19 -0
  170. data/Plugins/Apps/Umami/Umami.lmm.rb +108 -0
  171. data/Plugins/Apps/Valkey/Valkey.lmm.rb +64 -20
  172. data/Plugins/Apps/Vaultwarden/Vaultwarden.conf.erb +9 -6
  173. data/Plugins/Apps/Vaultwarden/Vaultwarden.container +7 -1
  174. data/Plugins/Apps/Vaultwarden/Vaultwarden.lmm.rb +67 -28
  175. data/Plugins/Apps/Wiki.js/Wiki.js.conf.erb +39 -0
  176. data/Plugins/Apps/Wiki.js/Wiki.js.container +20 -0
  177. data/Plugins/Apps/Wiki.js/Wiki.js.lmm.rb +55 -0
  178. data/Plugins/Apps/YaCy/YaCy.conf.erb +93 -0
  179. data/Plugins/Apps/YaCy/YaCy.container +21 -0
  180. data/Plugins/Apps/YaCy/YaCy.lmm.rb +160 -0
  181. data/Plugins/Apps/ZooKeeper/ZooKeeper.container +24 -0
  182. data/Plugins/Apps/ZooKeeper/ZooKeeper.lmm.rb +68 -0
  183. data/Plugins/Apps/bitmagnet/bitmagnet.conf.erb +0 -3
  184. data/Plugins/Apps/bitmagnet/bitmagnet.lmm.rb +0 -1
  185. data/Plugins/Apps/gollum/gollum.conf.erb +40 -4
  186. data/Plugins/Apps/gollum/gollum.container +10 -1
  187. data/Plugins/Apps/gollum/gollum.lmm.rb +56 -47
  188. data/Plugins/Apps/llama.cpp/llama.cpp.container +28 -0
  189. data/Plugins/Apps/llama.cpp/llama.cpp.lmm.rb +90 -0
  190. data/Plugins/Apps/vLLM/vLLM.container +32 -0
  191. data/Plugins/Apps/vLLM/vLLM.lmm.rb +89 -0
  192. data/Plugins/OS/General/Utils.lmm.rb +26 -0
  193. data/Plugins/OS/Linux/Connection.rb +472 -0
  194. data/Plugins/OS/Linux/Debian/preseed.cfg.erb +81 -0
  195. data/Plugins/OS/Linux/Distributions.yaml +32 -0
  196. data/Plugins/OS/Linux/Flavours.yaml +24 -0
  197. data/Plugins/OS/Linux/Grub/grub.cfg +10 -0
  198. data/Plugins/OS/Linux/HTTP.rb +32 -0
  199. data/Plugins/OS/Linux/Linux.lmm.rb +708 -174
  200. data/Plugins/OS/Linux/Packages.yaml +67 -3
  201. data/Plugins/OS/Linux/Proxmox/answer.toml.erb +30 -0
  202. data/Plugins/OS/Linux/Services.yaml +8 -0
  203. data/Plugins/OS/Linux/Shell.rb +70 -0
  204. data/Plugins/OS/Linux/Syslinux/default +8 -0
  205. data/Plugins/OS/Linux/WireGuard/WireGuard.lmm.rb +93 -40
  206. data/Plugins/OS/Linux/WireGuard/wg0.conf.erb +3 -0
  207. data/Plugins/OS/Linux/openSUSE/autoinst.xml.erb +29 -3
  208. data/Plugins/OS/Linux/systemd/systemd.lmm.rb +13 -11
  209. data/Plugins/OS/Routers/Aruba/ArubaInstant.lmm.rb +6 -5
  210. data/Plugins/Platforms/GitHub.lmm.rb +73 -28
  211. data/Plugins/Platforms/GoDaddy/GoDaddy.lmm.rb +10 -7
  212. data/Plugins/Platforms/Proxmox/Proxmox.lmm.rb +402 -0
  213. data/Plugins/Platforms/Proxmox/XTerm.rb +321 -0
  214. data/Plugins/Platforms/libvirt/libvirt.lmm.rb +41 -15
  215. data/Plugins/Platforms/porkbun.lmm.rb +12 -2
  216. data/Plugins/Platforms/porkbun_spec.rb +2 -2
  217. data/Plugins/Services/DNS/AmberBit.lmm.rb +1 -1
  218. data/Plugins/Services/DNS/ArubaItDNS.lmm.rb +1 -1
  219. data/Plugins/Services/DNS/NICLV.lmm.rb +1 -1
  220. data/Plugins/Services/DNS/PowerDNS.lmm.rb +130 -41
  221. data/Plugins/Services/DNS/tonic.lmm.rb +22 -12
  222. data/bootstrap.sh +41 -3
  223. data/lib/ConfigLMM/Framework/plugins/dns.rb +4 -3
  224. data/lib/ConfigLMM/Framework/plugins/linuxApp.rb +187 -144
  225. data/lib/ConfigLMM/Framework/plugins/nginxApp.rb +54 -6
  226. data/lib/ConfigLMM/Framework/plugins/plugin.rb +68 -140
  227. data/lib/ConfigLMM/Framework/plugins/store.rb +4 -4
  228. data/lib/ConfigLMM/Framework/variables.rb +75 -0
  229. data/lib/ConfigLMM/Framework.rb +1 -0
  230. data/lib/ConfigLMM/cli.rb +13 -5
  231. data/lib/ConfigLMM/commands/cleanup.rb +1 -0
  232. data/lib/ConfigLMM/commands/configsCommand.rb +38 -5
  233. data/lib/ConfigLMM/commands/diff.rb +33 -9
  234. data/lib/ConfigLMM/context.rb +22 -3
  235. data/lib/ConfigLMM/io/configList.rb +85 -7
  236. data/lib/ConfigLMM/io/connection.rb +143 -0
  237. data/lib/ConfigLMM/io/dhcp.rb +330 -0
  238. data/lib/ConfigLMM/io/http.rb +78 -0
  239. data/lib/ConfigLMM/io/local.rb +207 -0
  240. data/lib/ConfigLMM/io/pxe.rb +92 -0
  241. data/lib/ConfigLMM/io/ssh.rb +156 -0
  242. data/lib/ConfigLMM/io/tftp.rb +105 -0
  243. data/lib/ConfigLMM/io.rb +2 -0
  244. data/lib/ConfigLMM/secrets/envStore.rb +39 -0
  245. data/lib/ConfigLMM/secrets/fileStore.rb +43 -0
  246. data/lib/ConfigLMM/state.rb +12 -3
  247. data/lib/ConfigLMM/version.rb +2 -1
  248. data/lib/ConfigLMM.rb +1 -0
  249. data/{Examples → scripts}/configlmmAuth.sh +7 -5
  250. metadata +257 -9
@@ -6,21 +6,31 @@ Arch Linux:
6
6
  CyrusSASL: cyrus-sasl
7
7
  Dovecot: dovecot
8
8
  firewalld: firewalld
9
+ go: go
10
+ MariaDB: mariadb
9
11
  Nextcloud: nextcloud
10
12
  nginx: nginx
13
+ nodejs: nodejs
14
+ otelcol-contrib: AUR|otelcol-contrib
11
15
  PHP-FPM: php-fpm
12
16
  php-pecl: php-pecl
13
- Podman: podman
17
+ pnpm: pnpm
18
+ Podman:
19
+ - podman
20
+ - fuse-overlayfs
14
21
  PostgreSQL: postgresql
15
22
  Postfix: postfix
16
23
  PowerDNS: powerdns
24
+ Roundcube: roundcubemail
25
+ socat: socat
17
26
  sshd: openssh
18
27
  Valkey: redis
19
28
  WireGuard: wireguard-tools
29
+ xorriso: libisoburn
20
30
  Yarn: yarn
21
31
 
22
32
  openSUSE Leap:
23
- Cassandra: home:davispuh:branches:server:database|cassandra
33
+ Cassandra: server:database|cassandra
24
34
  CertBotNginx:
25
35
  - python3-certbot-nginx
26
36
  - certbot-systemd-timer
@@ -28,24 +38,78 @@ openSUSE Leap:
28
38
  CyrusSASL: cyrus-sasl-plain
29
39
  Dovecot: dovecot
30
40
  firewalld: firewalld
41
+ go: go
42
+ MariaDB: mariadb
31
43
  Nextcloud: server:php:applications|nextcloud
32
44
  nginx: nginx
45
+ nodejs: nodejs-default
46
+ otelcol-contrib: GitHub|open-telemetry/opentelemetry-collector-releases:otelcol-contrib_*_linux_amd64.rpm
33
47
  PHP-FPM:
34
48
  - php8-devel
35
49
  - php8-mbstring
36
50
  - php8-fpm
51
+ - php8-imagick
37
52
  - php8-redis
38
53
  - php8-pgsql
39
54
  - php8-mysql
40
55
  php-pecl: php8-pecl
56
+ pnpm: GitHub|pnpm/pnpm:pnpm-linux-x64
41
57
  Podman: podman
42
- PostgreSQL: postgresql-server
58
+ PostgreSQL:
59
+ - postgresql-server
60
+ - postgresql-contrib
43
61
  Postfix: postfix
44
62
  PowerDNS:
63
+ - pdns
45
64
  - pdns-backend-geoip
46
65
  - pdns-backend-sqlite3
47
66
  - pdns-backend-postgresql
67
+ Roundcube: roundcubemail
68
+ socat: socat
48
69
  sshd: openssh
49
70
  Valkey: redis
50
71
  WireGuard: wireguard-tools
72
+ xorriso: xorriso
51
73
  Yarn: yarn
74
+
75
+ Debian:
76
+ Cassandra: https://debian.cassandra.apache.org 41x main|cassandra
77
+ CertBotNginx:
78
+ - certbot
79
+ - python3-certbot-dns-rfc2136
80
+ CyrusSASL: libsasl2-modules
81
+ Dovecot:
82
+ - dovecot-imapd
83
+ - dovecot-lmtpd
84
+ - dovecot-submissiond
85
+ firewalld: firewalld
86
+ go: golang
87
+ MariaDB: mariadb-server
88
+ Nextcloud:
89
+ nginx: nginx
90
+ nodejs: nodejs
91
+ otelcol-contrib: GitHub|open-telemetry/opentelemetry-collector-releases:otelcol-contrib_*_linux_amd64.deb
92
+ PHP-FPM:
93
+ - php-mbstring
94
+ - php-fpm
95
+ - php-imagick
96
+ - php-redis
97
+ - php-pgsql
98
+ - php-mysql
99
+ php-pecl:
100
+ pnpm: GitHub|pnpm/pnpm:pnpm-linux-x64
101
+ Podman: podman
102
+ PostgreSQL: postgresql
103
+ Postfix: postfix-lmdb
104
+ PowerDNS:
105
+ - pdns-server
106
+ - pdns-backend-geoip
107
+ - pdns-backend-sqlite3
108
+ - pdns-backend-pgsql
109
+ Roundcube: roundcube-pgsql
110
+ socat: socat
111
+ sshd: openssh-server
112
+ Valkey: redis
113
+ WireGuard: wireguard
114
+ xorriso: xorriso
115
+ Yarn: yarnpkg
@@ -0,0 +1,30 @@
1
+ [global]
2
+ keyboard = "en-us"
3
+ country = "us"
4
+ fqdn = "<%= Addressable::IDNA.to_ascii(config['Domain']) %>"
5
+ mailto = "<%= config['EMail'] %>"
6
+ timezone = "UTC"
7
+ root_password = "<%= config['Users'].to_h['root'].to_h['Password'] %>"
8
+ <% if !config['Users'].to_h['root'].to_h['AuthorizedKeys'].to_a.empty? %>
9
+ root_ssh_keys = [
10
+ <% config['Users']['root']['AuthorizedKeys'].each do |entry| %>
11
+ "<%= entry %>"
12
+ <% end %>
13
+ ]
14
+ <% end %>
15
+
16
+ [network]
17
+ <% if config['Network'].is_a?(Hash) %>
18
+ source = "from-answer"
19
+ cidr = "<%= config['Network']['IP'] %>"
20
+ dns = "<%= config['Network']['DNS'] %>"
21
+ gateway = "<%= config['Network']['Gateway'] %>"
22
+ filter.IFINDEX = "2"
23
+ <% else %>
24
+ source = "from-dhcp"
25
+ <% end %>
26
+
27
+ [disk-setup]
28
+ filesystem = "btrfs"
29
+ btrfs.raid = "raid1"
30
+ disk_list = ["vda"]
@@ -0,0 +1,8 @@
1
+ Arch Linux:
2
+ sshd: sshd
3
+
4
+ openSUSE Leap:
5
+ sshd: sshd
6
+
7
+ Debian:
8
+ sshd: ssh
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'fileutils'
4
+ require 'open3'
5
+
6
+ module ConfigLMM
7
+ module LMM
8
+ class LinuxShell
9
+
10
+ attr_reader :connection
11
+ attr_reader :user
12
+
13
+ def initialize(connection, user)
14
+ @connection = connection
15
+ @user = user
16
+ end
17
+
18
+ def distroID
19
+ @connection.distroID
20
+ end
21
+
22
+ def updateFile(*args, &block)
23
+ @connection.updateFile(*args, &block)
24
+ end
25
+
26
+ def exec(command, allowFailure = false, options = {})
27
+ cmd = "su --login #{@user.shellescape} --shell /usr/bin/sh --command #{command.shellescape}"
28
+ if options[:hide]
29
+ cmd = ' ' + cmd
30
+ end
31
+ @connection.exec(cmd, allowFailure, options)
32
+ end
33
+
34
+ def rm(*args)
35
+ @connection.rm(*args)
36
+ end
37
+
38
+ def fileWrite(target, data, options = {})
39
+ hide = ''
40
+ hide = ' ' if options[:hide]
41
+ self.exec("#{hide}echo #{data.shellescape} > #{target}", false, options)
42
+ end
43
+
44
+ def fileAppend(target, data, options = {})
45
+ hide = ''
46
+ hide = ' ' if options[:hide]
47
+ self.exec("#{hide}echo #{data.shellescape} >> #{target}", false, options)
48
+ end
49
+
50
+ def fileMerge(target, file, options = {})
51
+ self.exec("cat #{file.shellescape} >> #{target}", false, options)
52
+ end
53
+
54
+ def fileReplace(target, placeholder, result, options = {})
55
+ hide = ''
56
+ hide = ' ' if options[:hide]
57
+ pattern = "s|#{placeholder}|#{result.gsub('\\', '\\\\\\').gsub('&', '\\\\&').gsub('|', '\\\\|')}|"
58
+ self.exec("#{hide}sed -i #{pattern.shellescape} #{target}", false, options)
59
+ end
60
+
61
+ def createDirs(options, *paths)
62
+ exec("mkdir -p #{paths.join(' ')}", false, options)
63
+ end
64
+
65
+ def self.escapeSingleQuotes(command)
66
+ command.gsub("'", "'\"'\"'")
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,8 @@
1
+
2
+ default auto
3
+ prompt 0
4
+ timeout 1
5
+
6
+ label auto
7
+ kernel linux
8
+ append initrd=initrd splash=silent $OPTIONS
@@ -13,42 +13,64 @@ module ConfigLMM
13
13
 
14
14
  def actionWireGuardDeploy(id, target, activeState, context, options)
15
15
  self.prepareConfig(target)
16
- if target['Location'] && target['Location'] != '@me'
17
- uri = Addressable::URI.parse(target['Location'])
18
- raise Framework::PluginProcessError.new("#{id}: Unknown Protocol: #{uri.scheme}!") if uri.scheme != 'ssh'
19
- self.class.sshStart(uri) do |ssh|
20
- sharedKey = self.class.sshExec!(ssh, "firewall-cmd -q --permanent --add-port='#{PORT}'/udp")
21
- sharedKey = self.class.sshExec!(ssh, "firewall-cmd -q --permanent --zone=trusted --add-source=#{SUBNET}")
22
- sharedKey = self.class.sshExec!(ssh, "firewall-cmd -q --permanent --direct --add-rule ipv4 nat POSTROUTING 0 -s #{SUBNET} ! -d #{SUBNET} -j MASQUERADE")
16
+ self.withConnection(target['Location'], target) do |connection|
17
+ Linux.withConnection(connection) do |linuxConnection|
18
+ linuxConnection.firewallAddPort("#{PORT}/udp", options)
19
+ linuxConnection.exec("firewall-cmd -q --permanent --zone=trusted --add-source=#{SUBNET}", options)
20
+ linuxConnection.exec("firewall-cmd -q --zone=trusted --add-source=#{SUBNET}", options)
21
+ linuxConnection.exec("firewall-cmd -q --permanent --direct --add-rule ipv4 nat POSTROUTING 0 -s #{SUBNET} ! -d #{SUBNET} -j MASQUERADE", options)
22
+ linuxConnection.exec("firewall-cmd -q --direct --add-rule ipv4 nat POSTROUTING 0 -s #{SUBNET} ! -d #{SUBNET} -j MASQUERADE", options)
23
23
 
24
- self.class.ensurePackages([WIREGUARD_PACKAGE], ssh)
25
- self.class.ensureServiceAutoStartOverSSH(SERVICE_NAME, ssh)
24
+ linuxConnection.ensurePackage(WIREGUARD_PACKAGE, options)
25
+ linuxConnection.ensureServiceAutoStart(SERVICE_NAME, options)
26
26
 
27
27
  dir = options['output'] + '/' + id + '/etc/wireguard/'
28
28
  mkdir(dir, false)
29
29
  template = ERB.new(File.read(__dir__ + '/wg0.conf.erb'))
30
30
 
31
- if self.class.remoteFilePresent?(CONFIG_FILE, ssh)
31
+ target = target.dup
32
+ target['PrivateKey'] = context.secrets.load(target['SecretId'], 'PRIVATEKEY')
33
+ if target['PrivateKey'].nil?
34
+ target['PrivateKey'] = genkey(connection, options)
35
+ if !options['dry']
36
+ context.secrets.store(target['SecretId'], 'PRIVATEKEY', target['PrivateKey'])
37
+ context.secrets.print("Private Key", target['PrivateKey'])
38
+ end
39
+ end
40
+
41
+ if connection.filePresent?(CONFIG_FILE, { **options, 'dry' => false })
32
42
  # TODO Implement adding and removing peers
33
43
  else
34
- if !target['PrivateKey']
35
- target['PrivateKey'] = ENV['WIREGUARD_PRIVATEKEY_' + id]
36
- if !target['PrivateKey']
37
- target['PrivateKey'] = genkeyOverSSH(ssh)
38
- end
39
- end
40
- publicKey = pubkeyOverSSH(target['PrivateKey'], ssh)
41
- self.class.sshExec!(ssh, "echo '#{publicKey}' > /etc/wireguard/pubkey")
44
+ publicKey = pubkey(target['PrivateKey'], connection, options)
45
+ context.secrets.store(target['SecretId'], 'PUBLICKEY', publicKey) unless options['dry']
46
+ connection.exec("echo '#{publicKey}' > /etc/wireguard/pubkey", false, options)
47
+
42
48
  target['Peers'].each do |name, data|
43
- if !data['PublicKey']
44
- data['PrivateKey'] = genkeyOverSSH(ssh)
45
- data['PublicKey'] = pubkeyOverSSH(data['PrivateKey'], ssh)
46
- end
47
- if !data['PresharedKey']
48
- data['PresharedKey'] = ENV['WIREGUARD_PRESHAREDKEY_' + id + '_' + name]
49
- if !data['PresharedKey']
50
- data['PresharedKey'] = genpskOverSSH(ssh)
49
+ if data['SecretId']
50
+ data['PublicKey'] = context.secrets.load(data['SecretId'], 'PUBLICKEY')
51
+ data['PrivateKey'] = context.secrets.load(data['SecretId'], 'PRIVATEKEY')
52
+ if data['PublicKey'].nil?
53
+ data['PrivateKey'] = genkey(connection, options)
54
+ data['PublicKey'] = pubkey(data['PrivateKey'], connection, options)
55
+ if !options['dry']
56
+ context.secrets.store(data['SecretId'], 'PRIVATEKEY', data['PrivateKey'])
57
+ context.secrets.store(data['SecretId'], 'PUBLICKEY', data['PublicKey'])
58
+ end
59
+ end
60
+ sharedSecretId = "#{target['SecretId'].upcase}_#{data['SecretId'].upcase}"
61
+ data['PresharedKey'] = context.secrets.load(sharedSecretId, 'PRESHAREDKEY')
62
+ if data['PresharedKey'].nil?
63
+ sharedSecretId2 = "#{data['SecretId'].upcase}_#{target['SecretId'].upcase}"
64
+ data['PresharedKey'] = context.secrets.load(sharedSecretId2, 'PRESHAREDKEY')
65
+ if data['PresharedKey'].nil?
66
+ data['PresharedKey'] = genpsk(connection, options)
67
+ context.secrets.store(sharedSecretId, 'PRESHAREDKEY', data['PresharedKey']) unless options['dry']
68
+ end
51
69
  end
70
+ else
71
+ data['PrivateKey'] = genkey(connection, options)
72
+ data['PublicKey'] = pubkey(data['PrivateKey'], connection, options)
73
+ data['PresharedKey'] = genpsk(connection, options)
52
74
  end
53
75
  end
54
76
 
@@ -65,7 +87,7 @@ module ConfigLMM
65
87
  psk = otherData[pskIdB]
66
88
  else
67
89
  pskIdA = 'PresharedKey_' + name + '_' + otherName
68
- data[pskIdA] = genpskOverSSH(ssh)
90
+ data[pskIdA] = genpsk(connection, options)
69
91
  psk = data[pskIdA]
70
92
  end
71
93
  templateData['Peers'][otherName] = { 'PublicKey' => otherData['PublicKey'], 'PresharedKey' => psk }
@@ -75,33 +97,64 @@ module ConfigLMM
75
97
  end
76
98
 
77
99
  renderTemplate(template, target, dir + 'wg0.conf', options)
78
- ssh.scp.upload!(dir + 'wg0.conf', CONFIG_FILE)
100
+ connection.upload(dir + 'wg0.conf', CONFIG_FILE, options)
79
101
  end
80
102
 
103
+ linuxConnection.restartService(SERVICE_NAME, options)
81
104
  end
82
- else
83
- # TODO
84
105
  end
85
- self.startService(SERVICE_NAME, target['Location'])
86
106
  end
87
107
 
88
- def genkeyOverSSH(ssh)
89
- self.class.sshExec!(ssh, 'wg genkey')
108
+ def cleanup(configs, state, context, options)
109
+ cleanupType(:WireGuard, configs, state, context, options) do |item, id, state, context, options, connection|
110
+ Linux.withConnection(connection) do |linuxConnection|
111
+ linuxConnection.stopService(SERVICE_NAME, options[:dry])
112
+ linuxConnection.disableService(SERVICE_NAME, options[:dry])
113
+ linuxConnection.removePackage(WIREGUARD_PACKAGE, options[:dry])
114
+
115
+ linuxConnection.firewallRemovePort("#{PORT}/udp", options)
116
+ linuxConnection.exec("firewall-cmd -q --permanent --zone=trusted --remove-source=#{SUBNET}", false, options[:dry])
117
+ linuxConnection.exec("firewall-cmd -q --zone=trusted --remove-source=#{SUBNET}", false, options[:dry])
118
+ linuxConnection.exec("firewall-cmd -q --permanent --direct --remove-rule ipv4 nat POSTROUTING 0 -s #{SUBNET} ! -d #{SUBNET} -j MASQUERADE", false, options[:dry])
119
+ linuxConnection.exec("firewall-cmd -q --direct --remove-rule ipv4 nat POSTROUTING 0 -s #{SUBNET} ! -d #{SUBNET} -j MASQUERADE", false, options[:dry])
120
+ end
121
+
122
+ state.item(id)['Status'] = State::STATUS_DELETED unless options[:dry]
123
+
124
+ if options[:destroy]
125
+ connection.rm('/etc/wireguard', options[:dry])
126
+
127
+ state.item(id)['Status'] = State::STATUS_DESTROYED unless options[:dry]
128
+ end
129
+ end
130
+ end
131
+
132
+ def genkey(connection, options)
133
+ key = connection.exec('wg genkey', false, options).strip
134
+ if options['dry']
135
+ key = connection.exec('wg genkey', false, { **options, 'dry' => false }).strip
136
+ end
137
+ key
90
138
  end
91
139
 
92
- def genpskOverSSH(ssh)
93
- self.class.sshExec!(ssh, 'wg genpsk')
140
+ def genpsk(connection, options)
141
+ key = connection.exec('wg genpsk', false, options).strip
142
+ if options['dry']
143
+ key = connection.exec('wg genpsk', false, { **options, 'dry' => false }).strip
144
+ end
145
+ key
94
146
  end
95
147
 
96
- def pubkeyOverSSH(privateKey, ssh)
97
- self.class.sshExec!(ssh, " echo '#{privateKey}' | wg pubkey")
148
+ def pubkey(privateKey, connection, options)
149
+ key = connection.exec(" echo '#{privateKey}' | wg pubkey", false, { **options, hide: true }).strip
150
+ if options['dry']
151
+ key = connection.exec(" echo '#{privateKey}' | wg pubkey", false, { **options, 'dry' => false, hide: true }).strip
152
+ end
153
+ key
98
154
  end
99
155
 
100
156
  def prepareConfig(target)
101
157
  target['Address'] = '172.20.0.1' unless target['Address']
102
- target['Peers'].each do |name, data|
103
- data['AllowedIPs'] = SUBNET unless data['AllowedIPs']
104
- end
105
158
  end
106
159
  end
107
160
  end
@@ -12,4 +12,7 @@ AllowedIPs = <%= peer['AllowedIPs'] %>
12
12
  <% if peer['Endpoint'] %>
13
13
  Endpoint = <%= peer['Endpoint'] %>:51820
14
14
  <% end %>
15
+ <% if peer['PersistentKeepalive'] %>
16
+ PersistentKeepalive = <%= peer['PersistentKeepalive'] %>
17
+ <% end %>
15
18
  <% end %>
@@ -31,9 +31,35 @@
31
31
  <dns t="map">
32
32
  <hostname><%= config['HostName'] %></hostname>
33
33
  <% if config['Domain'] %>
34
- <domain><%= config['Domain'] %></domain>
34
+ <domain><%= Addressable::IDNA.to_ascii(config['Domain']) %></domain>
35
+ <% end %>
36
+ <% if config['DefaultNetwork']['DNS'] %>
37
+ <nameservers config:type="list">
38
+ <nameserver><%= config['DefaultNetwork']['DNS'] %></nameserver>
39
+ </nameservers>
35
40
  <% end %>
36
41
  </dns>
42
+ <% if config['DefaultNetwork']['IP'] %>
43
+ <interfaces config:type="list">
44
+ <interface>
45
+ <bootproto><%= config['DefaultNetwork']['IP'] == 'dhcp' ? 'dhcp' : 'static' %></bootproto>
46
+ <name>eth0</name>
47
+ <% if config['DefaultNetwork']['IP'] != 'dhcp' %><ipaddr><%= config['DefaultNetwork']['IP'] %></ipaddr><% end %>
48
+ <startmode>auto</startmode>
49
+ </interface>
50
+ </interfaces>
51
+ <% end %>
52
+ <% if config['DefaultNetwork']['Gateway'] %>
53
+ <routing>
54
+ <routes config:type="list">
55
+ <route>
56
+ <destination>default</destination>
57
+ <device>eth0</device>
58
+ <gateway><%= config['DefaultNetwork']['Gateway'] %></gateway>
59
+ </route>
60
+ </routes>
61
+ </routing>
62
+ <% end %>
37
63
  </networking>
38
64
  <software t="map">
39
65
  <% if !config['Apps'].to_a.empty? %>
@@ -49,7 +75,7 @@
49
75
  <% if !config['Services'].to_a.empty? %>
50
76
  <enable t="list">
51
77
  <% config['Services'].each do |service| %>
52
- <service><%= service %></service>
78
+ <service><%= service.to_s %></service>
53
79
  <% end %>
54
80
  </enable>
55
81
  <% end %>
@@ -62,7 +88,7 @@
62
88
  <users config:type="list">
63
89
  <% config['Users'].each do |user, info| %>
64
90
  <user>
65
- <username>root</username>
91
+ <username><%= user %></username>
66
92
  <% if info['PasswordHash'] %>
67
93
  <encrypted config:type="boolean">true</encrypted>
68
94
  <user_password><%= info['PasswordHash'] %></user_password>
@@ -7,20 +7,22 @@ module ConfigLMM
7
7
  USER_SERVICE_DIR = '/etc/systemd/system/user@.service.d/'
8
8
 
9
9
  def actionSystemdDeploy(id, target, activeState, context, options)
10
- if target['Location'] && target['Location'] != '@me'
11
- if target['UserCgroups']
12
- uri = Addressable::URI.parse(target['Location'])
13
- raise Framework::PluginProcessError.new("#{id}: Unknown Protocol: #{uri.scheme}!") if uri.scheme != 'ssh'
14
- self.class.sshStart(uri) do |ssh|
15
- self.class.sshExec!(ssh, "mkdir -p #{USER_SERVICE_DIR}")
16
- ssh.scp.upload!(__dir__ + '/user-0.slice', SYSTEMD_CONFIG_PATH)
17
- ssh.scp.upload!(__dir__ + '/user@.service.d/delegate.conf', USER_SERVICE_DIR)
10
+ self.withConnection(target['Location'], target) do |connection|
11
+ Linux.withConnection(connection) do |linuxConnection|
12
+ if target['UserCgroups']
13
+ linuxConnection.createDirs(options, USER_SERVICE_DIR)
14
+ linuxConnection.upload(__dir__ + '/user-0.slice', SYSTEMD_CONFIG_PATH, options)
15
+ linuxConnection.upload(__dir__ + '/user@.service.d/delegate.conf', USER_SERVICE_DIR, options)
16
+ end
17
+ if target['InstallServices']
18
+ target['InstallServices'].each do |file, data|
19
+ linuxConnection.upload(file, SYSTEMD_CONFIG_PATH, options)
20
+ linuxConnection.reloadServiceManager(options)
21
+ linuxConnection.ensureServiceAutoStart(File.basename(file), options)
22
+ end
18
23
  end
19
24
  end
20
- else
21
- # TODO
22
25
  end
23
-
24
26
  end
25
27
 
26
28
  end
@@ -46,7 +46,7 @@ module ConfigLMM
46
46
  end
47
47
 
48
48
  creds = parseLocation(target['Location'])
49
- password = ENV['ARUBA_INSTANT_PASSWORD']
49
+ password = context.secrets.load(target['SecretId'], 'PASSWORD')
50
50
 
51
51
  # Couldn't get it working with net-ssh gem so using `ssh` as workaround
52
52
  # Net::SSH.start(creds[:hostname], creds[:user], password: password, port: creds[:port]) do |ssh|
@@ -128,14 +128,15 @@ module ConfigLMM
128
128
  end
129
129
 
130
130
  def authenticate(actionMethod, target, activeState, context, options)
131
- if ENV['ARUBA_INSTANT_PASSWORD'].to_s.empty? || ENV['ARUBA_INSTANT_PASSWORD'].to_s.empty?
132
- prompt.error('Set your Aruba Instant SSH password to ARUBA_INSTANT_PASSWORD as Environment Variable')
133
- raise Framework::PluginPrerequisite.new('Need ARUBA_INSTANT_PASSWORD')
131
+ authSecret = context.secrets.load(target['SecretId'], 'PASSWORD')
132
+ if authSecret.to_s.empty?
133
+ prompt.error("Set your Aruba Instant SSH password in #{target['SecretId']}_PASSWORD")
134
+ raise Framework::PluginPrerequisite.new('Need Aruba Instant password!')
134
135
  else
135
136
  if !target['Location']
136
137
  raise Framework::PluginProcessError.new('Location must be provided!')
137
138
  end
138
- checkSSHAuth!(target['Location'], ENV['ARUBA_INSTANT_PASSWORD'])
139
+ checkSSHAuth!(target['Location'], authSecret)
139
140
  end
140
141
  true
141
142
  end