train-core 2.1.7 → 2.1.13

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/lib/train.rb +20 -20
  3. data/lib/train/errors.rb +1 -1
  4. data/lib/train/extras.rb +2 -2
  5. data/lib/train/extras/command_wrapper.rb +24 -24
  6. data/lib/train/extras/stat.rb +27 -27
  7. data/lib/train/file.rb +30 -30
  8. data/lib/train/file/local.rb +8 -8
  9. data/lib/train/file/local/unix.rb +5 -5
  10. data/lib/train/file/local/windows.rb +1 -1
  11. data/lib/train/file/remote.rb +8 -8
  12. data/lib/train/file/remote/aix.rb +1 -1
  13. data/lib/train/file/remote/linux.rb +2 -2
  14. data/lib/train/file/remote/qnx.rb +8 -8
  15. data/lib/train/file/remote/unix.rb +10 -14
  16. data/lib/train/file/remote/windows.rb +5 -5
  17. data/lib/train/globals.rb +1 -1
  18. data/lib/train/options.rb +8 -8
  19. data/lib/train/platforms.rb +8 -8
  20. data/lib/train/platforms/common.rb +1 -1
  21. data/lib/train/platforms/detect/helpers/os_common.rb +36 -32
  22. data/lib/train/platforms/detect/helpers/os_linux.rb +12 -12
  23. data/lib/train/platforms/detect/helpers/os_windows.rb +27 -29
  24. data/lib/train/platforms/detect/scanner.rb +4 -4
  25. data/lib/train/platforms/detect/specifications/api.rb +8 -8
  26. data/lib/train/platforms/detect/specifications/os.rb +252 -252
  27. data/lib/train/platforms/detect/uuid.rb +5 -7
  28. data/lib/train/platforms/platform.rb +9 -5
  29. data/lib/train/plugin_test_helper.rb +12 -12
  30. data/lib/train/plugins.rb +5 -5
  31. data/lib/train/plugins/base_connection.rb +13 -13
  32. data/lib/train/plugins/transport.rb +7 -7
  33. data/lib/train/transports/cisco_ios_connection.rb +20 -20
  34. data/lib/train/transports/local.rb +22 -22
  35. data/lib/train/transports/mock.rb +33 -35
  36. data/lib/train/transports/ssh.rb +47 -47
  37. data/lib/train/transports/ssh_connection.rb +28 -28
  38. data/lib/train/transports/winrm.rb +37 -37
  39. data/lib/train/transports/winrm_connection.rb +12 -12
  40. data/lib/train/version.rb +1 -1
  41. metadata +2 -2
@@ -1,11 +1,9 @@
1
- # encoding: utf-8
2
-
3
- require 'train/plugins'
4
- require 'digest'
1
+ require "train/plugins"
2
+ require "digest"
5
3
 
6
4
  module Train::Transports
7
5
  class Mock < Train.plugin(1)
8
- name 'mock'
6
+ name "mock"
9
7
 
10
8
  def initialize(conf = nil)
11
9
  @conf = conf || {}
@@ -17,39 +15,39 @@ module Train::Transports
17
15
  end
18
16
 
19
17
  def to_s
20
- 'Mock Transport'
18
+ "Mock Transport"
21
19
  end
22
20
 
23
21
  private
24
22
 
25
23
  def trace_calls
26
24
  interface_methods = {
27
- 'Train::Transports::Mock' =>
25
+ "Train::Transports::Mock" =>
28
26
  Train::Transports::Mock.instance_methods(false),
29
- 'Train::Transports::Mock::Connection' =>
27
+ "Train::Transports::Mock::Connection" =>
30
28
  Connection.instance_methods(false),
31
- 'Train::Transports::Mock::Connection::File' =>
29
+ "Train::Transports::Mock::Connection::File" =>
32
30
  Connection::FileCommon.instance_methods(false),
33
- 'Train::Transports::Mock::Connection::OS' =>
31
+ "Train::Transports::Mock::Connection::OS" =>
34
32
  Train::Platform.instance_methods(false),
35
33
  }
36
34
 
37
35
  # rubocop:disable Metrics/ParameterLists
