ConfigLMM 0.1.0 → 0.3.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 (70) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +63 -1
  3. data/Examples/Implemented.mm.yaml +120 -0
  4. data/Examples/Keys.ini +2 -0
  5. data/Examples/Linux.mm.yaml +14 -3
  6. data/Images/configINconfig.png +0 -0
  7. data/Images/singleConfig.png +0 -0
  8. data/Plugins/Apps/Authentik/Authentik-Server.container +18 -0
  9. data/Plugins/Apps/Authentik/Authentik-Worker.container +17 -0
  10. data/Plugins/Apps/Authentik/Authentik.conf.erb +35 -0
  11. data/Plugins/Apps/Authentik/Authentik.lmm.rb +73 -0
  12. data/Plugins/Apps/Cassandra/Cassandra.lmm.rb +41 -0
  13. data/Plugins/Apps/Dovecot/Dovecot.lmm.rb +165 -0
  14. data/Plugins/Apps/GitLab/GitLab.conf.erb +26 -0
  15. data/Plugins/Apps/GitLab/GitLab.container +17 -0
  16. data/Plugins/Apps/GitLab/GitLab.lmm.rb +75 -0
  17. data/Plugins/Apps/Nextcloud/Nextcloud.conf.erb +48 -10
  18. data/Plugins/Apps/Nextcloud/Nextcloud.lmm.rb +59 -2
  19. data/Plugins/Apps/Nextcloud/config.php +18 -0
  20. data/Plugins/Apps/Nginx/conf.d/configlmm.conf +62 -0
  21. data/Plugins/Apps/Nginx/config-lmm/errors.conf +2 -2
  22. data/Plugins/Apps/Nginx/config-lmm/security.conf +4 -0
  23. data/Plugins/Apps/Nginx/main.conf.erb +31 -0
  24. data/Plugins/Apps/Nginx/nginx.conf +3 -68
  25. data/Plugins/Apps/Nginx/nginx.lmm.rb +71 -14
  26. data/Plugins/Apps/Odoo/Odoo.conf.erb +30 -13
  27. data/Plugins/Apps/Odoo/Odoo.container +17 -0
  28. data/Plugins/Apps/Odoo/Odoo.lmm.rb +62 -2
  29. data/Plugins/Apps/Odoo/odoo.conf +37 -0
  30. data/Plugins/Apps/PHP-FPM/PHP-FPM.lmm.rb +95 -0
  31. data/Plugins/Apps/Peppermint/Peppermint.conf.erb +64 -0
  32. data/Plugins/Apps/Peppermint/Peppermint.container +14 -0
  33. data/Plugins/Apps/Peppermint/Peppermint.lmm.rb +58 -0
  34. data/Plugins/Apps/Postfix/Postfix.lmm.rb +184 -0
  35. data/Plugins/Apps/Postfix/smtpd.conf +3 -0
  36. data/Plugins/Apps/PostgreSQL/PostgreSQL.lmm.rb +225 -0
  37. data/Plugins/Apps/SSH/SSH.lmm.rb +51 -0
  38. data/Plugins/Apps/UVdesk/UVdesk.conf.erb +52 -0
  39. data/Plugins/Apps/UVdesk/UVdesk.lmm.rb +85 -0
  40. data/Plugins/Apps/Valkey/Valkey.lmm.rb +56 -0
  41. data/Plugins/Apps/Vaultwarden/Vaultwarden.conf.erb +35 -18
  42. data/Plugins/Apps/Vaultwarden/Vaultwarden.container +16 -0
  43. data/Plugins/Apps/Vaultwarden/Vaultwarden.lmm.rb +42 -3
  44. data/Plugins/Apps/gollum/gollum.conf.erb +45 -18
  45. data/Plugins/Apps/gollum/gollum.container +12 -0
  46. data/Plugins/Apps/gollum/gollum.lmm.rb +39 -10
  47. data/Plugins/OS/Linux/Distributions.yaml +16 -0
  48. data/Plugins/OS/Linux/Linux.lmm.rb +389 -0
  49. data/Plugins/OS/Linux/Packages.yaml +51 -0
  50. data/Plugins/OS/Linux/WireGuard/WireGuard.lmm.rb +108 -0
  51. data/Plugins/OS/Linux/WireGuard/wg0.conf.erb +15 -0
  52. data/Plugins/OS/Linux/openSUSE/autoinst.xml.erb +87 -0
  53. data/Plugins/OS/Linux/systemd/systemd.lmm.rb +28 -0
  54. data/Plugins/OS/Linux/systemd/user-0.slice +9 -0
  55. data/Plugins/OS/Linux/systemd/user@.service.d/delegate.conf +3 -0
  56. data/Plugins/Platforms/GoDaddy/GoDaddy.lmm.rb +6 -1
  57. data/Plugins/Platforms/libvirt/libvirt.lmm.rb +103 -0
  58. data/Plugins/Services/DNS/PowerDNS.lmm.rb +69 -6
  59. data/README.md +10 -0
  60. data/bootstrap.sh +54 -0
  61. data/lib/ConfigLMM/Framework/plugins/dns.rb +1 -2
  62. data/lib/ConfigLMM/Framework/plugins/linuxApp.rb +237 -0
  63. data/lib/ConfigLMM/Framework/plugins/nginxApp.rb +24 -6
  64. data/lib/ConfigLMM/Framework/plugins/plugin.rb +150 -0
  65. data/lib/ConfigLMM/Framework/plugins.rb +1 -0
  66. data/lib/ConfigLMM/commands/configsCommand.rb +3 -0
  67. data/lib/ConfigLMM/version.rb +1 -1
  68. metadata +87 -5
  69. data/Plugins/Apps/Nginx/main.conf +0 -30
  70. data/Plugins/OS/Linux.lmm.rb +0 -64
