train 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 (50) 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/azure.rb +23 -23
  34. data/lib/train/transports/cisco_ios_connection.rb +20 -20
  35. data/lib/train/transports/clients/azure/graph_rbac.rb +2 -2
  36. data/lib/train/transports/clients/azure/vault.rb +4 -4
  37. data/lib/train/transports/docker.rb +4 -10
  38. data/lib/train/transports/gcp.rb +23 -23
  39. data/lib/train/transports/helpers/azure/file_credentials.rb +8 -8
  40. data/lib/train/transports/helpers/azure/file_parser.rb +1 -1
  41. data/lib/train/transports/helpers/azure/subscription_number_file_parser.rb +1 -1
  42. data/lib/train/transports/local.rb +22 -22
  43. data/lib/train/transports/mock.rb +33 -35
  44. data/lib/train/transports/ssh.rb +47 -47
  45. data/lib/train/transports/ssh_connection.rb +28 -28
  46. data/lib/train/transports/vmware.rb +32 -34
  47. data/lib/train/transports/winrm.rb +37 -37
  48. data/lib/train/transports/winrm_connection.rb +12 -12
  49. data/lib/train/version.rb +1 -1
  50. metadata +2 -2
@@ -1,8 +1,6 @@
1
- # encoding: utf-8
2
-
3
- require 'digest/sha1'
4
- require 'securerandom'
5
- require 'json'
1
+ require "digest/sha1"
2
+ require "securerandom"
3
+ require "json"
6
4
 
7
5
  module Train::Platforms::Detect
8
6
  class UUID
@@ -24,10 +22,10 @@ module Train::Platforms::Detect
24
22
  else
25
23
  if @platform[:uuid_command]
26
24
  result = @backend.run_command(@platform[:uuid_command])
27
- return uuid_from_string(result.stdout.chomp) if result.exit_status.zero? && !result.stdout.empty?
25
+ return uuid_from_string(result.stdout.chomp) if result.exit_status == 0 && !result.stdout.empty?
28
26
  end
29
27
 
30
- raise 'Could not find platform uuid! Please set a uuid_command for your platform.'
28
+ raise "Could not find platform uuid! Please set a uuid_command for your platform."
31
29
  end
32
30
  end
33
31
  end
@@ -44,7 +44,7 @@ module Train::Platforms
44
44
  @cleaned_name = nil if force
45
45
  @cleaned_name ||= begin
46
46
  name = (@platform[:name] || @name)
47
- name.downcase!.tr!(' ', '_') if name =~ /[A-Z ]/
47
+ name.downcase!.tr!(" ", "_") if name =~ /[A-Z ]/
48
48
  name
49
49
  end
50
50
  end
@@ -59,7 +59,7 @@ module Train::Platforms
59
59
  if respond_to?(name)
60
60
  send(name)
61
61
  else
62
- 'unknown'
62
+ "unknown"
63
63
  end
64
64
  end
65
65
 
@@ -73,6 +73,10 @@ module Train::Platforms
73
73
  @platform
74
74
  end
75
75
 
76
+ def cisco_ios? # TODO: kinda a hack. needed to prevent tests from corrupting.
77
+ false
78
+ end
79
+
76
80
  # Add generic family? and platform methods to an existing platform
77
81
  #
78
82
  # This is done later to add any custom
@@ -84,8 +88,8 @@ module Train::Platforms
84
88
  # Add in family methods
85
89
  family_list = Train::Platforms.families
86
90
  family_list.each_value do |k|
87
- next if respond_to?(k.name + '?')
88
- define_singleton_method(k.name + '?') do
91
+ next if respond_to?(k.name + "?")
92
+ define_singleton_method(k.name + "?") do
89
93
  family_hierarchy.include?(k.name)
90
94
  end
91
95
  end
@@ -99,7 +103,7 @@ module Train::Platforms
99
103
  end
100
104
 
101
105
  # Create method for name if its not already true
102
- m = name + '?'
106
+ m = name + "?"
103
107
  return if respond_to?(m)
104
108
  define_singleton_method(m) do
105
109
  true
@@ -3,27 +3,27 @@
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
- require 'train'
6
+ require "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
10
10
  # probably want to use something like minitest/spec, which provides Spec-style
11
11
  # tests.
