ridley-connectors 1.0.1

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.
Files changed (36) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +22 -0
  3. data/.ruby-version +1 -0
  4. data/.travis.yml +10 -0
  5. data/CHANGELOG.md +8 -0
  6. data/Gemfile +18 -0
  7. data/Guardfile +22 -0
  8. data/LICENSE +16 -0
  9. data/README.md +107 -0
  10. data/Thorfile +39 -0
  11. data/lib/ridley-connectors/chef_objects/node_object.rb +17 -0
  12. data/lib/ridley-connectors/client.rb +54 -0
  13. data/lib/ridley-connectors/host_commander.rb +231 -0
  14. data/lib/ridley-connectors/host_connector/response.rb +27 -0
  15. data/lib/ridley-connectors/host_connector/ssh.rb +211 -0
  16. data/lib/ridley-connectors/host_connector/winrm/command_uploader.rb +87 -0
  17. data/lib/ridley-connectors/host_connector/winrm.rb +218 -0
  18. data/lib/ridley-connectors/host_connector.rb +83 -0
  19. data/lib/ridley-connectors/resources/node_resource.rb +198 -0
  20. data/lib/ridley-connectors/version.rb +5 -0
  21. data/lib/ridley-connectors.rb +11 -0
  22. data/ridley-connectors.gemspec +27 -0
  23. data/spec/fixtures/encrypted_data_bag_secret +1 -0
  24. data/spec/fixtures/my-fake.pem +27 -0
  25. data/spec/spec_helper.rb +40 -0
  26. data/spec/support/actor_mocking.rb +9 -0
  27. data/spec/support/spec_helpers.rb +20 -0
  28. data/spec/unit/ridley-connectors/chef_objects/node_object_spec.rb +22 -0
  29. data/spec/unit/ridley-connectors/client_spec.rb +32 -0
  30. data/spec/unit/ridley-connectors/host_commander_spec.rb +173 -0
  31. data/spec/unit/ridley-connectors/host_connector/ssh_spec.rb +57 -0
  32. data/spec/unit/ridley-connectors/host_connector/winrm/command_uploader_spec.rb +67 -0
  33. data/spec/unit/ridley-connectors/host_connector/winrm_spec.rb +145 -0
  34. data/spec/unit/ridley-connectors/host_connector_spec.rb +50 -0
  35. data/spec/unit/ridley-connectors/resources/node_resource_spec.rb +139 -0
  36. metadata +178 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: c1d5f17ffd3feb5cafb982a127e2395f533e8413
