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
@@ -4,6 +4,7 @@ require 'uri'
4
4
  require 'addressable/uri'
5
5
  require 'addressable/idna'
6
6
  require 'fog/powerdns'
7
+ require 'http'
7
8
 
8
9
  module ConfigLMM
9
10
  module LMM
@@ -48,11 +49,42 @@ module ConfigLMM
48
49
  def actionPowerDNSDeploy(id, target, activeState, context, options)
49
50
  #actionPowerDNSDiff(id, target, activeState, context, options)
50
51
 
51
- deploySettings(target, options)
52
- if target['DNS']
53
- connect(id, target, activeState, context, options) do |host, port, key|
52
+ deploySettings(target, activeState, context, options)
53
+ connect(id, target, activeState, context, options) do |host, port, key|
54
+ if target['TSIG']
55
+ updateTSIG(host, port, key, target, context)
56
+ end
57
+ if target['DNS']
54
58
  updateDNS(host, port, key, target['DNS'])
55
59
  end
60
+ if target['Metadata']
61
+ updateMetadata(host, port, key, target['Metadata'])
62
+ end
63
+ end
64
+ end
65
+
66
+ def cleanup(configs, state, context, options)
67
+ cleanupType(:PowerDNS, configs, state, context, options) do |item, id, state, context, options, connection|
68
+ if item['Config']['Deploy']
69
+ Linux.withConnection(connection) do |linuxConnection|
70
+ linuxConnection.stopService(SERVICE_NAME, options)
71
+ linuxConnection.firewallRemoveService('dns', options)
72
+ linuxConnection.removePackage(PACKAGE_NAME, options)
73
+
74
+ state.item(id)['Status'] = State::STATUS_DELETED unless options[:dry]
75
+
76
+ if options[:destroy]
77
+ item['Config']['Database'] ||= {}
78
+ PostgreSQL.withConnection(item['Config']['Database'], linuxConnection) do |connectionDB|
79
+ connectionDB.dropUserAndDB(USER, options)
80
+ end
81
+ linuxConnection.rm('/etc/pdns', options[:dry])
82
+ state.item(id)['Status'] = State::STATUS_DESTROYED unless options[:dry]
83
+ end
84
+ end
85
+ else
86
+ # TODO
87
+ end
56
88
  end
57
89
  end
58
90
 
@@ -99,7 +131,9 @@ module ConfigLMM
99
131
  canonicalDomain = domain + '.'
100
132
 
101
133
  if !dns.list_zones(server).map { |zone| zone['name'].downcase }.include?(canonicalDomain.downcase)
102
- dns.create_zone(server, canonicalDomain, [], { kind: 'Native' })
134
+ dns.create_zone(server, canonicalDomain, [], { kind: 'Native' }.update(info['!'].to_h))
135
+ elsif !info['!'].to_h.empty?
136
+ dns.update_zone(server, canonicalDomain, { kind: 'Native' }.update(info['!'].to_h))
103
137
  end
104
138
 
105
139
  zone = dns.get_zone(server, canonicalDomain)
@@ -107,9 +141,10 @@ module ConfigLMM
107
141
  rrsets = []
108
142
  remove = []
109
143
  info.each do |name, data|
144
+ next if name == '!'
110
145
  fullName = Addressable::IDNA.to_ascii(name) + '.' + Addressable::IDNA.to_ascii(domain) + '.'
111
146
  fullName = Addressable::IDNA.to_ascii(domain) + '.' if name == '@'
112
- self.processDNS(domain, data).each do |type, records|
147
+ self.processDNS(domain, data, context).each do |type, records|
113
148
  #remove += removeConflicting(zone, fullName, type)
114
149
  rrset = {
115
150
  name: fullName,
@@ -119,11 +154,20 @@ module ConfigLMM
119
154
  records: []
120
155
  }
121
156
  records.each do |record|
122
- record[:content] = Addressable::IDNA.to_ascii(record[:content]) + '.' if type == 'CNAME' || type == 'ALIAS'
157
+ record[:content] = Addressable::IDNA.to_ascii(record[:content]) + '.' if type == 'CNAME' || type == 'ALIAS' || type == 'NS'
123
158
  if type == 'MX'
124
159
  priority, name = record[:content].split(' ')
125
160
  name = Addressable::IDNA.to_ascii(name) + '.'
126
161
  record[:content] = [priority, name].join(' ')