12
- require 'minitest/spec'
13
- require 'minitest/autorun'
12
+ require "minitest/spec"
13
+ require "minitest/autorun"
14
14
 
15
15
  # Data formats commonly used in testing
16
- require 'json'
17
- require 'ostruct'
16
+ require "json"
17
+ require "ostruct"
18
18
 
19
19
  # Utilities often needed
20
- require 'fileutils'
21
- require 'tmpdir'
22
- require 'pathname'
20
+ require "fileutils"
21
+ require "tmpdir"
22
+ require "pathname"
23
23
 
24
24
  # You might want to put some debugging tools here. We run tests to find bugs,
25
25
  # after all.
26
- require 'byebug'
26
+ require "byebug"
27
27
 
28
28
  # Configure MiniTest to expose things like `let`
29
29
  class Module
@@ -38,11 +38,11 @@ module TrainPluginBaseHelper
38
38
  plugin_test_helper_path = Pathname.new(caller_locations(4, 1).first.absolute_path)
39
39
  plugin_src_root = plugin_test_helper_path.parent.parent
40
40
  base.let(:plugin_src_path) { plugin_src_root }
41
- base.let(:plugin_fixtures_path) { File.join(plugin_src_root, 'test', 'fixtures') }
41
+ base.let(:plugin_fixtures_path) { File.join(plugin_src_root, "test", "fixtures") }
42
42
  end
43
43
 
44
- let(:train_src_path) { File.expand_path(File.join(__FILE__, '..', '..')) }
45
- let(:train_fixtures_path) { File.join(train_src_path, 'test', 'fixtures') }
44
+ let(:train_src_path) { File.expand_path(File.join(__FILE__, "..", "..")) }
45
+ let(:train_fixtures_path) { File.join(train_src_path, "test", "fixtures") }
46
46
  let(:registry) { Train::Plugins.registry }
47
47
  end
48
48
 
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
- require 'train/errors'
6
+ require "train/errors"
7
7
 
8
8
  module Train
9
9
  class Plugins
10
- require 'train/plugins/transport'
10
+ require "train/plugins/transport"
11
11
 
12
12
  class << self
13
13
  # Retrieve the current plugin registry, containing all plugin names
@@ -30,10 +30,10 @@ module Train
30
30
  # @return [Transport] the versioned transport base class
31
31
  def self.plugin(version = 1)
32
32
  if version != 1
33
- fail ClientError,
34
- 'Only understand train plugin version 1. You are trying to '\
33
+ raise ClientError,
34
+ "Only understand train plugin version 1. You are trying to "\
35
35
  "initialize a train plugin #{version}, which is not supported "\
36
- 'in the current release of train.'
36
+ "in the current release of train."
37
37
  end
38
38
  ::Train::Plugins::Transport
39
39
  end
@@ -1,9 +1,9 @@
1
1
  # encoding: utf-8
2
2
 
3
- require 'train/errors'
4
- require 'train/extras'
5
- require 'train/file'
6
- require 'logger'
3
+ require "train/errors"
4
+ require "train/extras"
5
+ require "train/file"
6
+ require "logger"
7
7
 
8
8
  class Train::Plugins::Transport
9
9
  # A Connection instance can be generated and re-generated, given new
@@ -21,7 +21,7 @@ class Train::Plugins::Transport
21
21
  # @yield [self] yields itself for block-style invocation
22
22
  def initialize(options = nil)
23
23
  @options = options || {}
24
- @logger = @options.delete(:logger) || Logger.new(STDOUT)
24
+ @logger = @options.delete(:logger) || Logger.new($stdout, level: :fatal)
25
25
  Train::Platforms::Detect::Specifications::OS.load
26
26
  Train::Platforms::Detect::Specifications::Api.load
27
27
 
@@ -64,12 +64,12 @@ class Train::Plugins::Transport
64
64
  # Enable caching types for Train. Currently we support
65
65
  # :api_call, :file and :command types
66
66
  def enable_cache(type)
67
- fail Train::UnknownCacheType, "#{type} is not a valid cache type" unless @cache_enabled.keys.include?(type.to_sym)
67
+ raise Train::UnknownCacheType, "#{type} is not a valid cache type" unless @cache_enabled.keys.include?(type.to_sym)
68
68
  @cache_enabled[type.to_sym] = true
69
69
  end
70
70
 
