train-core 3.3.21 → 3.4.7

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: c4bfda9949a3f24a3c7d48f8bb23384c73f064eccfa0f44029872e13913880c9
4
- data.tar.gz: 6598c63e265c79e1344010ace35b40d1f5bd1919bb8039d4ae868c54f9f85dc5
3
+ metadata.gz: e85ed8cc37da145f7dabcff7855b85b9c2a6bc8f216945aeaa693843c07f8b95
4
+ data.tar.gz: a4ac06f8b1c2ced955d933ba1a9553d9434c9d255d11ec5d8cc43e14e1cc0469
5
5
  SHA512:
6
- metadata.gz: aeb75022b5ff8c0f93ce22b35a6d8af8b31c8f3906fe357e502cd6f7ab8e7cb0bf55df61c8e891579b5338f875413b6c1372535e5af30d3011d54fd8b7822968
7
- data.tar.gz: 3c23b61031fe8c0e8d691929ccb9007a8272d1de9736b8c5bef1ffcfd8a3078b31f556454f6676cc9d9a2515333015852f64f8e5ce47d2313e393eb4b230f9f7
6
+ metadata.gz: 0b920c8d01dbdd94eae308fcca501cf9dc5f24619f8e023e4c5cedbdd11eebcfc4b4bcb41683435325f3ede4afa5b6a7981164e1cf8242aa472e2e801282c284
7
+ data.tar.gz: e3d5e835b15d0cc84f86066fe66aafc7456544f53fbe91d2a66c7341ed4db3b2f6a3d890e98aab26d0fe294af587fc246a89a10c7d56b9f4ac1cf09a99fae9d8
@@ -113,6 +113,9 @@ module Train
113
113
  # TODO: rewrite next line using compact! once we drop support for ruby 2.3
114
114
  creds = creds.delete_if { |_, value| value.nil? }
115
115
 
116
+ # merge train options in from the URI query string
117
+ creds.merge!(uri.query_values.map { |k, v| [k.to_sym, v] }.to_h) unless uri.query_values.nil?
118
+
116
119
  # return the updated config
117
120
  creds
118
121
  end
@@ -40,4 +40,7 @@ module Train
40
40
 
41
41
  # Exception for when a invalid cache type is passed.
42
42
  class UnknownCacheType < Error; end
43
+
44
+ # Exception for when a command reaches configured timeout
45
+ class CommandTimeoutReached < Error; end
43
46
  end
@@ -1,7 +1,7 @@
1
1
  # author: Dominik Richter
2
2
  # author: Christoph Hartmann
3
3
 
4
- require "base64"
4
+ require "base64" unless defined?(Base64)
5
5
  require_relative "../errors"
6
6
 
7
7
  module Train::Extras
@@ -33,15 +33,20 @@ module Train::Platforms::Detect::Helpers
33
33
  command = @backend.run_command(
34
34
  "Get-WmiObject Win32_OperatingSystem | Select Caption,Version | ConvertTo-Json"
35
35
  )
36
- return false if (command.exit_status != 0) || command.stdout.empty?
37
-
38
- payload = JSON.parse(command.stdout)
39
- @platform[:family] = "windows"
40
- @platform[:release] = payload["Version"]
41
- @platform[:name] = payload["Caption"]
42
-
43
- read_wmic
44
- true
36
+ # some targets (e.g. Cisco) may return 0 and print an error to stdout
37
+ return false if (command.exit_status != 0) || command.stdout.downcase !~ /window/
38
+
39
+ begin
40
+ payload = JSON.parse(command.stdout)
41
+ @platform[:family] = "windows"
42
+ @platform[:release] = payload["Version"]
43
+ @platform[:name] = payload["Caption"]
44
+
45
+ read_wmic
46
+ true
47
+ rescue
48
+ false
49
+ end
45
50
  end
46
51
 
47
52
  def local_windows?
@@ -126,7 +131,7 @@ module Train::Platforms::Detect::Helpers
126
131
  return if !file.exist? || file.size == 0