@@ -0,0 +1,108 @@
1
+
2
+ module ConfigLMM
3
+ module LMM
4
+ class WireGuard < Framework::LinuxApp
5
+
6
+ WIREGUARD_PACKAGE = 'WireGuard'
7
+ SERVICE_NAME = 'wg-quick@wg0'
8
+ CONFIG_FILE = '/etc/wireguard/wg0.conf'
9
+ PORT = '51820'
10
+ SUBNET = '172.20.0.0/20'
11
+
12
+ persistBuildDir
13
+
14
+ def actionWireGuardDeploy(id, target, activeState, context, options)
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")
23
+
24
+ self.class.ensurePackages([WIREGUARD_PACKAGE], ssh)
25
+ self.class.ensureServiceAutoStartOverSSH(SERVICE_NAME, ssh)
26
+
27
+ dir = options['output'] + '/' + id + '/etc/wireguard/'
28
+ mkdir(dir, false)
29
+ template = ERB.new(File.read(__dir__ + '/wg0.conf.erb'))
30
+
31
+ if self.class.remoteFilePresent?(CONFIG_FILE, ssh)
32
+ # TODO Implement adding and removing peers
33
+ 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")
42
+ 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)
51
+ end
52
+ end
53
+ end
54
+
55
+ target['Peers'].each do |name, data|
56
+ templateData = {}
57
+ templateData['Address'] = target['Address']
58
+ templateData['PrivateKey'] = data['PrivateKey']
59
+ templateData['Peers'] = {}
60
+ templateData['Peers'][id] = { 'PublicKey' => publicKey, 'PresharedKey' => data['PresharedKey'] }
61
+ target['Peers'].each do |otherName, otherData|
62
+ next if name == otherName
63
+ pskIdB = 'PresharedKey_' + otherName + '_' + name
64
+ if otherData.key?(pskIdB)
65
+ psk = otherData[pskIdB]
66
+ else
67
+ pskIdA = 'PresharedKey_' + name + '_' + otherName
68
+ data[pskIdA] = genpskOverSSH(ssh)
69
+ psk = data[pskIdA]
70
+ end
71
+ templateData['Peers'][otherName] = { 'PublicKey' => otherData['PublicKey'], 'PresharedKey' => psk }
72
+ end
73
+
74
+ renderTemplate(template, templateData, dir + name + '.conf', options)
75
+ end
76
+
77
+ renderTemplate(template, target, dir + 'wg0.conf', options)
78
+ ssh.scp.upload!(dir + 'wg0.conf', CONFIG_FILE)
79
+ end
80
+
81
+ end
82
+ else
83
+ # TODO
84
+ end
85
+ self.startService(SERVICE_NAME, target['Location'])
86
+ end
87
+
88
+ def genkeyOverSSH(ssh)
89
+ self.class.sshExec!(ssh, 'wg genkey')
90
+ end
91
+
92
+ def genpskOverSSH(ssh)
93
+ self.class.sshExec!(ssh, 'wg genpsk')
94
+ end
95
+
96
+ def pubkeyOverSSH(privateKey, ssh)
97
+ self.class.sshExec!(ssh, " echo '#{privateKey}' | wg pubkey")
98
+ end
99
+
100
+ def prepareConfig(target)
101
+ 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
+ end
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,15 @@
1
+ [Interface]
2
+ Address = <%= config['Address'] %>
3
+ ListenPort = 51820
4
+ PrivateKey = <%= config['PrivateKey'] %>
5
+
6
+ <% config['Peers'].to_h.each do |name, peer| %>
7
+ # <%= name %>
8
+ [Peer]
9
+ PublicKey = <%= peer['PublicKey'] %>
10
+ PresharedKey = <%= peer['PresharedKey'] %>
11
+ AllowedIPs = <%= peer['AllowedIPs'] %>
12
+ <% if peer['Endpoint'] %>
13
+ Endpoint = <%= peer['Endpoint'] %>:51820
14
+ <% end %>
15
+ <% end %>
@@ -0,0 +1,87 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE profile>
3
+ <profile xmlns="http://www.suse.com/1.0/yast2ns" xmlns:config="http://www.suse.com/1.0/configns">
4
+ <general config:type="map">
5
+ <mode config:type="map">
6
+ <confirm config:type="boolean">false</confirm>
7
+ </mode>
8
+ </general>
9
+ <bootloader t="map">
10
+ <global t="map">
11
+ <append>splash=silent preempt=full mitigations=auto quiet security=apparmor console=ttyS0,115200</append>
12
+ </global>
13
+ </bootloader>
14
+ <host t="map">
15
+ <% if !config['Hosts'].to_a.empty? %>
16
+ <hosts t="list">
17
+ <% config['Hosts'].each do |address, names| %>
18
+ <hosts_entry t="map">
19
+ <host_address><%= address %></host_address>
20
+ <names t="list">
21
+ <% names.each do |name| %>
22
+ <name><%= name %></name>
23
+ <% end %>
24
+ </names>
25
+ </hosts_entry>
26
+ <% end %>
27
+ </hosts>
28
+ <% end %>
29
+ </host>
30
+ <networking t="map">
31
+ <dns t="map">
32
+ <hostname><%= config['HostName'] %></hostname>
33
+ <% if config['Domain'] %>
34
+ <domain><%= config['Domain'] %></domain>
35
+ <% end %>
36
+ </dns>
37
+ </networking>
38
+ <software t="map">
39
+ <% if !config['Apps'].to_a.empty? %>
40
+ <packages t="list">
41
+ <% config['Apps'].each do |app| %>
42
+ <package><%= app.downcase %></package>
43
+ <% end %>
44
+ </packages>
45
+ <% end %>
46
+ </software>
47
+ <services-manager t="map">
48
+ <services t="map">
49
+ <% if !config['Services'].to_a.empty? %>
50
+ <enable t="list">
51
+ <% config['Services'].each do |service| %>
52
+ <service><%= service %></service>
53
+ <% end %>
54
+ </enable>
55
+ <% end %>
56
+ </services>
57
+ </services-manager>
58
+ <timezone t="map">
59
+ <timezone>Etc/UTC</timezone>
60
+ </timezone>
61
+ <% if !config['Users'].to_h.empty? %>
62
+ <users config:type="list">
63
+ <% config['Users'].each do |user, info| %>
64
+ <user>
65
+ <username>root</username>
66
+ <% if info['PasswordHash'] %>
67
+ <encrypted config:type="boolean">true</encrypted>
68
+ <user_password><%= info['PasswordHash'] %></user_password>
69
+ <% elsif info['Password'] %>
70
+ <encrypted config:type="boolean">false</encrypted>
71
+ <user_password><%= info['Password'] %></user_password>
72
+ <% end %>
73
+ <% if info['Shell'] %>
74
+ <shell>/usr/bin/<%= info['Shell'] %></shell>
75
+ <% end %>
76
+ <% if !info['AuthorizedKeys'].to_a.empty? %>
77
+ <authorized_keys config:type="list">
78
+ <% info['AuthorizedKeys'].each do |entry| %>
79
+ <listentry><%= entry %></listentry>
80
+ <% end %>
81
+ </authorized_keys>
82
+ <% end %>
83
+ </user>
84
+ <% end %>
85
+ </users>
86
+ <% end %>
87
+ </profile>
@@ -0,0 +1,28 @@
1
+
2
+ module ConfigLMM
3
+ module LMM
4
+ class Systemd < Framework::LinuxApp
5
+
6
+ SYSTEMD_CONFIG_PATH = '/etc/systemd/system/'
7
+ USER_SERVICE_DIR = '/etc/systemd/system/user@.service.d/'
8
+
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)
18
+ end
19
+ end
20
+ else
21
+ # TODO
22
+ end
23
+
24
+ end
25
+
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,9 @@
1
+
2
+ [Unit]
3
+ Before=systemd-logind.service
4
+
5
+ [Slice]
6
+ Slice=user.slice
7
+
8
+ [Install]
9
+ WantedBy=multi-user.target
@@ -0,0 +1,3 @@
1
+
2
+ [Service]
3
+ Delegate=memory pids
@@ -26,7 +26,12 @@ module ConfigLMM
26
26
  data.each do |name, data|