38
36
  # rubocop:disable Lint/Eval
39
- set_trace_func proc { |event, _file, _line, id, binding, classname|
40
- unless classname.to_s.start_with?('Train::Transports::Mock') and
41
- event == 'call' and
42
- interface_methods[classname.to_s].include?(id)
37
+ set_trace_func(proc { |event, _file, _line, id, binding, classname|
38
+ unless classname.to_s.start_with?("Train::Transports::Mock") &&
39
+ (event == "call") &&
40
+ interface_methods[classname.to_s].include?(id)
43
41
  next
44
42
  end
45
43
  # kindly borrowed from the wonderful simple-tracer by matugm
46
44
  arg_names = eval(
47
- 'method(__method__).parameters.map { |arg| arg[1].to_s }',
45
+ "method(__method__).parameters.map { |arg| arg[1].to_s }",
48
46
  binding)
49
- args = eval("#{arg_names}.map { |arg| eval(arg) }", binding).join(', ')
50
- prefix = '-' * (classname.to_s.count(':') - 2) + '> '
47
+ args = eval("#{arg_names}.map { |arg| eval(arg) }", binding).join(", ")
48
+ prefix = "-" * (classname.to_s.count(":") - 2) + "> "
51
49
  puts("#{prefix}#{id} #{args}")
52
- }
50
+ })
53
51
  # rubocop:enable all
54
52
  end
55
53
  end
@@ -67,14 +65,14 @@ class Train::Transports::Mock
67
65
  end
68
66
 
69
67
  def uri
70
- 'mock://'
68
+ "mock://"
71
69
  end
72
70
 
73
71
  def mock_os(value = {})
74
72
  # if a user passes a nil value, set to an empty hash so the merge still succeeds
75
73
  value ||= {}
76
- value.each { |k, v| value[k] = 'unknown' if v.nil? }
77
- value = { name: 'mock', family: 'mock', release: 'unknown', arch: 'unknown' }.merge(value)
74
+ value.each { |k, v| value[k] = "unknown" if v.nil? }
75
+ value = { name: "mock", family: "mock", release: "unknown", arch: "unknown" }.merge(value)
78
76
 
79
77
  platform = Train::Platforms.name(value[:name])
80
78
  platform.find_family_hierarchy
@@ -100,26 +98,26 @@ class Train::Transports::Mock
100
98
  end
101
99
 
102
100
  def mock_command(cmd, stdout = nil, stderr = nil, exit_status = 0)
103
- @cache[:command][cmd] = Command.new(stdout || '', stderr || '', exit_status)
101
+ @cache[:command][cmd] = Command.new(stdout || "", stderr || "", exit_status)
104
102
  end
105
103
 
106
104
  def command_not_found(cmd)
107
105
  if @options[:verbose]
108
- STDERR.puts('Command not mocked:')
109
- STDERR.puts(' '+cmd.to_s.split("\n").join("\n "))
110
- STDERR.puts(' SHA: ' + Digest::SHA256.hexdigest(cmd.to_s))
106
+ $stderr.puts("Command not mocked:")
107
+ $stderr.puts(" " + cmd.to_s.split("\n").join("\n "))
108
+ $stderr.puts(" SHA: " + Digest::SHA256.hexdigest(cmd.to_s))
111
109
  end
112
110
  # return a non-zero exit code
113
111
  mock_command(cmd, nil, nil, 1)
114
112
  end
115
113
 
116
114
  def file_not_found(path)
117
- STDERR.puts('File not mocked: '+path.to_s) if @options[:verbose]
115
+ $stderr.puts("File not mocked: " + path.to_s) if @options[:verbose]
118
116
  File.new(self, path)
119
117
  end
120
118
 
121
119
  def to_s
122
- 'Mock Connection'
120
+ "Mock Connection"
123
121
  end
124
122
 
125
123
  private
@@ -142,23 +140,23 @@ end
142
140
  class Train::Transports::Mock::Connection
143
141
  class File < Train::File
144
142
  def self.from_json(json)
145
- res = new(json['backend'],
146
- json['path'],
147
- json['follow_symlink'])
148
- res.type = json['type']
143
+ res = new(json["backend"],
144
+ json["path"],
145
+ json["follow_symlink"])
146
+ res.type = json["type"]
149
147
  Train::File::DATA_FIELDS.each do |f|
