train 3.2.14 → 3.2.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- metadata +29 -149
- data/LICENSE +0 -201
- data/lib/train.rb +0 -193
- data/lib/train/errors.rb +0 -44
- data/lib/train/extras.rb +0 -11
- data/lib/train/extras/command_wrapper.rb +0 -201
- data/lib/train/extras/stat.rb +0 -136
- data/lib/train/file.rb +0 -212
- data/lib/train/file/local.rb +0 -82
- data/lib/train/file/local/unix.rb +0 -96
- data/lib/train/file/local/windows.rb +0 -68
- data/lib/train/file/remote.rb +0 -40
- data/lib/train/file/remote/aix.rb +0 -29
- data/lib/train/file/remote/linux.rb +0 -21
- data/lib/train/file/remote/qnx.rb +0 -41
- data/lib/train/file/remote/unix.rb +0 -110
- data/lib/train/file/remote/windows.rb +0 -110
- data/lib/train/globals.rb +0 -5
- data/lib/train/options.rb +0 -81
- data/lib/train/platforms.rb +0 -102
- data/lib/train/platforms/common.rb +0 -34
- data/lib/train/platforms/detect.rb +0 -12
- data/lib/train/platforms/detect/helpers/os_common.rb +0 -160
- data/lib/train/platforms/detect/helpers/os_linux.rb +0 -80
- data/lib/train/platforms/detect/helpers/os_windows.rb +0 -142
- data/lib/train/platforms/detect/scanner.rb +0 -85
- data/lib/train/platforms/detect/specifications/api.rb +0 -20
- data/lib/train/platforms/detect/specifications/os.rb +0 -629
- data/lib/train/platforms/detect/uuid.rb +0 -32
- data/lib/train/platforms/family.rb +0 -31
- data/lib/train/platforms/platform.rb +0 -109
- data/lib/train/plugin_test_helper.rb +0 -51
- data/lib/train/plugins.rb +0 -40
- data/lib/train/plugins/base_connection.rb +0 -198
- data/lib/train/plugins/transport.rb +0 -49
- data/lib/train/transports/cisco_ios_connection.rb +0 -133
- data/lib/train/transports/local.rb +0 -240
- data/lib/train/transports/mock.rb +0 -183
- data/lib/train/transports/ssh.rb +0 -271
- data/lib/train/transports/ssh_connection.rb +0 -342
- data/lib/train/version.rb +0 -7
@@ -1,32 +0,0 @@
|
|
1
|
-
require "digest/sha1"
|
2
|
-
require "securerandom"
|
3
|
-
require "json"
|
4
|
-
|
5
|
-
module Train::Platforms::Detect
|
6
|
-
class UUID
|
7
|
-
include Train::Platforms::Detect::Helpers::OSCommon
|
8
|
-
|
9
|
-
def initialize(platform)
|
10
|
-
@platform = platform
|
11
|
-
@backend = @platform.backend
|
12
|
-
end
|
13
|
-
|
14
|
-
def find_or_create_uuid
|
15
|
-
# for api transports uuid is defined on the connection
|
16
|
-
if defined?(@backend.unique_identifier)
|
17
|
-
uuid_from_string(@backend.unique_identifier)
|
18
|
-
elsif @platform.unix?
|
19
|
-
unix_uuid
|
20
|
-
elsif @platform.windows?
|
21
|
-
windows_uuid
|
22
|
-
else
|
23
|
-
if @platform[:uuid_command]
|
24
|
-
result = @backend.run_command(@platform[:uuid_command])
|
25
|
-
return uuid_from_string(result.stdout.chomp) if result.exit_status == 0 && !result.stdout.empty?
|
26
|
-
end
|
27
|
-
|
28
|
-
raise "Could not find platform uuid! Please set a uuid_command for your platform."
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
@@ -1,31 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
module Train::Platforms
|
4
|
-
class Family
|
5
|
-
include Train::Platforms::Common
|
6
|
-
attr_accessor :children, :condition, :families, :name
|
7
|
-
|
8
|
-
def initialize(name, condition)
|
9
|
-
@name = name
|
10
|
-
@condition = condition
|
11
|
-
@families = {}
|
12
|
-
@children = {}
|
13
|
-
@detect = nil
|
14
|
-
@title = "#{name.to_s.capitalize} Family"
|
15
|
-
|
16
|
-
# add itself to the families list
|
17
|
-
Train::Platforms.families[@name.to_s] = self
|
18
|
-
end
|
19
|
-
|
20
|
-
def title(title = nil)
|
21
|
-
return @title if title.nil?
|
22
|
-
|
23
|
-
@title = title
|
24
|
-
self
|
25
|
-
end
|
26
|
-
|
27
|
-
def inspect
|
28
|
-
"%p[%s]" % [self.class, name]
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
@@ -1,109 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
module Train::Platforms
|
4
|
-
class Platform
|
5
|
-
include Train::Platforms::Common
|
6
|
-
attr_accessor :backend, :condition, :families, :family_hierarchy, :platform
|
7
|
-
|
8
|
-
def initialize(name, condition = {})
|
9
|
-
@name = name
|
10
|
-
@condition = condition
|
11
|
-
@families = {}
|
12
|
-
@family_hierarchy = []
|
13
|
-
@platform = {}
|
14
|
-
@detect = nil
|
15
|
-
@title = name.to_s.capitalize
|
16
|
-
|
17
|
-
# add itself to the platform list
|
18
|
-
Train::Platforms.list[name] = self
|
19
|
-
end
|
20
|
-
|
21
|
-
def direct_families
|
22
|
-
@families.collect { |k, _v| k.name }
|
23
|
-
end
|
24
|
-
|
25
|
-
def find_family_hierarchy(platform = self)
|
26
|
-
families = platform.families.map { |k, v| [k.name, find_family_hierarchy(k)] }
|
27
|
-
|
28
|
-
@family_hierarchy = families.flatten
|
29
|
-
end
|
30
|
-
|
31
|
-
def family
|
32
|
-
@platform[:family] || @family_hierarchy[0]
|
33
|
-
end
|
34
|
-
|
35
|
-
def name
|
36
|
-
# Override here incase a updated name was set
|
37
|
-
# during the detect logic
|
38
|
-
clean_name
|
39
|
-
end
|
40
|
-
|
41
|
-
def clean_name(force: false)
|
42
|
-
@cleaned_name = nil if force
|
43
|
-
@cleaned_name ||= (@platform[:name] || @name).downcase.tr(" ", "_")
|
44
|
-
end
|
45
|
-
|
46
|
-
def uuid
|
47
|
-
@uuid ||= Train::Platforms::Detect::UUID.new(self).find_or_create_uuid.downcase
|
48
|
-
end
|
49
|
-
|
50
|
-
# This is for backwords compatability with
|
51
|
-
# the current inspec os resource.
|
52
|
-
def[](name)
|
53
|
-
if respond_to?(name)
|
54
|
-
send(name)
|
55
|
-
else
|
56
|
-
"unknown"
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
def title(title = nil)
|
61
|
-
return @title if title.nil?
|
62
|
-
|
63
|
-
@title = title
|
64
|
-
self
|
65
|
-
end
|
66
|
-
|
67
|
-
def to_hash
|
68
|
-
@platform
|
69
|
-
end
|
70
|
-
|
71
|
-
# Add generic family? and platform methods to an existing platform
|
72
|
-
#
|
73
|
-
# This is done later to add any custom
|
74
|
-
# families/properties that were created
|
75
|
-
def add_platform_methods
|
76
|
-
# Redo clean name if there is a detect override
|
77
|
-
clean_name(force: true) unless @platform[:name].nil?
|
78
|
-
|
79
|
-
# Add in family methods
|
80
|
-
family_list = Train::Platforms.families
|
81
|
-
family_list.each_value do |k|
|
82
|
-
name = "#{k.name}?"
|
83
|
-
|
84
|
-
next if respond_to?(name)
|
85
|
-
|
86
|
-
define_singleton_method(name) do
|
87
|
-
family_hierarchy.include?(k.name)
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
# Helper methods for direct platform info
|
92
|
-
@platform.each_key do |m|
|
93
|
-
next if respond_to?(m)
|
94
|
-
|
95
|
-
define_singleton_method(m) do
|
96
|
-
@platform[m]
|
97
|
-
end
|
98
|
-
end
|
99
|
-
|
100
|
-
# Create method for name if its not already true
|
101
|
-
m = name + "?"
|
102
|
-
return if respond_to?(m)
|
103
|
-
|
104
|
-
define_singleton_method(m) do
|
105
|
-
true
|
106
|
-
end
|
107
|
-
end
|
108
|
-
end
|
109
|
-
end
|
@@ -1,51 +0,0 @@
|
|
1
|
-
# This file is intended to be 'require'd by plugin authors who are developing a
|
2
|
-
# plugin outside of the Train source tree.
|
3
|
-
|
4
|
-
# Load Train. We certainly need the plugin system, and also several other parts
|
5
|
-
# that are tightly coupled. Train itself is fairly light, and non-invasive.
|
6
|
-
require_relative "../train"
|
7
|
-
|
8
|
-
# You can select from a number of test harnesses. Since Train is closely related
|
9
|
-
# to InSpec, and InSpec uses Spec-style controls in profile code, you will
|
10
|
-
# probably want to use something like minitest/spec, which provides Spec-style
|
11
|
-
# tests.
|
12
|
-
require "minitest/spec"
|
13
|
-
require "minitest/autorun"
|
14
|
-
|
15
|
-
# Data formats commonly used in testing
|
16
|
-
require "json"
|
17
|
-
require "ostruct"
|
18
|
-
|
19
|
-
# Utilities often needed
|
20
|
-
require "fileutils"
|
21
|
-
require "tmpdir"
|
22
|
-
require "pathname"
|
23
|
-
|
24
|
-
# You might want to put some debugging tools here. We run tests to find bugs,
|
25
|
-
# after all.
|
26
|
-
require "byebug"
|
27
|
-
|
28
|
-
# Configure MiniTest to expose things like `let`
|
29
|
-
class Module
|
30
|
-
include Minitest::Spec::DSL
|
31
|
-
end
|
32
|
-
|
33
|
-
# Finally, let's make some modules that can help us out.
|
34
|
-
module TrainPluginBaseHelper
|
35
|
-
# Sneakily detect the location of the plugin
|
36
|
-
# source code when they include this Module
|
37
|
-
def self.included(base)
|
38
|
-
plugin_test_helper_path = Pathname.new(caller_locations(4, 1).first.absolute_path)
|
39
|
-
plugin_src_root = plugin_test_helper_path.parent.parent
|
40
|
-
base.let(:plugin_src_path) { plugin_src_root }
|
41
|
-
base.let(:plugin_fixtures_path) { File.join(plugin_src_root, "test", "fixtures") }
|
42
|
-
end
|
43
|
-
|
44
|
-
let(:train_src_path) { File.expand_path(File.join(__FILE__, "..", "..")) }
|
45
|
-
let(:train_fixtures_path) { File.join(train_src_path, "test", "fixtures") }
|
46
|
-
let(:registry) { Train::Plugins.registry }
|
47
|
-
end
|
48
|
-
|
49
|
-
module TrainPluginFunctionalHelper
|
50
|
-
include TrainPluginBaseHelper
|
51
|
-
end
|
data/lib/train/plugins.rb
DELETED
@@ -1,40 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
#
|
3
|
-
# Author:: Dominik Richter (<dominik.richter@gmail.com>)
|
4
|
-
# Author:: Christoph Hartmann (<chris@lollyrock.com>)
|
5
|
-
|
6
|
-
require_relative "errors"
|
7
|
-
|
8
|
-
module Train
|
9
|
-
class Plugins
|
10
|
-
require_relative "plugins/transport"
|
11
|
-
|
12
|
-
class << self
|
13
|
-
# Retrieve the current plugin registry, containing all plugin names
|
14
|
-
# and their transport handlers.
|
15
|
-
#
|
16
|
-
# @return [Hash] map with plugin names and plugins
|
17
|
-
def registry
|
18
|
-
@registry ||= {}
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
# Create a new plugin by inheriting from the class returned by this method.
|
24
|
-
# Create a versioned plugin by providing the transport layer plugin version
|
25
|
-
# to this method. It will then select the correct class to inherit from.
|
26
|
-
#
|
27
|
-
# The plugin version determins what methods will be available to your plugin.
|
28
|
-
#
|
29
|
-
# @param [Int] version = 1 the plugin version to use
|
30
|
-
# @return [Transport] the versioned transport base class
|
31
|
-
def self.plugin(version = 1)
|
32
|
-
if version != 1
|
33
|
-
raise ClientError,
|
34
|
-
"Only understand train plugin version 1. You are trying to "\
|
35
|
-
"initialize a train plugin #{version}, which is not supported "\
|
36
|
-
"in the current release of train."
|
37
|
-
end
|
38
|
-
::Train::Plugins::Transport
|
39
|
-
end
|
40
|
-
end
|
@@ -1,198 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
require_relative "../errors"
|
4
|
-
require_relative "../extras"
|
5
|
-
require_relative "../file"
|
6
|
-
require "logger"
|
7
|
-
|
8
|
-
class Train::Plugins::Transport
|
9
|
-
# A Connection instance can be generated and re-generated, given new
|
10
|
-
# connection details such as connection port, hostname, credentials, etc.
|
11
|
-
# This object is responsible for carrying out the actions on the remote
|
12
|
-
# host such as executing commands, transferring files, etc.
|
13
|
-
#
|
14
|
-
# @author Fletcher Nichol <fnichol@nichol.ca>
|
15
|
-
class BaseConnection
|
16
|
-
include Train::Extras
|
17
|
-
|
18
|
-
# Create a new Connection instance.
|
19
|
-
#
|
20
|
-
# @param options [Hash] connection options
|
21
|
-
# @yield [self] yields itself for block-style invocation
|
22
|
-
def initialize(options = nil)
|
23
|
-
@options = options || {}
|
24
|
-
@logger = @options.delete(:logger) || Logger.new($stdout, level: :fatal)
|
25
|
-
Train::Platforms::Detect::Specifications::OS.load
|
26
|
-
Train::Platforms::Detect::Specifications::Api.load
|
27
|
-
|
28
|
-
# default caching options
|
29
|
-
@cache_enabled = {
|
30
|
-
file: true,
|
31
|
-
command: false,
|
32
|
-
api_call: false,
|
33
|
-
}
|
34
|
-
|
35
|
-
@cache = {}
|
36
|
-
@cache_enabled.each_key do |type|
|
37
|
-
clear_cache(type)
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
def with_sudo_pty
|
42
|
-
yield
|
43
|
-
end
|
44
|
-
|
45
|
-
# Returns cached client if caching enabled. Otherwise returns whatever is
|
46
|
-
# given in the block.
|
47
|
-
#
|
48
|
-
# @example
|
49
|
-
#
|
50
|
-
# def demo_client
|
51
|
-
# cached_client(:api_call, :demo_connection) do
|
52
|
-
# DemoClient.new(args)
|
53
|
-
# end
|
54
|
-
# end
|
55
|
-
#
|
56
|
-
# @param [symbol] type one of [:api_call, :file, :command]
|
57
|
-
# @param [symbol] key for your cached connection
|
58
|
-
def cached_client(type, key)
|
59
|
-
return yield unless cache_enabled?(type)
|
60
|
-
|
61
|
-
@cache[type][key] ||= yield
|
62
|
-
end
|
63
|
-
|
64
|
-
def cache_enabled?(type)
|
65
|
-
@cache_enabled[type.to_sym]
|
66
|
-
end
|
67
|
-
|
68
|
-
# Enable caching types for Train. Currently we support
|
69
|
-
# :api_call, :file and :command types
|
70
|
-
def enable_cache(type)
|
71
|
-
raise Train::UnknownCacheType, "#{type} is not a valid cache type" unless @cache_enabled.keys.include?(type.to_sym)
|
72
|
-
|
73
|
-
@cache_enabled[type.to_sym] = true
|
74
|
-
end
|
75
|
-
|
76
|
-
def disable_cache(type)
|
77
|
-
raise Train::UnknownCacheType, "#{type} is not a valid cache type" unless @cache_enabled.keys.include?(type.to_sym)
|
78
|
-
|
79
|
-
@cache_enabled[type.to_sym] = false
|
80
|
-
clear_cache(type.to_sym)
|
81
|
-
end
|
82
|
-
|
83
|
-
# Closes the session connection, if it is still active.
|
84
|
-
def close
|
85
|
-
# this method may be left unimplemented if that is applicable
|
86
|
-
end
|
87
|
-
|
88
|
-
def to_json
|
89
|
-
{
|
90
|
-
"files" => Hash[@cache[:file].map { |x, y| [x, y.to_json] }],
|
91
|
-
}
|
92
|
-
end
|
93
|
-
|
94
|
-
def load_json(j)
|
95
|
-
require_relative "../transports/mock"
|
96
|
-
j["files"].each do |path, jf|
|
97
|
-
@cache[:file][path] = Train::Transports::Mock::Connection::File.from_json(jf)
|
98
|
-
end
|
99
|
-
end
|
100
|
-
|
101
|
-
def force_platform!(name, platform_details = nil)
|
102
|
-
plat = Train::Platforms.name(name)
|
103
|
-
plat.backend = self
|
104
|
-
plat.platform = platform_details unless platform_details.nil?
|
105
|
-
plat.find_family_hierarchy
|
106
|
-
plat.add_platform_methods
|
107
|
-
plat
|
108
|
-
end
|
109
|
-
|
110
|
-
def inspect
|
111
|
-
"%s[%s]" % [self.class, (@options[:backend] || "Unknown")]
|
112
|
-
end
|
113
|
-
|
114
|
-
alias direct_platform force_platform!
|
115
|
-
|
116
|
-
# Get information on the operating system which this transport connects to.
|
117
|
-
#
|
118
|
-
# @return [Platform] system information
|
119
|
-
def platform
|
120
|
-
@platform ||= Train::Platforms::Detect.scan(self)
|
121
|
-
end
|
122
|
-
# we need to keep os as a method for backwards compatibility with inspec
|
123
|
-
alias os platform
|
124
|
-
|
125
|
-
# This is the main command call for all connections. This will call the private
|
126
|
-
# run_command_via_connection on the connection with optional caching
|
127
|
-
#
|
128
|
-
# This command accepts an optional data handler block. When provided,
|
129
|
-
# inbound data will be published vi `data_handler.call(data)`. This can allow
|
130
|
-
# callers to receive and render updates from remote command execution.
|
131
|
-
def run_command(cmd, &data_handler)
|
132
|
-
return run_command_via_connection(cmd, &data_handler) unless cache_enabled?(:command)
|
133
|
-
|
134
|
-
@cache[:command][cmd] ||= run_command_via_connection(cmd, &data_handler)
|
135
|
-
end
|
136
|
-
|
137
|
-
# This is the main file call for all connections. This will call the private
|
138
|
-
# file_via_connection on the connection with optional caching
|
139
|
-
def file(path, *args)
|
140
|
-
return file_via_connection(path, *args) unless cache_enabled?(:file)
|
141
|
-
|
142
|
-
@cache[:file][path] ||= file_via_connection(path, *args)
|
143
|
-
end
|
144
|
-
|
145
|
-
# Builds a LoginCommand which can be used to open an interactive
|
146
|
-
# session on the remote host.
|
147
|
-
#
|
148
|
-
# @return [LoginCommand] array of command line tokens
|
149
|
-
def login_command
|
150
|
-
raise NotImplementedError, "#{self.class} does not implement #login_command()"
|
151
|
-
end
|
152
|
-
|
153
|
-
# Block and return only when the remote host is prepared and ready to
|
154
|
-
# execute command and upload files. The semantics and details will
|
155
|
-
# vary by implementation, but a round trip through the hosted
|
156
|
-
# service is preferred to simply waiting on a socket to become
|
157
|
-
# available.
|
158
|
-
def wait_until_ready
|
159
|
-
# this method may be left unimplemented if that is applicablelog
|
160
|
-
end
|
161
|
-
|
162
|
-
private
|
163
|
-
|
164
|
-
# Execute a command using this connection.
|
165
|
-
#
|
166
|
-
# @param command [String] command string to execute
|
167
|
-
# @param &data_handler(data) [Proc] proc that is called when data arrives from
|
168
|
-
# the connection. This block is optional. Individual transports will need
|
169
|
-
# to explicitly invoke the block in their implementation of run_command_via_connection;
|
170
|
-
# if they do not, the block is ignored and will not be used to report data back to the caller.
|
171
|
-
#
|
172
|
-
# @return [CommandResult] contains the result of running the command
|
173
|
-
def run_command_via_connection(_command, &_data_handler)
|
174
|
-
raise NotImplementedError, "#{self.class} does not implement #run_command_via_connection()"
|
175
|
-
end
|
176
|
-
|
177
|
-
# Interact with files on the target. Read, write, and get metadata
|
178
|
-
# from files via the transport.
|
179
|
-
#
|
180
|
-
# @param [String] path which is being inspected
|
181
|
-
# @return [FileCommon] file object that allows for interaction
|
182
|
-
def file_via_connection(_path, *_args)
|
183
|
-
raise NotImplementedError, "#{self.class} does not implement #file_via_connection(...)"
|
184
|
-
end
|
185
|
-
|
186
|
-
def clear_cache(type)
|
187
|
-
@cache[type.to_sym] = {}
|
188
|
-
end
|
189
|
-
|
190
|
-
# @return [Logger] logger for reporting information
|
191
|
-
# @api private
|
192
|
-
attr_reader :logger
|
193
|
-
|
194
|
-
# @return [Hash] connection options
|
195
|
-
# @api private
|
196
|
-
attr_reader :options
|
197
|
-
end
|
198
|
-
end
|