27
27
  self.processDNS(domain, data).each do |type, records|
28
28
  records.each do |record|
29
- shortName = name
29
+ shortName = Addressable::IDNA.to_ascii(name) + '.' if type == 'CNAME' || type == 'ALIAS'
30
+ if record[:type] == 'MX'
31
+ priority, name = record[:content].split(' ')
32
+ name = Addressable::IDNA.to_ascii(name) + '.'
33
+ record[:content] = [priority, name].join(' ')
34
+ end
30
35
  config['Records'] += [shortName, record[:ttl], ' IN ', record[:type], record[:content]].join("\t") + "\n"
31
36
  end
32
37
  end
@@ -0,0 +1,103 @@
1
+
2
+ require 'fog/libvirt'
3
+ require 'filesize'
4
+
5
+ module ConfigLMM
6
+ module LMM
7
+ class Libvirt < Framework::Plugin
8
+
9
+ DEFAULT_IMAGE_PATH = '~/.local/share/libvirt/images/'
10
+ DEFAULT_VRAM = 16 * 1024 # 16 MiB
11
+
12
+ def actionLibvirtDeploy(id, target, activeState, context, options)
13
+ if !target['Location']
14
+ target['Location'] = 'qemu:///session'
15
+ end
16
+ compute = Fog::Compute.new(provider: :libvirt, libvirt_uri: target['Location'])
17
+ createPools(target, compute, self.class.isLocal?(target['Location']))
18
+ end
19
+
20
+ def createPools(target, compute, isLocal)
21
+ if target['Pools']
22
+ allPools = compute.pools.all
23
+ target['Pools'].each do |name, location|
24
+ next if allPools.find { |pool| pool.name == name }
25
+ location = DEFAULT_IMAGE_PATH unless location
26
+ location = File.expand_path(location) if isLocal
27
+ xml = dirPoolXML(name, location)
28
+ pool = compute.pools.create(persistent: true, autostart: true, xml: xml)
29
+ pool.build
30
+ pool.start
31
+ end
32
+ end
33
+ end
34
+
35
+ def createVM(serverName, serverInfo, targetUri, iso, activeState)
36
+ compute = Fog::Compute.new(provider: :libvirt, libvirt_uri: targetUri)
37
+ server = compute.servers.all.find { |server| server.name == serverName }
38
+ if server
39
+ server.start
40
+ return
41
+ end
42
+ settings = {
43
+ name: serverName,
44
+ cpu: {
45
+ mode: 'host-passthrough'
46
+ },
47
+ video: { type: 'qxl', vram: DEFAULT_VRAM }
48
+ }
49
+ if serverInfo['CPU']
50
+ settings[:cpus] = serverInfo['CPU']
51
+ end
52
+ if serverInfo['RAM']
53
+ settings[:memory_size] = Filesize.from(serverInfo['RAM']).to_f('KiB').to_i
54
+ end
55
+ volumeName = serverName + '.img'
56
+ volume = compute.volumes.all.find { |volume| volume.name == volumeName }
57
+ if volume
58
+ settings[:volumes] = [volume]
59
+ elsif serverInfo['Storage']
60
+ storage = Filesize.from(serverInfo['Storage']).to_f('GiB').to_i
61
+ volume = compute.volumes.create(
62
+ name: volumeName,
63
+ pool_name: compute.pools.first.name,
64
+ capacity: storage
65
+ )
66
+ settings[:volumes] = [volume]
67
+ end
68
+ if serverInfo['NetworkBridge']
69
+ nic = {
70
+ bridge: serverInfo['NetworkBridge'],
71
+ }
72
+ settings[:nics] = [nic]
73
+ end
74
+ server = compute.servers.new(**settings)
75
+ if iso
76
+ server.iso_dir = File.dirname(iso)
77
+ server.iso_file = File.basename(iso)
78
+ end
79
+ server.save
80
+ activeState['Status'] = 'CREATED'
81
+ state.save
82
+ server.start
83
+ end
84
+
85
+ def dirPoolXML(name, path)
86
+ xml = '<pool type="dir">'
87
+ xml += " <name>#{name.encode(:xml => :text)}</name>"
88
+ xml += "<target><path>#{path.encode(:xml => :text)}</path></target>"
89
+ xml += '</pool>'
90
+ xml
91
+ end
92
+
93
+ def self.isLocal?(location)
94
+ self.getLocation(location).empty?
95
+ end
96
+
97
+ def self.getLocation(location)
98
+ uri = Addressable::URI.parse(location)
99
+ uri.hostname
100
+ end
101
+ end
102
+ end
103
+ end
@@ -13,6 +13,9 @@ module ConfigLMM
13
13
  DEFAULT_HOST = 'localhost'