150
- m = (f.tr('?', '') + '=').to_sym
148
+ m = (f.tr("?", "") + "=").to_sym
151
149
  res.method(m).call(json[f])
152
150
  end
153
151
  res
154
152
  end
155
153
 
156
154
  Train::File::DATA_FIELDS.each do |m|
157
- attr_accessor m.tr('?', '').to_sym
158
- next unless m.include?('?')
155
+ attr_accessor m.tr("?", "").to_sym
156
+ next unless m.include?("?")
159
157
 
160
158
  define_method m.to_sym do
161
- method(m.tr('?', '').to_sym).call
159
+ method(m.tr("?", "").to_sym).call
162
160
  end
163
161
  end
164
162
  attr_accessor :type
@@ -18,9 +18,9 @@
18
18
  # See the License for the specific language governing permissions and
19
19
  # limitations under the License.
20
20
 
21
- require 'net/ssh'
22
- require 'net/scp'
23
- require 'train/errors'
21
+ require "net/ssh"
22
+ require "net/scp"
23
+ require "train/errors"
24
24
 
25
25
  module Train::Transports
26
26
  # Wrapped exception for any internally raised SSH-related errors.
@@ -34,10 +34,10 @@ module Train::Transports
34
34
  #
35
35
  # @author Fletcher Nichol <fnichol@nichol.ca>
36
36
  class SSH < Train.plugin(1) # rubocop:disable Metrics/ClassLength
37
- name 'ssh'
37
+ name "ssh"
38
38
 
39
- require 'train/transports/ssh_connection'
40
- require 'train/transports/cisco_ios_connection'
39
+ require "train/transports/ssh_connection"
40
+ require "train/transports/cisco_ios_connection"
41
41
 
42
42
  # add options for submodules
43
43
  include_options Train::Extras::CommandWrapper
@@ -45,7 +45,7 @@ module Train::Transports
45
45
  # common target configuration
46
46
  option :host, required: true
47
47
  option :port, default: 22, required: true
48
- option :user, default: 'root', required: true
48
+ option :user, default: "root", required: true
49
49
  option :key_files, default: nil
50
50
  option :password, default: nil
51
51
 
@@ -60,7 +60,7 @@ module Train::Transports
60
60
  option :pty, default: false
61
61
  option :proxy_command, default: nil
62
62
  option :bastion_host, default: nil
63
- option :bastion_user, default: 'root'
63
+ option :bastion_user, default: "root"
64
64
  option :bastion_port, default: 22
65
65
  option :non_interactive, default: false
66
66
  option :verify_host_key, default: false
@@ -89,34 +89,34 @@ module Train::Transports
89
89
  super(options)
90
90
 
91
91
  key_files = Array(options[:key_files])
92
- options[:auth_methods] ||= ['none']
92
+ options[:auth_methods] ||= ["none"]
93
93
 
94
94
  unless key_files.empty?
95
- options[:auth_methods].push('publickey')
95
+ options[:auth_methods].push("publickey")
96
96
  options[:keys_only] = true if options[:password].nil?
97
97
  options[:key_files] = key_files
98
98
  end
99
99
 
100
100
  unless options[:password].nil?
101
- options[:auth_methods].push('password', 'keyboard-interactive')
101
+ options[:auth_methods].push("password", "keyboard-interactive")
102
102
  end
103
103
 
104
- if options[:auth_methods] == ['none']
104
+ if options[:auth_methods] == ["none"]
105
105
  if ssh_known_identities.empty?
106
- fail Train::ClientError,
107
- 'Your SSH Agent has no keys added, and you have not specified a password or a key file'
106
+ raise Train::ClientError,
107
+ "Your SSH Agent has no keys added, and you have not specified a password or a key file"
108
108
  else
109
- logger.debug('[SSH] Using Agent keys as no password or key file have been specified')
110
- options[:auth_methods].push('publickey')
109
+ logger.debug("[SSH] Using Agent keys as no password or key file have been specified")
110
+ options[:auth_methods].push("publickey")
111
111
  end
