train-core 3.2.5 → 3.2.14
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 -5
- data/lib/train/extras.rb +2 -2
- data/lib/train/extras/command_wrapper.rb +29 -34
- data/lib/train/extras/stat.rb +1 -1
- data/lib/train/file.rb +3 -3
- data/lib/train/file/local.rb +2 -2
- data/lib/train/file/local/unix.rb +1 -1
- data/lib/train/file/remote.rb +5 -5
- data/lib/train/file/remote/aix.rb +1 -1
- data/lib/train/file/remote/linux.rb +1 -1
- data/lib/train/file/remote/qnx.rb +1 -1
- data/lib/train/platforms.rb +8 -8
- data/lib/train/platforms/detect/helpers/os_common.rb +2 -2
- data/lib/train/platforms/detect/scanner.rb +1 -1
- data/lib/train/platforms/detect/specifications/os.rb +43 -14
- data/lib/train/plugin_test_helper.rb +1 -1
- data/lib/train/plugins.rb +2 -2
- data/lib/train/plugins/base_connection.rb +8 -4
- data/lib/train/plugins/transport.rb +4 -4
- data/lib/train/transports/local.rb +2 -2
- data/lib/train/transports/mock.rb +1 -1
- data/lib/train/transports/ssh.rb +3 -3
- data/lib/train/transports/ssh_connection.rb +15 -6
- 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: c4a9a2b3342fe17d7bcbfe3fcee05215b867798a4c8f01a6924e8ac57846fa9d
|
4
|
+
data.tar.gz: 0041aaaeeb3405feda9ec52c0cdc04867245e3b9b2259a122ed9db44f4506504
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a8d25991efa5582a917b6eb8b89cfc4bb04c54202558043c601fa29be600f384885672cb7371f76cca5709fecb06b0c3fbdd735b6898c4fea96f39f200b987ce
|
7
|
+
data.tar.gz: c9421752289a00b535b7fdff660e9e1e19ff23e37647741e8e042a5ec31e36c9b6af1eef8445217f05905b0178981000681f1c0b0b028b623b7ef2408371da6b
|
data/lib/train.rb
CHANGED
@@ -2,11 +2,11 @@
|
|
2
2
|
#
|
3
3
|
# Author:: Dominik Richter (<dominik.richter@gmail.com>)
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
5
|
+
require_relative "train/version"
|
6
|
+
require_relative "train/options"
|
7
|
+
require_relative "train/plugins"
|
8
|
+
require_relative "train/errors"
|
9
|
+
require_relative "train/platforms"
|
10
10
|
require "uri"
|
11
11
|
|
12
12
|
module Train
|
data/lib/train/extras.rb
CHANGED
@@ -3,8 +3,8 @@
|
|
3
3
|
# Author:: Dominik Richter (<dominik.richter@gmail.com>)
|
4
4
|
|
5
5
|
module Train::Extras
|
6
|
-
|
7
|
-
|
6
|
+
require_relative "extras/command_wrapper"
|
7
|
+
require_relative "extras/stat"
|
8
8
|
|
9
9
|
CommandResult = Struct.new(:stdout, :stderr, :exit_status)
|
10
10
|
LoginCommand = Struct.new(:command, :arguments)
|
@@ -3,7 +3,7 @@
|
|
3
3
|
# author: Christoph Hartmann
|
4
4
|
|
5
5
|
require "base64"
|
6
|
-
|
6
|
+
require_relative "../errors"
|
7
7
|
|
8
8
|
module Train::Extras
|
9
9
|
# Define the interface of all command wrappers.
|
@@ -53,47 +53,46 @@ module Train::Extras
|
|
53
53
|
@user = options[:user]
|
54
54
|
end
|
55
55
|
|
56
|
-
def with_sudo_pty
|
57
|
-
old_pty = backend.transport_options[:pty]
|
58
|
-
backend.transport_options[:pty] = true if @sudo
|
59
|
-
|
60
|
-
yield
|
61
|
-
ensure
|
62
|
-
backend.transport_options[:pty] = old_pty
|
63
|
-
end
|
64
|
-
|
65
56
|
# (see CommandWrapperBase::verify)
|
66
57
|
def verify
|
67
58
|
cmd = if @sudo
|
68
59
|
# Wrap it up. It needs /dev/null on the outside to disable stdin
|
69
|
-
|
60
|
+
# NOTE: can't use @sudo_command because -v conflicts with -E.
|
61
|
+
# See test-kitchen's use of this variable for conflict.
|
62
|
+
"sh -c '(sudo -v) < /dev/null'"
|
70
63
|
else
|
71
64
|
run("echo")
|
72
65
|
end
|
73
66
|
|
74
67
|
# rubocop:disable Style/BlockDelimiters
|
75
|
-
res = with_sudo_pty {
|
68
|
+
res = @backend.with_sudo_pty {
|
76
69
|
@backend.run_command(cmd)
|
77
70
|
}
|
78
71
|
return nil if res.exit_status == 0
|
79
72
|
|
80
|
-
rawerr = res.stdout
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
"sudo
|
85
|
-
|
86
|
-
"
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
73
|
+
rawerr = "#{res.stdout} #{res.stderr}".strip
|
74
|
+
|
75
|
+
case rawerr
|
76
|
+
when "Sorry, try again"
|
77
|
+
["Wrong sudo password.", :bad_sudo_password]
|
78
|
+
when "sudo: no tty present and no askpass program specified"
|
79
|
+
["Sudo requires a password, please configure it.", :sudo_password_required]
|
80
|
+
when "sudo: command not found"
|
81
|
+
["Can't find sudo command. Please either install and "\
|
82
|
+
"configure it on the target or deactivate sudo.", :sudo_command_not_found]
|
83
|
+
when "sudo: sorry, you must have a tty to run sudo"
|
84
|
+
["Sudo requires a TTY. Please see the README on how to configure "\
|
85
|
+
"sudo to allow for non-interactive usage.", :sudo_no_tty]
|
86
|
+
else
|
87
|
+
[rawerr, nil]
|
94
88
|
end
|
89
|
+
end
|
95
90
|
|
96
|
-
|
91
|
+
def verify!
|
92
|
+
msg, reason = verify
|
93
|
+
return nil unless msg
|
94
|
+
|
95
|
+
raise Train::UserError.new("Sudo failed: #{msg}", reason)
|
97
96
|
end
|
98
97
|
|
99
98
|
# (see CommandWrapperBase::run)
|
@@ -191,15 +190,11 @@ module Train::Extras
|
|
191
190
|
return nil unless LinuxCommand.active?(options)
|
192
191
|
|
193
192
|
res = LinuxCommand.new(transport, options)
|
194
|
-
|
195
|
-
|
196
|
-
msg, reason = verification_res
|
197
|
-
raise Train::UserError.new("Sudo failed: #{msg}", reason)
|
198
|
-
end
|
193
|
+
res.verify!
|
194
|
+
|
199
195
|
res
|
200
196
|
elsif transport.platform.windows?
|
201
|
-
|
202
|
-
res
|
197
|
+
WindowsCommand.new(transport, options)
|
203
198
|
end
|
204
199
|
end
|
205
200
|
end
|
data/lib/train/extras/stat.rb
CHANGED
@@ -35,7 +35,7 @@ module Train::Extras
|
|
35
35
|
|
36
36
|
def self.linux_stat(shell_escaped_path, backend, follow_symlink)
|
37
37
|
lstat = follow_symlink ? " -L" : ""
|
38
|
-
format = (backend.os.esx? || backend.os[:name] == "alpine") ? "-c" : "--printf"
|
38
|
+
format = (backend.os.esx? || backend.os[:name] == "alpine" || backend.os[:name] == "yocto") ? "-c" : "--printf"
|
39
39
|
res = backend.run_command("stat#{lstat} #{shell_escaped_path} 2>/dev/null #{format} '%s\n%f\n%U\n%u\n%G\n%g\n%X\n%Y\n%C'")
|
40
40
|
# ignore the exit_code: it is != 0 if selinux labels are not supported
|
41
41
|
# on the system.
|
data/lib/train/file.rb
CHANGED
@@ -3,9 +3,9 @@
|
|
3
3
|
# author: Christoph Hartmann
|
4
4
|
# author: Dominik Richter
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
6
|
+
require_relative "file/local"
|
7
|
+
require_relative "file/remote"
|
8
|
+
require_relative "extras/stat"
|
9
9
|
|
10
10
|
module Train
|
11
11
|
class File # rubocop:disable Metrics/ClassLength
|
data/lib/train/file/local.rb
CHANGED
data/lib/train/file/remote.rb
CHANGED
@@ -33,8 +33,8 @@ end
|
|
33
33
|
|
34
34
|
# subclass requires are loaded after Train::File::Remote is defined
|
35
35
|
# to avoid superclass mismatch errors
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
36
|
+
require_relative "remote/aix"
|
37
|
+
require_relative "remote/linux"
|
38
|
+
require_relative "remote/qnx"
|
39
|
+
require_relative "remote/unix"
|
40
|
+
require_relative "remote/windows"
|
data/lib/train/platforms.rb
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
3
|
+
require_relative "platforms/common"
|
4
|
+
require_relative "platforms/detect"
|
5
|
+
require_relative "platforms/detect/scanner"
|
6
|
+
require_relative "platforms/detect/specifications/os"
|
7
|
+
require_relative "platforms/detect/specifications/api"
|
8
|
+
require_relative "platforms/detect/uuid"
|
9
|
+
require_relative "platforms/family"
|
10
|
+
require_relative "platforms/platform"
|
11
11
|
|
12
12
|
module Train::Platforms
|
13
13
|
# Retrieve the current platform list
|
@@ -17,7 +17,7 @@ module Train::Platforms::Detect::Specifications
|
|
17
17
|
|
18
18
|
plat.family("windows").in_family("os")
|
19
19
|
.detect do
|
20
|
-
|
20
|
+
# Can't return from a `proc` thus the `is_windows` shenanigans
|
21
21
|
is_windows = false
|
22
22
|
is_windows = true if winrm?
|
23
23
|
|
@@ -25,7 +25,7 @@ module Train::Platforms::Detect::Specifications
|
|
25
25
|
is_windows = true if ruby_host_os(/mswin|mingw32|windows/)
|
26
26
|
end
|
27
27
|
|
28
|
-
|
28
|
+
# Try to detect windows even for ssh transport
|
29
29
|
if !is_windows && detect_windows == true
|
30
30
|
is_windows = true
|
31
31
|
end
|
@@ -41,8 +41,8 @@ module Train::Platforms::Detect::Specifications
|
|
41
41
|
# unix master family
|
42
42
|
plat.family("unix").in_family("os")
|
43
43
|
.detect do
|
44
|
-
|
45
|
-
|
44
|
+
# we want to catch a special case here where cisco commands
|
45
|
+
# don't return an exit status and still print to stdout
|
46
46
|
if unix_uname_s =~ /./ && !unix_uname_s.start_with?("Line has invalid autocommand ") && !unix_uname_s.start_with?("The command you have entered")
|
47
47
|
@platform[:arch] = unix_uname_m
|
48
48
|
true
|
@@ -92,7 +92,7 @@ module Train::Platforms::Detect::Specifications
|
|
92
92
|
true
|
93
93
|
end
|
94
94
|
|
95
|
-
|
95
|
+
# if we get this far we have to be some type of debian
|
96
96
|
@platform[:release] = unix_file_contents("/etc/debian_version").chomp
|
97
97
|
true
|
98
98
|
end
|
@@ -136,9 +136,9 @@ module Train::Platforms::Detect::Specifications
|
|
136
136
|
# redhat family
|
137
137
|
plat.family("redhat").in_family("linux")
|
138
138
|
.detect do
|
139
|
-
|
140
|
-
|
141
|
-
|
139
|
+
# I am not sure this returns true for all redhats in this family
|
140
|
+
# for now we are going to just try each platform
|
141
|
+
# return true unless unix_file_contents('/etc/redhat-release').nil?
|
142
142
|
|
143
143
|
true
|
144
144
|
end
|
@@ -318,6 +318,35 @@ module Train::Platforms::Detect::Specifications
|
|
318
318
|
end
|
319
319
|
end
|
320
320
|
|
321
|
+
# yocto family
|
322
|
+
plat.family("yocto").in_family("linux")
|
323
|
+
.detect do
|
324
|
+
# /etc/issue isn't specific to yocto, but it's the only way to detect
|
325
|
+
# the platform because there are no other identifying files
|
326
|
+
if unix_file_contents("/etc/issue") &&
|
327
|
+
(unix_file_contents("/etc/issue").match?("Poky") ||
|
328
|
+
unix_file_contents("/etc/issue").match?("balenaOS"))
|
329
|
+
true
|
330
|
+
end
|
331
|
+
end
|
332
|
+
plat.name("yocto").title("Yocto Project Linux").in_family("yocto")
|
333
|
+
.detect do
|
334
|
+
if unix_file_contents("/etc/issue").match?("Poky")
|
335
|
+
# assuming the Poky version is preferred over the /etc/version build
|
336
|
+
@platform[:release] = unix_file_contents("/etc/issue").match('\d+(\.\d+)+')[0]
|
337
|
+
true
|
338
|
+
end
|
339
|
+
end
|
340
|
+
plat.name("balenaos").title("balenaOS Linux").in_family("yocto")
|
341
|
+
.detect do
|
342
|
+
# balenaOS does have the /etc/os-release file
|
343
|
+
if unix_file_contents("/etc/issue").match?("balenaOS") &&
|
344
|
+
linux_os_release["NAME"] =~ /balenaos/i
|
345
|
+
@platform[:release] = linux_os_release["META_BALENA_VERSION"]
|
346
|
+
true
|
347
|
+
end
|
348
|
+
end
|
349
|
+
|
321
350
|
# brocade family detected here if device responds to 'uname' command,
|
322
351
|
# happens when logging in as root
|
323
352
|
plat.family("brocade").title("Brocade Family").in_family("linux")
|
@@ -325,9 +354,9 @@ module Train::Platforms::Detect::Specifications
|
|
325
354
|
!brocade_version.nil?
|
326
355
|
end
|
327
356
|
|
328
|
-
#
|
357
|
+
# generic linux
|
329
358
|
# this should always be last in the linux family list
|
330
|
-
plat.name("linux").title("
|
359
|
+
plat.name("linux").title("Generic Linux").in_family("linux")
|
331
360
|
.detect do
|
332
361
|
true
|
333
362
|
end
|
@@ -426,7 +455,7 @@ module Train::Platforms::Detect::Specifications
|
|
426
455
|
true
|
427
456
|
end
|
428
457
|
|
429
|
-
|
458
|
+
# must be some unknown solaris
|
430
459
|
true
|
431
460
|
end
|
432
461
|
|
@@ -457,8 +486,8 @@ module Train::Platforms::Detect::Specifications
|
|
457
486
|
# bsd family
|
458
487
|
plat.family("bsd").in_family("unix")
|
459
488
|
.detect do
|
460
|
-
|
461
|
-
|
489
|
+
# we need a better way to determine this family
|
490
|
+
# for now we are going to just try each platform
|
462
491
|
true
|
463
492
|
end
|
464
493
|
plat.family("darwin").in_family("bsd")
|
@@ -484,7 +513,7 @@ module Train::Platforms::Detect::Specifications
|
|
484
513
|
end
|
485
514
|
plat.name("darwin").title("Darwin").in_family("darwin")
|
486
515
|
.detect do
|
487
|
-
|
516
|
+
# must be some other type of darwin
|
488
517
|
@platform[:name] = unix_uname_s.lines[0].chomp
|
489
518
|
true
|
490
519
|
end
|
@@ -3,7 +3,7 @@
|
|
3
3
|
|
4
4
|
# Load Train. We certainly need the plugin system, and also several other parts
|
5
5
|
# that are tightly coupled. Train itself is fairly light, and non-invasive.
|
6
|
-
|
6
|
+
require_relative "../train"
|
7
7
|
|
8
8
|
# You can select from a number of test harnesses. Since Train is closely related
|
9
9
|
# to InSpec, and InSpec uses Spec-style controls in profile code, you will
|
data/lib/train/plugins.rb
CHANGED
@@ -3,11 +3,11 @@
|
|
3
3
|
# Author:: Dominik Richter (<dominik.richter@gmail.com>)
|
4
4
|
# Author:: Christoph Hartmann (<chris@lollyrock.com>)
|
5
5
|
|
6
|
-
|
6
|
+
require_relative "errors"
|
7
7
|
|
8
8
|
module Train
|
9
9
|
class Plugins
|
10
|
-
|
10
|
+
require_relative "plugins/transport"
|
11
11
|
|
12
12
|
class << self
|
13
13
|
# Retrieve the current plugin registry, containing all plugin names
|
@@ -1,8 +1,8 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
3
|
+
require_relative "../errors"
|
4
|
+
require_relative "../extras"
|
5
|
+
require_relative "../file"
|
6
6
|
require "logger"
|
7
7
|
|
8
8
|
class Train::Plugins::Transport
|
@@ -38,6 +38,10 @@ class Train::Plugins::Transport
|
|
38
38
|
end
|
39
39
|
end
|
40
40
|
|
41
|
+
def with_sudo_pty
|
42
|
+
yield
|
43
|
+
end
|
44
|
+
|
41
45
|
# Returns cached client if caching enabled. Otherwise returns whatever is
|
42
46
|
# given in the block.
|
43
47
|
#
|
@@ -88,7 +92,7 @@ class Train::Plugins::Transport
|
|
88
92
|
end
|
89
93
|
|
90
94
|
def load_json(j)
|
91
|
-
|
95
|
+
require_relative "../transports/mock"
|
92
96
|
j["files"].each do |path, jf|
|
93
97
|
@cache[:file][path] = Train::Transports::Mock::Connection::File.from_json(jf)
|
94
98
|
end
|
@@ -4,16 +4,16 @@
|
|
4
4
|
# Author:: Christoph Hartmann (<chris@lollyrock.com>)
|
5
5
|
|
6
6
|
require "logger"
|
7
|
-
|
8
|
-
|
9
|
-
|
7
|
+
require_relative "../errors"
|
8
|
+
require_relative "../extras"
|
9
|
+
require_relative "../options"
|
10
10
|
|
11
11
|
class Train::Plugins
|
12
12
|
class Transport
|
13
13
|
include Train::Extras
|
14
14
|
Train::Options.attach(self)
|
15
15
|
|
16
|
-
|
16
|
+
require_relative "base_connection"
|
17
17
|
|
18
18
|
# Initialize a new Transport object
|
19
19
|
#
|
data/lib/train/transports/ssh.rb
CHANGED
@@ -20,7 +20,7 @@
|
|
20
20
|
|
21
21
|
require "net/ssh"
|
22
22
|
require "net/scp"
|
23
|
-
|
23
|
+
require_relative "../errors"
|
24
24
|
|
25
25
|
module Train::Transports
|
26
26
|
# Wrapped exception for any internally raised SSH-related errors.
|
@@ -36,8 +36,8 @@ module Train::Transports
|
|
36
36
|
class SSH < Train.plugin(1) # rubocop:disable Metrics/ClassLength
|
37
37
|
name "ssh"
|
38
38
|
|
39
|
-
|
40
|
-
|
39
|
+
require_relative "ssh_connection"
|
40
|
+
require_relative "cisco_ios_connection"
|
41
41
|
|
42
42
|
# add options for submodules
|
43
43
|
include_options Train::Extras::CommandWrapper
|
@@ -164,6 +164,15 @@ class Train::Transports::SSH
|
|
164
164
|
options_to_print
|
165
165
|
end
|
166
166
|
|
167
|
+
def with_sudo_pty
|
168
|
+
old_pty = transport_options[:pty]
|
169
|
+
transport_options[:pty] = true if @sudo
|
170
|
+
|
171
|
+
yield
|
172
|
+
ensure
|
173
|
+
transport_options[:pty] = old_pty
|
174
|
+
end
|
175
|
+
|
167
176
|
private
|
168
177
|
|
169
178
|
PING_COMMAND = "echo '[SSH] Established'".freeze
|
@@ -213,17 +222,17 @@ class Train::Transports::SSH
|
|
213
222
|
retry
|
214
223
|
end
|
215
224
|
|
216
|
-
def file_via_connection(path)
|
225
|
+
def file_via_connection(path, *args)
|
217
226
|
if os.aix?
|
218
|
-
Train::File::Remote::Aix.new(self, path)
|
227
|
+
Train::File::Remote::Aix.new(self, path, *args)
|
219
228
|
elsif os.solaris?
|
220
|
-
Train::File::Remote::Unix.new(self, path)
|
229
|
+
Train::File::Remote::Unix.new(self, path, *args)
|
221
230
|
elsif os[:name] == "qnx"
|
222
|
-
Train::File::Remote::Qnx.new(self, path)
|
231
|
+
Train::File::Remote::Qnx.new(self, path, *args)
|
223
232
|
elsif os.windows?
|
224
|
-
Train::File::Remote::Windows.new(self, path)
|
233
|
+
Train::File::Remote::Windows.new(self, path, *args)
|
225
234
|
else
|
226
|
-
Train::File::Remote::Linux.new(self, path)
|
235
|
+
Train::File::Remote::Linux.new(self, path, *args)
|
227
236
|
end
|
228
237
|
end
|
229
238
|
|
data/lib/train/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: train-core
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.2.
|
4
|
+
version: 3.2.14
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dominik Richter
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-01-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: json
|