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
@@ -1,151 +0,0 @@
1
- # encoding: utf-8
2
- # author: Dominik Richter
3
- # author: Christoph Hartmann
4
- #
5
- # This is heavily based on:
6
- #
7
- # OHAI https://github.com/chef/ohai
8
- # by Adam Jacob, Chef Software Inc
9
- #
10
-
11
- require 'train/extras/os_detect_darwin'
12
- require 'train/extras/os_detect_linux'
13
- require 'train/extras/os_detect_unix'
14
- require 'train/extras/os_detect_windows'
15
- require 'train/extras/os_detect_esx'
16
- require 'train/extras/os_detect_arista_eos'
17
- require 'train/extras/os_detect_openvms'
18
-
19
- module Train::Extras
20
- class OSCommon
21
- include Train::Extras::DetectDarwin
22
- include Train::Extras::DetectLinux
23
- include Train::Extras::DetectUnix
24
- include Train::Extras::DetectWindows
25
- include Train::Extras::DetectEsx
26
- include Train::Extras::DetectAristaEos
27
- include Train::Extras::DetectOpenVMS
28
-
29
- attr_accessor :backend
30
- def initialize(backend, platform = nil)
31
- @backend = backend
32
- @platform = platform || {}
33
- detect_family
34
- end
35
-
36
- def [](key)
37
- @platform[key]
38
- end
39
-
40
- def to_hash
41
- @platform
42
- end
43
-
44
- OS = { # rubocop:disable Style/MutableConstant
45
- 'redhat' => REDHAT_FAMILY,
46
- 'debian' => DEBIAN_FAMILY,
47
- 'suse' => SUSE_FAMILY,
48
- 'fedora' => %w{fedora},
49
- 'bsd' => %w{
50
- freebsd netbsd openbsd darwin
51
- },
52
- 'solaris' => %w{
53
- solaris smartos omnios openindiana opensolaris nexentacore
54
- },
55
- 'windows' => %w{
56
- windows
57
- },
58
- 'aix' => %w{
59
- aix
60
- },
61
- 'hpux' => %w{
62
- hpux
63
- },
64
- 'esx' => %w{
65
- esx
66
- },
67
- 'darwin' => %w{
68
- darwin
69
- },
70
- }
71
-
72
- OS['linux'] = %w{linux alpine arch coreos exherbo gentoo slackware fedora amazon} + OS['redhat'] + OS['debian'] + OS['suse']
73
-
74
- OS['unix'] = %w{unix aix hpux qnx} + OS['linux'] + OS['solaris'] + OS['bsd']
75
-
76
- # Helper methods to check the OS type
77
- # Provides methods in the form of: linux?, unix?, solaris? ...
78
- OS.keys.each do |os_family|
79
- define_method((os_family + '?').to_sym) do
80
- OS[os_family].include?(@platform[:family])
81
- end
82
- end
83
-
84
- private
85
-
86
- def detect_family
87
- # if some information is already defined, try to verify it
88
- # with the remaining detection
89
- unless @platform[:family].nil?
90
- # return ok if the preconfigured family yielded a good result
91
- return true if detect_family_type
92
- # if not, reset the platform to presets and run the full detection
93
- # TODO: print an error message in this case, as the instantiating
94
- # backend is doing something wrong
95
- @platform = {}
96
- end
97
-
98
- # TODO: extend base implementation for detecting the family type
99
- # to Windows and others
100
- case uname_s
101
- when /unrecognized command verb/
102
- @platform[:family] = 'openvms'
103
- when /linux/i
104
- @platform[:family] = 'linux'
105
- when /./
106
- @platform[:family] = 'unix'
107
- else
108
- # Don't know what this is
109
- @platform[:family] = nil
110
- end
111
-
112
- # try to detect the platform if the platform is set to nil, otherwise this code will never work
113
- return nil if @platform[:family].nil?
114
- detect_family_type
115
- end
116
-
117
- def detect_family_type # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
118
- pf = @platform[:family]
119
-
120
- return detect_windows if pf == 'windows'
121
- return detect_darwin if pf == 'darwin'
122
- return detect_esx if pf == 'esx'
123
- return detect_openvms if pf =='openvms'
124
-
125
- if %w{freebsd netbsd openbsd aix solaris2 hpux}.include?(pf)
126
- return detect_via_uname
127
- end
128
-
129
- # unix based systems combine the above
130
- return true if pf == 'unix' and detect_darwin
131
- return true if pf == 'unix' and detect_esx
132
- # This is assuming that pf is set to unix, this should be if pf == 'linux'
133
- return true if pf == 'unix' and detect_arista_eos
134
- return true if pf == 'unix' and detect_via_uname
135
-
136
- # if we arrive here, we most likey have a regular linux
137
- detect_linux
138
- end
139
-
140
- def get_config(path)
141
- res = @backend.run_command("test -f #{path} && cat #{path}")
142
- # ignore files that can't be read
143
- return nil if res.exit_status != 0
144
- res.stdout
145
- end
146
-
147
- def unix_file?(path)
148
- @backend.run_command("test -f #{path}").exit_status == 0
149
- end
150
- end
151
- end
@@ -1,34 +0,0 @@
1
- # encoding: utf-8
2
- # author: Jere Julian
3
- #
4
- # Arista EOS has 2 modes. Most compliance tests will use the network CLI
5
- # but when working with vagrant, its common to encounter the raw bash shell.
6
- require 'json'
7
-
8
- module Train::Extras
9
- module DetectAristaEos
10
- def detect_arista_eos
11
- if unix_file?('/usr/bin/FastCli')
12
- cmd = @backend.run_command('FastCli -p 15 -c "show version | json"')
13
- @platform[:name] = 'arista_eos_bash'
14
- family = 'fedora'
15
- else
16
- cmd = @backend.run_command('show version | json')
17
- end
18
-
19
- # in PTY mode, stderr is matched with stdout, therefore it may not be empty
20
- output = cmd.stdout
21
- if cmd.exit_status == 0 && !output.empty?
22
- eos_ver = JSON.parse(output)
23
- @platform[:name] = @platform[:name] || 'arista_eos'
24
- family ||= 'arista_eos'
25
- @platform[:family] = family
26
- @platform[:release] = eos_ver['version']
27
- @platform[:arch] = eos_ver['architecture']
28
- true
29
- else
30
- false
31
- end
32
- end
33
- end
34
- end
@@ -1,40 +0,0 @@
1
- # encoding: utf-8
2
- # author: Dominik Richter
3
- # author: Christoph Hartmann
4
- #
5
- # This is heavily based on:
6
- #
7
- # OHAI https://github.com/chef/ohai
8
- # by Adam Jacob, Chef Software Inc
9
- #
10
- require 'train/extras/uname'
11
-
12
- module Train::Extras
13
- module DetectDarwin
14
- include Train::Extras::Uname
15
-
16
- def detect_darwin
17
- cmd = @backend.run_command('/usr/bin/sw_vers')
18
- # TODO: print an error in this step of the detection,
19
- # as it shouldnt happen
20
- return false if cmd.exit_status != 0
21
- # TODO: ditto on error
22
- return false if cmd.stdout.empty?
23
-
24
- name = cmd.stdout[/^ProductName:\s+(.+)$/, 1]
25
- # TODO: ditto on error
26
- return false if name.nil?
27
- @platform[:name] = name.downcase.chomp.tr(' ', '_')
28
- @platform[:release] = cmd.stdout[/^ProductVersion:\s+(.+)$/, 1]
29
- @platform[:build] = cmd.stdout[/^BuildVersion:\s+(.+)$/, 1]
30
- # TODO: keep for now due to backwards compatibility with serverspec
31
- @platform[:family] = 'darwin'
32
- detect_darwin_arch
33
- true
34
- end
35
-
36
- def detect_darwin_arch
37
- @platform[:arch] = uname_m
38
- end
39
- end
40
- end
@@ -1,22 +0,0 @@
1
- # encoding: utf-8
2
- # author: Dominik Richter
3
- # author: Christoph Hartmann
4
- #
5
- # This is heavily based on:
6
- #
7
- # OHAI https://github.com/chef/ohai
8
- # by Adam Jacob, Chef Software Inc
9
- #
10
-
11
- module Train::Extras
12
- module DetectEsx
13
- def detect_esx
14
- if uname_s.downcase.chomp == 'vmkernel'
15
- @platform[:family] = 'esx'
16
- @platform[:name] = uname_s.lines[0].chomp
17
- @platform[:release] = uname_r.lines[0].chomp
18
- true
19
- end
20
- end
21
- end
22
- end
@@ -1,164 +0,0 @@
1
- # encoding: utf-8
2
- # author: Dominik Richter
3
- # author: Christoph Hartmann
4
- #
5
- # This is heavily based on:
6
- #
7
- # OHAI https://github.com/chef/ohai
8
- # by Adam Jacob, Chef Software Inc
9
- #
10
-
11
- require 'train/extras/linux_lsb'
12
- require 'train/extras/uname'
13
-
14
- module Train::Extras
15
- module DetectLinux # rubocop:disable Metrics/ModuleLength
16
- DEBIAN_FAMILY = %w{debian ubuntu linuxmint raspbian}.freeze
17
- REDHAT_FAMILY = %w{centos redhat oracle scientific enterpriseenterprise xenserver cloudlinux ibm_powerkvm nexus_centos wrlinux virtuozzo parallels}.freeze
18
- SUSE_FAMILY = %w{suse opensuse}.freeze
19
-
20
- include Train::Extras::LinuxLSB
21
- include Train::Extras::Uname
22
-
23
- def detect_linux_via_config # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
24
- if !(raw = get_config('/etc/oracle-release')).nil?
25
- @platform[:name] = 'oracle'
26
- @platform[:release] = redhatish_version(raw)
27
- elsif !(raw = get_config('/etc/enterprise-release')).nil?
28
- @platform[:name] = 'oracle'
29
- @platform[:release] = redhatish_version(raw)
30
- elsif !(raw = get_config('/etc/debian_version')).nil?
31
- case lsb[:id]
32
- when /ubuntu/i
33
- @platform[:name] = 'ubuntu'
34
- @platform[:release] = lsb[:release]
35
- when /linuxmint/i
36
- @platform[:name] = 'linuxmint'
37
- @platform[:release] = lsb[:release]
38
- else
39
- @platform[:name] = unix_file?('/usr/bin/raspi-config') ? 'raspbian' : 'debian'
40
- @platform[:release] = raw.chomp
41
- end
42
- elsif !(raw = get_config('/etc/parallels-release')).nil?
43
- @platform[:name] = redhatish_platform(raw)
44
- @platform[:release] = raw[/(\d\.\d\.\d)/, 1]
45
- elsif !(raw = get_config('/etc/redhat-release')).nil?
46
- # TODO: Cisco
47
- # TODO: fully investigate os-release and integrate it;
48
- # here we just use it for centos
49
- @platform[:name] = if !(osrel = get_config('/etc/os-release')).nil? && osrel =~ /centos/i
50
- 'centos'
51
- else
52
- redhatish_platform(raw)
53
- end
54
-
55
- @platform[:release] = redhatish_version(raw)
56
- elsif !(raw = get_config('/etc/system-release')).nil?
57
- # Amazon Linux
58
- @platform[:name] = redhatish_platform(raw)
59
- @platform[:release] = redhatish_version(raw)
60
- elsif !(suse = get_config('/etc/SuSE-release')).nil?
61
- version = suse.scan(/VERSION = (\d+)\nPATCHLEVEL = (\d+)/).flatten.join('.')
62
- version = suse[/VERSION = ([\d\.]{2,})/, 1] if version == ''
63
- @platform[:release] = version
64
- @platform[:name] = if suse =~ /^openSUSE/
65
- 'opensuse'
66
- else
67
- 'suse'
68
- end
69
- elsif !(raw = get_config('/etc/arch-release')).nil?
70
- @platform[:name] = 'arch'
71
- # Because this is a rolling release distribution,
72
- # use the kernel release, ex. 4.1.6-1-ARCH
73
- @platform[:release] = uname_r
74
- elsif !(raw = get_config('/etc/slackware-version')).nil?
75
- @platform[:name] = 'slackware'
76
- @platform[:release] = raw.scan(/(\d+|\.+)/).join
77
- elsif !(raw = get_config('/etc/exherbo-release')).nil?
78
- @platform[:name] = 'exherbo'
79
- # Because this is a rolling release distribution,
80
- # use the kernel release, ex. 4.1.6
81
- @platform[:release] = uname_r
82
- elsif !(raw = get_config('/etc/gentoo-release')).nil?
83
- @platform[:name] = 'gentoo'
84
- @platform[:release] = raw.scan(/(\d+|\.+)/).join
85
- elsif !(raw = get_config('/etc/alpine-release')).nil?
86
- @platform[:name] = 'alpine'
87
- @platform[:release] = raw.strip
88
- elsif !get_config('/etc/coreos/update.conf').nil?
89
- @platform[:name] = 'coreos'
90
- @platform[:release] = lsb[:release]
91
- elsif !(os_info = fetch_os_release).nil?
92
- if os_info['ID_LIKE'] =~ /wrlinux/
93
- @platform[:name] = 'wrlinux'
94
- @platform[:release] = os_info['VERSION']
95
- end
96
- end
97
-
98
- @platform[:family] = family_for_platform
99
-
100
- !@platform[:family].nil? && !@platform[:release].nil?
101
- end
102
-
103
- def family_for_platform
104
- if DEBIAN_FAMILY.include?(@platform[:name])
105
- 'debian'
106
- elsif REDHAT_FAMILY.include?(@platform[:name])
107
- 'redhat'
108
- elsif SUSE_FAMILY.include?(@platform[:name])
109
- 'suse'
110
- else
111
- @platform[:name] || @platform[:family]
112
- end
113
- end
114
-
115
- def redhatish_platform(conf)
116
- conf[/^red hat/i] ? 'redhat' : conf[/(\w+)/i, 1].downcase
117
- end
118
-
119
- def redhatish_version(conf)
120
- return conf[/((\d+) \(Rawhide\))/i, 1].downcase if conf[/rawhide/i]
121
- return conf[/Linux ((\d+|\.)+)/i, 1] if conf[/derived from .*linux/i]
122
- conf[/release ([\d\.]+)/, 1]
123
- end
124
-
125
- def detect_linux_arch
126
- @platform[:arch] = uname_m
127
- end
128
-
129
- def detect_linux
130
- # TODO: print an error in this step of the detection
131
- return false if uname_s.nil? || uname_s.empty?
132
- return false if uname_r.nil? || uname_r.empty?
133
-
134
- detect_linux_arch
135
- return true if detect_linux_via_config
136
- return true if detect_linux_via_lsb
137
- # in all other cases we failed the detection
138
- @platform[:family] = 'unknown'
139
- end
140
-
141
- def fetch_os_release
142
- data = get_config('/etc/os-release')
143
- return if data.nil?
144
-
145
- os_info = parse_os_release_info(data)
146
- cisco_info_file = os_info['CISCO_RELEASE_INFO']
147
- if cisco_info_file
148
- os_info.merge!(parse_os_release_info(get_config(cisco_info_file)))
149
- end
150
-
151
- os_info
152
- end
153
-
154
- def parse_os_release_info(raw)
155
- return {} if raw.nil?
156
-
157
- raw.lines.each_with_object({}) do |line, memo|
158
- line.strip!
159
- key, value = line.split('=', 2)
160
- memo[key] = value.gsub(/\A"|"\Z/, '') unless value.empty?
161
- end
162
- end
163
- end
164
- end
@@ -1,29 +0,0 @@
1
- # encoding: utf-8
2
- # author: Brian Doody (HPE)
3
- # This is heavily based on:
4
- #
5
- # OHAI https://github.com/chef/ohai
6
- # by Adam Jacob, Chef Software Inc
7
- #
8
- require 'train/extras/uname'
9
-
10
- module Train::Extras
11
- module DetectOpenVMS
12
- include Train::Extras::Uname
13
-
14
- def detect_openvms
15
- cmd = @backend.run_command('show system/noprocess')
16
-
17
- return false if cmd.exit_status != 0
18
- return false if cmd.stdout.empty?
19
-
20
- @platform[:name] = cmd.stdout.downcase.split(' ')[0]
21
- cmd = @backend.run_command('write sys$output f$getsyi("VERSION")')
22
- @platform[:release] = cmd.stdout.downcase.split("\n")[1][1..-1]
23
- cmd = @backend.run_command('write sys$output f$getsyi("ARCH_NAME")')
24
- @platform[:arch] = cmd.stdout.downcase.split("\n")[1]
25
-
26
- true
27
- end
28
- end
29
- end
@@ -1,106 +0,0 @@
1
- # encoding: utf-8
2
- # author: Dominik Richter
3
- # author: Christoph Hartmann
4
- #
5
- # This is heavily based on:
6
- #
7
- # OHAI https://github.com/chef/ohai
8
- # by Adam Jacob, Chef Software Inc
9
- #
10
-
11
- module Train::Extras
12
- module DetectUnix
13
- def detect_via_uname # rubocop:disable Metrics/AbcSize
14
- case uname_s.downcase
15
- when /aix/
16
- @platform[:family] = 'aix'
17
- @platform[:name] = uname_s.lines[0].chomp
18
- out = @backend.run_command('uname -rvp').stdout
19
- m = out.match(/(\d+)\s+(\d+)\s+(.*)/)
20
- unless m.nil?
21
- @platform[:release] = "#{m[2]}.#{m[1]}"
22
- @platform[:arch] = m[3].to_s
23
- end
24
- when /hp-ux/
25
- @platform[:family] = 'hpux'
26
- @platform[:name] = uname_s.lines[0].chomp
27
- @platform[:release] = uname_r.lines[0].chomp
28
-
29
- when /freebsd/
30
- @platform[:family] = 'freebsd'
31
- @platform[:name] = uname_s.lines[0].chomp
32
- @platform[:release] = uname_r.lines[0].chomp
33
-
34
- when /netbsd/
35
- @platform[:family] = 'netbsd'
36
- @platform[:name] = uname_s.lines[0].chomp
37
- @platform[:release] = uname_r.lines[0].chomp
38
-
39
- when /openbsd/
40
- @platform[:family] = 'openbsd'
41
- @platform[:name] = uname_s.lines[0].chomp
42
- @platform[:release] = uname_r.lines[0].chomp
43
-
44
- when /qnx/
45
- @platform[:family] = 'qnx'
46
- @platform[:name] = uname_s.lines[0].chomp.downcase
47
- @platform[:release] = uname_r.lines[0].chomp
48
- @platform[:arch] = uname_m
49
-
50
- when /sunos/
51
- detect_solaris
52
- else
53
- # in all other cases we didn't detect it
54
- return false
55
- end
56
- # when we get here the detection returned a result
57
- true
58
- end
59
-
60
- def detect_solaris # rubocop:disable Metrics/AbcSize, Metrics/PerceivedComplexity
61
- # read specific os name
62
- # DEPRECATED: os[:family] is going to be deprecated, use os.solaris?
63
- rel = get_config('/etc/release')
64
- if /^.*(SmartOS).*$/ =~ rel
65
- @platform[:name] = 'smartos'
66
- @platform[:family] = 'smartos'
67
- elsif !(m = /^\s*(OmniOS).*r(\d+).*$/.match(rel)).nil?
68
- @platform[:name] = 'omnios'
69
- @platform[:family] = 'omnios'
70
- @platform[:release] = m[2]
71
- elsif !(m = /^\s*(OpenIndiana).*oi_(\d+).*$/.match(rel)).nil?
72
- @platform[:name] = 'openindiana'
73
- @platform[:family] = 'openindiana'
74
- @platform[:release] = m[2]
75
- elsif /^\s*(OpenSolaris).*snv_(\d+).*$/ =~ rel
76
- @platform[:name] = 'opensolaris'
77
- @platform[:family] = 'opensolaris'
78
- @platform[:release] = m[2]
79
- elsif !(m = /Oracle Solaris (\d+)/.match(rel)).nil?
80
- # TODO: should be string!
81
- @platform[:release] = m[1]
82
- @platform[:name] = 'solaris'
83
- @platform[:family] = 'solaris'
84
- elsif /^\s*(Solaris)\s.*$/ =~ rel
85
- @platform[:name] = 'solaris'
86
- @platform[:family] = 'solaris'
87
- elsif /^\s*(NexentaCore)\s.*$/ =~ rel
88
- @platform[:name] = 'nexentacore'
89
- @platform[:family] = 'nexentacore'
90
- else
91
- # unknown solaris
92
- @platform[:name] = 'solaris_distro'
93
- @platform[:family] = 'solaris'
94
- end
95
-
96
- # read release version
97
- unless (version = /^5\.(?<release>\d+)$/.match(uname_r)).nil?
98
- @platform[:release] = version['release']
99
- end
100
-
101
- # read architecture
102
- arch = @backend.run_command('uname -p')
103
- @platform[:arch] = arch.stdout.chomp if arch.exit_status == 0
104
- end
105
- end
106
- end