127
132
 
128
133
  json = JSON.parse(file.content)
129
- json["node_uuid"] if json["node_uuid"]
134
+ json["node_uuid"]
130
135
  end
131
136
 
132
137
  def windows_uuid_from_wmic
@@ -1,4 +1,4 @@
1
- require "digest/sha1"
1
+ require "digest/sha1" unless defined?(Digest::SHA1)
2
2
  require "securerandom" unless defined?(SecureRandom)
3
3
  require "json" unless defined?(JSON)
4
4
 
@@ -130,10 +130,27 @@ class Train::Plugins::Transport
130
130
  # This command accepts an optional data handler block. When provided,
131
131
  # inbound data will be published vi `data_handler.call(data)`. This can allow
132
132
  # callers to receive and render updates from remote command execution.
133
- def run_command(cmd, &data_handler)
134
- return run_command_via_connection(cmd, &data_handler) unless cache_enabled?(:command)
135
-
136
- @cache[:command][cmd] ||= run_command_via_connection(cmd, &data_handler)
133
+ #
134
+ # @param [String] the command to run
135
+ # @param [Hash] optional hash of options for this command. The derived connection
136
+ # class's implementation of run_command_via_connection should receive
137
+ # and apply these options.
138
+ def run_command(cmd, opts = {}, &data_handler)
139
+ # Some implementations do not accept an opts argument.
140
+ # We cannot update all implementations to accept opts due to them being separate plugins.
141
+ # Therefore here we check the implementation's arity to maintain compatibility.
142
+ case method(:run_command_via_connection).arity.abs
143
+ when 1
144
+ return run_command_via_connection(cmd, &data_handler) unless cache_enabled?(:command)
145
+
146
+ @cache[:command][cmd] ||= run_command_via_connection(cmd, &data_handler)
147
+ when 2
148
+ return run_command_via_connection(cmd, opts, &data_handler) unless cache_enabled?(:command)
149
+
150
+ @cache[:command][cmd] ||= run_command_via_connection(cmd, opts, &data_handler)
151
+ else
152
+ raise NotImplementedError, "#{self.class} does not implement run_command_via_connection with arity #{method(:run_command_via_connection).arity}"
153
+ end
137
154
  end
138
155
 
139
156
  # This is the main file call for all connections. This will call the private
@@ -112,7 +112,7 @@ module Train::Transports
112
112
 
113
113
  class WindowsShellRunner
114
114
  require "json" unless defined?(JSON)
115
- require "base64"
115
+ require "base64" unless defined?(Base64)
116
116
 
117
117
  def initialize(powershell_cmd = "powershell")
118
118
  @powershell_cmd = powershell_cmd
@@ -136,7 +136,7 @@ module Train::Transports
136
136
 
137
137
  class WindowsPipeRunner
138
138
  require "json" unless defined?(JSON)
139
- require "base64"
139
+ require "base64" unless defined?(Base64)
140
140
  require "securerandom" unless defined?(SecureRandom)
141
141
 
142
142
  def initialize(powershell_cmd = "powershell")
@@ -1,5 +1,5 @@
1
1
  require_relative "../plugins"
2
- require "digest"
2
+ require "digest" unless defined?(Digest)
3
3
 
4
4
  module Train::Transports
5
5
  class Mock < Train.plugin(1)
@@ -63,6 +63,7 @@ module Train::Transports
63
63
  option :bastion_port, default: 22
64
64
  option :non_interactive, default: false
65
65
  option :verify_host_key, default: false
66
+ option :forward_agent, default: false
66
67
 
67
68
  # Allow connecting with older algorithms
68
69
  option :append_all_supported_algorithms, default: true
@@ -72,13 +72,18 @@ class Train::Transports::SSH
72
72
 
73
73
  args = %w{ -o UserKnownHostsFile=/dev/null }
74
74
  args += %w{ -o StrictHostKeyChecking=no }