112
112
  end
113
113
 
114
114
  if options[:pty]
115
- logger.warn('[SSH] PTY requested: stderr will be merged into stdout')
115
+ logger.warn("[SSH] PTY requested: stderr will be merged into stdout")
116
116
  end
117
117
 
118
118
  if [options[:proxy_command], options[:bastion_host]].all? { |type| !type.nil? }
119
- fail Train::ClientError, 'Only one of proxy_command or bastion_host needs to be specified'
119
+ raise Train::ClientError, "Only one of proxy_command or bastion_host needs to be specified"
120
120
  end
121
121
 
122
122
  super
@@ -142,30 +142,30 @@ module Train::Transports
142
142
  # @api private
143
143
  def connection_options(opts)
144
144
  connection_options = {
145
- logger: logger,
146
- user_known_hosts_file: '/dev/null',
147
- hostname: opts[:host],
148
- port: opts[:port],
149
- username: opts[:user],
150
- compression: opts[:compression],
151
- compression_level: opts[:compression_level],
152
- keepalive: opts[:keepalive],
153
- keepalive_interval: opts[:keepalive_interval],
154
- timeout: opts[:connection_timeout],
155
- connection_retries: opts[:connection_retries],
145
+ logger: logger,
146
+ user_known_hosts_file: "/dev/null",
147
+ hostname: opts[:host],
148
+ port: opts[:port],
149
+ username: opts[:user],
150
+ compression: opts[:compression],
151
+ compression_level: opts[:compression_level],
152
+ keepalive: opts[:keepalive],
153
+ keepalive_interval: opts[:keepalive_interval],
154
+ timeout: opts[:connection_timeout],
155
+ connection_retries: opts[:connection_retries],
156
156
  connection_retry_sleep: opts[:connection_retry_sleep],
157
- max_wait_until_ready: opts[:max_wait_until_ready],
158
- auth_methods: opts[:auth_methods],
159
- keys_only: opts[:keys_only],
160
- keys: opts[:key_files],
161
- password: opts[:password],
162
- forward_agent: opts[:forward_agent],
163
- proxy_command: opts[:proxy_command],
164
- bastion_host: opts[:bastion_host],
165
- bastion_user: opts[:bastion_user],
166
- bastion_port: opts[:bastion_port],
167
- non_interactive: opts[:non_interactive],
168
- transport_options: opts,
157
+ max_wait_until_ready: opts[:max_wait_until_ready],
158
+ auth_methods: opts[:auth_methods],
159
+ keys_only: opts[:keys_only],
160
+ keys: opts[:key_files],
161
+ password: opts[:password],
162
+ forward_agent: opts[:forward_agent],
163
+ proxy_command: opts[:proxy_command],
164
+ bastion_host: opts[:bastion_host],
165
+ bastion_user: opts[:bastion_user],
166
+ bastion_port: opts[:bastion_port],
167
+ non_interactive: opts[:non_interactive],
168
+ transport_options: opts,
169
169
  }
170
170
  # disable host key verification. The hash key and value to use
171
171
  # depends on the version of net-ssh in use.
@@ -203,20 +203,20 @@ module Train::Transports
203
203
  # 5.0+ style
204
204
  {
205
205
  # It's not a boolean anymore.
206
- 'true' => :always,
207
- 'false' => :never,
206
+ "true" => :always,
207
+ "false" => :never,
208
208
  true => :always,
209
209
  false => :never,
210
210
  # May be correct value, but strings from JSON config
211
- 'always' => :always,
212
- 'never' => :never,
211
+ "always" => :always,
212
+ "never" => :never,
213
213
  nil => :never,
214
214
  }.fetch(given, given)
215
215
  else
216
216
  # up to 4.2 style
217
217
  {
218
- 'true' => true,
219
- 'false' => false,
218
+ "true" => true,
219
+ "false" => false,
220
220
  nil => false,
221
221
  }.fetch(given, given)
222
222
  end
@@ -18,9 +18,9 @@
18
18
  # See the License for the specific language governing permissions and
19
19
  # limitations under the License.
20
20
 
