ConfigLMM 0.1.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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 }