75
- args += %w{ -o IdentitiesOnly=yes } if options[:keys]
76
- args += %w{ -o BatchMode=yes } if options[:non_interactive]
75
+ args += %w{ -o BatchMode=yes } if options[:non_interactive]
77
76
  args += %W{ -o LogLevel=#{level} }
78
77
  args += %W{ -o ForwardAgent=#{fwd_agent} } if options.key?(:forward_agent)
79
- Array(options[:keys]).each do |ssh_key|
80
- args += %W{ -i #{ssh_key} }
78
+
79
+ keys = Array(options[:keys])
80
+ unless keys.empty?
81
+ args += %w{ -o IdentitiesOnly=yes }
82
+ keys.each do |ssh_key|
83
+ args += %W{ -i #{ssh_key} }
84
+ end
81
85
  end
86
+
82
87
  args
83
88
  end
84
89
 
@@ -235,12 +240,12 @@ class Train::Transports::SSH
235
240
  end
236
241
  end
237
242
 
238
- def run_command_via_connection(cmd, &data_handler)
243
+ def run_command_via_connection(cmd, opts = {}, &data_handler)
239
244
  cmd.dup.force_encoding("binary") if cmd.respond_to?(:force_encoding)
240
245
 
241
246
  reset_session if session.closed?
242
247
 
243
- exit_status, stdout, stderr = execute_on_channel(cmd, &data_handler)
248
+ exit_status, stdout, stderr = execute_on_channel(cmd, opts, &data_handler)
244
249
 
245
250
  # Since `@session.loop` succeeded, reset the IOS command retry counter
246
251
  @ios_cmd_retries = 0
@@ -297,7 +302,8 @@ class Train::Transports::SSH
297
302
  # not received.
298
303
  #
299
304
  # @api private
300
- def execute_on_channel(cmd)
305
+ def execute_on_channel(cmd, opts)
306
+ timeout = opts[:timeout]&.to_i
301
307
  stdout = ""
302
308
  stderr = ""
303
309
  exit_status = nil
@@ -307,7 +313,7 @@ class Train::Transports::SSH
307
313
 
308
314
  logger.debug("[SSH] #{self} cmd = #{cmd}")
309
315
 
310
- if @transport_options[:pty]
316
+ if @transport_options[:pty] || timeout
311
317
  channel.request_pty do |_ch, success|
312
318
  raise Train::Transports::SSHPTYFailed, "Requesting PTY failed" unless success
313
319
  end
@@ -334,7 +340,20 @@ class Train::Transports::SSH
334
340
  end
335
341
  end
336
342
  end
337
- session.loop
343
+
344
+ thr = Thread.new { session.loop }
345
+
346
+ if timeout
347
+ res = thr.join(timeout)
348
+ unless res
349
+ logger.debug("train ssh command '#{cmd}' reached requested timeout (#{timeout}s)")
350
+ session.channels.each_value { |c| c.eof!; c.close }
351
+ raise Train::CommandTimeoutReached.new "ssh command reached timeout (#{timeout}s)"
352
+ end
353
+ else
354
+ thr.join
355
+ end
356
+
338
357
  [exit_status, stdout, stderr]
339
358
  end
340
359
  end
@@ -2,5 +2,5 @@
2
2
  # Author:: Dominik Richter (<dominik.richter@gmail.com>)
3
3
 
4
4
  module Train
5
- VERSION = "3.3.21".freeze
5
+ VERSION = "3.4.7".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.3.21
4
+ version: 3.4.7
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: 2020-09-14 00:00:00.000000000 Z
11
+ date: 2021-01-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: addressable
@@ -188,7 +188,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
188
188
  - !ruby/object:Gem::Version
189
189
  version: '0'
190
190
  requirements: []
191
- rubygems_version: 3.0.3
191
+ rubygems_version: 3.1.4
192
192
  signing_key:
193
193
  specification_version: 4
194
194
  summary: Transport interface to talk to a selected set of backends.