train-core 3.5.5 → 3.7.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: dbe3fad014697c3f0a1d5fb5d3f4ff422f9e552362179f72019f7c2f9784f975
4
- data.tar.gz: 337a74095aa5e41b4dd4f24ba2e41857190161a035c2adaf809617205525e442
3
+ metadata.gz: 6ccf18cbe443b73ae4ddf1d26acd7bd86730482130481d2d1ab4110311829cba
4
+ data.tar.gz: 4e377e9a24cfe32eefa8b4a09a5c54a65f1acf8d1d120eb76e4170e45238dc3f
5
5
  SHA512:
6
- metadata.gz: a066352b95be252da1de517176e98fe67804484bfb7f9371a23762b04a5050e7a3a7ca814eb27c773c5b23e7eb85a6eb26fd251df67bfd25c500e34a1075f7dc
7
- data.tar.gz: fdfa95f6c1278dd04760e5dface6b4feacac3d0dd2b77f8844215d6f9b17760967afa482181415368fd8c3ca869e697e205c5abd45913e6cbfb12dcfc93044c1
6
+ metadata.gz: 23bec0bbce7a152996c8c881211fc46908637720f768c3e1254b44409b7da2091984806165d6545e08354b2291d7652f9c1db0b9f930e6a6998a0e5506553d48
7
+ data.tar.gz: 0eb390214488b1b6ae193235b4c9addc1c3750349b8e5ec59c8314dc5a746ab9533d47b8774bb872baabd339768dd1f0e8b6c7c84edb1fbb7a95b2cadf2a71ba
@@ -34,7 +34,7 @@ module Train::Extras
34
34
 
35
35
  def self.linux_stat(shell_escaped_path, backend, follow_symlink)
36
36
  lstat = follow_symlink ? " -L" : ""
37
- format = (backend.os.esx? || backend.os[:name] == "alpine" || backend.os[:name] == "yocto") ? "-c" : "--printf"
37
+ format = (backend.os.esx? || %w{alpine yocto ubios}.include?(backend.os[:name])) ? "-c" : "--printf"
38
38
  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'")
39
39
  # ignore the exit_code: it is != 0 if selinux labels are not supported
40
40
  # on the system.
