train 2.1.13 → 2.1.19
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/lib/train.rb +5 -3
- data/lib/train/extras/command_wrapper.rb +2 -0
- data/lib/train/extras/stat.rb +5 -1
- data/lib/train/file/local.rb +2 -0
- data/lib/train/file/local/windows.rb +8 -3
- data/lib/train/file/remote.rb +4 -0
- data/lib/train/file/remote/aix.rb +2 -0
- data/lib/train/file/remote/linux.rb +2 -0
- data/lib/train/file/remote/unix.rb +3 -1
- data/lib/train/file/remote/windows.rb +17 -5
- data/lib/train/options.rb +6 -5
- data/lib/train/platforms.rb +22 -22
- data/lib/train/platforms/detect/helpers/os_common.rb +9 -1
- data/lib/train/platforms/detect/helpers/os_linux.rb +2 -0
- data/lib/train/platforms/detect/helpers/os_windows.rb +8 -3
- data/lib/train/platforms/detect/scanner.rb +1 -0
- data/lib/train/platforms/detect/specifications/os.rb +395 -391
- data/lib/train/platforms/family.rb +5 -0
- data/lib/train/platforms/platform.rb +8 -6
- data/lib/train/plugins.rb +3 -3
- data/lib/train/plugins/base_connection.rb +6 -0
- data/lib/train/transports/cisco_ios_connection.rb +2 -0
- data/lib/train/transports/docker.rb +2 -1
- data/lib/train/transports/gcp.rb +1 -0
- data/lib/train/transports/helpers/azure/file_credentials.rb +1 -0
- data/lib/train/transports/local.rb +1 -1
- data/lib/train/transports/mock.rb +5 -3
- data/lib/train/transports/ssh.rb +1 -1
- data/lib/train/transports/ssh_connection.rb +2 -0
- data/lib/train/transports/winrm.rb +1 -1
- data/lib/train/transports/winrm_connection.rb +4 -2
- data/lib/train/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f4262fbc901f2d107019887434f1aade83d2341d8bbf113296a6bd5d72b1fc4d
|
4
|
+
data.tar.gz: ab8130c7b17d3bb245fdad4d1e5419b1325df364bdaecdc62c34ddbba27d3b8a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 95f034184039cecf0bf4d78b02b65bed306ee46d953b25f6870fbbd58e65eebd71dcb3ebfd9381c1287322bfada1fd0d8a3d44be57275e6748fb8be9e6a744f6
|
7
|
+
data.tar.gz: 86bddfca26a15768245310f82814fdebb80cbfa0609530bf587cbc82b9edf95857fa1d6de4bd2f89283f197a16b965692ce84ef20fd4fa54a4b3b45d61edc712
|
data/lib/train.rb
CHANGED
@@ -76,6 +76,7 @@ module Train
|
|
76
76
|
|
77
77
|
group_keys_and_keyfiles(conf) # TODO: move logic into SSH plugin
|
78
78
|
return conf if conf[:target].to_s.empty?
|
79
|
+
|
79
80
|
unpack_target_from_uri(conf[:target], conf).merge(conf)
|
80
81
|
end
|
81
82
|
|
@@ -146,6 +147,7 @@ module Train
|
|
146
147
|
# TODO: this actually does no validation of the credential options whatsoever
|
147
148
|
def self.validate_backend(credentials, default_transport_name = "local")
|
148
149
|
return default_transport_name if credentials.nil?
|
150
|
+
|
149
151
|
transport_name = credentials[:backend]
|
150
152
|
|
151
153
|
# TODO: Determine if it is ever possible (or supported) for transport_name to be 'localhost'
|
@@ -155,16 +157,16 @@ module Train
|
|
155
157
|
"To run this locally with elevated privileges, run the command with `sudo ...`."
|
156
158
|
end
|
157
159
|
|
158
|
-
return transport_name
|
160
|
+
return transport_name unless transport_name.nil?
|
159
161
|
|
160
|
-
|
162
|
+
unless credentials[:target].nil?
|
161
163
|
# We should not get here, because if target_uri unpacking was successful,
|
162
164
|
# it would have set credentials[:backend]
|
163
165
|
raise Train::UserError, "Cannot determine backend from target "\
|
164
166
|
"configuration #{credentials[:target]}. Valid example: ssh://192.168.0.1"
|
165
167
|
end
|
166
168
|
|
167
|
-
|
169
|
+
unless credentials[:host].nil?
|
168
170
|
raise Train::UserError, "Host configured, but no backend was provided. Please "\
|
169
171
|
"specify how you want to connect. Valid example: ssh://192.168.0.1"
|
170
172
|
end
|
@@ -55,6 +55,7 @@ module Train::Extras
|
|
55
55
|
def verify
|
56
56
|
res = @backend.run_command(run("echo"))
|
57
57
|
return nil if res.exit_status == 0
|
58
|
+
|
58
59
|
rawerr = res.stdout + " " + res.stderr
|
59
60
|
|
60
61
|
{
|
@@ -164,6 +165,7 @@ module Train::Extras
|
|
164
165
|
def self.load(transport, options)
|
165
166
|
if transport.platform.unix?
|
166
167
|
return nil unless LinuxCommand.active?(options)
|
168
|
+
|
167
169
|
res = LinuxCommand.new(transport, options)
|
168
170
|
verification_res = res.verify
|
169
171
|
if verification_res
|
data/lib/train/extras/stat.rb
CHANGED
@@ -26,6 +26,7 @@ module Train::Extras
|
|
26
26
|
return bsd_stat(shell_escaped_path, backend, follow_symlink) if backend.os.bsd?
|
27
27
|
# linux,solaris 11 and esx will use standard linux stats
|
28
28
|
return linux_stat(shell_escaped_path, backend, follow_symlink) if backend.os.unix? || backend.os.esx?
|
29
|
+
|
29
30
|
# all other cases we don't handle
|
30
31
|
# TODO: print an error if we get here, as it shouldn't be invoked
|
31
32
|
# on non-unix
|
@@ -77,7 +78,8 @@ module Train::Extras
|
|
77
78
|
lstat = follow_symlink ? " -L" : ""
|
78
79
|
res = backend.run_command(
|
79
80
|
"stat#{lstat} -f '%z\n%p\n%Su\n%u\n%Sg\n%g\n%a\n%m' "\
|
80
|
-
"#{shell_escaped_path}"
|
81
|
+
"#{shell_escaped_path}"
|
82
|
+
)
|
81
83
|
|
82
84
|
return {} if res.exit_status != 0
|
83
85
|
|
@@ -113,8 +115,10 @@ module Train::Extras
|
|
113
115
|
|
114
116
|
res = backend.run_command(stat_cmd)
|
115
117
|
return {} if res.exit_status != 0
|
118
|
+
|
116
119
|
fields = res.stdout.split("\n")
|
117
120
|
return {} if fields.length != 7
|
121
|
+
|
118
122
|
tmask = fields[0].to_i(8)
|
119
123
|
{
|
120
124
|
type: find_type(tmask),
|
data/lib/train/file/local.rb
CHANGED
@@ -19,6 +19,7 @@ module Train
|
|
19
19
|
|
20
20
|
def link_path
|
21
21
|
return nil unless symlink?
|
22
|
+
|
22
23
|
begin
|
23
24
|
@link_path ||= ::File.realpath(@path)
|
24
25
|
rescue Errno::ELOOP => _
|
@@ -29,6 +30,7 @@ module Train
|
|
29
30
|
|
30
31
|
def shallow_link_path
|
31
32
|
return nil unless symlink?
|
33
|
+
|
32
34
|
@link_path ||= ::File.readlink(@path)
|
33
35
|
end
|
34
36
|
|
@@ -8,24 +8,29 @@ module Train
|
|
8
8
|
# @see https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx#naming_conventions
|
9
9
|
def sanitize_filename(path)
|
10
10
|
return if path.nil?
|
11
|
+
|
11
12
|
# we do not filter :, backslash and forward slash, since they are part of the path
|
12
13
|
@spath = path.gsub(/[<>"|?*]/, "")
|
13
14
|
end
|
14
15
|
|
15
16
|
def product_version
|
16
17
|
@product_version ||= @backend.run_command(
|
17
|
-
"[System.Diagnostics.FileVersionInfo]::GetVersionInfo(\"#{@spath}\").ProductVersion"
|
18
|
+
"[System.Diagnostics.FileVersionInfo]::GetVersionInfo(\"#{@spath}\").ProductVersion"
|
19
|
+
).stdout.chomp
|
18
20
|
end
|
19
21
|
|
20
22
|
def file_version
|
21
23
|
@file_version ||= @backend.run_command(
|
22
|
-
"[System.Diagnostics.FileVersionInfo]::GetVersionInfo(\"#{@spath}\").FileVersion"
|
24
|
+
"[System.Diagnostics.FileVersionInfo]::GetVersionInfo(\"#{@spath}\").FileVersion"
|
25
|
+
).stdout.chomp
|
23
26
|
end
|
24
27
|
|
25
28
|
def owner
|
26
29
|
owner = @backend.run_command(
|
27
|
-
"Get-Acl \"#{@spath}\" | select -expand Owner"
|
30
|
+
"Get-Acl \"#{@spath}\" | select -expand Owner"
|
31
|
+
).stdout.strip
|
28
32
|
return if owner.empty?
|
33
|
+
|
29
34
|
owner
|
30
35
|
end
|
31
36
|
|
data/lib/train/file/remote.rb
CHANGED
@@ -5,11 +5,13 @@ module Train
|
|
5
5
|
class Remote < Train::File
|
6
6
|
def basename(suffix = nil, sep = "/")
|
7
7
|
raise "Not yet supported: Suffix in file.basename" unless suffix.nil?
|
8
|
+
|
8
9
|
@basename ||= detect_filename(path, sep || "/")
|
9
10
|
end
|
10
11
|
|
11
12
|
def stat
|
12
13
|
return @stat if defined?(@stat)
|
14
|
+
|
13
15
|
@stat = Train::Extras::Stat.stat(@spath, @backend, @follow_symlink)
|
14
16
|
end
|
15
17
|
|
@@ -19,8 +21,10 @@ module Train
|
|
19
21
|
def detect_filename(path, sep)
|
20
22
|
idx = path.rindex(sep)
|
21
23
|
return path if idx.nil?
|
24
|
+
|
22
25
|
idx += 1
|
23
26
|
return detect_filename(path[0..-2], sep) if idx == path.length
|
27
|
+
|
24
28
|
path[idx..-1]
|
25
29
|
end
|
26
30
|
end
|
@@ -8,12 +8,14 @@ module Train
|
|
8
8
|
class Aix < Train::File::Remote::Unix
|
9
9
|
def link_path
|
10
10
|
return nil unless symlink?
|
11
|
+
|
11
12
|
@link_path ||=
|
12
13
|
@backend.run_command("perl -e 'print readlink shift' #{@spath}").stdout.chomp
|
13
14
|
end
|
14
15
|
|
15
16
|
def shallow_link_path
|
16
17
|
return nil unless symlink?
|
18
|
+
|
17
19
|
@shallow_link_path ||=
|
18
20
|
@backend.run_command("perl -e 'print readlink shift' #{@spath}").stdout.chomp
|
19
21
|
end
|
@@ -8,8 +8,10 @@ module Train
|
|
8
8
|
class Linux < Train::File::Remote::Unix
|
9
9
|
def content
|
10
10
|
return @content if defined?(@content)
|
11
|
+
|
11
12
|
@content = @backend.run_command("cat #{@spath} || echo -n").stdout
|
12
13
|
return @content unless @content.empty?
|
14
|
+
|
13
15
|
@content = nil if directory? || size.nil? || (size > 0)
|
14
16
|
@content
|
15
17
|
end
|
@@ -23,7 +23,7 @@ module Train
|
|
23
23
|
@exist ||= begin
|
24
24
|
f = @follow_symlink ? "" : " || test -L #{@spath}"
|
25
25
|
@backend.run_command("test -e #{@spath}" + f)
|
26
|
-
|
26
|
+
.exit_status == 0
|
27
27
|
end
|
28
28
|
end
|
29
29
|
|
@@ -58,6 +58,7 @@ module Train
|
|
58
58
|
|
59
59
|
def shallow_link_path
|
60
60
|
return nil unless symlink?
|
61
|
+
|
61
62
|
@shallow_link_path ||=
|
62
63
|
@backend.run_command("readlink #{@spath}").stdout.chomp
|
63
64
|
end
|
@@ -74,6 +75,7 @@ module Train
|
|
74
75
|
|
75
76
|
def path
|
76
77
|
return @path unless @follow_symlink && symlink?
|
78
|
+
|
77
79
|
@link_path ||= read_target_path
|
78
80
|
end
|
79
81
|
|
@@ -9,6 +9,7 @@ module Train
|
|
9
9
|
# @see https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx#naming_conventions
|
10
10
|
def sanitize_filename(path)
|
11
11
|
return if path.nil?
|
12
|
+
|
12
13
|
# we do not filter :, backslash and forward slash, since they are part of the path
|
13
14
|
@spath = path.gsub(/[<>"|?*]/, "")
|
14
15
|
end
|
@@ -19,22 +20,28 @@ module Train
|
|
19
20
|
|
20
21
|
def content
|
21
22
|
return @content if defined?(@content)
|
23
|
+
|
22
24
|
@content = @backend.run_command("Get-Content(\"#{@spath}\") | Out-String").stdout
|
23
25
|
return @content unless @content.empty?
|
26
|
+
|
24
27
|
@content = nil if directory? # or size.nil? or size > 0
|
25
28
|
@content
|
26
29
|
end
|
27
30
|
|
28
31
|
def exist?
|
29
32
|
return @exist if defined?(@exist)
|
33
|
+
|
30
34
|
@exist = @backend.run_command(
|
31
|
-
"(Test-Path -Path \"#{@spath}\").ToString()"
|
35
|
+
"(Test-Path -Path \"#{@spath}\").ToString()"
|
36
|
+
).stdout.chomp == "True"
|
32
37
|
end
|
33
38
|
|
34
39
|
def owner
|
35
40
|
owner = @backend.run_command(
|
36
|
-
"Get-Acl \"#{@spath}\" | select -expand Owner"
|
41
|
+
"Get-Acl \"#{@spath}\" | select -expand Owner"
|
42
|
+
).stdout.strip
|
37
43
|
return if owner.empty?
|
44
|
+
|
38
45
|
owner
|
39
46
|
end
|
40
47
|
|
@@ -46,6 +53,7 @@ module Train
|
|
46
53
|
elsif attributes.include?("Directory")
|
47
54
|
return :directory
|
48
55
|
end
|
56
|
+
|
49
57
|
:unknown
|
50
58
|
end
|
51
59
|
|
@@ -57,12 +65,14 @@ module Train
|
|
57
65
|
|
58
66
|
def product_version
|
59
67
|
@product_version ||= @backend.run_command(
|
60
|
-
"[System.Diagnostics.FileVersionInfo]::GetVersionInfo(\"#{@spath}\").ProductVersion"
|
68
|
+
"[System.Diagnostics.FileVersionInfo]::GetVersionInfo(\"#{@spath}\").ProductVersion"
|
69
|
+
).stdout.chomp
|
61
70
|
end
|
62
71
|
|
63
72
|
def file_version
|
64
73
|
@file_version ||= @backend.run_command(
|
65
|
-
"[System.Diagnostics.FileVersionInfo]::GetVersionInfo(\"#{@spath}\").FileVersion"
|
74
|
+
"[System.Diagnostics.FileVersionInfo]::GetVersionInfo(\"#{@spath}\").FileVersion"
|
75
|
+
).stdout.chomp
|
66
76
|
end
|
67
77
|
|
68
78
|
%w{
|
@@ -89,8 +99,10 @@ module Train
|
|
89
99
|
|
90
100
|
def attributes
|
91
101
|
return @attributes if defined?(@attributes)
|
102
|
+
|
92
103
|
@attributes = @backend.run_command(
|
93
|
-
"(Get-ItemProperty -Path \"#{@spath}\").attributes.ToString()"
|
104
|
+
"(Get-ItemProperty -Path \"#{@spath}\").attributes.ToString()"
|
105
|
+
).stdout.chomp.split(/\s*,\s*/)
|
94
106
|
end
|
95
107
|
end
|
96
108
|
end
|
data/lib/train/options.rb
CHANGED
@@ -15,14 +15,14 @@ module Train
|
|
15
15
|
d = conf || {}
|
16
16
|
unless d.is_a? Hash
|
17
17
|
raise Train::ClientError,
|
18
|
-
|
19
|
-
|
18
|
+
"The transport plugin #{self} declared an option #{name} "\
|
19
|
+
"and didn't provide a valid configuration hash."
|
20
20
|
end
|
21
21
|
|
22
22
|
if !conf.nil? && !conf[:default].nil? && block_given?
|
23
23
|
raise Train::ClientError,
|
24
|
-
|
25
|
-
|
24
|
+
"The transport plugin #{self} declared an option #{name} "\
|
25
|
+
"with both a default value and block. Only use one of these."
|
26
26
|
end
|
27
27
|
|
28
28
|
d[:default] = block if block_given?
|
@@ -56,6 +56,7 @@ module Train
|
|
56
56
|
res = base.merge(opts || {})
|
57
57
|
default_options.each do |field, hm|
|
58
58
|
next unless res[field].nil? && hm.key?(:default)
|
59
|
+
|
59
60
|
default = hm[:default]
|
60
61
|
if default.is_a? Proc
|
61
62
|
res[field] = default.call(res)
|
@@ -70,7 +71,7 @@ module Train
|
|
70
71
|
default_options.each do |field, hm|
|
71
72
|
if opts[field].nil? && hm[:required]
|
72
73
|
raise Train::ClientError,
|
73
|
-
|
74
|
+
"You must provide a value for #{field.to_s.inspect}."
|
74
75
|
end
|
75
76
|
end
|
76
77
|
opts
|
data/lib/train/platforms.rb
CHANGED
@@ -10,32 +10,31 @@ require "train/platforms/family"
|
|
10
10
|
require "train/platforms/platform"
|
11
11
|
|
12
12
|
module Train::Platforms
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
end
|
13
|
+
# Retrieve the current platform list
|
14
|
+
#
|
15
|
+
# @return [Hash] map with platform names and their objects
|
16
|
+
def self.list
|
17
|
+
@list ||= {}
|
18
|
+
end
|
20
19
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
20
|
+
# Retrieve the current family list
|
21
|
+
#
|
22
|
+
# @return [Hash] map with family names and their objects
|
23
|
+
def self.families
|
24
|
+
@families ||= {}
|
25
|
+
end
|
27
26
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
end
|
27
|
+
# Clear all platform settings. Only used for testing.
|
28
|
+
def self.__reset
|
29
|
+
@list = {}
|
30
|
+
@families = {}
|
33
31
|
end
|
34
32
|
|
35
33
|
# Create or update a platform
|
36
34
|
#
|
37
35
|
# @return Train::Platform
|
38
36
|
def self.name(name, condition = {})
|
37
|
+
# TODO: refactor this against family. They're stupidly similar
|
39
38
|
# Check the list to see if one is already created
|
40
39
|
plat = list[name]
|
41
40
|
unless plat.nil?
|
@@ -66,9 +65,10 @@ module Train::Platforms
|
|
66
65
|
#
|
67
66
|
# @return [Hash] with top level family and platforms
|
68
67
|
def self.top_platforms
|
69
|
-
|
70
|
-
|
71
|
-
|
68
|
+
empty_list = list.select { |_key, value| value.families.empty? }
|
69
|
+
empty_fams = families.select { |_key, value| value.families.empty? }
|
70
|
+
|
71
|
+
empty_list.merge empty_fams
|
72
72
|
end
|
73
73
|
|
74
74
|
# List all platforms and families in a readable output
|
@@ -83,7 +83,7 @@ module Train::Platforms
|
|
83
83
|
def self.print_children(parent, pad = 2)
|
84
84
|
parent.children.each do |key, value|
|
85
85
|
obj = key
|
86
|
-
puts "#{
|
86
|
+
puts "#{" " * pad}-> #{obj.title}#{value unless value.empty?}"
|
87
87
|
print_children(obj, pad + 2) if defined?(obj.children) && !obj.children.nil?
|
88
88
|
end
|
89
89
|
end
|
@@ -37,27 +37,32 @@ module Train::Platforms::Detect::Helpers
|
|
37
37
|
if @backend.class.to_s == "Train::Transports::SSH::Connection" && res =~ /Please login as the user/
|
38
38
|
raise Train::UserError, "SSH failed: #{res}"
|
39
39
|
end
|
40
|
+
|
40
41
|
res.strip! unless res.nil?
|
41
42
|
res
|
42
43
|
end
|
43
44
|
|
44
45
|
def unix_uname_s
|
45
46
|
return @uname[:s] if @uname.key?(:s)
|
47
|
+
|
46
48
|
@uname[:s] = command_output("uname -s")
|
47
49
|
end
|
48
50
|
|
49
51
|
def unix_uname_r
|
50
52
|
return @uname[:r] if @uname.key?(:r)
|
53
|
+
|
51
54
|
@uname[:r] = command_output("uname -r")
|
52
55
|
end
|
53
56
|
|
54
57
|
def unix_uname_m
|
55
58
|
return @uname[:m] if @uname.key?(:m)
|
59
|
+
|
56
60
|
@uname[:m] = command_output("uname -m")
|
57
61
|
end
|
58
62
|
|
59
63
|
def brocade_version
|
60
64
|
return @cache[:brocade] if @cache.key?(:brocade)
|
65
|
+
|
61
66
|
res = command_output("version")
|
62
67
|
|
63
68
|
m = res.match(/^Fabric OS:\s+v(\S+)$/)
|
@@ -70,6 +75,7 @@ module Train::Platforms::Detect::Helpers
|
|
70
75
|
|
71
76
|
def cisco_show_version
|
72
77
|
return @cache[:cisco] if @cache.key?(:cisco)
|
78
|
+
|
73
79
|
res = command_output("show version")
|
74
80
|
|
75
81
|
m = res.match(/Cisco IOS Software, [^,]+? \(([^,]+?)\), Version (\d+\.\d+)/)
|
@@ -110,7 +116,7 @@ module Train::Platforms::Detect::Helpers
|
|
110
116
|
# require 'pry';binding.pry
|
111
117
|
%W{
|
112
118
|
/etc/chef/chef_guid
|
113
|
-
#{ENV[
|
119
|
+
#{ENV["HOME"]}/.chef/chef_guid
|
114
120
|
/etc/machine-id
|
115
121
|
/var/lib/dbus/machine-id
|
116
122
|
/var/db/dbus/machine-id
|
@@ -118,6 +124,7 @@ module Train::Platforms::Detect::Helpers
|
|
118
124
|
file = @backend.file(path)
|
119
125
|
next unless file.exist? && file.size != 0
|
120
126
|
return file.content.chomp if path =~ /guid/
|
127
|
+
|
121
128
|
return uuid_from_string(file.content.chomp)
|
122
129
|
end
|
123
130
|
nil
|
@@ -128,6 +135,7 @@ module Train::Platforms::Detect::Helpers
|
|
128
135
|
# we turn into a UUID.
|
129
136
|
def uuid_from_command
|
130
137
|
return unless @platform[:uuid_command]
|
138
|
+
|
131
139
|
result = @backend.run_command(@platform[:uuid_command])
|
132
140
|
uuid_from_string(result.stdout.chomp) if result.exit_status == 0 && !result.stdout.empty?
|
133
141
|
end
|