14
14
  DEFAULT_PORT = 8081
15
15
  SSH_TIMEOUT = 10
16
+ PACKAGE_NAME = 'PowerDNS'
17
+ SERVICE_NAME = 'pdns'
18
+ USER = 'pdns'
16
19
 
17
20
  # TODO
18
21
  # def actionPowerDNSValidate(id, target, activeState, context, options)
@@ -21,6 +24,7 @@ module ConfigLMM
21
24
 
22
25
  def actionPowerDNSBuild(id, target, activeState, context, options)
23
26
  if target['Settings']
27
+ prepareSettings(target)
24
28
  targetDir = options['output'] + CONFIG_DIR + '/'
25
29
  mkdir(targetDir, options['dry'])
26
30
  content = ''
@@ -44,7 +48,7 @@ module ConfigLMM
44
48
  def actionPowerDNSDeploy(id, target, activeState, context, options)
45
49
  #actionPowerDNSDiff(id, target, activeState, context, options)
46
50
 
47
- deploySettings(target)
51
+ deploySettings(target, options)
48
52
  if target['DNS']
49
53
  connect(id, target, activeState, context, options) do |host, port, key|
50
54
  updateDNS(host, port, key, target['DNS'])
@@ -103,8 +107,8 @@ module ConfigLMM
103
107
  rrsets = []