162
+ elsif type == 'SOA'
163
+ ns, email, serial, refresh, again, expire, ttl = record[:content].split(' ')
164
+ record[:content] = [Addressable::IDNA.to_ascii(ns) + '.',
165
+ Addressable::IDNA.to_ascii(email) + '.',
166
+ serial.to_s,
167
+ refresh.to_s,
168
+ again.to_s,
169
+ expire.to_s,
170
+ ttl.to_s].join(' ')
127
171
  end
128
172
  rrset[:records] << { content: record[:content], disabled: false }
129
173
  end
@@ -139,6 +183,42 @@ module ConfigLMM
139
183
 
140
184
  end
141
185
 
186
+ def updateTSIG(host, port, key, target, context)
187
+ server = 'localhost'
188
+ url = "http://#{host}:#{port}/api/v1/servers/#{server}/tsigkeys"
189
+ headers = { 'X-Api-Key' => key }
190
+ target['TSIG'].each do |name, info|
191
+ data = { name: name, algorithm: info['Algorithm'] }
192
+ response = HTTP.headers(headers).post(url, json: data)
193
+ if response.status == 201
194
+ result = response.parse(:json)
195
+ key = result['key']
196
+ context.secrets.store(target['SecretId'], "TSIG_#{result['name'].upcase}_KEY", key)
197
+ context.secrets.print("TSIG #{result['name']} Key", key)
198
+ elsif response.status != 409
199
+ prompt.say(response.body.to_s, :color => :red)
200
+ raise 'Failed to create TSIG key!'
201
+ end
202
+ end
203
+ end
204
+
205
+ def updateMetadata(host, port, key, targetMetadata)
206
+ server = 'localhost'
207
+ headers = { 'X-Api-Key' => key }
208
+ targetMetadata.each do |zone, info|
209
+ info.each do |kind, metadata|
210
+ url = "http://#{host}:#{port}/api/v1/servers/#{server}/zones/#{Addressable::IDNA.to_ascii(zone)}/metadata/#{kind}"
211
+ metadata = [metadata] unless metadata.is_a?(Array)
212
+ data = { kind: kind, metadata: metadata }
213
+ response = HTTP.headers(headers).put(url, json: data)
214
+ if response.status != 200
215
+ prompt.say(response.body.to_s, :color => :red)
216
+ raise "Failed to update Metadata for #{zone}!"
217
+ end
218
+ end
219
+ end
220
+ end
221
+
142
222
  def prepareSettings(target)
143
223
  if !target['Settings'].key?('api')
144
224
  target['Settings']['api'] = 'yes'
@@ -154,62 +234,71 @@ module ConfigLMM
154
234
  end
155
235
  end
156
236
 
157
- def deploySettings(target, options)
158
- if target['Location']
159
- uri = Addressable::URI.parse(target['Location'])
160
- params = {}
161
- params = CGI.parse(uri.query) if uri.query
162
- if uri.scheme == 'ssh' && !params.key?('host')
163
- self.class.sshStart(uri) do |ssh|
164
- Framework::LinuxApp.ensurePackages([PACKAGE_NAME], ssh)
165
- Framework::LinuxApp.ensureServiceAutoStartOverSSH(SERVICE_NAME, ssh)
237
+ def deploySettings(target, activeState, context, options)
238
+ target['Deploy'] = !!target['Settings'] unless target.key?('Deploy')
239
+ if target['Deploy']
240
+ self.withConnection(target['Location'], target) do |connection|
241
+ Linux.withConnection(connection) do |linuxConnection|
242
+ linuxConnection.ensurePackages([PACKAGE_NAME], options)
243
+ linuxConnection.ensureServiceAutoStart(SERVICE_NAME, options)
166
244
  if target['Settings']
167
245
  prepareSettings(target)
168
- self.class.sshExec!(ssh, "mkdir -p #{CONFIG_DIR}")
169
- self.class.sshExec!(ssh, "sed -i 's|# include-dir=|include-dir=#{CONFIG_DIR}|' /etc/pdns/pdns.conf")
170
- ssh.scp.upload!(options['output'] + CONFIG_DIR + '/configlmm.conf', CONFIG_DIR + '/configlmm.conf')
246
+ linuxConnection.createDirs(options, CONFIG_DIR)
247
+ linuxConnection.fileReplace('/etc/pdns/pdns.conf', '# include-dir=', "include-dir=#{CONFIG_DIR}", options)
248
+ linuxConnection.upload(options['output'] + CONFIG_DIR + '/configlmm.conf', CONFIG_DIR + '/configlmm.conf', options)
171
249
  apiKeyFile = CONFIG_DIR + '/apiKey.conf'
