train 0.29.2 → 0.30.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +26 -2
  3. data/lib/train.rb +1 -0
  4. data/lib/train/errors.rb +6 -0
  5. data/lib/train/extras.rb +0 -1
  6. data/lib/train/platforms.rb +82 -0
  7. data/lib/train/platforms/common.rb +34 -0
  8. data/lib/train/platforms/detect.rb +12 -0
  9. data/lib/train/platforms/detect/helpers/os_common.rb +56 -0
  10. data/lib/train/platforms/detect/helpers/os_linux.rb +75 -0
  11. data/lib/train/{extras/os_detect_windows.rb → platforms/detect/helpers/os_windows.rb} +3 -10
  12. data/lib/train/platforms/detect/scanner.rb +84 -0
  13. data/lib/train/platforms/detect/specifications/os.rb +480 -0
  14. data/lib/train/platforms/family.rb +26 -0
  15. data/lib/train/platforms/platform.rb +80 -0
  16. data/lib/train/plugins/base_connection.rb +75 -27
  17. data/lib/train/transports/docker.rb +17 -28
  18. data/lib/train/transports/local.rb +21 -22
  19. data/lib/train/transports/mock.rb +44 -30
  20. data/lib/train/transports/ssh_connection.rb +55 -67
  21. data/lib/train/transports/winrm_connection.rb +16 -26
  22. data/lib/train/version.rb +1 -1
  23. data/test/unit/file/remote/linux_test.rb +2 -2
  24. data/test/unit/platforms/detect/os_common_test.rb +85 -0
  25. data/test/unit/platforms/detect/os_linux_test.rb +124 -0
  26. data/test/unit/{extras/os_detect_windows_test.rb → platforms/detect/os_windows_test.rb} +5 -2
  27. data/test/unit/platforms/detect/scanner_test.rb +61 -0
  28. data/test/unit/platforms/family_test.rb +32 -0
  29. data/test/unit/platforms/os_detect_test.rb +175 -0
  30. data/test/unit/{extras/os_common_test.rb → platforms/platform_test.rb} +103 -18
  31. data/test/unit/platforms/platforms_test.rb +42 -0
  32. data/test/unit/plugins/connection_test.rb +106 -8
  33. data/test/unit/transports/local_test.rb +20 -15
  34. data/test/unit/transports/mock_test.rb +16 -6
  35. data/test/unit/transports/ssh_test.rb +17 -15
  36. metadata +28 -19
  37. data/lib/train/extras/linux_lsb.rb +0 -60
  38. data/lib/train/extras/os_common.rb +0 -151
  39. data/lib/train/extras/os_detect_arista_eos.rb +0 -34
  40. data/lib/train/extras/os_detect_darwin.rb +0 -40
  41. data/lib/train/extras/os_detect_esx.rb +0 -22
  42. data/lib/train/extras/os_detect_linux.rb +0 -164
  43. data/lib/train/extras/os_detect_openvms.rb +0 -29
  44. data/lib/train/extras/os_detect_unix.rb +0 -106
  45. data/lib/train/extras/uname.rb +0 -28
  46. data/lib/train/transports/local_os.rb +0 -51
  47. data/test/unit/extras/os_detect_linux_test.rb +0 -230