@@ -12,7 +12,7 @@ module Train
12
12
  @spath = path.gsub(/[<>"|?*]/, "")
13
13
  end
14
14
 
15
- def basename(suffix = nil, sep = '\\')
15
+ def basename(suffix = nil, sep = "\\")
16
16
  super(suffix, sep)
17
17
  end
18
18
 
data/lib/train/options.rb CHANGED
@@ -59,6 +59,9 @@ module Train
59
59
  default = hm[:default]
60
60
  if default.is_a? Proc
61
61
  res[field] = default.call(res)
62
+ elsif hm.key?(:coerce)
63
+ field_value = hm[:coerce].call(res)
64
+ res[field] = field_value.nil? ? default : field_value
62
65
  else
63
66
  res[field] = default
64
67
  end
@@ -74,6 +74,14 @@ module Train::Platforms::Detect::Specifications
74
74
  end
75
75
  end
76
76
 
77
+ declare_instance("ubios", "Ubiquiti UbiOS", "ubios") do
78
+ l_o_r = linux_os_release
79
+ if l_o_r && l_o_r["ID"] == "ubios"
80
+ @platform[:release] = l_o_r["VERSION_ID"]
81
+ true
82
+ end
83
+ end
84
+
77
85
  declare_instance("debian", "Debian Linux", "debian") do
78
86
  # if we get this far we have to be some type of debian
79
87
  @platform[:release] = unix_file_contents("/etc/debian_version").chomp
@@ -190,8 +190,23 @@ module Train::Transports
190
190
  script = "$ProgressPreference='SilentlyContinue';" + cmd
191
191
  encoded_script = Base64.strict_encode64(script)
192
192
  # TODO: no way to safely implement timeouts here.
193
- @pipe.puts(encoded_script)
194
- @pipe.flush
193
+ begin
194
+ @pipe.puts(encoded_script)
195
+ @pipe.flush
196
+ rescue Errno::EPIPE
197
+ # Retry once if the pipe went away
198
+ begin
199
+ # Maybe the pipe went away, but the server didn't? Reset it, to get a clean start.
200
+ close
201
+ rescue Errno::EIO
202
+ # Ignore - server already went away
203
+ end
204
+ @pipe = acquire_pipe
205
+ raise PipeError if @pipe.nil?
206
+
207
+ @pipe.puts(encoded_script)
208
+ @pipe.flush
209
+ end
195
210
  res = OpenStruct.new(JSON.parse(Base64.decode64(@pipe.readline)))
196
211
  Local::CommandResult.new(res.stdout, res.stderr, res.exitstatus)
197
212
  end
@@ -216,12 +231,10 @@ module Train::Transports
216
231
 
217
232
  # PowerShell needs time to create pipe.
218
233
  100.times do
219
- begin
220
- pipe = open("//./pipe/#{pipe_name}", "r+")
221
- break
222
- rescue
223
- sleep 0.1
224
- end
234
+ pipe = open("//./pipe/#{pipe_name}", "r+")
235
+ break
236
+ rescue
237
+ sleep 0.1
225
238
  end
226
239
 
227
240
  pipe
@@ -43,8 +43,8 @@ module Train::Transports
43
43
 
44
44
  # common target configuration
45
45
  option :host, required: true
46
- option :port, default: 22, required: true
47
- option :user, default: "root", required: true
46
+ option :port, default: 22, coerce: proc { |u| read_options_from_ssh_config(u, :port) }, required: true
47
+ option :user, default: "root", coerce: proc { |u| read_options_from_ssh_config(u, :user) }, required: true
48
48
  option :key_files, default: nil
49
49
  option :password, default: nil
50
50
 
@@ -86,6 +86,14 @@ module Train::Transports
86
86
  end
87
87
  end
88
88
 
89
+ # Returns the ssh config option like user, port from config files
90
+ # Params options [Hash], option_type [String]
91
+ # Return String
92
+ def self.read_options_from_ssh_config(options, option_type)
93
+ config_options = Net::SSH.configuration_for(options[:host], true)
94
+ config_options[option_type]
95
+ end
96
+
89
97
  private
90
98
 
91
99
  def reusable_connection?(conn_opts)
@@ -278,5 +286,6 @@ module Train::Transports
278
286
  yield @connection if block_given?
279
287
  @connection
280
288
  end
289
+
281
290
  end
282
291
  end
@@ -32,6 +32,10 @@ class Train::Transports::SSH
32
32
  attr_reader :hostname
33
33
  attr_accessor :transport_options
34
34
 
35
+ # If we use the GNU timeout utility to timout a command server-side, it will
36
+ # exit with this status code if the command timed out.
37
+ GNU_TIMEOUT_EXIT_STATUS = 124
38
+
35
39
  def initialize(options)
36
40
  # Track IOS command retries to prevent infinite loop on IOError. This must
37
41
  # be done before `super()` because the parent runs detection commands.
@@ -321,9 +325,12 @@ class Train::Transports::SSH
321
325
  # wrap commands if that is configured
322
326
  cmd = @cmd_wrapper.run(cmd) if @cmd_wrapper
323
327
 
328
+ # Timeout the command if requested and able
329
+ cmd = "timeout #{timeout}s #{cmd}" if timeout && timeoutable?(cmd)
330
+
324
331
  logger.debug("[SSH] #{self} cmd = #{cmd}")
325
332
 
326
- if @transport_options[:pty] || timeout
333
+ if @transport_options[:pty]
327
334
  channel.request_pty do |_ch, success|
328
335
  raise Train::Transports::SSHPTYFailed, "Requesting PTY failed" unless success
329
336
  end
@@ -350,21 +357,30 @@ class Train::Transports::SSH
350
357
  end
351
358
  end
352
359
  end
360
+ session.loop
353
361
 
354
- thr = Thread.new { session.loop }
355
-
356
- if timeout
357
- res = thr.join(timeout)
358
- unless res
359
- logger.debug("train ssh command '#{cmd}' reached requested timeout (#{timeout}s)")
360
- session.channels.each_value { |c| c.eof!; c.close }
361
- raise Train::CommandTimeoutReached.new "ssh command reached timeout (#{timeout}s)"
362
- end
363
- else
364
- thr.join
362
+ if timeout && timeoutable?(cmd) && exit_status == GNU_TIMEOUT_EXIT_STATUS
363
+ logger.debug("train ssh command '#{cmd}' reached requested timeout (#{timeout}s)")
364
+ session.channels.each_value { |c| c.eof!; c.close }
365
+ raise Train::CommandTimeoutReached.new "ssh command reached timeout (#{timeout}s)"
365
366
  end
366
367
 
367
368
  [exit_status, stdout, stderr]
368
369
  end
370
+
371
+ # Returns true if we think we can attempt to timeout the command
372
+ def timeoutable?(cmd)
373
+ have_timeout_cli? && !cmd.include?("|") # Don't try to timeout a command that has pipes
374
+ end
375
+
376
+ # Returns true if the GNU timeout command is available
377
+ def have_timeout_cli?
378
+ return @have_timeout_cli unless @have_timeout_cli.nil?
379
+
380
+ res = session.exec!("timeout --version")
381
+ @have_timeout_cli = res.exitstatus == 0
382
+ logger.debug("train ssh have_timeout_cli status is '#{@have_timeout_cli}'")
383
+ @have_timeout_cli
384
+ end
369
385
  end
370
386
  end
data/lib/train/version.rb CHANGED
@@ -2,5 +2,5 @@
2
2
  # Author:: Dominik Richter (<dominik.richter@gmail.com>)
3
3
 
4
4
  module Train
5
- VERSION = "3.5.5".freeze
5
+ VERSION = "3.7.4".freeze
6
6
  end
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.5.5
4
+ version: 3.7.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chef InSpec Team
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-03-24 00:00:00.000000000 Z
11
+ date: 2021-06-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: addressable
@@ -181,7 +181,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
181
181
  requirements:
182
182
  - - ">="
183
183
  - !ruby/object:Gem::Version
184
- version: '2.4'
184
+ version: '2.5'
185
185
  required_rubygems_version: !ruby/object:Gem::Requirement
186
186
  requirements:
187
187
  - - ">="