21
- require 'net/ssh'
22
- require 'net/scp'
23
- require 'timeout'
21
+ require "net/ssh"
22
+ require "net/scp"
23
+ require "timeout"
24
24
 
25
25
  class Train::Transports::SSH
26
26
  # A Connection instance can be generated and re-generated, given new
@@ -63,17 +63,17 @@ class Train::Transports::SSH
63
63
  end
64
64
 
65
65
  def ssh_opts
66
- level = logger.debug? ? 'VERBOSE' : 'ERROR'
67
- fwd_agent = options[:forward_agent] ? 'yes' : 'no'
66
+ level = logger.debug? ? "VERBOSE" : "ERROR"
67
+ fwd_agent = options[:forward_agent] ? "yes" : "no"
68
68
 
69
69
  args = %w{ -o UserKnownHostsFile=/dev/null }
70
70
  args += %w{ -o StrictHostKeyChecking=no }
71
71
  args += %w{ -o IdentitiesOnly=yes } if options[:keys]
72
72
  args += %w{ -o BatchMode=yes } if options[:non_interactive]
73
- args += %W( -o LogLevel=#{level} )
74
- args += %W( -o ForwardAgent=#{fwd_agent} ) if options.key?(:forward_agent)
73
+ args += %W{ -o LogLevel=#{level} }
74
+ args += %W{ -o ForwardAgent=#{fwd_agent} } if options.key?(:forward_agent)
75
75
  Array(options[:keys]).each do |ssh_key|
76
- args += %W( -i #{ssh_key} )
76
+ args += %W{ -i #{ssh_key} }
77
77
  end
78
78
  args
79
79
  end
@@ -86,19 +86,19 @@ class Train::Transports::SSH
86
86
  return @proxy_command unless @proxy_command.nil?
87
87
  args = %w{ ssh }
88
88
  args += ssh_opts
89
- args += %W( #{@bastion_user}@#{@bastion_host} )
90
- args += %W( -p #{@bastion_port} )
89
+ args += %W{ #{@bastion_user}@#{@bastion_host} }
90
+ args += %W{ -p #{@bastion_port} }
91
91
  args += %w{ -W %h:%p }
92
- args.join(' ')
92
+ args.join(" ")
93
93
  end
94
94
 
95
95
  # (see Base::Connection#login_command)
96
96
  def login_command
97
97
  args = ssh_opts
98
- args += %W( -o ProxyCommand='#{generate_proxy_command}' ) if check_proxy
99
- args += %W( -p #{@port} )
100
- args += %W( #{@username}@#{@hostname} )
101
- LoginCommand.new('ssh', args)
98
+ args += %W{ -o ProxyCommand='#{generate_proxy_command}' } if check_proxy
99
+ args += %W{ -p #{@port} }
100
+ args += %W{ #{@username}@#{@hostname} }
101
+ LoginCommand.new("ssh", args)
102
102
  end
103
103
 
104
104
  # (see Base::Connection#upload)
@@ -138,7 +138,7 @@ class Train::Transports::SSH
138
138
  retries: @max_wait_until_ready / delay,
139
139
  delay: delay,
140
140
  message: "Waiting for SSH service on #{@hostname}:#{@port}, " \
141
- "retrying in #{delay} seconds",
141
+ "retrying in #{delay} seconds"
142
142
  )
143
143
  run_command(PING_COMMAND.dup)
144
144
  end
@@ -172,14 +172,14 @@ class Train::Transports::SSH
172
172
  def establish_connection(opts)
173
173
  logger.debug("[SSH] opening connection to #{self}")
174
174
  if check_proxy
175
- require 'net/ssh/proxy/command'
175
+ require "net/ssh/proxy/command"
176
176
  @options[:proxy] = Net::SSH::Proxy::Command.new(generate_proxy_command)
177
177
  end
178
178
  Net::SSH.start(@hostname, @username, @options.clone.delete_if { |_key, value| value.nil? })
179
179
  rescue *RESCUE_EXCEPTIONS_ON_ESTABLISH => e
180
180
  if (opts[:retries] -= 1) <= 0
181
181
  logger.warn("[SSH] connection failed, terminating (#{e.inspect})")
182
- raise Train::Transports::SSHFailed, 'SSH session could not be established'
182
+ raise Train::Transports::SSHFailed, "SSH session could not be established"
183
183
  end
184
184
 
185
185
  if opts[:message]
@@ -200,7 +200,7 @@ class Train::Transports::SSH
200
200
  Train::File::Remote::Aix.new(self, path)
201
201
  elsif os.solaris?
202
202
  Train::File::Remote::Unix.new(self, path)
203
- elsif os[:name] == 'qnx'
203
+ elsif os[:name] == "qnx"
204
204
  Train::File::Remote::Qnx.new(self, path)
205
205
  elsif os.windows?
206
206
  Train::File::Remote::Windows.new(self, path)
@@ -210,7 +210,7 @@ class Train::Transports::SSH
210
210
  end
211
211
 
212
212
  def run_command_via_connection(cmd, &data_handler)
213
- cmd.dup.force_encoding('binary') if cmd.respond_to?(:force_encoding)
213
+ cmd.dup.force_encoding("binary") if cmd.respond_to?(:force_encoding)
214
214
  logger.debug("[SSH] #{self} (#{cmd})")
215
215
 
216
216
  reset_session if session.closed?
@@ -228,7 +228,7 @@ class Train::Transports::SSH
228
228
  # transport. This retries the command if this is the case.
229
229
  # See:
230
230
  # https://github.com/inspec/train/pull/271
231
- logger.debug('[SSH] Possible Cisco IOS race condition, retrying command')
231
+ logger.debug("[SSH] Possible Cisco IOS race condition, retrying command")
232
232
 
233
233
  # Only attempt retry up to 5 times to avoid infinite loop
234
234
  @ios_cmd_retries += 1
@@ -246,7 +246,7 @@ class Train::Transports::SSH
246
246
  def session(retry_options = {})
247
247
  @session ||= establish_connection({
248
248
  retries: @connection_retries.to_i,
249
- delay: @connection_retry_sleep.to_i,
249
+ delay: @connection_retry_sleep.to_i,
250
250
  }.merge(retry_options))
251
251
  end
252
252
 
@@ -260,7 +260,7 @@ class Train::Transports::SSH
260
260
  # @api private
261
261
  def to_s
262
262
  options_to_print = @options.clone
263
- options_to_print[:password] = '<hidden>' if options_to_print.key?(:password)
263
+ options_to_print[:password] = "<hidden>" if options_to_print.key?(:password)
264
264
  "#{@username}@#{@hostname}<#{options_to_print.inspect}>"
265
265
  end
266
266
 
@@ -274,7 +274,7 @@ class Train::Transports::SSH
274
274
  #
275
275
  # @api private
276
276
  def execute_on_channel(cmd, &data_handler)
277
- stdout = stderr = ''
277
+ stdout = stderr = ""
278
278
  exit_status = nil
279
279
  session.open_channel do |channel|
280
280
  # wrap commands if that is configured
@@ -282,11 +282,11 @@ class Train::Transports::SSH
282
282
 
283
283
  if @transport_options[:pty]
284
284
  channel.request_pty do |_ch, success|
285
- fail Train::Transports::SSHPTYFailed, 'Requesting PTY failed' unless success
285
+ raise Train::Transports::SSHPTYFailed, "Requesting PTY failed" unless success
286
286
  end
287
287
  end
288
288
  channel.exec(cmd) do |_, success|
289
- abort 'Couldn\'t execute command on SSH.' unless success
289
+ abort "Couldn't execute command on SSH." unless success
290
290
  channel.on_data do |_, data|
291
291
  yield(data) unless data_handler.nil?
292
292
  stdout += data
@@ -297,11 +297,11 @@ class Train::Transports::SSH
297
297
  stderr += data
298
298
  end
299
299
 
300
- channel.on_request('exit-status') do |_, data|
300
+ channel.on_request("exit-status") do |_, data|
301
301
  exit_status = data.read_long
302
302
  end
303
303
 
304
- channel.on_request('exit-signal') do |_, data|
304
+ channel.on_request("exit-signal") do |_, data|
305
305
  exit_status = data.read_long
306
306
  end
307
307
  end