172
- if !self.class.remoteFilePresent?(apiKeyFile, ssh)
173
- apiKey = ENV['POWERDNS_API_KEY']
174
- apiKey = SecureRandom.urlsafe_base64(60) unless apiKey
175
- self.class.sshExec!(ssh, " echo 'api-key=#{apiKey}' > #{apiKeyFile}")
176
- self.class.sshExec!(ssh, " chown #{USER}:#{USER} #{apiKeyFile}")
177
- self.class.sshExec!(ssh, " chmod 400 #{apiKeyFile}")
178
- prompt.say("PowerDNS API Key: #{apiKey}", )
250
+ apiKey = context.secrets.load(target['SecretId'], 'POWERDNS_API_KEY')
251
+ if linuxConnection.filePresent?(apiKeyFile, options)
252
+ if !apiKey
253
+ if options['dry']
254
+ linuxConnection.exec("cat #{apiKeyFile} | grep api-key | cut -d '=' -f 2", false, options)
255
+ end
256
+ apiKey = linuxConnection.exec("cat #{apiKeyFile} | grep api-key | cut -d '=' -f 2", false, { **options, 'dry' => false }).strip
257
+ context.secrets.store(target['SecretId'], 'POWERDNS_API_KEY', apiKey)
258
+ end
259
+ else
260
+ if !apiKey
261
+ apiKey = SecureRandom.urlsafe_base64(60)
262
+ context.secrets.store(target['SecretId'], 'POWERDNS_API_KEY', apiKey)
263
+ context.secrets.print('PowerDNS API Key', apiKey)
264
+ end
265
+ linuxConnection.fileWrite(apiKeyFile, "api-key=#{apiKey}", options)
266
+ linuxConnection.setUserGroup(apiKeyFile, USER, USER, options)
267
+ linuxConnection.setPrivate(apiKeyFile, options)
268
+ end
269
+ if !target.key?('Database') || target['Database']
270
+ self.configurePostgreSQL(target['Settings'], linuxConnection, options)
179
271
  end
180
- self.configurePostgreSQL(target['Settings'], ssh)
181
272
  end
182
- Framework::LinuxApp.startServiceOverSSH(SERVICE_NAME, ssh)
273
+ linuxConnection.firewallAddService('dns', options)
274
+ linuxConnection.restartService(SERVICE_NAME, options)
183
275
  end
184
276
  end
185
277
  end
186
278
  end
187
279
 
188
- def configurePostgreSQL(settings, ssh)
189
- password = SecureRandom.alphanumeric(20)
190
- if settings['gpgsql-host'] == 'localhost' || settings['gpgsql-host'].start_with?('/')
191
- PostgreSQL.createUserAndDBOverSSH(USER, password, ssh)
192
- PostgreSQL.importSQL(USER, USER, '/usr/share/doc/packages/pdns/schema.pgsql.sql', ssh)
193
- else
194
- self.class.sshStart("ssh://#{settings['gpgsql-host']}/") do |ssh|
195
- PostgreSQL.createUserAndDBOverSSH(USER, password, ssh)
196
- PostgreSQL.importSQL(USER, USER, '/usr/share/doc/packages/pdns/schema.pgsql.sql', ssh)
197
- end
280
+ def configurePostgreSQL(settings, linuxConnection, options)
281
+ dbSettings = {}
282
+ dbSettings['HostName'] = settings['gpgsql-host']
283
+ dbSettings['HostName'] = 'localhost' if dbSettings['HostName'].start_with?('/')
284
+ PostgreSQL.withConnection(dbSettings, linuxConnection) do |postgresConnection|
285
+ password = SecureRandom.alphanumeric(20)
286
+ postgresConnection.createUserAndDB(USER, password, options)
287
+ postgresConnection.importSQL(USER, USER, '/usr/share/doc/packages/pdns/schema.pgsql.sql', options)
288
+ postgresConnection.updateOwner(USER, USER, options)
198
289
  end
199
- password
200
290
  end
201
291
 
202
292
  def connect(id, target, activeState, context, options)
203
293
  host = DEFAULT_HOST
204
294
  port = DEFAULT_PORT
205
- key = ENV['POWERDNS_API_KEY']
206
- key = target['Key'] if target['Key']
295
+ key = context.secrets.load(target['SecretId'], 'POWERDNS_API_KEY')
207
296
  raise Framework::PluginProcessError.new('PowerDNS missing API key!') unless key
208
297
 
209
298
  sshServer = nil
210
299
  sshUser = nil
211
300
  sshPort = nil
