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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +26 -2
- data/lib/train.rb +1 -0
- data/lib/train/errors.rb +6 -0
- data/lib/train/extras.rb +0 -1
- data/lib/train/platforms.rb +82 -0
- data/lib/train/platforms/common.rb +34 -0
- data/lib/train/platforms/detect.rb +12 -0
- data/lib/train/platforms/detect/helpers/os_common.rb +56 -0
- data/lib/train/platforms/detect/helpers/os_linux.rb +75 -0
- data/lib/train/{extras/os_detect_windows.rb → platforms/detect/helpers/os_windows.rb} +3 -10
- data/lib/train/platforms/detect/scanner.rb +84 -0
- data/lib/train/platforms/detect/specifications/os.rb +480 -0
- data/lib/train/platforms/family.rb +26 -0
- data/lib/train/platforms/platform.rb +80 -0
- data/lib/train/plugins/base_connection.rb +75 -27
- data/lib/train/transports/docker.rb +17 -28
- data/lib/train/transports/local.rb +21 -22
- data/lib/train/transports/mock.rb +44 -30
- data/lib/train/transports/ssh_connection.rb +55 -67
- data/lib/train/transports/winrm_connection.rb +16 -26
- data/lib/train/version.rb +1 -1
- data/test/unit/file/remote/linux_test.rb +2 -2
- data/test/unit/platforms/detect/os_common_test.rb +85 -0
- data/test/unit/platforms/detect/os_linux_test.rb +124 -0
- data/test/unit/{extras/os_detect_windows_test.rb → platforms/detect/os_windows_test.rb} +5 -2
- data/test/unit/platforms/detect/scanner_test.rb +61 -0
- data/test/unit/platforms/family_test.rb +32 -0
- data/test/unit/platforms/os_detect_test.rb +175 -0
- data/test/unit/{extras/os_common_test.rb → platforms/platform_test.rb} +103 -18
- data/test/unit/platforms/platforms_test.rb +42 -0
- data/test/unit/plugins/connection_test.rb +106 -8
- data/test/unit/transports/local_test.rb +20 -15
- data/test/unit/transports/mock_test.rb +16 -6
- data/test/unit/transports/ssh_test.rb +17 -15
- metadata +28 -19
- data/lib/train/extras/linux_lsb.rb +0 -60
- data/lib/train/extras/os_common.rb +0 -151
- data/lib/train/extras/os_detect_arista_eos.rb +0 -34
- data/lib/train/extras/os_detect_darwin.rb +0 -40
- data/lib/train/extras/os_detect_esx.rb +0 -22
- data/lib/train/extras/os_detect_linux.rb +0 -164
- data/lib/train/extras/os_detect_openvms.rb +0 -29
- data/lib/train/extras/os_detect_unix.rb +0 -106
- data/lib/train/extras/uname.rb +0 -28
- data/lib/train/transports/local_os.rb +0 -51
- data/test/unit/extras/os_detect_linux_test.rb +0 -230
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0e4971c8f699dbb772e9eb5532fa2de1771de4a5
|
4
|
+
data.tar.gz: 40bf72dd2c53b33379c256b4a4f4acc42dc46efd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3c5fdd0a5d53e68d3eb928d5e9ddcbcaea5a8c3fa39b57d7aa3a20f7135f4436d78e334e4d93b3ce1e8f2fd2a3310462d10ae4099899372bd4f4fbd6309af4e4
|
7
|
+
data.tar.gz: db6f8f5c82f459a9f78c60cf758aaad8c4877e5adee714add3e060e5328c85a4275ef3502aae0525d80a49b0100b92fea2345f5f493fddf2ecc766954dae9c44
|
data/CHANGELOG.md
CHANGED
@@ -1,10 +1,34 @@
|
|
1
1
|
# Change Log
|
2
2
|
|
3
|
-
## [0.
|
4
|
-
[Full Changelog](https://github.com/chef/train/compare/v0.29.
|
3
|
+
## [0.30.0](https://github.com/chef/train/tree/0.30.0) (2017-12-04)
|
4
|
+
[Full Changelog](https://github.com/chef/train/compare/v0.29.2...0.30.0)
|
5
5
|
|
6
6
|
**Merged pull requests:**
|
7
7
|
|
8
|
+
- Change the mock transport name to be 'mock' [\#221](https://github.com/chef/train/pull/221) ([jquick](https://github.com/jquick))
|
9
|
+
- Enable caching on connections [\#214](https://github.com/chef/train/pull/214) ([jquick](https://github.com/jquick))
|
10
|
+
|
11
|
+
## [v0.29.2](https://github.com/chef/train/tree/v0.29.2) (2017-11-21)
|
12
|
+
[Full Changelog](https://github.com/chef/train/compare/v0.29.1...v0.29.2)
|
13
|
+
|
14
|
+
**Fixed bugs:**
|
15
|
+
|
16
|
+
- Add unix\_mode\_mask method to Train::File::Local::Unix [\#215](https://github.com/chef/train/pull/215) ([adamleff](https://github.com/adamleff))
|
17
|
+
|
18
|
+
**Merged pull requests:**
|
19
|
+
|
20
|
+
- Fix regressions in 0.29.1 [\#219](https://github.com/chef/train/pull/219) ([adamleff](https://github.com/adamleff))
|
21
|
+
- Use the sanitized file path for remote linux files [\#218](https://github.com/chef/train/pull/218) ([RoboticCheese](https://github.com/RoboticCheese))
|
22
|
+
- Remove bundler install during Appveyor tests [\#217](https://github.com/chef/train/pull/217) ([adamleff](https://github.com/adamleff))
|
23
|
+
- Fix inspec mock tests [\#216](https://github.com/chef/train/pull/216) ([jquick](https://github.com/jquick))
|
24
|
+
- Platform framework and detect DSL [\#209](https://github.com/chef/train/pull/209) ([jquick](https://github.com/jquick))
|
25
|
+
|
26
|
+
## [v0.29.1](https://github.com/chef/train/tree/v0.29.1) (2017-11-13)
|
27
|
+
[Full Changelog](https://github.com/chef/train/compare/v0.29.0...v0.29.1)
|
28
|
+
|
29
|
+
**Merged pull requests:**
|
30
|
+
|
31
|
+
- Release 0.29.1 [\#213](https://github.com/chef/train/pull/213) ([adamleff](https://github.com/adamleff))
|
8
32
|
- Allow for a nil value when mocking OS [\#212](https://github.com/chef/train/pull/212) ([adamleff](https://github.com/adamleff))
|
9
33
|
- Ensure a `mounted?` method exists for all File classes, including Mock [\#211](https://github.com/chef/train/pull/211) ([adamleff](https://github.com/adamleff))
|
10
34
|
|
data/lib/train.rb
CHANGED
data/lib/train/errors.rb
CHANGED
@@ -20,4 +20,10 @@ module Train
|
|
20
20
|
# Base exception class for all exceptions that are caused by other failures
|
21
21
|
# in the transport layer.
|
22
22
|
class TransportError < ::StandardError; end
|
23
|
+
|
24
|
+
# Exception for when no platform can be detected.
|
25
|
+
class PlatformDetectionFailed < ::StandardError; end
|
26
|
+
|
27
|
+
# Exception for when a invalid cache type is passed.
|
28
|
+
class UnknownCacheType < ::StandardError; end
|
23
29
|
end
|
data/lib/train/extras.rb
CHANGED
@@ -0,0 +1,82 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'train/platforms/common'
|
4
|
+
require 'train/platforms/family'
|
5
|
+
require 'train/platforms/platform'
|
6
|
+
require 'train/platforms/detect'
|
7
|
+
require 'train/platforms/detect/scanner'
|
8
|
+
require 'train/platforms/detect/specifications/os'
|
9
|
+
|
10
|
+
module Train::Platforms
|
11
|
+
class << self
|
12
|
+
# Retrieve the current platform list
|
13
|
+
#
|
14
|
+
# @return [Hash] map with platform names and their objects
|
15
|
+
def list
|
16
|
+
@list ||= {}
|
17
|
+
end
|
18
|
+
|
19
|
+
# Retrieve the current family list
|
20
|
+
#
|
21
|
+
# @return [Hash] map with family names and their objects
|
22
|
+
def families
|
23
|
+
@families ||= {}
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# Create or update a platform
|
28
|
+
#
|
29
|
+
# @return Train::Platform
|
30
|
+
def self.name(name, condition = {})
|
31
|
+
# Check the list to see if one is already created
|
32
|
+
plat = list[name]
|
33
|
+
unless plat.nil?
|
34
|
+
# Pass the condition incase we are adding a family relationship
|
35
|
+
plat.condition = condition unless condition.nil?
|
36
|
+
return plat
|
37
|
+
end
|
38
|
+
|
39
|
+
Train::Platforms::Platform.new(name, condition)
|
40
|
+
end
|
41
|
+
|
42
|
+
# Create or update a family
|
43
|
+
#
|
44
|
+
# @return Train::Platforms::Family
|
45
|
+
def self.family(name, condition = {})
|
46
|
+
# Check the families to see if one is already created
|
47
|
+
family = families[name]
|
48
|
+
unless family.nil?
|
49
|
+
# Pass the condition incase we are adding a family relationship
|
50
|
+
family.condition = condition unless condition.nil?
|
51
|
+
return family
|
52
|
+
end
|
53
|
+
|
54
|
+
Train::Platforms::Family.new(name, condition)
|
55
|
+
end
|
56
|
+
|
57
|
+
# Find the families or top level platforms
|
58
|
+
#
|
59
|
+
# @return [Hash] with top level family and platforms
|
60
|
+
def self.top_platforms
|
61
|
+
top_platforms = list.select { |_key, value| value.families.empty? }
|
62
|
+
top_platforms.merge!(families.select { |_key, value| value.families.empty? })
|
63
|
+
top_platforms
|
64
|
+
end
|
65
|
+
|
66
|
+
# List all platforms and families in a readable output
|
67
|
+
def self.list_all
|
68
|
+
top_platforms = self.top_platforms
|
69
|
+
top_platforms.each_value do |platform|
|
70
|
+
puts platform.title
|
71
|
+
print_children(platform) if defined?(platform.children)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def self.print_children(parent, pad = 2)
|
76
|
+
parent.children.each do |key, value|
|
77
|
+
obj = key
|
78
|
+
puts "#{' ' * pad}-> #{obj.title}#{value unless value.empty?}"
|
79
|
+
print_children(obj, pad + 2) if defined?(obj.children) && !obj.children.nil?
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Train::Platforms
|
4
|
+
module Common
|
5
|
+
# Add a family connection. This will create a family
|
6
|
+
# if it does not exist and add a child relationship.
|
7
|
+
def in_family(family)
|
8
|
+
if self.class == Train::Platforms::Family && @name == family
|
9
|
+
fail "Unable to add family #{@name} to itself: '#{@name}.in_family(#{family})'"
|
10
|
+
end
|
11
|
+
|
12
|
+
# add family to the family list
|
13
|
+
family = Train::Platforms.family(family)
|
14
|
+
family.children[self] = @condition
|
15
|
+
|
16
|
+
@families[family] = @condition
|
17
|
+
@condition = nil
|
18
|
+
self
|
19
|
+
end
|
20
|
+
|
21
|
+
def detect(&block)
|
22
|
+
if block_given?
|
23
|
+
@detect = block
|
24
|
+
self
|
25
|
+
elsif @detect.nil?
|
26
|
+
# we are returning a block that just returns false here
|
27
|
+
# to skip the family/platform evaluation if detect is not set
|
28
|
+
->(_) { false }
|
29
|
+
else
|
30
|
+
@detect
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'train/platforms/detect/helpers/os_linux'
|
4
|
+
require 'train/platforms/detect/helpers/os_windows'
|
5
|
+
require 'rbconfig'
|
6
|
+
|
7
|
+
module Train::Platforms::Detect::Helpers
|
8
|
+
module OSCommon
|
9
|
+
include Train::Platforms::Detect::Helpers::Linux
|
10
|
+
include Train::Platforms::Detect::Helpers::Windows
|
11
|
+
|
12
|
+
def ruby_host_os(regex)
|
13
|
+
::RbConfig::CONFIG['host_os'] =~ regex
|
14
|
+
end
|
15
|
+
|
16
|
+
def winrm?
|
17
|
+
Object.const_defined?('Train::Transports::WinRM::Connection') &&
|
18
|
+
@backend.class == Train::Transports::WinRM::Connection
|
19
|
+
end
|
20
|
+
|
21
|
+
def unix_file_contents(path)
|
22
|
+
# keep a log of files incase multiple checks call the same one
|
23
|
+
return @files[path] if @files.key?(path)
|
24
|
+
|
25
|
+
res = @backend.run_command("test -f #{path} && cat #{path}")
|
26
|
+
# ignore files that can't be read
|
27
|
+
@files[path] = res.exit_status.zero? ? res.stdout : nil
|
28
|
+
@files[path]
|
29
|
+
end
|
30
|
+
|
31
|
+
def unix_file_exist?(path)
|
32
|
+
@backend.run_command("test -f #{path}").exit_status.zero?
|
33
|
+
end
|
34
|
+
|
35
|
+
def command_output(cmd)
|
36
|
+
res = @backend.run_command(cmd).stdout
|
37
|
+
res.strip! unless res.nil?
|
38
|
+
res
|
39
|
+
end
|
40
|
+
|
41
|
+
def unix_uname_s
|
42
|
+
return @uname[:s] if @uname.key?(:s)
|
43
|
+
@uname[:s] = command_output('uname -s')
|
44
|
+
end
|
45
|
+
|
46
|
+
def unix_uname_r
|
47
|
+
return @uname[:r] if @uname.key?(:r)
|
48
|
+
@uname[:r] = command_output('uname -r')
|
49
|
+
end
|
50
|
+
|
51
|
+
def unix_uname_m
|
52
|
+
return @uname[:m] if @uname.key?(:m)
|
53
|
+
@uname[:m] = command_output('uname -m')
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Train::Platforms::Detect::Helpers
|
4
|
+
module Linux
|
5
|
+
def redhatish_platform(conf)
|
6
|
+
conf =~ /^red hat/i ? 'redhat' : /(\w+)/i.match(conf)[1].downcase
|
7
|
+
end
|
8
|
+
|
9
|
+
def redhatish_version(conf)
|
10
|
+
case conf
|
11
|
+
when /rawhide/i
|
12
|
+
/((\d+) \(Rawhide\))/i.match(conf)[1].downcase
|
13
|
+
when /derived from .*linux/i
|
14
|
+
/Linux ((\d+|\.)+)/i.match(conf)[1]
|
15
|
+
else
|
16
|
+
/release ([\d\.]+)/.match(conf)[1]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def linux_os_release
|
21
|
+
data = unix_file_contents('/etc/os-release')
|
22
|
+
return if data.nil?
|
23
|
+
|
24
|
+
os_info = parse_os_release_info(data)
|
25
|
+
cisco_info_file = os_info['CISCO_RELEASE_INFO']
|
26
|
+
if cisco_info_file
|
27
|
+
os_info.merge!(parse_os_release_info(unix_file_contents(cisco_info_file)))
|
28
|
+
end
|
29
|
+
|
30
|
+
os_info
|
31
|
+
end
|
32
|
+
|
33
|
+
def parse_os_release_info(raw)
|
34
|
+
return {} if raw.nil?
|
35
|
+
|
36
|
+
raw.lines.each_with_object({}) do |line, memo|
|
37
|
+
line.strip!
|
38
|
+
next if line.empty?
|
39
|
+
key, value = line.split('=', 2)
|
40
|
+
memo[key] = value.gsub(/\A"|"\Z/, '') unless value.empty?
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def lsb_config(content)
|
45
|
+
id = /^DISTRIB_ID=["']?(.+?)["']?$/.match(content)
|
46
|
+
release = /^DISTRIB_RELEASE=["']?(.+?)["']?$/.match(content)
|
47
|
+
codename = /^DISTRIB_CODENAME=["']?(.+?)["']?$/.match(content)
|
48
|
+
{
|
49
|
+
id: id.nil? ? nil : id[1],
|
50
|
+
release: release.nil? ? nil : release[1],
|
51
|
+
codename: codename.nil? ? nil : codename[1],
|
52
|
+
}
|
53
|
+
end
|
54
|
+
|
55
|
+
def lsb_release(content)
|
56
|
+
id = /^Distributor ID:\s+(.+)$/.match(content)
|
57
|
+
release = /^Release:\s+(.+)$/.match(content)
|
58
|
+
codename = /^Codename:\s+(.+)$/.match(content)
|
59
|
+
{
|
60
|
+
id: id.nil? ? nil : id[1],
|
61
|
+
release: release.nil? ? nil : release[1],
|
62
|
+
codename: codename.nil? ? nil : codename[1],
|
63
|
+
}
|
64
|
+
end
|
65
|
+
|
66
|
+
def read_linux_lsb
|
67
|
+
return @lsb unless @lsb.empty?
|
68
|
+
if !(raw = unix_file_contents('/etc/lsb-release')).nil?
|
69
|
+
@lsb = lsb_config(raw)
|
70
|
+
elsif !(raw = unix_file_contents('/usr/bin/lsb-release')).nil?
|
71
|
+
@lsb = lsb_release(raw)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -1,14 +1,7 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
# This is heavily based on:
|
6
|
-
#
|
7
|
-
# OHAI https://github.com/chef/ohai
|
8
|
-
# by Adam Jacob, Chef Software Inc
|
9
|
-
#
|
10
|
-
module Train::Extras
|
11
|
-
module DetectWindows
|
2
|
+
|
3
|
+
module Train::Platforms::Detect::Helpers
|
4
|
+
module Windows
|
12
5
|
def detect_windows
|
13
6
|
res = @backend.run_command('cmd /c ver')
|
14
7
|
return false if res.exit_status != 0 or res.stdout.empty?
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'train/platforms/detect/helpers/os_common'
|
4
|
+
|
5
|
+
module Train::Platforms::Detect
|
6
|
+
class Scanner
|
7
|
+
include Train::Platforms::Detect::Helpers::OSCommon
|
8
|
+
|
9
|
+
def initialize(backend)
|
10
|
+
@backend = backend
|
11
|
+
@platform = {}
|
12
|
+
@family_hierarchy = []
|
13
|
+
|
14
|
+
# detect cache variables
|
15
|
+
@files = {}
|
16
|
+
@uname = {}
|
17
|
+
@lsb = {}
|
18
|
+
end
|
19
|
+
|
20
|
+
# Main detect method to scan all platforms for a match
|
21
|
+
#
|
22
|
+
# @return Train::Platform instance or error if none found
|
23
|
+
def scan
|
24
|
+
# start with the platform/families who have no families (the top levels)
|
25
|
+
top = Train::Platforms.top_platforms
|
26
|
+
top.each do |_name, plat|
|
27
|
+
# we are doing a instance_eval here to make sure we have the proper
|
28
|
+
# context with all the detect helper methods
|
29
|
+
next unless instance_eval(&plat.detect) == true
|
30
|
+
|
31
|
+
# if we have a match start looking at the children
|
32
|
+
plat_result = scan_children(plat)
|
33
|
+
next if plat_result.nil?
|
34
|
+
|
35
|
+
# return platform to backend
|
36
|
+
@family_hierarchy << plat.name
|
37
|
+
return get_platform(plat_result)
|
38
|
+
end
|
39
|
+
|
40
|
+
fail Train::PlatformDetectionFailed, 'Sorry, we are unable to detect your platform'
|
41
|
+
end
|
42
|
+
|
43
|
+
def scan_children(parent)
|
44
|
+
parent.children.each do |plat, condition|
|
45
|
+
next unless instance_eval(&plat.detect) == true
|
46
|
+
|
47
|
+
if plat.class == Train::Platforms::Platform
|
48
|
+
@platform[:family] = parent.name
|
49
|
+
return plat if condition.empty? || check_condition(condition)
|
50
|
+
elsif plat.class == Train::Platforms::Family
|
51
|
+
plat = scan_family_children(plat)
|
52
|
+
return plat unless plat.nil?
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
nil
|
57
|
+
end
|
58
|
+
|
59
|
+
def scan_family_children(plat)
|
60
|
+
child_result = scan_children(plat) unless plat.children.nil?
|
61
|
+
return if child_result.nil?
|
62
|
+
@family_hierarchy << plat.name
|
63
|
+
child_result
|
64
|
+
end
|
65
|
+
|
66
|
+
def check_condition(condition)
|
67
|
+
condition.each do |k, v|
|
68
|
+
op, expected = v.strip.split(' ')
|
69
|
+
op = '==' if op == '='
|
70
|
+
return false if @platform[k].nil? || !instance_eval("'#{@platform[k]}' #{op} '#{expected}'")
|
71
|
+
end
|
72
|
+
|
73
|
+
true
|
74
|
+
end
|
75
|
+
|
76
|
+
def get_platform(plat)
|
77
|
+
plat.backend = @backend
|
78
|
+
plat.platform = @platform
|
79
|
+
plat.add_platform_methods
|
80
|
+
plat.family_hierarchy = @family_hierarchy
|
81
|
+
plat
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|