ConfigLMM 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,256 @@
1
+
2
+ require 'addressable/uri'
3
+ require 'http'
4
+ require 'securerandom'
5
+ require 'shellwords'
6
+
7
+ module ConfigLMM
8
+ module LMM
9
+ class Linux < Framework::LinuxApp
10
+
11
+ ISO_LOCATION = '~/.cache/configlmm/images/'
12
+ HOSTS_FILE = '/etc/hosts'
13
+ SSH_CONFIG = '~/.ssh/config'
14
+ SYSCTL_FILE = '/etc/sysctl.d/10-configlmm.conf'
15
+
16
+ def actionLinuxBuild(id, target, activeState, context, options)
17
+ prepareConfig(target)
18
+ buildHostsFile(id, target, options)
19
+ buildSSHConfig(id, target, options)
20
+ buildAutoYaST(id, target, options)
21
+ end
22
+
23
+ def actionLinuxDeploy(id, target, activeState, context, options)
24
+ prepareConfig(target)
25
+ if target['Location'] && target['Location'] != '@me'
26
+ uri = Addressable::URI.parse(target['Location'])
27
+ case uri.scheme
28
+ when 'qemu'
29
+ deployOverLibvirt(id, target, activeState, context, options)
30
+ when 'ssh'
31
+ deployOverSSH(uri, id, target, activeState, context, options)
32
+ else
33
+ raise Framework::PluginProcessError.new("#{id}: Unknown protocol: #{uri.scheme}!")
34
+ end
35
+ else
36
+ deployLocalHostsFile(target, options)
37
+ deployLocalSSHConfig(target, options)
38
+ end
39
+ if target['AlternativeLocation']
40
+ uri = Addressable::URI.parse(target['AlternativeLocation'])
41
+ raise Framework::PluginProcessError.new("#{id}: Unsupported protocol: #{uri.scheme}!") if uri.scheme != 'ssh'
42
+ deployOverSSH(uri, id, target, activeState, context, options)
43
+ end
44
+ end
45
+
46
+ def deployOverSSH(locationUri, id, target, activeState, context, options)
47
+ if target['Domain'] || target['Hosts']
48
+ hostsLines = []
49
+ if target['Domain']
50
+ self.class.sshStart(locationUri) do |ssh|
51
+ envs = self.class.sshExec!(ssh, "env").split("\n")
52
+ envVars = Hash[envs.map { |vars| vars.split('=', 2) }]
53
+ ipAddr = envVars['SSH_CONNECTION'].split[-2]
54
+ hostsLines << ipAddr.ljust(16) + target['Domain'] + ' ' + target['Name'] + "\n"
55
+ end
56
+ end
57
+ target['Hosts'].to_a.each do |ip, entries|
58
+ hostsLines << ip.ljust(16) + entries.join(' ') + "\n"
59
+ end
60
+ updateRemoteFile(locationUri, HOSTS_FILE, options, false) do |fileLines|
61
+ fileLines + hostsLines
62
+ end
63
+ end
64
+ if target['Sysctl']
65
+ updateRemoteFile(locationUri, SYSCTL_FILE, options, false) do |fileLines|
66
+ target['Sysctl'].each do |name, value|
67
+ fileLines << "#{name} = #{value}\n"
68
+ end
69
+ fileLines
70
+ end
71
+ end
72
+ end
73
+
74
+ def deployOverLibvirt(id, target, activeState, context, options)
75
+ location = Libvirt.getLocation(target['Location'])
76
+ iso = installationISO(target['Distro'], location)
77
+ iso = buildISOAutoYaST(id, iso, target, options) if target['Distro'] == SUSE_NAME
78
+ plugins[:Libvirt].createVM(target['Name'], target, target['Location'], iso, activeState)
79
+ end
80
+
81
+ def buildHostsFile(id, target, options)
82
+ if target['Hosts']
83
+ hosts = "#\n"
84
+ hosts += "# /etc/hosts: static lookup table for host names\n"
85
+ hosts += "#\n\n"
86
+ hosts += "#<ip-address> <hostname.domain.org> <hostname>\n"
87
+ hosts += "127.0.0.1 localhost\n"
88
+ hosts += "::1 localhost\n\n"
89
+ hosts += CONFIGLMM_SECTION_BEGIN
90
+ target['Hosts'].each do |ip, entries|
91
+ hosts += ip.ljust(16) + entries.join(' ') + "\n"
92
+ end
93
+ hosts += CONFIGLMM_SECTION_END
94
+
95
+ path = options['output'] + '/' + id
96
+ mkdir(path + '/etc', options[:dry])
97
+ fileWrite(path + HOSTS_FILE, hosts, options[:dry])
98
+ end
99
+ end
100
+
101
+ def buildSSHConfig(id, target, options)
102
+ if !target['SSH']['Config'].empty?
103
+ sshConfig = "\n"
104
+ sshConfig += CONFIGLMM_SECTION_BEGIN
105
+ target['SSH']['Config'].each do |name, info|
106
+ sshConfig += "Host #{name} #{info['HostName']}\n"
107
+ sshConfig += " HostName " + info['HostName'] + "\n" if info['HostName']
108
+ sshConfig += " Port " + info['Port'] + "\n" if info['Port']
109
+ sshConfig += " User " + info['User'] + "\n" if info['User']
110
+ sshConfig += " IdentityFile " + info['IdentityFile'] + "\n" if info['IdentityFile']
111
+ sshConfig += "\n"
112
+ end
113
+ sshConfig += CONFIGLMM_SECTION_END
114
+ sshConfig += "\n"
115
+
116
+ configPath = options['output'] + '/' + id
117
+ mkdir(configPath + '/root/.ssh', options[:dry])
118
+ fileWrite(configPath + SSH_CONFIG.gsub('~', '/root'), sshConfig, options[:dry])
119
+ end
120
+ end
121
+
122
+ def buildAutoYaST(id, target, options)
123
+ if target['Distro'] == SUSE_NAME
124
+ outputFolder = options['output'] + '/' + id + '/'
125
+ template = ERB.new(File.read(__dir__ + '/openSUSE/autoinst.xml.erb'))
126
+ renderTemplate(template, target, outputFolder + 'autoinst.xml', options)
127
+ end
128
+ end
129
+
130
+ def deployLocalHostsFile(target, options)
131
+ if target['Hosts']
132
+ updateLocalFile(HOSTS_FILE, options) do |hostsLines|
133
+ target['Hosts'].each do |ip, entries|
134
+ hostsLines << ip.ljust(16) + entries.join(' ') + "\n"
135
+ end
136
+ hostsLines
137
+ end
138
+ end
139
+ end
140
+
141
+ def deployLocalSSHConfig(target, options)
142
+ if !target['SSH']['Config'].empty?
143
+ updateLocalFile(File.expand_path(SSH_CONFIG), options) do |configLines|
144
+ target['SSH']['Config'].each do |name, info|
145
+ configLines << "Host #{name} #{info['HostName']}\n"
146
+ configLines << " HostName " + info['HostName'] + "\n" if info['HostName']
147
+ configLines << " Port " + info['Port'] + "\n" if info['Port']
148
+ configLines << " User " + info['User'] + "\n" if info['User']
149
+ configLines << " IdentityFile " + info['IdentityFile'] + "\n" if info['IdentityFile']
150
+ end
151
+ configLines
152
+ end
153
+ end
154
+ end
155
+
156
+ def installationISO(distro, location)
157
+ url = nil
158
+ case distro
159
+ when SUSE_NAME
160
+ if location.empty?
161
+ # TODO automatically fetch latest version from website
162
+ url = 'https://download.opensuse.org/distribution/leap/15.6/iso/openSUSE-Leap-15.6-NET-x86_64-Media.iso'
163
+ else
164
+ raise Framework::PluginProcessError.new("#{id}: Unimplemented!")
165
+ end
166
+ else
167
+ raise Framework::PluginProcessError.new("#{id}: Unknown Linux Distro: #{distro}!")
168
+ end
169
+
170
+ filename = File.basename(Addressable::URI.parse(url).path)
171
+ iso = File.expand_path(ISO_LOCATION + filename)
172
+ if !File.exist?(iso)
173
+ mkdir(File.expand_path(ISO_LOCATION), false)
174
+ prompt.say('Downloading... ' + url)
175
+ response = HTTP.follow.get(url)
176
+ raise "Failed to download file: #{response.status}" unless response.status.success?
177
+ File.open(iso, 'wb') do |file|
178
+ response.body.each do |chunk|
179
+ file.write(chunk)
180
+ end
181
+ end
182
+ end
183
+ iso
184
+ end
185
+
186
+ def buildISOAutoYaST(id, iso, target, options)
187
+ outputFolder = options['output'] + '/iso/'
188
+ mkdir(outputFolder, false)
189
+ `xorriso -osirrox on -indev #{iso} -extract / #{outputFolder} 2>&1 >/dev/null`
190
+ FileUtils.chmod_R(0750, outputFolder) # Need to make it writeable so it can be deleted
191
+ copy(options['output'] + '/' + id + '/autoinst.xml', outputFolder, false)
192
+
193
+ cfg = outputFolder + "boot/x86_64/loader/isolinux.cfg"
194
+ `sed -i 's|default harddisk|default linux|' #{cfg}`
195
+ `sed -i 's|append initrd=initrd splash=silent showopts|append initrd=initrd splash=silent autoyast=device://sr0/autoinst.xml|' #{cfg}`
196
+ `sed -i 's|prompt 1|prompt 0|' #{cfg}`
197
+ `sed -i 's|timeout 600|timeout 1|' #{cfg}`
198
+
199
+ patchedIso = File.dirname(iso) + '/patched.iso'
200
+ `xorriso -as mkisofs -no-emul-boot -boot-load-size 4 -boot-info-table -iso-level 4 -b boot/x86_64/loader/isolinux.bin -c boot/x86_64/loader/boot.cat -eltorito-alt-boot -e boot/x86_64/efi -no-emul-boot -o #{patchedIso} #{outputFolder} 2>&1 >/dev/null`
201
+ patchedIso
202
+ end
203
+
204
+ def prepareConfig(target)
205
+ target['SSH'] ||= {}
206
+ target['SSH']['Config'] ||= {}
207
+ target['Users'] ||= {}
208
+ target['HostName'] = target['Name'] unless target['HostName']
209
+
210
+ if ENV['LINUX_ROOT_PASSWORD_HASH']
211
+ target['Users']['root'] ||= {}
212
+ target['Users']['root']['PasswordHash'] = ENV['LINUX_ROOT_PASSWORD_HASH']
213
+ elsif ENV['LINUX_ROOT_PASSWORD']
214
+ target['Users']['root'] ||= {}
215
+ target['Users']['root']['PasswordHash'] = self.class.linuxPasswordHash(ENV['LINUX_ROOT_PASSWORD'])
216
+ elsif target['Users'].key?('root')
217
+ if !target['Users']['root']['Password'] &&
218
+ !target['Users']['root']['PasswordHash']
219
+ rootPassword = SecureRandom.urlsafe_base64(12)
220
+ prompt.say("Root password: #{rootPassword}", :color => :magenta)
221
+ target['Users']['root']['PasswordHash'] = self.class.linuxPasswordHash(rootPassword)
222
+ elsif target['Users']['root']['Password'] == 'no'
223
+ target['Users']['root'].delete('Password')
224
+ end
225
+ end
226
+
227
+ target['Users'].each do |user, info|
228
+ newKeys = []
229
+ info['AuthorizedKeys'].to_a.each do |key|
230
+ if key.start_with?('/') || key.start_with?('~')
231
+ newKeys << File.read(File.expand_path(key)).strip
232
+ else
233
+ newKeys << key
234
+ end
235
+ end
236
+ info['AuthorizedKeys'] = newKeys
237
+ end
238
+
239
+ packages = YAML.load_file(__dir__ + '/Packages.yaml')
240
+ newApps = []
241
+ target['Services'] ||= []
242
+ if target['Apps'].to_a.include?('sshd')
243
+ target['Services'] << 'sshd'
244
+ target['Services'].uniq!
245
+ end
246
+ target['Apps'] = self.class.mapPackages(target['Apps'], target['Distro'])
247
+ end
248
+
249
+ def self.linuxPasswordHash(password)
250
+ salt = SecureRandom.alphanumeric(16)
251
+ password.crypt('$6$' + salt)
252
+ end
253
+
254
+ end
255
+ end
256
+ end
@@ -0,0 +1,13 @@
1
+ Arch Linux:
2
+ sshd: openssh
3
+ Postfix: postfix
4
+ Dovecot: dovecot
5
+ PostgreSQL: postgresql
6
+ Valkey: redis
7
+
8
+ openSUSE Leap:
9
+ sshd: openssh
10
+ Postfix: postfix
11
+ Dovecot: dovecot
12
+ PostgreSQL: postgresql-server
13
+ Valkey: redis
@@ -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>
@@ -26,7 +26,8 @@ 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)
30
+ record[:content] = Addressable::IDNA.to_ascii(record[:content]) if record[:type] == 'CNAME'
30
31
  config['Records'] += [shortName, record[:ttl], ' IN ', record[:type], record[:content]].join("\t") + "\n"