104
108
  remove = []
105
109
  info.each do |name, data|
106
- fullName = name + '.' + domain + '.'
107
- fullName = domain + '.' if name == '@'
110
+ fullName = Addressable::IDNA.to_ascii(name) + '.' + Addressable::IDNA.to_ascii(domain) + '.'
111
+ fullName = Addressable::IDNA.to_ascii(domain) + '.' if name == '@'
108
112
  self.processDNS(domain, data).each do |type, records|
109
113
  #remove += removeConflicting(zone, fullName, type)
110
114
  rrset = {
@@ -115,6 +119,12 @@ module ConfigLMM
115
119
  records: []
116
120
  }
117
121
  records.each do |record|
122
+ record[:content] = Addressable::IDNA.to_ascii(record[:content]) + '.' if type == 'CNAME' || type == 'ALIAS'
123
+ if type == 'MX'
124
+ priority, name = record[:content].split(' ')
125
+ name = Addressable::IDNA.to_ascii(name) + '.'
126
+ record[:content] = [priority, name].join(' ')
127
+ end
118
128
  rrset[:records] << { content: record[:content], disabled: false }
119
129
  end
120
130
  rrsets << rrset
@@ -129,12 +139,65 @@ module ConfigLMM
129
139
 
130
140
  end
131
141
 
132
- def deploySettings(target)
133
- if target['Settings']
134
- # TODO
142
+ def prepareSettings(target)
143
+ if !target['Settings'].key?('api')
144
+ target['Settings']['api'] = 'yes'
145
+ end
146
+ if !target['Settings'].key?('expand-alias')
147
+ target['Settings']['expand-alias'] = 'yes'
148
+ end
149
+ if !target['Settings'].key?('launch')
150
+ target['Settings']['launch'] = 'gpgsql'
151
+ target['Settings']['gpgsql-host'] = '/run/postgresql'
152
+ target['Settings']['gpgsql-user'] = USER
153
+ target['Settings']['gpgsql-dbname'] = USER
154
+ end
155
+ end
156
+
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)
166
+ if target['Settings']
167
+ 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')
171
+ 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}", )
179
+ end
180
+ self.configurePostgreSQL(target['Settings'], ssh)
181
+ end
182
+ Framework::LinuxApp.startServiceOverSSH(SERVICE_NAME, ssh)
183
+ end
184
+ end
135
185
  end
