train 0.29.2 → 0.30.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 (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