212
- sshPassword = ENV['POWERDNS_SSH_PASSWORD']
301
+ sshPassword = context.secrets.load(target['SecretId'], 'POWERDNS_SSH_PASSWORD')
213
302
 
214
303
  if target['Location']
215
304
  uri = Addressable::URI.parse(target['Location'])
@@ -21,17 +21,26 @@ module ConfigLMM
21
21
  errors
22
22
  end
23
23
 
24
+ def getPassword(target, context)
25
+ tonicPassword = context.secrets.load(target['SecretId'], 'PASSWORD')
26
+ tonicPassword = context.secrets.load('TONIC', 'PASSWORD') if tonicPassword.nil?
27
+ raise Framework::PluginProcessError.new('Missing Tonic DNS password!') unless tonicPassword
28
+ tonicPassword
29
+ end
30
+
24
31
  def actionTonicDNSRefresh(id, target, activeState, context, options)
25
32
  domain = target['Domain'].split('.').first
26
33
  if domain.empty?
27
34
  raise Framework::PluginProcessError.new('Invalid Domain for ' + id)
28
35
  end
29
- activeState['Domain'] = target['Domain']
36
+
37
+ tonicPassword = getPassword(target, context)
38
+
30
39
  response = HTTP.post(EDIT_URL, :form => {
31
40
  command: 'editdns',
32
41
  error: 'badpass.htm',
33
42
  sld: domain,
34
- password: ENV['TONIC_PASSWORD'],
43
+ password: tonicPassword,
35
44
  'B1.x' => "40",
36
45
  'B1.y' => "20"
37
46
  })
@@ -50,15 +59,15 @@ module ConfigLMM
50
59
  raise Framework::PluginProcessError.new('Unexpected value in response for ' + id)
51
60
  end
52
61
  else
53
- raise Framework::PluginProcessError.new("Couldn't refresh " + id + "! Invalid TONIC_PASSWORD ?")
62
+ raise Framework::PluginProcessError.new("Couldn't refresh " + id + "! Invalid Tonic password?")
54
63
  end
55
64
  end
56
65
 
57
66
  def actionTonicDNSDiff(id, target, activeState, context, options)
58
- shouldMatch(id, 'Domain', 'Domain', target, activeState)
67
+ shouldMatch(id, activeState['Config'], 'Domain', target, 'Domain')
59
68
  nameservers = activeState['Nameservers']&.transform_keys { |ns| Addressable::IDNA.to_unicode(ns) }
60
69
  if target['Nameservers'] != nameservers
61
- @Diff.update({'Nameservers' => [target['Nameservers'], nameservers]})
70
+ @Diff.update({'Nameservers' => [nameservers, target['Nameservers']]})
62
71
  end
63
72
  end
64
73
 
@@ -73,11 +82,13 @@ module ConfigLMM
73
82
  hosts = target['Nameservers'].keys.map { |ns| Addressable::IDNA.to_ascii(ns) }
74
83
  addrs = target['Nameservers'].values
75
84
 
85
+ tonicPassword = getPassword(target, context)
86
+
76
87
  response = HTTP.post(EDIT_URL, :form => {
77
88
  command: 'editdns',
78
89
  error: 'badpass.htm',
79
90
  sld: domain,
80
- password: ENV['TONIC_PASSWORD'],
91
+ password: tonicPassword,
81
92
  'B1.x' => "40",
82
93
  'B1.y' => "20"
83
94
  })
@@ -105,18 +116,17 @@ module ConfigLMM
105
116
  'B1.y': 30
106
117
  })
107
118
 
108
- activeState['Domain'] = target['Domain']
109
- activeState['Nameservers'] = target['Nameservers']
110
-
111
119
  prompt.say(Nokogiri::HTML(response.to_s).at('//title/text()'))
120
+ activeState['Nameservers'] = target['Nameservers']
112
121
  end
113
122
  end
114
123
 
115
124
  def authenticate(actionMethod, target, activeState, context, options)
116
- authSecret = ENV['TONIC_PASSWORD']
125
+ authSecret = context.secrets.load(target['SecretId'], 'PASSWORD')
126
+ authSecret = context.secrets.load('TONIC', 'PASSWORD') if authSecret.nil?
117
127
  if authSecret.to_s.empty?
118
- prompt.say('Set your Tonic DNS password to TONIC_PASSWORD as Environment Variable')
119
- raise Framework::PluginPrerequisite.new('Need TONIC_PASSWORD')
128
+ prompt.say("Set your Tonic DNS password in #{target['SecretId']}_PASSWORD")
129
+ raise Framework::PluginPrerequisite.new('Need Tonic DNS password!')
120
130
  end
