train-core 3.2.5 → 3.2.14
Sign up to get free protection for your applications and to get access to all the features.
- 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
|