136
186
  end
137
187
 
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
198
+ end
199
+ password
200
+ end
138
201
 
139
202
  def connect(id, target, activeState, context, options)
140
203
  host = DEFAULT_HOST
data/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # ConfigLMM - Large Configuration Management Manager
2
2
 
3
+ ![Yo Dawg I Heard you like config so I put a config in your Config](/Images/configINconfig.png)
4
+
3
5
  ## Manage The Management with ease!
4
6
 
5
7
  You define how you want your applications/systems/containers/services/servers
@@ -57,6 +59,8 @@ to work without being vendor locked into any particular implementation or provid
57
59
 
58
60
  The true [GitOps](https://en.wikipedia.org/wiki/DevOps#GitOps)/DevOps/DevSecOps/[TestOps](https://en.wikipedia.org/wiki/TestOps)/SysOps/[AIOps](https://en.wikipedia.org/wiki/Artificial_Intelligence_for_IT_Operations)[DataOps](https://en.wikipedia.org/wiki/DataOps) which I call AllTheOps :)
59
61
 
62
+ ![One Config to Rule Them All](/Images/singleConfig.png)
63
+
60
64
  ## Benefits
61
65
 
62
66
  * Compare performance and price among different providers
@@ -217,6 +221,12 @@ First you need to have Ruby and RubyGems. Then you can install it with:
217
221
 
218
222
  $ gem install ConfigLMM
219
223
 
224
+ If that doesn't work (eg. your Ruby is too old) then install with (it will install [RVM](https://rvm.io/))
225
+
226
+ ```
227
+ $ curl -sS https://raw.githubusercontent.com/ConfigLMM/ConfigLMM/master/bootstrap.sh | sh
228
+ ```
229
+
220
230
  ## Usage
221
231
 
222
232
  Create yaml file with desired config, eg.
data/bootstrap.sh ADDED
@@ -0,0 +1,54 @@
1
+ #!/usr/bin/sh
2
+
3
+ distro=$(cat /etc/os-release | grep ^ID= | cut -d '=' -f 2 | cut -d '"' -f 2)
4
+
5
+ function admin {
6
+ if [ "$EUID" -eq "0" ]; then
7
+ "$@"
8
+ else
9
+ sudo "$@"
10
+ fi
11
+ }
12
+
13
+
14
+ case $distro in
15
+
16
+ opensuse-leap)
17
+ admin zypper install --no-confirm ruby libvirt-devel
18
+ ;;
19
+
20
+ arch)
21
+ admin pacman -S --noconfirm --needed ruby rubygems
22
+ ;;
23
+
24
+ *)
25
+ if ! command -v ruby &> /dev/null
26
+ then
27
+ echo "Ruby not found!" >&2
28
+ echo "Don't know how to install it for your $distro distribution!" >&2
29
+ echo "Submit a PR :)" >&2
30
+ exit 1
31
+ fi
32
+ ;;
33
+ esac
34
+
35
+ if ! command -v gem &> /dev/null; then
36
+ echo "RubyGems not found!" >&2
37
+ exit 2
38
+ fi
39
+
40
+ rubyTooOld=$(ruby -e 'puts RUBY_VERSION.to_f < 3.3 ? 1 : 0')
41
+
42
+ if [ "$rubyTooOld" -eq "1" ]; then
43
+ echo "Ruby is too old! Will install RVM" >&2
44
+ gpg2 --keyserver hkp://keyserver.ubuntu.com --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB >/dev/null
45
+ curl -sSL https://get.rvm.io | bash -s stable --ruby=3.3.4
46
+ source /etc/profile.d/rvm.sh
47
+
48
+ 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
50
+ echo "rvm default" >> ~/.config/fish/config.fish
51
+ fi
52
+ fi
53
+
54
+ gem install ConfigLMM
@@ -23,8 +23,7 @@ module ConfigLMM
23
23
 
24
24
  items.each do |item|
25
25
  type, content = item.strip.split('=')
26
- content += '.' if type == 'CNAME' || type == 'ALIAS'
27
- content = domain + '.' if content == '@' || content == '@.'
26
+ content = domain if content == '@'
28
27
  content = self.class.externalIp if content == '@me'
29
28
  records[type] ||= []
30
29
  records[type] << { type: type, content: content, ttl: DEFAULT_TTL }