train 3.2.14 → 3.2.20
Sign up to get free protection for your applications and to get access to all the features.
- 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
|