31
32
  end
32
33
  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
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
@@ -0,0 +1,115 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ConfigLMM
4
+ module Framework
5
+
6
+ class LinuxApp < Framework::Plugin
7
+
8
+ LINUX_FOLDER = __dir__ + '/../../../../Plugins/OS/Linux/'
9
+ SUSE_NAME = 'openSUSE Leap'
10
+ SUSE_ID = 'opensuse-leap'
11
+
12
+ def ensurePackage(name, location)
13
+ self.class.ensurePackage(name, location)
14
+ end
15
+
16
+ def self.ensurePackage(name, location)
17
+ if location && location != '@me'
18
+ uri = Addressable::URI.parse(location)
19
+ raise Framework::PluginProcessError.new("#{id}: Unknown Protocol: #{uri.scheme}!") if uri.scheme != 'ssh'
20
+ self.ensurePackageOverSSH(name, uri)
21
+ else
22
+ # TODO
23
+ end
24
+ end
25
+
26
+ def self.ensurePackageOverSSH(name, locationOrSSH)
27
+
28
+ closure = Proc.new do |ssh|
29
+ distroInfo = self.distroInfoFromSSH(ssh)
30
+ pkgs = self.mapPackages([name], distroInfo['Name']).first
31
+
32
+ pkgs = [pkgs] unless pkgs.is_a?(Array)
33
+ command = distroInfo['InstallPackage'] + ' ' + pkgs.map { |pkg| pkg.shellescape }.join(' ')
34
+ self.sshExec!(ssh, command)
35
+ end
36
+
37
+ if locationOrSSH.is_a?(String) || locationOrSSH.is_a?(Addressable::URI)
38
+ self.sshStart(locationOrSSH) do |ssh|
39
+ closure.call(ssh)
40
+ end
41
+ else
42
+ closure.call(locationOrSSH)
43
+ end
44
+
45
+ end
46
+
47
+ def ensureServiceAutoStart(name, location)
48
+ if location && location != '@me'
49
+ uri = Addressable::URI.parse(location)
50
+ raise Framework::PluginProcessError.new("#{id}: Unknown Protocol: #{uri.scheme}!") if uri.scheme != 'ssh'
51
+ self.class.sshStart(uri) do |ssh|
52
+ distroInfo = self.class.distroInfoFromSSH(ssh)
53
+
54
+ command = distroInfo['AutoStartService'] + ' ' + name.shellescape
55
+ self.class.sshExec!(ssh, command)
56
+ end
57
+ else
58
+ # TODO
59
+ end
60
+ end
61
+
62
+ def startService(name, location)
63
+ if location && location != '@me'
64
+ uri = Addressable::URI.parse(location)
65
+ raise Framework::PluginProcessError.new("#{id}: Unknown Protocol: #{uri.scheme}!") if uri.scheme != 'ssh'
66
+ self.class.sshStart(uri) do |ssh|
67
+ distroInfo = self.class.distroInfoFromSSH(ssh)
68
+
69
+ command = distroInfo['StartService'] + ' ' + name.shellescape
70
+ self.class.sshExec!(ssh, command)
71
+ end
72
+ else
73
+ # TODO
74
+ end
75
+ end
76
+
77
+ def self.mapPackages(packages, distroName)
78
+ distroPackages = YAML.load_file(LINUX_FOLDER + 'Packages.yaml')
79
+ names = []
80
+ packages.to_a.each do |pkg|
81
+ packageName = distroPackages[distroName][pkg]
82
+ if packageName
83
+ names << packageName
84
+ else
85
+ names << pkg.downcase
86
+ end
87
+ end
88
+ names
89
+ end
90
+
91
+ def self.createSubuidsOverSSH(user, distroInfo, ssh)
92
+ self.sshExec!(ssh, "#{distroInfo['ModifyUser']} --add-subuids 100000-165535 --add-subgids 100000-165535 #{user}")
93
+ end
94
+
95
+ def self.distroID
96
+ `cat /etc/os-release | grep "^ID=" | cut -d "=" -f 2`.strip.gsub('"', '')
97
+ end
98
+
99
+ def self.distroIDfromSSH(ssh)
100
+ ssh.exec!('cat /etc/os-release | grep "^ID=" | cut -d "=" -f 2').strip.gsub('"', '')
101
+ end
102
+
103
+ def self.distroInfoFromSSH(ssh)
104
+ distroInfo = self.distroInfo(self.distroIDfromSSH(ssh))
105
+ end
106
+
107
+ def self.distroInfo(distroID)
108
+ distributions = YAML.load_file(LINUX_FOLDER + 'Distributions.yaml')
109
+ raise Framework::PluginProcessError.new("Unknown Linux Distro: #{distroID}!") unless distributions.key?(distroID)
110
+ distributions[distroID]
111
+ end
112
+
113
+ end
114
+ end
115
+ end