4
+ data.tar.gz: 489a86773e6532a1e39896062c4057625cd64d0e
5
+ SHA512:
6
+ metadata.gz: 0e0d43263f510aafd2f797e00d6401af61bd6f98dce4461804de9d6c538808b709c45eef96ed2ea963ad61af8255da5cd0a19936b84fd6293a747a5f0792568d
7
+ data.tar.gz: b4e15afa128530307f6b21c8dc857a6c26c1807d5ed53aecd3461efd68a126fee293eb6395bcb2be96522a71cd4374d766473f712a158d5624906af228ec8d31
data/.gitignore ADDED
@@ -0,0 +1,22 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.sw[op]
19
+ .DS_Store
20
+ .rspec
21
+ .bin/
22
+ vendor/
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.0.0-p247
data/.travis.yml ADDED
@@ -0,0 +1,10 @@
1
+ script: "bundle exec thor spec:all"
2
+ language: ruby
3
+ rvm:
4
+ - 1.9.3
5
+ - 2.0.0
6
+ - jruby-19mode
7
+ matrix:
8
+ allow_failures:
9
+ - rvm: jruby-19mode
10
+ bundler_args: --without development
data/CHANGELOG.md ADDED
@@ -0,0 +1,8 @@
1
+ ## v.1.0.1
2
+
3
+ * [#3](https://github.com/RiotGames/ridley-connectors/pull/3) Fix the broken Ridley::Client
4
+
5
+ ## v.1.0.0
6
+
7
+ * [Ridley #227](https://github.com/RiotGames/ridley/pull/227) Move code out of Ridley and into its own gem
8
+ * See the [Ridley 2.0.0 Changelog](https://github.com/RiotGames/ridley/blob/v2.0.0/CHANGELOG.md) for more details.
data/Gemfile ADDED
@@ -0,0 +1,18 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ group :development do
6
+ gem 'yard'
7
+ gem 'spork'
8
+ gem 'guard', '>= 1.5.0'
9
+ gem 'guard-yard'
10
+ gem 'guard-rspec'
11
+ gem 'guard-spork', platforms: :ruby
12
+ end
13
+
14
+ group :test do
15
+ gem 'rspec', '~> 2.14.0'
16
+ gem 'webmock'
17
+ gem 'thor'
18
+ end
data/Guardfile ADDED
@@ -0,0 +1,22 @@
1
+ notification :off
2
+
3
+ guard 'spork' do
4
+ watch('Gemfile')
5
+ watch('spec/spec_helper.rb') { :rspec }
6
+ watch(%r{^spec/support/.+\.rb$}) { :rspec }
7
+ end
8
+
9
+ guard 'yard', stdout: '/dev/null', stderr: '/dev/null' do
10
+ watch(%r{app/.+\.rb})
11
+ watch(%r{lib/.+\.rb})
12
+ watch(%r{ext/.+\.c})
13
+ end
14
+
15
+ guard 'rspec', cli: "--color --drb --format Fuubar", all_on_start: false, all_after_pass: false do
16
+ watch(%r{^spec/unit/.+_spec\.rb$})
17
+ watch(%r{^spec/acceptance/.+_spec\.rb$})
18
+
19
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/unit/#{m[1]}_spec.rb" }
20
+ watch('spec/spec_helper.rb') { "spec" }
21
+ watch(%r{^spec/support/.+\.rb$}) { "spec" }
22
+ end
data/LICENSE ADDED
@@ -0,0 +1,16 @@
1
+ Copyright 2012-2013 Riot Games
2
+
3
+ Jamie Winsor (<jamie@vialstudios.com>)
4
+ Kyle Allan (<kallan@riotgames.com>)
5
+
6
+ Licensed under the Apache License, Version 2.0 (the "License");
7
+ you may not use this file except in compliance with the License.
8
+ You may obtain a copy of the License at
9
+
10
+ http://www.apache.org/licenses/LICENSE-2.0
11
+
12
+ Unless required by applicable law or agreed to in writing, software
13
+ distributed under the License is distributed on an "AS IS" BASIS,
14
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ See the License for the specific language governing permissions and
16
+ limitations under the License.
data/README.md ADDED
@@ -0,0 +1,107 @@
1
+ # Ridley Connectors
2
+ [![Gem Version](https://badge.fury.io/rb/ridley-connectors.png)](http://badge.fury.io/rb/ridley-connectors)
3
+ [![Build Status](https://secure.travis-ci.org/RiotGames/ridley-connectors.png?branch=master)](http://travis-ci.org/RiotGames/ridley-connectors)
4
+ [![Dependency Status](https://gemnasium.com/RiotGames/ridley-connectors.png?travis)](https://gemnasium.com/RiotGames/ridley-connectors)
5
+ [![Code Climate](https://codeclimate.com/github/RiotGames/ridley-connectors.png)](https://codeclimate.com/github/RiotGames/ridley-connectors)
6
+
7
+ An extension on [Ridley](https://github.com/RiotGames/ridley) adding support for connecting and communicating with nodes in Chef.
8
+
9
+ Installation
10
+ ------------
11
+ Add ridley-connectors to your `Gemfile`:
12
+
13
+ ```ruby
14
+ gem 'ridley-connectors'
15
+ ```
16
+
17
+ And run the `bundle` command to install. Alternatively, you can install the gem directly:
18
+
19
+ $ gem install ridley-connectors
20
+
21
+ Usage
22
+ -----
23
+ You can use ridley-connectors just like using Ridley.
24
+
25
+ ```ruby
26
+ require 'ridley'
27
+ ```
28
+
29
+ ### Creating a new Ridley client
30
+
31
+ ```ruby
32
+ ridley = Ridley.new(
33
+ server_url: "https://api.opscode.com/organizations/ridley",
34
+ client_name: "me",
35
+ client_key: "/Users/me/.chef/me.pem"
36
+ )
37
+ ```
38
+
39
+ ridley-connectors exposes all the usual features of Ridley, but adds some sugar for interacting with nodes.
40
+
41
+ ```ruby
42
+ ridley.node.bootstrap("hostname.to.bootstrap.com") # Bootstraps a hostname or IP
43
+ ridley.node.put_secret("hostname") # Puts your configured encrypted data bag secret onto a hostname or IP
44
+ ridley.node.chef_run("hostname") # Runs Chef on a hostname or IP
45
+
46
+ ```
47
+ Node Resource
48
+ -------------
49
+
50
+ ### Bootstrapping Unix nodes
51
+
52
+ ```ruby
53
+ ridley = Ridley.new(
54
+ server_url: "https://api.opscode.com",
55
+ organization: "vialstudios",
56
+ validator_client: "vialstudios-validator",
57
+ validator_path: "/Users/reset/.chef/vialstudios-validator.pem",
58
+ ssh: {
59
+ user: "vagrant",
60
+ password: "vagrant"
61
+ }
62
+ )
63
+
64
+ ridley.node.bootstrap("33.33.33.10", "33.33.33.11")
65
+ ```
66
+
67
+ ### Bootstrapping Windows Nodes
68
+
69
+ Windows Nodes are bootstrapped using a combination of WinRM, Batch, and PowerShell. You will probably need to tweak some settings on your Windows servers to ensure the commands are successful.
70
+
71
+ #### WinRM Settings
72
+
73
+ 1. Enable WinRM: `winrm quickconfig` and say Yes.
74
+ 2. Set some WinRM settings to ensure that you don't get 401 Unauthorized responses and 500 Responses because of timeouts.
75
+
76
+ ```
77
+ winrm set winrm/config/service/auth @{Basic="true"}
78
+ winrm set winrm/config/service @{AllowUnencrypted="true"}
79
+ winrm set winrm/config/service @{EnumerationTimeoutms="600000"}
80
+ winrm set winrm/config @{MaxTimeoutms="600000"}
81
+ winrm set winrm/config/client @{TrustedHosts="*"}
82
+ ```
83
+
84
+ #### PowerShell Settings
85
+
86
+ 1. You should also configure your PowerShell profile, so that PowerShell commands have a more lenient timeout period.
87
+
88
+ ```
89
+ mkdir C:\Users\my_user\Documents\WindowsPowerShell
90
+ echo "$PSSessionOption = New-PSSessionOption -OpenTimeout 0 -CancelTimeout 0 -IdleTimeout 0 -OperationTimeout 0" > C:\Users\my_user\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1
91
+ ```
92
+
93
+ Verify the PowerShell settings by opening up the PowerShell Console and entering `$PSSessionOption` and ensure those values are set, and that there are no errors output.
94
+
95
+ The following links offer some information about configuring a machine's PowerShell settings:
96
+ - [PowerShell Profiles](http://technet.microsoft.com/en-us/library/ee692764.aspx)
97
+ - [The $PSSessionOptions Preference Variable](http://technet.microsoft.com/library/hh847796.aspx)
98
+ - [Creating a new PSSessionOption](http://technet.microsoft.com/en-us/library/hh849703.aspx)
99
+
100
+ You may also want to tweak your Windows boxes a bit more ex: turning UAC off, turning off the Windows Firewall.
101
+
102
+ Authors and Contributors
103
+ ------------------------
104
+ - Jamie Winsor (<jamie@vialstudios.com>)
105
+ - Kyle Allan (<kallan@riotgames.com>)
106
+
107
+ Thank you to all of our [Contributors](https://github.com/RiotGames/ridley-connectors/graphs/contributors), testers, and users.
data/Thorfile ADDED
@@ -0,0 +1,39 @@
1
+ # encoding: utf-8
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+
4
+ require 'bundler'
5
+ require 'bundler/setup'
6
+ require 'ridley-connectors'
7
+
8
+ class Default < Thor
9
+
10
+ require 'thor/rake_compat'
11
+
12
+ include Thor::RakeCompat
13
+ Bundler::GemHelper.install_tasks
14
+
15
+ desc "build", "Build ridley-connectors-#{Ridley::Connectors::VERSION}.gem into the pkg directory"
16
+ def build
17
+ Rake::Task["build"].execute
18
+ end
19
+
20
+ desc "install", "Build and install ridley-connectors-#{Ridley::Connectors::VERSION}.gem into system gems"
21
+ def install
22
+ Rake::Task["install"].execute
23
+ end
24
+
25
+ desc "release", "Create tag v#{Ridley::Connectors::VERSION} and build and push ridley-connectors-#{Ridley::Connectors::VERSION}.gem to Rubygems"
26
+ def release
27
+ Rake::Task["release"].execute
28
+ end
29
+
30
+ class Spec < Thor
31
+ namespace :spec
32
+ default_task :all
33
+
34
+ desc "all", "run all tests"
35
+ def all
36
+ exec "rspec --color --format=documentation spec"
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,17 @@
1
+ module Ridley
2
+ class NodeObject
3
+ # Executes a Chef run on the node
4
+ #
5
+ # @return [HostConnector::Response]
6
+ def chef_run
7
+ resource.chef_run(self.public_hostname)
8
+ end
9
+
10
+ # Puts the configured encrypted data bag secret on the node
11
+ #
12
+ # @return [HostConnector::Response]
13
+ def put_secret
14
+ resource.put_secret(self.public_hostname)
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,54 @@
1
+ module Ridley
2
+ class Client
3
+ attr_accessor :ssh
4
+ attr_accessor :winrm
5
+
6
+ # @option options [String] :server_url
7
+ # URL to the Chef API
8
+ # @option options [String] :client_name
9
+ # name of the client used to authenticate with the Chef API
10
+ # @option options [String] :client_key
11
+ # filepath to the client's private key used to authenticate with the Chef API
12
+ # @option options [String] :validator_client (nil)
13
+ # @option options [String] :validator_path (nil)
14
+ # @option options [String] :encrypted_data_bag_secret_path (nil)
15
+ # @option options [Hash] :ssh (Hash.new)
16
+ # * :user (String) a shell user that will login to each node and perform the bootstrap command on (required)
17
+ # * :password (String) the password for the shell user that will perform the bootstrap
18
+ # * :keys (Array, String) an array of keys (or a single key) to authenticate the ssh user with instead of a password
19
+ # * :timeout (Float) [5.0] timeout value for SSH bootstrap
20
+ # * :sudo (Boolean) [true] bootstrap with sudo
21
+ # @option options [Hash] :winrm (Hash.new)
22
+ # * :user (String) a user that will login to each node and perform the bootstrap command on (required)
23
+ # * :password (String) the password for the user that will perform the bootstrap
24
+ # * :port (Fixnum) the winrm port to connect on the node the bootstrap will be performed on (5985)
25
+ # @option options [String] :chef_version
26
+ # the version of Chef to use when bootstrapping
27
+ # @option options [Hash] :params
28
+ # URI query unencoded key/value pairs
29
+ # @option options [Hash] :headers
30
+ # unencoded HTTP header key/value pairs
31
+ # @option options [Hash] :request
32
+ # request options
33
+ # @option options [Hash] :ssl
34
+ # * :verify (Boolean) [true] set to false to disable SSL verification
35
+ # @option options [URI, String, Hash] :proxy
36
+ # URI, String, or Hash of HTTP proxy options
37
+ # @option options [Integer] :pool_size (4)
38
+ # size of the connection pool
39
+ #
40
+ # @raise [Errors::ClientKeyFileNotFoundOrInvalid] if the option for :client_key does not contain
41
+ # a file path pointing to a readable client key, or is a string containing a valid key
42
+ alias_method :old_initialize, :initialize
43
+ def initialize(options = {})
44
+ old_initialize(options)
45
+ @options = options.reverse_merge(
46
+ ssh: Hash.new,
47
+ winrm: Hash.new,
48
+ ).deep_symbolize_keys
49
+
50
+ @ssh = @options[:ssh]
51
+ @winrm = @options[:winrm]
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,231 @@
1
+ module Ridley
2
+ class ConnectorSupervisor < ::Celluloid::SupervisionGroup
3
+ # @param [Celluloid::Registry] registry
4
+ def initialize(registry)
5
+ super(registry)
6
+ supervise_as :ssh, HostConnector::SSH
7
+ supervise_as :winrm, HostConnector::WinRM
8
+ end
9
+ end
10
+
11
+ class HostCommander
12
+ include Celluloid
13
+ include Ridley::Logging
14
+
15
+ PORT_CHECK_TIMEOUT = 3
16
+
17
+ finalizer :finalize_callback
18
+
19
+ def initialize
20
+ @connector_registry = Celluloid::Registry.new
21
+ @connector_supervisor = ConnectorSupervisor.new_link(@connector_registry)
22
+ end
23
+
24
+ # Execute a shell command on a node
25
+ #
26
+ # @param [String] host
27
+ # the host to perform the action on
28
+ # @param [String] command
29
+ #
30
+ # @option options [Hash] :ssh
31
+ # * :user (String) a shell user that will login to each node and perform the bootstrap command on
32
+ # * :password (String) the password for the shell user that will perform the bootstrap
33
+ # * :keys (Array, String) an array of key(s) to authenticate the ssh user with instead of a password
34
+ # * :timeout (Float) timeout value for SSH bootstrap (5.0)
35
+ # * :sudo (Boolean) run as sudo
36
+ # @option options [Hash] :winrm
37
+ # * :user (String) a user that will login to each node and perform the bootstrap command on
38
+ # * :password (String) the password for the user that will perform the bootstrap (required)
39
+ # * :port (Fixnum) the winrm port to connect on the node the bootstrap will be performed on (5985)
40
+ #
41
+ # @return [HostConnector::Response]
42
+ def run(host, command, options = {})
43
+ execute(__method__, host, command, options)
44
+ end
45
+
46
+ # Bootstrap a node
47
+ #
48
+ # @param [String] host
49
+ # the host to perform the action on
50
+ #
51
+ # @option options [Hash] :ssh
52
+ # * :user (String) a shell user that will login to each node and perform the bootstrap command on
53
+ # * :password (String) the password for the shell user that will perform the bootstrap
54
+ # * :keys (Array, String) an array of key(s) to authenticate the ssh user with instead of a password
55
+ # * :timeout (Float) timeout value for SSH bootstrap (5.0)
56
+ # * :sudo (Boolean) run as sudo
57
+ # @option options [Hash] :winrm
58
+ # * :user (String) a user that will login to each node and perform the bootstrap command on
59
+ # * :password (String) the password for the user that will perform the bootstrap (required)
60
+ # * :port (Fixnum) the winrm port to connect on the node the bootstrap will be performed on (5985)
61
+ #
62
+ # @return [HostConnector::Response]
63
+ def bootstrap(host, options = {})
64
+ execute(__method__, host, options)
65
+ end
66
+
67
+ # Perform a chef client run on a node
68
+ #
69
+ # @param [String] host
70
+ # the host to perform the action on
71
+ #
72
+ # @option options [Hash] :ssh
73
+ # * :user (String) a shell user that will login to each node and perform the bootstrap command on
74
+ # * :password (String) the password for the shell user that will perform the bootstrap
75
+ # * :keys (Array, String) an array of key(s) to authenticate the ssh user with instead of a password
76
+ # * :timeout (Float) timeout value for SSH bootstrap (5.0)
77
+ # * :sudo (Boolean) run as sudo
78
+ # @option options [Hash] :winrm
79
+ # * :user (String) a user that will login to each node and perform the bootstrap command on
80
+ # * :password (String) the password for the user that will perform the bootstrap (required)
81
+ # * :port (Fixnum) the winrm port to connect on the node the bootstrap will be performed on (5985)
82
+ #
83
+ # @return [HostConnector::Response]
84
+ def chef_client(host, options = {})
85
+ execute(__method__, host, options)
86
+ end
87
+
88
+ # Write your encrypted data bag secret on a node
89
+ #
90
+ # @param [String] host
91
+ # the host to perform the action on
92
+ # @param [String] secret
93
+ # your organization's encrypted data bag secret
94
+ #
95
+ # @option options [Hash] :ssh
96
+ # * :user (String) a shell user that will login to each node and perform the bootstrap command on
97
+ # * :password (String) the password for the shell user that will perform the bootstrap
98
+ # * :keys (Array, String) an array of key(s) to authenticate the ssh user with instead of a password
99
+ # * :timeout (Float) timeout value for SSH bootstrap (5.0)
100
+ # * :sudo (Boolean) run as sudo
101
+ # @option options [Hash] :winrm
102
+ # * :user (String) a user that will login to each node and perform the bootstrap command on
103
+ # * :password (String) the password for the user that will perform the bootstrap (required)
104
+ # * :port (Fixnum) the winrm port to connect on the node the bootstrap will be performed on (5985)
105
+ #
106
+ # @return [HostConnector::Response]
107
+ def put_secret(host, secret, options = {})
108
+ execute(__method__, host, secret, options)
109
+ end
110
+
111
+ # Execute line(s) of Ruby code on a node using Chef's embedded Ruby
112
+ #
113
+ # @param [String] host
114
+ # the host to perform the action on
115
+ # @param [Array<String>] command_lines
116
+ # An Array of lines of the command to be executed
117
+ #
118
+ # @option options [Hash] :ssh
119
+ # * :user (String) a shell user that will login to each node and perform the bootstrap command on
120
+ # * :password (String) the password for the shell user that will perform the bootstrap
121
+ # * :keys (Array, String) an array of key(s) to authenticate the ssh user with instead of a password
122
+ # * :timeout (Float) timeout value for SSH bootstrap (5.0)
123
+ # * :sudo (Boolean) run as sudo
124
+ # @option options [Hash] :winrm
125
+ # * :user (String) a user that will login to each node and perform the bootstrap command on
126
+ # * :password (String) the password for the user that will perform the bootstrap (required)
127
+ # * :port (Fixnum) the winrm port to connect on the node the bootstrap will be performed on (5985)
128
+ #
129
+ # @return [HostConnector::Response]
130
+ def ruby_script(host, command_lines, options = {})
131
+ execute(__method__, host, command_lines, options)
132
+ end
133
+
134
+ # Uninstall Chef from a node
135
+ #
136
+ # @param [String] host
137
+ # the host to perform the action on
138
+ #
139
+ # @option options [Boolena] :skip_chef (false)
140
+ # skip removal of the Chef package and the contents of the installation
141
+ # directory. Setting this to true will only remove any data and configurations
142
+ # generated by running Chef client.
143
+ # @option options [Hash] :ssh
144
+ # * :user (String) a shell user that will login to each node and perform the bootstrap command on
145
+ # * :password (String) the password for the shell user that will perform the bootstrap
146
+ # * :keys (Array, String) an array of key(s) to authenticate the ssh user with instead of a password
147
+ # * :timeout (Float) timeout value for SSH bootstrap (5.0)
148
+ # * :sudo (Boolean) run as sudo (true)
149
+ # @option options [Hash] :winrm
150
+ # * :user (String) a user that will login to each node and perform the bootstrap command on
151
+ # * :password (String) the password for the user that will perform the bootstrap (required)
152
+ # * :port (Fixnum) the winrm port to connect on the node the bootstrap will be performed on (5985)
153
+ #
154
+ # @return [HostConnector::Response]
155
+ def uninstall_chef(host, options = {})
156
+ execute(__method__, host, options)
157
+ end
158
+
159
+ # Finds and returns the best HostConnector for a given host
160
+ #
161
+ # @param [String] host
162
+ # the host to attempt to connect to
163
+ # @option options [Hash] :ssh
164
+ # * :port (Fixnum) the ssh port to connect on the node the bootstrap will be performed on (22)
165
+ # * :timeout (Float) [5.0] timeout value for testing SSH connection
166
+ # @option options [Hash] :winrm
167
+ # * :port (Fixnum) the winrm port to connect on the node the bootstrap will be performed on (5985)
168
+ # @param block [Proc]
169
+ # an optional block that is yielded the best HostConnector
170
+ #
171
+ # @return [HostConnector::SSH, HostConnector::WinRM]
172
+ def connector_for(host, options = {})
173
+ options = options.reverse_merge(ssh: Hash.new, winrm: Hash.new)
174
+ options[:ssh][:port] ||= HostConnector::SSH::DEFAULT_PORT
175
+ options[:winrm][:port] ||= HostConnector::WinRM::DEFAULT_PORT
176
+
177
+ if connector_port_open?(host, options[:winrm][:port])
178
+ options.delete(:ssh)
179
+ winrm
180
+ elsif connector_port_open?(host, options[:ssh][:port], options[:ssh][:timeout])
181
+ options.delete(:winrm)
182
+ ssh
183
+ else
184
+ raise Errors::HostConnectionError, "No connector ports open on '#{host}'"
185
+ end
186
+ end
187
+
188
+ private
189
+
190
+ def execute(method, host, *args)
191
+ options = args.last.is_a?(Hash) ? args.pop : Hash.new
192
+
193
+ connector_for(host, options).send(method, host, *args, options)
194
+ rescue Errors::HostConnectionError => ex
195
+ abort(ex)
196
+ rescue Resolv::ResolvError => ex
197
+ abort Errors::DNSResolvError.new(ex)
198
+ end
199
+
200
+ # Checks to see if the given port is open for TCP connections
201
+ # on the given host.
202
+ #
203
+ # @param [String] host
204
+ # the host to attempt to connect to
205
+ # @param [Fixnum] port
206
+ # the port to attempt to connect on
207
+ # @param [Float] wait_time ({PORT_CHECK_TIMEOUT})
208
+ # the number of seconds to wait
209
+ #
210
+ # @return [Boolean]
211
+ def connector_port_open?(host, port, wait_time = nil)
212
+ defer {
213
+ Timeout.timeout(wait_time || PORT_CHECK_TIMEOUT) { Celluloid::IO::TCPSocket.new(host, port).close; true }
214
+ }
215
+ rescue Errno::ETIMEDOUT, Timeout::Error, SocketError, Errno::ECONNREFUSED, Errno::EHOSTUNREACH, Errno::EADDRNOTAVAIL => ex
216
+ false
217
+ end
218
+
219
+ def finalize_callback
220
+ @connector_supervisor.async.terminate if @connector_supervisor && @connector_supervisor.alive?
221
+ end
222
+
223
+ def ssh
224
+ @connector_registry[:ssh]
225
+ end
226
+
227
+ def winrm
228
+ @connector_registry[:winrm]
229
+ end
230
+ end
231
+ end
@@ -0,0 +1,27 @@
1
+ module Ridley
2
+ module HostConnector
3
+ class Response
4
+ attr_reader :host
5
+
6
+ attr_accessor :stdout
7
+ attr_accessor :stderr
8
+ attr_accessor :exit_code
9
+ attr_accessor :exit_signal
10
+
11
+ def initialize(host, options = {})
12
+ @host = host
13
+ @stdout = options[:stdout] || String.new
14
+ @stderr = options[:stderr] || String.new
15
+ @exit_code = options[:exit_code] || -1
16
+ @exit_signal = options[:exit_signal] || nil
17
+ end
18
+
19
+ # Return true if the response was not successful
20
+ #
21
+ # @return [Boolean]
22
+ def error?
23
+ self.exit_code != 0
24
+ end
25
+ end
26
+ end
27
+ end