ridley 0.9.1 → 0.10.0.rc1
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.
- data/.gitignore +1 -0
- data/.ruby-version +1 -0
- data/Guardfile +1 -1
- data/README.md +1 -1
- data/bootstrappers/{omnibus.erb → unix_omnibus.erb} +20 -5
- data/bootstrappers/windows_omnibus.erb +133 -0
- data/lib/ridley.rb +4 -1
- data/lib/ridley/bootstrap_bindings.rb +5 -0
- data/lib/ridley/bootstrap_bindings/unix_template_binding.rb +112 -0
- data/lib/ridley/bootstrap_bindings/windows_template_binding.rb +221 -0
- data/lib/ridley/bootstrapper.rb +14 -22
- data/lib/ridley/bootstrapper/context.rb +53 -162
- data/lib/ridley/chef.rb +0 -1
- data/lib/ridley/chef/cookbook.rb +0 -9
- data/lib/ridley/client.rb +12 -1
- data/lib/ridley/errors.rb +1 -0
- data/lib/ridley/host_connector.rb +76 -0
- data/lib/ridley/{ssh → host_connector}/response.rb +1 -1
- data/lib/ridley/{ssh → host_connector}/response_set.rb +11 -11
- data/lib/ridley/host_connector/ssh.rb +58 -0
- data/lib/ridley/host_connector/ssh/worker.rb +99 -0
- data/lib/ridley/host_connector/winrm.rb +55 -0
- data/lib/ridley/host_connector/winrm/worker.rb +126 -0
- data/lib/ridley/mixin/bootstrap_binding.rb +88 -0
- data/lib/ridley/resource.rb +1 -1
- data/lib/ridley/resources/client_resource.rb +7 -0
- data/lib/ridley/resources/node_resource.rb +9 -4
- data/lib/ridley/sandbox_uploader.rb +1 -7
- data/lib/ridley/version.rb +1 -1
- data/ridley.gemspec +1 -0
- data/spec/unit/ridley/bootstrap_bindings/unix_template_binding_spec.rb +102 -0
- data/spec/unit/ridley/bootstrap_bindings/windows_template_binding_spec.rb +118 -0
- data/spec/unit/ridley/bootstrapper/context_spec.rb +19 -106
- data/spec/unit/ridley/bootstrapper_spec.rb +2 -12
- data/spec/unit/ridley/client_spec.rb +20 -2
- data/spec/unit/ridley/{ssh → host_connector}/response_set_spec.rb +17 -17
- data/spec/unit/ridley/host_connector/ssh/worker_spec.rb +15 -0
- data/spec/unit/ridley/{ssh_spec.rb → host_connector/ssh_spec.rb} +5 -5
- data/spec/unit/ridley/host_connector/winrm/worker_spec.rb +41 -0
- data/spec/unit/ridley/host_connector/winrm_spec.rb +47 -0
- data/spec/unit/ridley/host_connector_spec.rb +102 -0
- data/spec/unit/ridley/mixin/bootstrap_binding_spec.rb +56 -0
- data/spec/unit/ridley/sandbox_uploader_spec.rb +1 -28
- metadata +53 -25
- data/.rbenv-version +0 -1
- data/lib/ridley/chef/chefignore.rb +0 -76
- data/lib/ridley/ssh.rb +0 -56
- data/lib/ridley/ssh/worker.rb +0 -87
- data/spec/fixtures/chefignore +0 -8
- data/spec/unit/ridley/chef/chefignore_spec.rb +0 -40
- data/spec/unit/ridley/ssh/worker_spec.rb +0 -13
data/lib/ridley/bootstrapper.rb
CHANGED
@@ -3,22 +3,10 @@ module Ridley
|
|
3
3
|
class Bootstrapper
|
4
4
|
autoload :Context, 'ridley/bootstrapper/context'
|
5
5
|
|
6
|
-
class << self
|
7
|
-
# @return [Pathname]
|
8
|
-
def templates_path
|
9
|
-
Ridley.root.join('bootstrappers')
|
10
|
-
end
|
11
|
-
|
12
|
-
# @return [String]
|
13
|
-
def default_template
|
14
|
-
templates_path.join('omnibus.erb').to_s
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
6
|
include Celluloid
|
19
7
|
include Celluloid::Logger
|
20
|
-
|
21
|
-
# @return
|
8
|
+
|
9
|
+
# @return [Array<String>]
|
22
10
|
attr_reader :hosts
|
23
11
|
|
24
12
|
# @return [Array<Bootstrapper::Context>]
|
@@ -33,6 +21,10 @@ module Ridley
|
|
33
21
|
# * :password (String) the password for the shell user that will perform the bootstrap
|
34
22
|
# * :keys (Array, String) an array of keys (or a single key) to authenticate the ssh user with instead of a password
|
35
23
|
# * :timeout (Float) [5.0] timeout value for SSH bootstrap
|
24
|
+
# @option options [Hash] :winrm
|
25
|
+
# * :user (String) a user that will login to each node and perform the bootstrap command on (required)
|
26
|
+
# * :password (String) the password for the user that will perform the bootstrap
|
27
|
+
# * :port (Fixnum) the winrm port to connect on the node the bootstrap will be performed on (5985)
|
36
28
|
# @option options [String] :validator_client
|
37
29
|
# @option options [String] :validator_path
|
38
30
|
# filepath to the validator used to bootstrap the node (required)
|
@@ -46,13 +38,13 @@ module Ridley
|
|
46
38
|
# a hash of attributes to use in the first Chef run
|
47
39
|
# @option options [Array] :run_list (Array.new)
|
48
40
|
# an initial run list to bootstrap with
|
49
|
-
# @option options [String] :chef_version (
|
41
|
+
# @option options [String] :chef_version (nil)
|
50
42
|
# version of Chef to install on the node
|
51
43
|
# @option options [String] :environment ('_default')
|
52
44
|
# environment to join the node to
|
53
45
|
# @option options [Boolean] :sudo (true)
|
54
46
|
# bootstrap with sudo (default: true)
|
55
|
-
# @option options [String] :template
|
47
|
+
# @option options [String] :template
|
56
48
|
# bootstrap template to use
|
57
49
|
def initialize(hosts, options = {})
|
58
50
|
@hosts = Array(hosts).collect(&:to_s).uniq
|
@@ -64,23 +56,23 @@ module Ridley
|
|
64
56
|
}.merge(@options[:ssh])
|
65
57
|
|
66
58
|
@options[:sudo] = @options[:ssh][:sudo]
|
67
|
-
|
68
59
|
@contexts = @hosts.collect do |host|
|
69
|
-
Context.
|
60
|
+
Context.create(host, options)
|
70
61
|
end
|
71
62
|
end
|
72
63
|
|
73
|
-
# @return [
|
64
|
+
# @return [HostConnector::ResponseSet]
|
74
65
|
def run
|
75
66
|
workers = Array.new
|
76
67
|
futures = contexts.collect do |context|
|
77
68
|
info "Running bootstrap command on #{context.host}"
|
78
69
|
|
79
|
-
workers << worker =
|
80
|
-
|
70
|
+
workers << worker = context.host_connector::Worker.new(context.host, self.options.freeze)
|
71
|
+
|
72
|
+
worker.future.run(context.template_binding.boot_command)
|
81
73
|
end
|
82
74
|
|
83
|
-
|
75
|
+
HostConnector::ResponseSet.new.tap do |response_set|
|
84
76
|
futures.each do |future|
|
85
77
|
status, response = future.value
|
86
78
|
response_set.add_response(response)
|
@@ -5,185 +5,76 @@ module Ridley
|
|
5
5
|
# @author Jamie Winsor <reset@riotgames.com>
|
6
6
|
class Context
|
7
7
|
class << self
|
8
|
-
def validate_options(options = {})
|
9
|
-
if options[:server_url].nil?
|
10
|
-
raise Errors::ArgumentError, "A server_url is required for bootstrapping"
|
11
|
-
end
|
12
8
|
|
13
|
-
|
14
|
-
|
9
|
+
# @param [String] host
|
10
|
+
# @option options [Hash] :ssh
|
11
|
+
# * :user (String) a shell user that will login to each node and perform the bootstrap command on (required)
|
12
|
+
# * :password (String) the password for the shell user that will perform the bootstrap
|
13
|
+
# * :port (Fixnum) the ssh port to connect on the node the bootstrap will be performed on (22)
|
14
|
+
# * :keys (Array, String) an array of keys (or a single key) to authenticate the ssh user with instead of a password
|
15
|
+
# * :timeout (Float) [5.0] timeout value for SSH bootstrap
|
16
|
+
# @option options [Hash] :winrm
|
17
|
+
# * :user (String) a user that will login to each node and perform the bootstrap command on (required)
|
18
|
+
# * :password (String) the password for the user that will perform the bootstrap
|
19
|
+
# * :port (Fixnum) the winrm port to connect on the node the bootstrap will be performed on (5985)
|
20
|
+
# @option options [String] :validator_client
|
21
|
+
# @option options [String] :validator_path
|
22
|
+
# filepath to the validator used to bootstrap the node (required)
|
23
|
+
# @option options [String] :bootstrap_proxy (nil)
|
24
|
+
# URL to a proxy server to bootstrap through
|
25
|
+
# @option options [String] :encrypted_data_bag_secret_path (nil)
|
26
|
+
# filepath on your host machine to your organizations encrypted data bag secret
|
27
|
+
# @option options [Hash] :hints (Hash.new)
|
28
|
+
# a hash of Ohai hints to place on the bootstrapped node
|
29
|
+
# @option options [Hash] :attributes (Hash.new)
|
30
|
+
# a hash of attributes to use in the first Chef run
|
31
|
+
# @option options [Array] :run_list (Array.new)
|
32
|
+
# an initial run list to bootstrap with
|
33
|
+
# @option options [String] :chef_version (nil)
|
34
|
+
# version of Chef to install on the node
|
35
|
+
# @option options [String] :environment ('_default')
|
36
|
+
# environment to join the node to
|
37
|
+
# @option options [Boolean] :sudo (true)
|
38
|
+
# bootstrap with sudo (default: true)
|
39
|
+
# @option options [String] :template ('omnibus')
|
40
|
+
# bootstrap template to use
|
41
|
+
def create(host, options = {})
|
42
|
+
host_connector = HostConnector.best_connector_for(host, options)
|
43
|
+
template_binding = case host_connector.to_s
|
44
|
+
when Ridley::HostConnector::SSH.to_s
|
45
|
+
Ridley::UnixTemplateBinding.new(options)
|
46
|
+
when Ridley::HostConnector::WinRM.to_s
|
47
|
+
Ridley::WindowsTemplateBinding.new(options)
|
48
|
+
else
|
49
|
+
raise Ridley::Errors::HostConnectionError, "Cannot find an appropriate Template Binding for an unknown connector."
|
15
50
|
end
|
16
|
-
|
17
|
-
|
18
|
-
# A hash of default options to be used in the Context initializer
|
19
|
-
#
|
20
|
-
# @return [Hash]
|
21
|
-
def default_options
|
22
|
-
@default_options ||= {
|
23
|
-
validator_client: "chef-validator",
|
24
|
-
hints: Hash.new,
|
25
|
-
attributes: Hash.new,
|
26
|
-
run_list: Array.new,
|
27
|
-
chef_version: Ridley::CHEF_VERSION,
|
28
|
-
environment: "_default",
|
29
|
-
sudo: true,
|
30
|
-
template: Bootstrapper.default_template
|
31
|
-
}
|
51
|
+
new(host, host_connector, template_binding)
|
32
52
|
end
|
33
53
|
end
|
34
54
|
|
35
55
|
# @return [String]
|
36
56
|
attr_reader :host
|
37
|
-
# @return [
|
38
|
-
attr_reader :
|
39
|
-
# @return [
|
40
|
-
attr_reader :
|
41
|
-
# @return [String]
|
42
|
-
attr_reader :validator_client
|
43
|
-
# @return [String]
|
44
|
-
attr_reader :validator_path
|
45
|
-
# @return [String]
|
46
|
-
attr_reader :bootstrap_proxy
|
47
|
-
# @return [Hash]
|
48
|
-
attr_reader :hints
|
49
|
-
# @return [String]
|
50
|
-
attr_reader :chef_version
|
51
|
-
# @return [String]
|
52
|
-
attr_reader :environment
|
57
|
+
# @return [Ridley::HostConnector]
|
58
|
+
attr_reader :host_connector
|
59
|
+
# @return [Ridley::Binding]
|
60
|
+
attr_reader :template_binding
|
53
61
|
|
54
62
|
# @param [String] host
|
55
63
|
# name of the node as identified in Chef
|
56
|
-
# @
|
57
|
-
#
|
58
|
-
# @
|
59
|
-
#
|
60
|
-
|
61
|
-
# @option options [String] :bootstrap_proxy
|
62
|
-
# URL to a proxy server to bootstrap through (default: nil)
|
63
|
-
# @option options [String] :encrypted_data_bag_secret_path
|
64
|
-
# filepath on your host machine to your organizations encrypted data bag secret (default: nil)
|
65
|
-
# @option options [Hash] :hints
|
66
|
-
# a hash of Ohai hints to place on the bootstrapped node (default: Hash.new)
|
67
|
-
# @option options [Hash] :attributes
|
68
|
-
# a hash of attributes to use in the first Chef run (default: Hash.new)
|
69
|
-
# @option options [Array] :run_list
|
70
|
-
# an initial run list to bootstrap with (default: Array.new)
|
71
|
-
# @option options [String] :chef_version
|
72
|
-
# version of Chef to install on the node (default: {Ridley::CHEF_VERSION})
|
73
|
-
# @option options [String] :environment
|
74
|
-
# environment to join the node to (default: '_default')
|
75
|
-
# @option options [Boolean] :sudo
|
76
|
-
# bootstrap with sudo (default: true)
|
77
|
-
# @option options [String] :template
|
78
|
-
# bootstrap template to use (default: omnibus)
|
79
|
-
def initialize(host, options = {})
|
80
|
-
options = self.class.default_options.merge(options)
|
81
|
-
self.class.validate_options(options)
|
82
|
-
|
64
|
+
# @param [Ridley::HostConnector] host_connector
|
65
|
+
# either the SSH or WinRM Connector class
|
66
|
+
# @param [Ridley::Binding] template_binding
|
67
|
+
# an instance of either the UnixTemplateBinding or WindowsTemplateBinding class
|
68
|
+
def initialize(host, host_connector, template_binding)
|
83
69
|
@host = host
|
84
|
-
@
|
85
|
-
@
|
86
|
-
@node_name = options[:node_name]
|
87
|
-
@validator_client = options[:validator_client]
|
88
|
-
@bootstrap_proxy = options[:bootstrap_proxy]
|
89
|
-
@encrypted_data_bag_secret_path = options[:encrypted_data_bag_secret_path]
|
90
|
-
@hints = options[:hints]
|
91
|
-
@attributes = options[:attributes]
|
92
|
-
@run_list = options[:run_list]
|
93
|
-
@chef_version = options[:chef_version]
|
94
|
-
@environment = options[:environment]
|
95
|
-
@sudo = options[:sudo]
|
96
|
-
@template_file = options[:template]
|
97
|
-
end
|
98
|
-
|
99
|
-
# @return [String]
|
100
|
-
def boot_command
|
101
|
-
cmd = template.evaluate(self)
|
102
|
-
|
103
|
-
if sudo
|
104
|
-
cmd = "sudo #{cmd}"
|
105
|
-
end
|
106
|
-
|
107
|
-
cmd
|
70
|
+
@host_connector = host_connector
|
71
|
+
@template_binding = template_binding
|
108
72
|
end
|
109
73
|
|
110
74
|
# @return [String]
|
111
75
|
def clean_command
|
112
76
|
"rm /etc/chef/first-boot.json; rm /etc/chef/validation.pem"
|
113
77
|
end
|
114
|
-
|
115
|
-
# @return [String]
|
116
|
-
def chef_run
|
117
|
-
"chef-client -j /etc/chef/first-boot.json -E #{environment}"
|
118
|
-
end
|
119
|
-
|
120
|
-
# @return [String]
|
121
|
-
def chef_config
|
122
|
-
body = <<-CONFIG
|
123
|
-
log_level :info
|
124
|
-
log_location STDOUT
|
125
|
-
chef_server_url "#{server_url}"
|
126
|
-
validation_client_name "#{validator_client}"
|
127
|
-
CONFIG
|
128
|
-
|
129
|
-
if node_name.present?
|
130
|
-
body << %Q{node_name "#{node_name}"\n}
|
131
|
-
else
|
132
|
-
body << "# Using default node name (fqdn)\n"
|
133
|
-
end
|
134
|
-
|
135
|
-
if bootstrap_proxy.present?
|
136
|
-
body << %Q{http_proxy "#{bootstrap_proxy}"\n}
|
137
|
-
body << %Q{https_proxy "#{bootstrap_proxy}"\n}
|
138
|
-
end
|
139
|
-
|
140
|
-
if encrypted_data_bag_secret.present?
|
141
|
-
body << %Q{encrypted_data_bag_secret "/etc/chef/encrypted_data_bag_secret"\n}
|
142
|
-
end
|
143
|
-
|
144
|
-
body
|
145
|
-
end
|
146
|
-
|
147
|
-
# @return [String]
|
148
|
-
def first_boot
|
149
|
-
MultiJson.encode attributes.merge(run_list: run_list)
|
150
|
-
end
|
151
|
-
|
152
|
-
# The validation key to create a new client for the node
|
153
|
-
#
|
154
|
-
# @raise [Ridley::Errors::ValidatorNotFound]
|
155
|
-
#
|
156
|
-
# @return [String]
|
157
|
-
def validation_key
|
158
|
-
IO.read(File.expand_path(validator_path)).chomp
|
159
|
-
rescue Errno::ENOENT
|
160
|
-
raise Errors::ValidatorNotFound, "Error bootstrapping: Validator not found at '#{validator_path}'"
|
161
|
-
end
|
162
|
-
|
163
|
-
# @raise [Ridley::Errors::EncryptedDataBagSecretNotFound]
|
164
|
-
#
|
165
|
-
# @return [String, nil]
|
166
|
-
def encrypted_data_bag_secret
|
167
|
-
return nil if encrypted_data_bag_secret_path.nil?
|
168
|
-
|
169
|
-
IO.read(encrypted_data_bag_secret_path).chomp
|
170
|
-
rescue Errno::ENOENT => encrypted_data_bag_secret
|
171
|
-
raise Errors::EncryptedDataBagSecretNotFound, "Error bootstrapping: Encrypted data bag secret provided but not found at '#{encrypted_data_bag_secret_path}'"
|
172
|
-
end
|
173
|
-
|
174
|
-
private
|
175
|
-
|
176
|
-
attr_reader :sudo
|
177
|
-
attr_reader :template_file
|
178
|
-
attr_reader :encrypted_data_bag_secret_path
|
179
|
-
attr_reader :validator_path
|
180
|
-
attr_reader :run_list
|
181
|
-
attr_reader :attributes
|
182
|
-
|
183
|
-
# @return [Erubis::Eruby]
|
184
|
-
def template
|
185
|
-
Erubis::Eruby.new(IO.read(template_file).chomp)
|
186
|
-
end
|
187
78
|
end
|
188
79
|
end
|
189
80
|
end
|
data/lib/ridley/chef.rb
CHANGED
data/lib/ridley/chef/cookbook.rb
CHANGED
@@ -96,7 +96,6 @@ module Ridley::Chef
|
|
96
96
|
root_files: Array.new
|
97
97
|
)
|
98
98
|
@frozen = false
|
99
|
-
@chefignore = Ridley::Chef::Chefignore.new(@path)
|
100
99
|
|
101
100
|
load_files
|
102
101
|
end
|
@@ -208,12 +207,7 @@ module Ridley::Chef
|
|
208
207
|
|
209
208
|
private
|
210
209
|
|
211
|
-
# @return [Array]
|
212
210
|
attr_reader :files
|
213
|
-
# @return [Ridley::Chef::Chefignore]
|
214
|
-
attr_reader :chefignore
|
215
|
-
|
216
|
-
def_delegator :chefignore, :ignored?
|
217
211
|
|
218
212
|
def load_files
|
219
213
|
load_shallow(:recipes, 'recipes', '*.rb')
|
@@ -231,7 +225,6 @@ module Ridley::Chef
|
|
231
225
|
[].tap do |files|
|
232
226
|
Dir.glob(path.join('*'), File::FNM_DOTMATCH).each do |file|
|
233
227
|
next if File.directory?(file)
|
234
|
-
next if ignored?(file)
|
235
228
|
@files << file
|
236
229
|
@manifest[:root_files] << file_metadata(:root_files, file)
|
237
230
|
end
|
@@ -243,7 +236,6 @@ module Ridley::Chef
|
|
243
236
|
file_spec = path.join(category_dir, '**', glob)
|
244
237
|
Dir.glob(file_spec, File::FNM_DOTMATCH).each do |file|
|
245
238
|
next if File.directory?(file)
|
246
|
-
next if ignored?(file)
|
247
239
|
@files << file
|
248
240
|
@manifest[category] << file_metadata(category, file)
|
249
241
|
end
|
@@ -253,7 +245,6 @@ module Ridley::Chef
|
|
253
245
|
def load_shallow(category, *path_glob)
|
254
246
|
[].tap do |files|
|
255
247
|
Dir[path.join(*path_glob)].each do |file|
|
256
|
-
next if ignored?(file)
|
257
248
|
@files << file
|
258
249
|
@manifest[category] << file_metadata(category, file)
|
259
250
|
end
|
data/lib/ridley/client.rb
CHANGED
@@ -77,6 +77,8 @@ module Ridley
|
|
77
77
|
attr_accessor :validator_path
|
78
78
|
attr_accessor :encrypted_data_bag_secret_path
|
79
79
|
attr_accessor :ssh
|
80
|
+
attr_accessor :winrm
|
81
|
+
attr_accessor :chef_version
|
80
82
|
|
81
83
|
# @option options [String] :server_url
|
82
84
|
# URL to the Chef API
|
@@ -93,6 +95,12 @@ module Ridley
|
|
93
95
|
# * :keys (Array, String) an array of keys (or a single key) to authenticate the ssh user with instead of a password
|
94
96
|
# * :timeout (Float) [5.0] timeout value for SSH bootstrap
|
95
97
|
# * :sudo (Boolean) [true] bootstrap with sudo
|
98
|
+
# @option options [Hash] :winrm (Hash.new)
|
99
|
+
# * :user (String) a user that will login to each node and perform the bootstrap command on (required)
|
100
|
+
# * :password (String) the password for the user that will perform the bootstrap
|
101
|
+
# * :port (Fixnum) the winrm port to connect on the node the bootstrap will be performed on (5985)
|
102
|
+
# @option options [String] :chef_version
|
103
|
+
# the version of Chef to use when bootstrapping
|
96
104
|
# @option options [Hash] :params
|
97
105
|
# URI query unencoded key/value pairs
|
98
106
|
# @option options [Hash] :headers
|
@@ -111,11 +119,14 @@ module Ridley
|
|
111
119
|
super()
|
112
120
|
|
113
121
|
@options = options.reverse_merge(
|
114
|
-
ssh: Hash.new
|
122
|
+
ssh: Hash.new,
|
123
|
+
winrm: Hash.new
|
115
124
|
).deep_symbolize_keys
|
116
125
|
self.class.validate_options(@options)
|
117
126
|
|
118
127
|
@ssh = @options[:ssh]
|
128
|
+
@winrm = @options[:winrm]
|
129
|
+
@chef_version = @options[:chef_version]
|
119
130
|
@validator_client = @options[:validator_client]
|
120
131
|
|
121
132
|
@options[:client_key] = File.expand_path(@options[:client_key])
|
data/lib/ridley/errors.rb
CHANGED
@@ -38,6 +38,7 @@ module Ridley
|
|
38
38
|
class BootstrapError < RidleyError; end
|
39
39
|
class ClientKeyFileNotFound < BootstrapError; end
|
40
40
|
class EncryptedDataBagSecretNotFound < BootstrapError; end
|
41
|
+
class HostConnectionError < BootstrapError; end
|
41
42
|
|
42
43
|
# Exception thrown when the maximum amount of requests is exceeded.
|
43
44
|
class RedirectLimitReached < RidleyError
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'socket'
|
2
|
+
require 'timeout'
|
3
|
+
|
4
|
+
module Ridley
|
5
|
+
# @author Kyle Allan <kallan@riotgames.com>
|
6
|
+
module HostConnector
|
7
|
+
autoload :Response, 'ridley/host_connector/response'
|
8
|
+
autoload :ResponseSet, 'ridley/host_connector/response_set'
|
9
|
+
autoload :SSH, 'ridley/host_connector/ssh'
|
10
|
+
autoload :WinRM, 'ridley/host_connector/winrm'
|
11
|
+
|
12
|
+
DEFAULT_SSH_PORT = 22.freeze
|
13
|
+
DEFAULT_WINRM_PORT = 5985.freeze
|
14
|
+
|
15
|
+
class << self
|
16
|
+
# Finds and returns the best HostConnector for a given host
|
17
|
+
#
|
18
|
+
# @param host [String]
|
19
|
+
# the host to attempt to connect to
|
20
|
+
# @option options [Hash] :ssh
|
21
|
+
# * :port (Fixnum) the ssh port to connect on the node the bootstrap will be performed on (22)
|
22
|
+
# @option options [Hash] :winrm
|
23
|
+
# * :port (Fixnum) the winrm port to connect on the node the bootstrap will be performed on (5985)
|
24
|
+
#
|
25
|
+
# @return [Ridley::HostConnector] a class under Ridley::HostConnector
|
26
|
+
def best_connector_for(host, options = {})
|
27
|
+
ssh_port, winrm_port = parse_port_options(options)
|
28
|
+
if connector_port_open?(host, ssh_port)
|
29
|
+
Ridley::HostConnector::SSH
|
30
|
+
elsif connector_port_open?(host, winrm_port)
|
31
|
+
Ridley::HostConnector::WinRM
|
32
|
+
else
|
33
|
+
raise Ridley::Errors::HostConnectionError, "No available connection method available on #{host}."
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Checks to see if the given port is open for TCP connections
|
38
|
+
# on the given host.
|
39
|
+
#
|
40
|
+
# @param host [String]
|
41
|
+
# the host to attempt to connect to
|
42
|
+
# @param port [Fixnum]
|
43
|
+
# the port to attempt to connect on
|
44
|
+
#
|
45
|
+
# @return [Boolean]
|
46
|
+
def connector_port_open?(host, port)
|
47
|
+
Timeout::timeout(1) do
|
48
|
+
begin
|
49
|
+
socket = TCPSocket.new(host, port)
|
50
|
+
socket.close
|
51
|
+
true
|
52
|
+
rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH
|
53
|
+
false
|
54
|
+
end
|
55
|
+
end
|
56
|
+
rescue Timeout::Error
|
57
|
+
false
|
58
|
+
end
|
59
|
+
|
60
|
+
# Parses the options Hash and returns an array of
|
61
|
+
# [SSH_PORT, WINRM_PORT] used to attempt to connect to.
|
62
|
+
#
|
63
|
+
# @option options [Hash] :ssh
|
64
|
+
# * :port (Fixnum) the ssh port to connect on the node the bootstrap will be performed on (22)
|
65
|
+
# @option options [Hash] :winrm
|
66
|
+
# * :port (Fixnum) the winrm port to connect on the node the bootstrap will be performed on (5985)
|
67
|
+
#
|
68
|
+
# @return [Array]
|
69
|
+
def parse_port_options(options)
|
70
|
+
ssh_port = options[:ssh][:port] if options[:ssh]
|
71
|
+
winrm_port = options[:winrm][:port] if options[:winrm]
|
72
|
+
[ssh_port || DEFAULT_SSH_PORT, winrm_port || DEFAULT_WINRM_PORT]
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|