121
131
  true
122
132
  end
data/bootstrap.sh CHANGED
@@ -10,6 +10,29 @@ function admin {
10
10
  fi
11
11
  }
12
12
 
13
+ if [ "$EUID" -ne "0" ]; then
14
+ if ! command -v sudo &> /dev/null; then
15
+ case $distro in
16
+
17
+ opensuse-leap)
18
+ echo "You don't have sudo! Enter root password to install it"
19
+ su root -c "zypper install --no-confirm sudo"
20
+ ;;
21
+
22
+ arch)
23
+ echo "You don't have sudo! Enter root password to install it"
24
+ admin pacman -S --noconfirm --needed sudo
25
+ ;;
26
+
27
+ *)
28
+ echo "Sudo not found but is needed!" >&2
29
+ echo "Don't know how to install it for your $distro distribution!" >&2
30
+ echo "Submit a PR :)" >&2
31
+ exit 3
32
+ ;;
33
+ esac
34
+ fi
35
+ fi
13
36
 
14
37
  case $distro in
15
38
 
@@ -43,12 +66,27 @@ if [ "$rubyTooOld" -eq "1" ]; then
43
66
  echo "Ruby is too old! Will install RVM" >&2
44
67
  gpg2 --keyserver hkp://keyserver.ubuntu.com --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB >/dev/null
45
68
  curl -sSL https://get.rvm.io | bash -s stable --ruby=3.3.4
46
- source /etc/profile.d/rvm.sh
69
+
70
+ if [ "$EUID" -eq "0" ]; then
71
+ source /etc/profile.d/rvm.sh
72
+ else
73
+ source ~/.rvm/scripts/rvm
74
+ fi
47
75
 
48
76
  if [ "$SHELL" = "/usr/bin/fish" ]; then
49
- curl -L --create-dirs -o ~/.config/fish/functions/rvm.fish https://raw.github.com/lunks/fish-nuggets/master/functions/rvm.fish
77
+ curl -sSL --create-dirs -o ~/.config/fish/functions/rvm.fish https://raw.github.com/lunks/fish-nuggets/master/functions/rvm.fish
78
+ sed -i "/rvm default/d" ~/.config/fish/config.fish
50
79
  echo "rvm default" >> ~/.config/fish/config.fish
51
80
  fi
52
81
  fi
53
82
 
54
- gem install ConfigLMM
83
+ if [ "$EUID" -eq "0" ]; then
84
+ # This shouldn't be needed but without it doesn't work
85
+ export PATH=/usr/local/rvm/gems/ruby-3.3.4/bin:/usr/local/rvm/rubies/ruby-3.3.4/bin:$PATH
86
+ export GEM_HOME=/usr/local/rvm/gems/ruby-3.3.4
87
+ export GEM_PATH=/usr/local/rvm/gems/ruby-3.3.4
88
+ fi
89
+
90
+ bash -lc 'gem install ConfigLMM'
91
+
92
+ echo "You need to close and reopen your shell" >&2
@@ -8,7 +8,7 @@ module ConfigLMM
8
8
  class DNS < Framework::Plugin
9
9
  DEFAULT_TTL = 600
10
10
 
11
- def processDNS(domain, items)
11
+ def processDNS(domain, items, context)
12
12
  records = {}
13
13
 
14
14
  if items.is_a?(Hash)
@@ -25,6 +25,7 @@ module ConfigLMM
25
25
  type, content = item.strip.split('=')
26
26
  content = domain if content == '@'
27
27
  content = self.class.externalIp if content == '@me'
28
+ content = Variables.stringEval(content, context)
28
29
  records[type] ||= []
29
30
  records[type] << { type: type, content: content, ttl: DEFAULT_TTL }
30
31
  end
@@ -32,13 +33,13 @@ module ConfigLMM
32
33
  records
33
34
  end
34
35
 
35
- def showManualDNSSteps(target, message)
36
+ def showManualDNSSteps(target, message, context)
36
37
  if !target['DNS'].to_h.empty?
37
38
  target['DNS'].each do |domain, data|
38
39
  yield(domain)
39
40
  prompt.say(message, :color => :magenta) if message
40
41
  data.each do |name, data|
41
- self.processDNS(domain, data).each do |type, records|
42
+ self.processDNS(domain, data, context).each do |type, records|
42
43
  records.each do |record|
43
44
  prompt.say(" * Type: #{record[:type]}\n Name: #{name}\n Content: #{record[:content]}", :color => :bold)
44
45
  end