@@ -0,0 +1,480 @@
1
+ # encoding: utf-8
2
+
3
+ # rubocop:disable Style/Next
4
+ # rubocop:disable Metrics/AbcSize
5
+ # rubocop:disable Metrics/CyclomaticComplexity
6
+ # rubocop:disable Metrics/ClassLength
7
+ # rubocop:disable Metrics/MethodLength
8
+ # rubocop:disable Metrics/PerceivedComplexity
9
+
10
+ module Train::Platforms::Detect::Specifications
11
+ class OS
12
+ def self.load
13
+ plat = Train::Platforms
14
+
15
+ plat.family('windows')
16
+ .detect {
17
+ if winrm? || (@backend.local? && ruby_host_os(/mswin|mingw32|windows/))
18
+ true
19
+ end
20
+ }
21
+ # windows platform
22
+ plat.name('windows').in_family('windows')
23
+ .detect {
24
+ true if detect_windows == true
25
+ }
26
+
27
+ # unix master family
28
+ plat.family('unix')
29
+ .detect {
30
+ if unix_uname_s =~ /./
31
+ @platform[:arch] = unix_uname_m
32
+ true
33
+ end
34
+ }
35
+
36
+ # arista_eos family
37
+ # this has to be before redhat as EOS is based off fedora
38
+ plat.family('arista_eos').title('Arista EOS Family').in_family('unix')
39
+ .detect {
40
+ # we need a better way to determin this family
41
+ # for now we are going to just try each platform
42
+ true
43
+ }
44
+ plat.name('arista_eos').title('Arista EOS').in_family('arista_eos')
45
+ .detect {
46
+ cmd = @backend.run_command('show version | json')
47
+ if cmd.exit_status == 0 && !cmd.stdout.empty?
48
+ require 'json'
49
+ eos_ver = JSON.parse(cmd.stdout)
50
+ @platform[:release] = eos_ver['version']
51
+ @platform[:arch] = eos_ver['architecture']
52
+ true
53
+ end
54
+ }
55
+ plat.name('arista_eos_bash').title('Arista EOS Bash Shell').in_family('arista_eos')
56
+ .detect {
57
+ if unix_file_exist?('/usr/bin/FastCli')
58
+ cmd = @backend.run_command('FastCli -p 15 -c "show version | json"')
59
+ if cmd.exit_status == 0 && !cmd.stdout.empty?
60
+ require 'json'
61
+ eos_ver = JSON.parse(cmd.stdout)
62
+ @platform[:release] = eos_ver['version']
63
+ @platform[:arch] = eos_ver['architecture']
64
+ true
65
+ end
66
+ end
67
+ }
68
+
69
+ # linux master family
70
+ plat.family('linux').in_family('unix')
71
+ .detect {
72
+ true if unix_uname_s =~ /linux/i
73
+ }
74
+
75
+ # debian family
76
+ plat.family('debian').in_family('linux')
77
+ .detect {
78
+ true unless unix_file_contents('/etc/debian_version').nil?
79
+ }
80
+ plat.name('ubuntu').title('Ubuntu Linux').in_family('debian')
81
+ .detect {
82
+ lsb = read_linux_lsb
83
+ if lsb && lsb[:id] =~ /ubuntu/i
84
+ @platform[:release] = lsb[:release]
85
+ true
86
+ end
87
+ }
88
+ plat.name('linuxmint').title('LinuxMint').in_family('debian')
89
+ .detect {
90
+ lsb = read_linux_lsb
91
+ if lsb && lsb[:id] =~ /linuxmint/i
92
+ @platform[:release] = lsb[:release]
93
+ true
94
+ end
95
+ }
96
+ plat.name('raspbian').title('Raspbian Linux').in_family('debian')
97
+ .detect {
98
+ if (linux_os_release && linux_os_release['NAME'] =~ /raspbian/i) || \
99
+ unix_file_exist?('/usr/bin/raspi-config')
100
+ @platform[:release] = unix_file_contents('/etc/debian_version').chomp
101
+ true
102
+ end
103
+ }
104
+ plat.name('debian').title('Debian Linux').in_family('debian')
105
+ .detect {
106
+ lsb = read_linux_lsb
107
+ if lsb && lsb[:id] =~ /debian/i
108
+ @platform[:release] = lsb[:release]
109
+ true
110
+ end
111
+
112
+ # if we get this far we have to be some type of debian
113
+ true
114
+ }
115
+
116
+ # fedora family
117
+ plat.family('fedora').in_family('linux')
118
+ .detect {
119
+ true if linux_os_release && linux_os_release['NAME'] =~ /fedora/i
120
+ }
121
+ plat.name('fedora').title('Fedora').in_family('fedora')
122
+ .detect {
123
+ @platform[:release] = linux_os_release['VERSION_ID']
124
+ true
125
+ }
126
+
127
+ # redhat family
128
+ plat.family('redhat').in_family('linux')
129
+ .detect {
130
+ # I am not sure this returns true for all redhats in this family
131
+ # for now we are going to just try each platform
132
+ # return true unless unix_file_contents('/etc/redhat-release').nil?
133
+
134
+ true
135
+ }
136
+ plat.name('centos').title('Centos Linux').in_family('redhat')
137
+ .detect {
138
+ lsb = read_linux_lsb
139
+ if lsb && lsb[:id] =~ /centos/i
140
+ @platform[:release] = lsb[:release]
141
+ true
142
+ elsif linux_os_release && linux_os_release['NAME'] =~ /centos/i
143
+ @platform[:release] = redhatish_version(unix_file_contents('/etc/redhat-release'))
144
+ true
145
+ end
146
+ }
147
+ plat.name('oracle').title('Oracle Linux').in_family('redhat')
148
+ .detect {
149
+ if !(raw = unix_file_contents('/etc/oracle-release')).nil?
150
+ @platform[:release] = redhatish_version(raw)
151
+ true
152
+ elsif !(raw = unix_file_contents('/etc/enterprise-release')).nil?
153
+ @platform[:release] = redhatish_version(raw)
154
+ true
155
+ end
156
+ }
157
+ plat.name('scientific').title('Scientific Linux').in_family('redhat')
158
+ .detect {
159
+ lsb = read_linux_lsb
160
+ if lsb && lsb[:id] =~ /scientificsl/i
161
+ @platform[:release] = lsb[:release]
162
+ true
163
+ end
164
+ }
165
+ plat.name('xenserver').title('Xenserer Linux').in_family('redhat')
166
+ .detect {
167
+ lsb = read_linux_lsb
168
+ if lsb && lsb[:id] =~ /xenserver/i
169
+ @platform[:release] = lsb[:release]
170
+ true
171
+ end
172
+ }
173
+ plat.name('parallels-release').title('Parallels Linux').in_family('redhat')
174
+ .detect {
175
+ if !(raw = unix_file_contents('/etc/parallels-release')).nil?
176
+ @platform[:name] = redhatish_platform(raw)
177
+ @platform[:release] = raw[/(\d\.\d\.\d)/, 1]
178
+ true
179
+ end
180
+ }
181
+ plat.name('wrlinux').title('Wind River Linux').in_family('redhat')
182
+ .detect {
183
+ if linux_os_release && linux_os_release['ID_LIKE'] =~ /wrlinux/i
184
+ @platform[:release] = linux_os_release['VERSION']
185
+ true
186
+ end
187
+ }
188
+ plat.name('amazon').title('Amazon Linux').in_family('redhat')
189
+ .detect {
190
+ lsb = read_linux_lsb
191
+ if lsb && lsb[:id] =~ /amazon/i
192
+ @platform[:release] = lsb[:release]
193
+ true
194
+ elsif (raw = unix_file_contents('/etc/system-release')) =~ /amazon/i
195
+ @platform[:name] = redhatish_platform(raw)
196
+ @platform[:release] = redhatish_version(raw)
197
+ true
198
+ end
199
+ }
200
+ # keep redhat at the end as a fallback for anything with a redhat-release
201
+ plat.name('redhat').title('Red Hat Linux').in_family('redhat')
202
+ .detect {
203
+ lsb = read_linux_lsb
204
+ if lsb && lsb[:id] =~ /redhat/i
205
+ @platform[:release] = lsb[:release]
206
+ true
207
+ elsif !(raw = unix_file_contents('/etc/redhat-release')).nil?
208
+ # must be some type of redhat
209
+ @platform[:name] = redhatish_platform(raw)
210
+ @platform[:release] = redhatish_version(raw)
211
+ true
212
+ end
213
+ }
214
+
215
+ # suse family
216
+ plat.family('suse').in_family('linux')
217
+ .detect {
218
+ if !(suse = unix_file_contents('/etc/SuSE-release')).nil?
219
+ version = suse.scan(/VERSION = (\d+)\nPATCHLEVEL = (\d+)/).flatten.join('.')
220
+ version = suse[/VERSION = ([\d\.]{2,})/, 1] if version == ''
221
+ @platform[:release] = version
222
+ true
223
+ end
224
+ }
225
+ plat.name('opensuse').title('OpenSUSE Linux').in_family('suse')
226
+ .detect {
227
+ true if unix_file_contents('/etc/SuSE-release') =~ /^opensuse/i
228
+ }
229
+ plat.name('suse').title('Suse Linux').in_family('suse')
230
+ .detect {
231
+ true if unix_file_contents('/etc/SuSE-release') =~ /suse/i
232
+ }
233
+
234
+ # arch
235
+ plat.name('arch').title('Arch Linux').in_family('linux')
236
+ .detect {
237
+ if !unix_file_contents('/etc/arch-release').nil?
238
+ # Because this is a rolling release distribution,
239
+ # use the kernel release, ex. 4.1.6-1-ARCH
240
+ @platform[:release] = unix_uname_r
241
+ true
242
+ end
243
+ }
244
+
245
+ # slackware
246
+ plat.name('slackware').title('Slackware Linux').in_family('linux')
247
+ .detect {
248
+ if !(raw = unix_file_contents('/etc/slackware-version')).nil?
249
+ @platform[:release] = raw.scan(/(\d+|\.+)/).join
250
+ true
251
+ end
252
+ }
253
+
254
+ # gentoo
255
+ plat.name('gentoo').title('Gentoo Linux').in_family('linux')
256
+ .detect {
257
+ if !(raw = unix_file_contents('/etc/gentoo-release')).nil?
258
+ @platform[:release] = raw.scan(/(\d+|\.+)/).join
259
+ true
260
+ end
261
+ }
262
+
263
+ # exherbo
264
+ plat.name('exherbo').title('Exherbo Linux').in_family('linux')
265
+ .detect {
266
+ unless unix_file_contents('/etc/exherbo-release').nil?
267
+ # Because this is a rolling release distribution,
268
+ # use the kernel release, ex. 4.1.6
269
+ @platform[:release] = unix_uname_r
270
+ true
271
+ end
272
+ }
273
+
274
+ # alpine
275
+ plat.name('alpine').title('Alpine Linux').in_family('linux')
276
+ .detect {
277
+ if !(raw = unix_file_contents('/etc/alpine-release')).nil?
278
+ @platform[:release] = raw.strip
279
+ true
280
+ end
281
+ }
282
+
283
+ # coreos
284
+ plat.name('coreos').title('CoreOS Linux').in_family('linux')
285
+ .detect {
286
+ unless unix_file_contents('/etc/coreos/update.conf').nil?
287
+ lsb = read_linux_lsb
288
+ @platform[:release] = lsb[:release]
289
+ true
290
+ end
291
+ }
292
+
293
+ # genaric linux
294
+ # this should always be last in the linux family list
295
+ plat.name('linux').title('Genaric Linux').in_family('linux')
296
+ .detect {
297
+ true
298
+ }
299
+
300
+ # openvms
301
+ plat.name('openvms').title('OpenVMS').in_family('unix')
302
+ .detect {
303
+ if unix_uname_s =~ /unrecognized command verb/i
304
+ cmd = @backend.run_command('show system/noprocess')
305
+ unless cmd.exit_status != 0 || cmd.stdout.empty?
306
+ @platform[:name] = cmd.stdout.downcase.split(' ')[0]
307
+ cmd = @backend.run_command('write sys$output f$getsyi("VERSION")')
308
+ @platform[:release] = cmd.stdout.downcase.split("\n")[1][1..-1]
309
+ cmd = @backend.run_command('write sys$output f$getsyi("ARCH_NAME")')
310
+ @platform[:arch] = cmd.stdout.downcase.split("\n")[1]
311
+ true
312
+ end
313
+ end
314
+ }
315
+
316
+ # esx
317
+ plat.family('esx').title('ESXi Family')
318
+ .detect {
319
+ true if unix_uname_s =~ /vmkernel/i
320
+ }
321
+ plat.name('vmkernel').in_family('esx')
322
+ .detect {
323
+ @platform[:name] = unix_uname_s.lines[0].chomp
324
+ @platform[:release] = unix_uname_r.lines[0].chomp
325
+ true
326
+ }
327
+
328
+ # aix
329
+ plat.family('aix').in_family('unix')
330
+ .detect {
331
+ true if unix_uname_s =~ /aix/i
332
+ }
333
+ plat.name('aix').title('Aix').in_family('aix')
334
+ .detect {
335
+ out = @backend.run_command('uname -rvp').stdout
336
+ m = out.match(/(\d+)\s+(\d+)\s+(.*)/)
337
+ unless m.nil?
338
+ @platform[:release] = "#{m[2]}.#{m[1]}"
339
+ @platform[:arch] = m[3].to_s
340
+ end
341
+ true
342
+ }
343
+
344
+ # solaris family
345
+ plat.family('solaris').in_family('unix')
346
+ .detect {
347
+ if unix_uname_s =~ /sunos/i
348
+ unless (version = /^5\.(?<release>\d+)$/.match(unix_uname_r)).nil?
349
+ @platform[:release] = version['release']
350
+ end
351
+
352
+ arch = @backend.run_command('uname -p')
353
+ @platform[:arch] = arch.stdout.chomp if arch.exit_status == 0
354
+ true
355
+ end
356
+ }
357
+ plat.name('smartos').title('SmartOS').in_family('solaris')
358
+ .detect {
359
+ rel = unix_file_contents('/etc/release')
360
+ if /^.*(SmartOS).*$/ =~ rel
361
+ true
362
+ end
363
+ }
364
+ plat.name('omnios').title('Omnios').in_family('solaris')
365
+ .detect {
366
+ rel = unix_file_contents('/etc/release')
367
+ if !(m = /^\s*(OmniOS).*r(\d+).*$/.match(rel)).nil?
368
+ @platform[:release] = m[2]
369
+ true
370
+ end
371
+ }
372
+ plat.name('openindiana').title('Openindiana').in_family('solaris')
373
+ .detect {
374
+ rel = unix_file_contents('/etc/release')
375
+ if !(m = /^\s*(OpenIndiana).*oi_(\d+).*$/.match(rel)).nil?
376
+ @platform[:release] = m[2]
377
+ true
378
+ end
379
+ }
380
+ plat.name('opensolaris').title('Open Solaris').in_family('solaris')
381
+ .detect {
382
+ rel = unix_file_contents('/etc/release')
383
+ if !(m = /^\s*(OpenSolaris).*snv_(\d+).*$/.match(rel)).nil?
384
+ @platform[:release] = m[2]
385
+ true
386
+ end
387
+ }
388
+ plat.name('nexentacore').title('Nexentacore').in_family('solaris')
389
+ .detect {
390
+ rel = unix_file_contents('/etc/release')
391
+ if /^\s*(NexentaCore)\s.*$/ =~ rel
392
+ true
393
+ end
394
+ }
395
+ plat.name('solaris').title('Solaris').in_family('solaris')
396
+ .detect {
397
+ rel = unix_file_contents('/etc/release')
398
+ if !(m = /Oracle Solaris (\d+)/.match(rel)).nil?
399
+ # TODO: should be string!
400
+ @platform[:release] = m[1]
401
+ true
402
+ elsif /^\s*(Solaris)\s.*$/ =~ rel
403
+ true
404
+ end
405
+
406
+ # must be some unknown solaris
407
+ true
408
+ }
409
+
410
+ # hpux
411
+ plat.family('hpux').in_family('unix')
412
+ .detect {
413
+ true if unix_uname_s =~ /hp-ux/i
414
+ }
415
+ plat.name('hpux').title('Hpux').in_family('hpux')
416
+ .detect {
417
+ @platform[:release] = unix_uname_r.lines[0].chomp
418
+ true
419
+ }
420
+
421
+ # bsd family
422
+ plat.family('bsd').in_family('unix')
423
+ .detect {
424
+ # we need a better way to determin this family
425
+ # for now we are going to just try each platform
426
+ true
427
+ }
428
+ plat.family('darwin').in_family('bsd')
429
+ .detect {
430
+ cmd = unix_file_contents('/usr/bin/sw_vers')
431
+ if unix_uname_s =~ /darwin/i || !cmd.nil?
432
+ unless cmd.nil?
433
+ m = cmd.match(/^ProductVersion:\s+(.+)$/)
434
+ @platform[:release] = m.nil? ? nil : m[1]
435
+ m = cmd.match(/^BuildVersion:\s+(.+)$/)
436
+ @platform[:build] = m.nil? ? nil : m[1]
437
+ end
438
+ @platform[:release] = unix_uname_r.lines[0].chomp if @platform[:release].nil?
439
+ @platform[:arch] = unix_uname_m
440
+ true
441
+ end
442
+ }
443
+ plat.name('mac_os_x').title('macOS X').in_family('darwin')
444
+ .detect {
445
+ cmd = unix_file_contents('/System/Library/CoreServices/SystemVersion.plist')
446
+ true if cmd =~ /Mac OS X/i
447
+ }
448
+ plat.name('darwin').title('Darwin').in_family('darwin')
449
+ .detect {
450
+ # must be some other type of darwin
451
+ @platform[:name] = unix_uname_s.lines[0].chomp
452
+ true
453
+ }
454
+ plat.name('freebsd').title('Freebsd').in_family('bsd')
455
+ .detect {
456
+ if unix_uname_s =~ /freebsd/i
457
+ @platform[:name] = unix_uname_s.lines[0].chomp
458
+ @platform[:release] = unix_uname_r.lines[0].chomp
459
+ true
460
+ end
461
+ }
462
+ plat.name('openbsd').title('Openbsd').in_family('bsd')
463
+ .detect {
464
+ if unix_uname_s =~ /openbsd/i
465
+ @platform[:name] = unix_uname_s.lines[0].chomp
466
+ @platform[:release] = unix_uname_r.lines[0].chomp
467
+ true
468
+ end
469
+ }
470
+ plat.name('netbsd').title('Netbsd').in_family('bsd')
471
+ .detect {
472
+ if unix_uname_s =~ /netbsd/i
473
+ @platform[:name] = unix_uname_s.lines[0].chomp
474
+ @platform[:release] = unix_uname_r.lines[0].chomp
475
+ true
476
+ end
477
+ }
478
+ end
479
+ end
480
+ end