71
71
  def disable_cache(type)
72
- fail Train::UnknownCacheType, "#{type} is not a valid cache type" unless @cache_enabled.keys.include?(type.to_sym)
72
+ raise Train::UnknownCacheType, "#{type} is not a valid cache type" unless @cache_enabled.keys.include?(type.to_sym)
73
73
  @cache_enabled[type.to_sym] = false
74
74
  clear_cache(type.to_sym)
75
75
  end
@@ -81,13 +81,13 @@ class Train::Plugins::Transport
81
81
 
82
82
  def to_json
83
83
  {
84
- 'files' => Hash[@cache[:file].map { |x, y| [x, y.to_json] }],
84
+ "files" => Hash[@cache[:file].map { |x, y| [x, y.to_json] }],
85
85
  }
86
86
  end
87
87
 
88
88
  def load_json(j)
89
- require 'train/transports/mock'
90
- j['files'].each do |path, jf|
89
+ require "train/transports/mock"
90
+ j["files"].each do |path, jf|
91
91
  @cache[:file][path] = Train::Transports::Mock::Connection::File.from_json(jf)
92
92
  end
93
93
  end
@@ -137,7 +137,7 @@ class Train::Plugins::Transport
137
137
  #
138
138
  # @return [LoginCommand] array of command line tokens
139
139
  def login_command
140
- fail NotImplementedError, "#{self.class} does not implement #login_command()"
140
+ raise NotImplementedError, "#{self.class} does not implement #login_command()"
141
141
  end
142
142
 
143
143
  # Block and return only when the remote host is prepared and ready to
@@ -161,7 +161,7 @@ class Train::Plugins::Transport
161
161
  #
162
162
  # @return [CommandResult] contains the result of running the command
163
163
  def run_command_via_connection(_command, &_data_handler)
164
- fail NotImplementedError, "#{self.class} does not implement #run_command_via_connection()"
164
+ raise NotImplementedError, "#{self.class} does not implement #run_command_via_connection()"
165
165
  end
166
166
 
167
167
  # Interact with files on the target. Read, write, and get metadata
@@ -170,7 +170,7 @@ class Train::Plugins::Transport
170
170
  # @param [String] path which is being inspected
171
171
  # @return [FileCommon] file object that allows for interaction
172
172
  def file_via_connection(_path, *_args)
173
- fail NotImplementedError, "#{self.class} does not implement #file_via_connection(...)"
173
+ raise NotImplementedError, "#{self.class} does not implement #file_via_connection(...)"
174
174
  end
175
175
 
176
176
  def clear_cache(type)
@@ -3,17 +3,17 @@
3
3
  # Author:: Dominik Richter (<dominik.richter@gmail.com>)
4
4
  # Author:: Christoph Hartmann (<chris@lollyrock.com>)
5
5
 
6
- require 'logger'
7
- require 'train/errors'
8
- require 'train/extras'
9
- require 'train/options'
6
+ require "logger"
7
+ require "train/errors"
8
+ require "train/extras"
9
+ require "train/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
- require 'train/plugins/base_connection'
16
+ require "train/plugins/base_connection"
17
17
 
18
18
  # Initialize a new Transport object
19
19
  #
@@ -21,7 +21,7 @@ class Train::Plugins
21
21
  # @return [Transport] the transport object
22
22
  def initialize(options = {})
23
23
  @options = merge_options({}, options || {})
24
- @logger = @options[:logger] || Logger.new(STDOUT)
24
+ @logger = @options[:logger] || Logger.new($stdout, level: :fatal)
25
25
  end
26
26
 
27
27
  # Create a connection to the target. Options may be provided
@@ -30,7 +30,7 @@ class Train::Plugins
30
30
  # @param [Hash] _options = nil provide optional configuration params
31
31
  # @return [Connection] the connection for this configuration
32
32
  def connection(_options = nil)
33
- fail Train::ClientError, "#{self.class} does not implement #connection()"
33
+ raise Train::ClientError, "#{self.class} does not implement #connection()"
34
34
  end
35
35
 
36
36
  # Register the inheriting class with as a train plugin using the
@@ -1,27 +1,27 @@
1
1
  # encoding: utf-8
2
2
 
3
- require 'train/plugins'
4
- require 'ms_rest_azure'
5
- require 'azure_mgmt_resources'
6
- require 'azure_graph_rbac'
7
- require 'azure_mgmt_key_vault'
8
- require 'socket'
9
- require 'timeout'
10
- require 'train/transports/helpers/azure/file_credentials'
11
- require 'train/transports/clients/azure/graph_rbac'
12
- require 'train/transports/clients/azure/vault'
3
+ require "train/plugins"
4
+ require "ms_rest_azure"
5
+ require "azure_mgmt_resources"
6
+ require "azure_graph_rbac"
7
+ require "azure_mgmt_key_vault"
8
+ require "socket"
9
+ require "timeout"
10
+ require "train/transports/helpers/azure/file_credentials"
11
+ require "train/transports/clients/azure/graph_rbac"
12
+ require "train/transports/clients/azure/vault"
13
13
 
14
14
  module Train::Transports
15
15
  class Azure < Train.plugin(1)
16
- name 'azure'
17
- option :tenant_id, default: ENV['AZURE_TENANT_ID']
18
- option :client_id, default: ENV['AZURE_CLIENT_ID']
19
- option :client_secret, default: ENV['AZURE_CLIENT_SECRET']
20
- option :subscription_id, default: ENV['AZURE_SUBSCRIPTION_ID']
21
- option :msi_port, default: ENV['AZURE_MSI_PORT'] || '50342'
16
+ name "azure"
17
+ option :tenant_id, default: ENV["AZURE_TENANT_ID"]
18
+ option :client_id, default: ENV["AZURE_CLIENT_ID"]
19
+ option :client_secret, default: ENV["AZURE_CLIENT_SECRET"]
20
+ option :subscription_id, default: ENV["AZURE_SUBSCRIPTION_ID"]
21
+ option :msi_port, default: ENV["AZURE_MSI_PORT"] || "50342"
22
22
 
23
23
  # This can provide the client id and secret
24
- option :credentials_file, default: ENV['AZURE_CRED_FILE']
24
+ option :credentials_file, default: ENV["AZURE_CRED_FILE"]
25
25
 
26
26
  def connection(_ = nil)
27
27
  @connection ||= Connection.new(@options)
@@ -30,7 +30,7 @@ module Train::Transports
30
30
  class Connection < BaseConnection
31
31
  attr_reader :options
32
32
 
33
- DEFAULT_FILE = ::File.join(Dir.home, '.azure', 'credentials')
33
+ DEFAULT_FILE = ::File.join(Dir.home, ".azure", "credentials")
34
34
 
35
35
  def initialize(options)
36
36
  @apis = {}
@@ -51,14 +51,14 @@ module Train::Transports
51
51
  @options[:msi_port] = @options[:msi_port].to_i unless @options[:msi_port].nil?
52
52
 
53
53
  # additional platform details
54
- release = Gem.loaded_specs['azure_mgmt_resources'].version
54
+ release = Gem.loaded_specs["azure_mgmt_resources"].version
55
55
  @platform_details = { release: "azure_mgmt_resources-v#{release}" }
56
56
 
57
57
  connect
58
58
  end
59
59
 
60
60
  def platform
61
- force_platform!('azure', @platform_details)
61
+ force_platform!("azure", @platform_details)
62
62
  end
63
63
 
64
64
  def azure_client(klass = ::Azure::Resources::Profiles::Latest::Mgmt::Client, opts = {})
@@ -85,13 +85,13 @@ module Train::Transports
85
85
  def connect
86
86
  if msi_auth?
87
87
  # this needs set for azure cloud to authenticate
88
- ENV['MSI_VM'] = 'true'
88
+ ENV["MSI_VM"] = "true"
89
89
  provider = ::MsRestAzure::MSITokenProvider.new(@options[:msi_port])
90
90
  else
91
91
  provider = ::MsRestAzure::ApplicationTokenProvider.new(
92
92
  @options[:tenant_id],
93
93
  @options[:client_id],
94
- @options[:client_secret],
94
+ @options[:client_secret]
95
95
  )
96
96
  end
97
97
 
@@ -166,7 +166,7 @@ module Train::Transports
166
166
  def port_open?(port, seconds = 3)
167
167
  Timeout.timeout(seconds) do
168
168
  begin
169
- TCPSocket.new('localhost', port).close
169
+ TCPSocket.new("localhost", port).close
170
170
  true
171
171
  rescue SystemCallError
172
172
  false
@@ -24,8 +24,8 @@ class Train::Transports::SSH
24
24
  end
25
25
 
26
26
  def unique_identifier
27
- result = run_command_via_connection('show version | include Processor')
28
- result.stdout.split(' ')[-1]
27
+ result = run_command_via_connection("show version | include Processor")
28
+ result.stdout.split(" ")[-1]
29
29
  end
30
30
 
31
31
  private
@@ -45,26 +45,26 @@ class Train::Transports::SSH
45
45
  if @enable_password
46
46
  # This verifies we are not in privileged exec mode before running the
47
47
  # enable command. Otherwise, the password will be in history.
48
- if run_command_via_connection('show privilege').stdout.split[-1] != '15'
48
+ if run_command_via_connection("show privilege").stdout.split[-1] != "15"
49
49
  # Extra newlines to get back to prompt if incorrect password is used
50
50
  run_command_via_connection("enable\n#{@enable_password}\n\n\n")
51
51
  end
52
52
  end
53
53
 
54
54
  # Prevent `--MORE--` by removing terminal length limit
55
- run_command_via_connection('terminal length 0')
55
+ run_command_via_connection("terminal length 0")
56
56
 
57
57
  @session
58
58
  end
59
59
 
60
60
  def run_command_via_connection(cmd, &_data_handler)
61
61
  # Ensure buffer is empty before sending data
62
- @buf = ''
62
+ @buf = ""
63
63
 
64
64
  logger.debug("[SSH] Running `#{cmd}` on #{self}")
65
65
  session.send_data(cmd + "\r\n")
66
66
 
67
- logger.debug('[SSH] waiting for prompt')
67
+ logger.debug("[SSH] waiting for prompt")
68
68
  until @buf =~ @prompt
69
69
  if @buf =~ /Bad (secrets|password)|Access denied/
70
70
  raise BadEnablePassword
@@ -74,16 +74,16 @@ class Train::Transports::SSH
74
74
 
75
75
  # Save the buffer and clear it for the next command
76
76
  output = @buf.dup
77
- @buf = ''
77
+ @buf = ""
78
78
 
79
79
  format_result(format_output(output, cmd))
80
80
  end
81
81
 
82
82
  ERROR_MATCHERS = [
83
- 'Bad IP address',
84
- 'Incomplete command',
85
- 'Invalid input detected',
86
- 'Unrecognized host',
83
+ "Bad IP address",
84
+ "Incomplete command",
85
+ "Invalid input detected",
86
+ "Unrecognized host",
87
87
  ].freeze
88
88
 
89
89
  # IOS commands do not have an exit code so we must compare the command
@@ -92,9 +92,9 @@ class Train::Transports::SSH
92
92
  # result.
93
93
  def format_result(result)
94
94
  if ERROR_MATCHERS.none? { |e| result.include?(e) }
95
- CommandResult.new(result, '', 0)
95
+ CommandResult.new(result, "", 0)
96
96
  else
97
- CommandResult.new('', result, 1)
97
+ CommandResult.new("", result, 1)
98
98
  end
99
99
  end
100
100
 
@@ -107,10 +107,10 @@ class Train::Transports::SSH
107
107
  trailing_line_endings = /(\r\n)+$/
108
108
 
109
109
  output
110
- .sub(leading_prompt, '')
111
- .sub(command_string, '')
112
- .gsub(trailing_prompt, '')
113
- .gsub(trailing_line_endings, '')
110
+ .sub(leading_prompt, "")
111
+ .sub(command_string, "")
112
+ .gsub(trailing_prompt, "")
113
+ .gsub(trailing_line_endings, "")
114
114
  end
115
115
 
116
116
  # Create an SSH channel that writes to @buf when data is received
@@ -121,9 +121,9 @@ class Train::Transports::SSH
121
121
  @buf += data
122
122
  end
123
123
 
124
- ch.send_channel_request('shell') do |_, success|
125
- raise 'Failed to open SSH shell' unless success
126
- logger.debug('[SSH] shell opened')
124
+ ch.send_channel_request("shell") do |_, success|
125
+ raise "Failed to open SSH shell" unless success
126
+ logger.debug("[SSH] shell opened")
127
127
  end
128
128
  end
129
129
  end