ridley-connectors 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -0,0 +1,198 @@
1
+ module Ridley
2
+ class NodeResource
3
+
4
+ attr_reader :server_url
5
+ attr_reader :validator_path
6
+ attr_reader :validator_client
7
+ attr_reader :encrypted_data_bag_secret
8
+ attr_reader :ssh
9
+ attr_reader :winrm
10
+ attr_reader :chef_version
11
+
12
+ finalizer :finalize_callback
13
+
14
+ # @param [Celluloid::Registry] connection_registry
15
+ #
16
+ # @option options [String] :server_url
17
+ # URL to the Chef API
18
+ # @option options [Hash] ssh
19
+ # * :user (String) a shell user that will login to each node and perform the bootstrap command on
20
+ # * :password (String) the password for the shell user that will perform the bootstrap
21
+ # * :keys (Array, String) an array of keys (or a single key) to authenticate the ssh user with instead of a password
22
+ # * :timeout (Float) [5.0] timeout value for SSH bootstrap
23
+ # @option options [Hash] :winrm
24
+ # * :user (String) a user that will login to each node and perform the bootstrap command on
25
+ # * :password (String) the password for the user that will perform the bootstrap
26
+ # * :port (Fixnum) the winrm port to connect on the node the bootstrap will be performed on
27
+ # @option options [String] :validator_client
28
+ # @option options [String] :validator_path
29
+ # filepath to the validator used to bootstrap the node
30
+ # @option options [String] :encrypted_data_bag_secret
31
+ # your organizations encrypted data bag secret
32
+ # @option options [String] :chef_version
33
+ # version of Chef to install on the node (default: nil)
34
+ def initialize(connection_registry, options = {})
35
+ super(connection_registry)
36
+ @server_url = options[:server_url]
37
+ @validator_path = options[:validator_path]
38
+ @validator_client = options[:validator_client]
39
+ @encrypted_data_bag_secret = options[:encrypted_data_bag_secret]
40
+ @ssh = options[:ssh]
41
+ @winrm = options[:winrm]
42
+ @chef_version = options[:chef_version]
43
+ @host_commander = HostCommander.new_link
44
+ end
45
+
46
+ # @param [String] host
47
+ #
48
+ # @option options [Hash] ssh
49
+ # * :user (String) a shell user that will login to each node and perform the bootstrap command on (required)
50
+ # * :password (String) the password for the shell user that will perform the bootstrap
51
+ # * :keys (Array, String) an array of keys (or a single key) to authenticate the ssh user with instead of a password
52
+ # * :timeout (Float) [5.0] timeout value for SSH bootstrap
53
+ # @option options [Hash] :winrm
54
+ # * :user (String) a user that will login to each node and perform the bootstrap command on (required)
55
+ # * :password (String) the password for the user that will perform the bootstrap
56
+ # * :port (Fixnum) the winrm port to connect on the node the bootstrap will be performed on (5985)
57
+ # @option options [String] :validator_client
58
+ # @option options [String] :validator_path
59
+ # filepath to the validator used to bootstrap the node (required)
60
+ # @option options [String] :bootstrap_proxy
61
+ # URL to a proxy server to bootstrap through (default: nil)
62
+ # @option options [String] :encrypted_data_bag_secret_path
63
+ # filepath on your host machine to your organizations encrypted data bag secret (default: nil)
64
+ # @option options [Hash] :hints
65
+ # a hash of Ohai hints to place on the bootstrapped node (default: Hash.new)
66
+ # @option options [Hash] :attributes
67
+ # a hash of attributes to use in the first Chef run (default: Hash.new)
68
+ # @option options [Array] :run_list
69
+ # an initial run list to bootstrap with (default: Array.new)
70
+ # @option options [String] :chef_version
71
+ # version of Chef to install on the node (default: nil)
72
+ # @option options [String] :environment
73
+ # environment to join the node to (default: '_default')
74
+ # @option options [Boolean] :sudo
75
+ # bootstrap with sudo (default: true)
76
+ # @option options [String] :template
77
+ # bootstrap template to use (default: omnibus)
78
+ #
79
+ # @return [HostConnector::Response]
80
+ def bootstrap(host, options = {})
81
+ options = options.reverse_merge(
82
+ server_url: server_url,
83
+ validator_path: validator_path,
84
+ validator_client: validator_client,
85
+ encrypted_data_bag_secret: encrypted_data_bag_secret,
86
+ ssh: ssh,
87
+ winrm: winrm,
88
+ chef_version: chef_version
89
+ )
90
+
91
+ host_commander.bootstrap(host, options)
92
+ end
93
+
94
+ # Executes a Chef run using the best worker available for the given
95
+ # host.
96
+ #
97
+ # @param [String] host
98
+ #
99
+ # @return [HostConnector::Response]
100
+ def chef_run(host)
101
+ host_commander.chef_client(host, ssh: ssh, winrm: winrm)
102
+ rescue Errors::HostConnectionError => ex
103
+ abort(ex)
104
+ end
105
+
106
+ # Puts a secret on the host using the best worker available for
107
+ # the given host.
108
+ #
109
+ # @param [String] host
110
+ #
111
+ # @return [HostConnector::Response]
112
+ def put_secret(host)
113
+ host_commander.put_secret(host, encrypted_data_bag_secret, ssh: ssh, winrm: winrm)
114
+ end
115
+
116
+ # Executes an arbitrary ruby script using the best worker available
117
+ # for the given host.
118
+ #
119
+ # @param [String] host
120
+ # @param [Array<String>] command_lines
121
+ #
122
+ # @return [HostConnector::Response]
123
+ def ruby_script(host, command_lines)
124
+ host_commander.ruby_script(host, command_lines, ssh: ssh, winrm: winrm)
125
+ end
126
+
127
+ # Executes the given command on a node using the best worker
128
+ # available for the given host.
129
+ #
130
+ # @param [String] host
131
+ # @param [String] command
132
+ #
133
+ # @return [HostConnector::Response]
134
+ def run(host, command)
135
+ host_commander.run(host, command, ssh: ssh, winrm: winrm)
136
+ end
137
+ alias_method :execute_command, :run
138
+
139
+ # Executes the given command on a node using a platform specific
140
+ # command.
141
+ #
142
+ # @param [String] host
143
+ # @param [Hash] commands
144
+ #
145
+ # @example
146
+ # platform_specific_run("host.example.com", linux: "hostname -f", windows: "echo %COMPUTERNAME%")
147
+ #
148
+ # @return [HostConnector::Response]
149
+ def platform_specific_run(host, commands)
150
+ case (type = host_commander.connector_for(host, ssh: ssh, winrm: winrm))
151
+ when HostConnector::SSH
152
+ raise Errors::CommandNotProvided.new(:ssh) unless commands[:ssh] and !commands[:ssh].empty?
153
+ run(host, commands[:ssh])
154
+ when HostConnector::WinRM
155
+ raise Errors::CommandNotProvided.new(:winrm) unless commands[:winrm] and !commands[:winrm].empty?
156
+ run(host, commands[:winrm])
157
+ else
158
+ raise RuntimeError, "#{type.class.to_s} is not a supported connector for #{self.class}##{__method__}"
159
+ end
160
+ end
161
+ alias_method :execute_platform_specific_command, :platform_specific_run
162
+
163
+ # Uninstall Chef from a node
164
+ #
165
+ # @param [String] host
166
+ # the host to perform the action on
167
+ #
168
+ # @option options [Boolena] :skip_chef (false)
169
+ # skip removal of the Chef package and the contents of the installation
170
+ # directory. Setting this to true will only remove any data and configurations
171
+ # generated by running Chef client.
172
+ # @option options [Hash] :ssh
173
+ # * :user (String) a shell user that will login to each node and perform the bootstrap command on
174
+ # * :password (String) the password for the shell user that will perform the bootstrap
175
+ # * :keys (Array, String) an array of key(s) to authenticate the ssh user with instead of a password
176
+ # * :timeout (Float) timeout value for SSH bootstrap (5.0)
177
+ # * :sudo (Boolean) run as sudo (true)
178
+ # @option options [Hash] :winrm
179
+ # * :user (String) a user that will login to each node and perform the bootstrap command on
180
+ # * :password (String) the password for the user that will perform the bootstrap (required)
181
+ # * :port (Fixnum) the winrm port to connect on the node the bootstrap will be performed on (5985)
182
+ #
183
+ # @return [HostConnector::Response]
184
+ def uninstall_chef(host, options = {})
185
+ options = options.reverse_merge(ssh: ssh, winrm: winrm)
186
+ host_commander.uninstall_chef(host, options)
187
+ end
188
+
189
+ private
190
+
191
+ # @return [Ridley::HostCommander]
192
+ attr_reader :host_commander
193
+
194
+ def finalize_callback
195
+ @host_commander.terminate if @host_commander && @host_commander.alive?
196
+ end
197
+ end
198
+ end
@@ -0,0 +1,5 @@
1
+ module Ridley
2
+ module Connectors
3
+ VERSION = '1.0.1'
4
+ end
5
+ end
@@ -0,0 +1,11 @@
1
+ require 'celluloid'
2
+ require 'celluloid/io'
3
+ require 'ridley'
4
+
5
+ module Ridley
6
+ require_relative 'ridley-connectors/client'
7
+ require_relative 'ridley-connectors/host_commander'
8
+ require_relative 'ridley-connectors/host_connector'
9
+ require_relative 'ridley-connectors/chef_objects/node_object'
10
+ require_relative 'ridley-connectors/resources/node_resource'
11
+ end
@@ -0,0 +1,27 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/ridley-connectors/version', __FILE__)
3
+
4
+ Gem::Specification.new do |s|
5
+ s.authors = ["Jamie Winsor", "Kyle Allan"]
6
+ s.email = ["jamie@vialstudios.com", "kallan@riotgames.com"]
7
+ s.description = %q{A Connector API for talking to nodes managed by Chef}
8
+ s.summary = s.description
9
+ s.homepage = "https://github.com/RiotGames/ridley-connectors"
10
+ s.license = "Apache 2.0"
11
+
12
+ s.files = `git ls-files`.split($\)
13
+ s.executables = Array.new
14
+ s.test_files = s.files.grep(%r{^(spec)/})
15
+ s.name = "ridley-connectors"
16
+ s.require_paths = ["lib"]
17
+ s.version = Ridley::Connectors::VERSION
18
+ s.required_ruby_version = ">= 1.9.1"
19
+
20
+ s.add_dependency 'celluloid', '~> 0.15'
21
+ s.add_dependency 'celluloid-io', '~> 0.15'
22
+ s.add_dependency 'net-ssh'
23
+ s.add_dependency 'ridley', '~> 2.0.0'
24
+ s.add_dependency 'winrm', '~> 1.1.0'
25
+
26
+ s.add_development_dependency 'buff-ruby_engine', '~> 0.1'
27
+ end
@@ -0,0 +1 @@
1
+ NTE5C5gzbe3F7fGBlrT/YTuMQuHlxaOWhY81KsgYXJ0mzDsDMFvCpfi4CUXu5M7n/Umgsf8jdHw/IIkJLZcXgk+Ll75kDU/VI5FyRzib0U0SX4JB8JLM7wRFgRpuk3GD27LnYR1APmLncE7R6ZSJc6iaFHcEL2MdR+hv0nhUZPUqITxYHyrYvqNSfroyxldQ/cvnrIMBS8JrpjIsLdYhcgL6mPJiakl4fM36cFk6Wl2Mxw7vOvGXRSR5l+t42pGDhtOjE3os5reLVoWkYoiQ1fpx3NrOdxsVuz17+3jMLBlmni2SGf2wncui2r9PqCrVbUbaCi6aNV1+SRbeh5kxBxjWSzw59BNXtna4vSK6hFPsT6tfXlOi67Q2vwjjAqltAVStGas/VZyU7DRzxMkbnPPtue+7Pajqe/TfSNWA5SX2cHtkG2X3EqZ8ftOa9p+b/VJlUnnnV2ilVfgjCW2q6XXMbC0C5yIbrDZm+aCJyhueA0j+ZHWM4k07OAuB7FRcuJJBs8H2StEx2o22OdAYUBcN5PRGlOAEBemL+sZAztbex2NjjOYV90806UFvSJLPixVWJgDTSA5OvXtNvUQYDYSGRQ/BmH86aA5gJ60AM9vEVB0BfPi946m9D4LZ/2uK6fqq3zVIV1s0EgfYHYUVz0oaf3srofc5YUAP3Ge/VLE=
@@ -0,0 +1,27 @@
1
+ -----BEGIN RSA PRIVATE KEY-----
2
+ MIIEpQIBAAKCAQEAyyUMqrTh1IzKOyE0fvXEWC7m0AdMI8/dr9JJMUKtK9vhhP0w
3
+ rm6m95GoybFM2IRryukFsAxpcir3M1ungTU3Smq4MshhMJ7H9FbvZVfQoknTbCsR
4
+ w6scg2fBepxT2+fcGRufr8nAh92M3uUkN9bMMTAkt18D4br6035YvdmvHDJERxYq
5
+ ByA/720AdI9VNSIvw+x8oqsIkXLEdF6dgT9MpG5iWZT66pbFsnNZpRrd4/bFNWBY
6
+ +13aOqdmjiTL08/EdgQFKMT5qimpos1TuQhA7mwInOjQgzVu9uCDkMiYejaLbUz0
7
+ lGyS8y4uxu6z2hA900Jg/z+JJuXymH5QAX3GZQIDAQABAoIBAQCtFXkwbYPI1Nht
8
+ /wG6du5+8B9K+hy+mppY9wPTy+q+Zs9Ev3Fd/fuXDm1QxBckl9c8AMUO1dR2KPOM
9
+ t7gFl/DvH/SnmCFvCqp1nijFIUgrLlnMXPn6zG0z7RBlxpKQ2IGohufNIEpBuNwR
10
+ Ag2U4hgChPGTp4ooJ2cVEh7MS5AupYPDbC62dWEdW68aRTWhh2BCGAWBb6s16yl9
11
+ aZ7+OcxW2eeRJVbRfLkLQEDutJZi5TfOEn5QPc86ZgxcCmnvwulnpnhpz6QCkgQt
12
+ OP/+KRqDhWSDVCFREVT30fUIj1EWvK7NFWASZQxueZStuIvMEKeFebYfrbHxRFzJ
13
+ UmaxJnWVAoGBAPbKLpeky6ClccBaHHrCgjzakoDfGgyNKDQ9g753lJxB8nn7d9X4
14
+ HQpkWpfqAGFRZp1hI2H+VxyUXLh2Ob5OUeTm0OZJll35vycOaQEtfgIScXTcvzn0
15
+ 16J9eX2YY4wIHEEMh85nKk8BEGgiNP5nuEviHocCeYXoi/Zq3+qj6v63AoGBANK5
16
+ 4nyi6LBQFs1CUc7Sh7vjtOE3ia7KeRmOr7gS6QhS3iK3Oa8FzBLJ6ETjN2a9Bw8N
17
+ cF7I/+cr4s7DUJjxdb53D/J6TVSYORNNCUVnpF/uB2LqqdXDYmpO0PvFkXFoYTnJ
18
+ kaLAN8uCoLKr6JH9tq3DfXIfDIHiZ+BOIvI070fDAoGBAMDyzEDFmGruTyRLj66u
19
+ +rJnVVmqlKwxhLhrS+CTj74nlVOnt0a0KMhiM65IRqnPwcHUG5zXBPaUTHXwAS93
20
+ /nFPwQ37hLPOupPnoVNJZRZrowbyPBQtCJbDMURv64ylHqoBCQDoCd0hANnZvMMX
21
+ BrFVhfaaibaXXS542r6SD/27AoGAECadHE5kJTdOOBcwK/jo3Fa8g1J9Y/8yvum3
22
+ wBT69V9clS6T5j08geglvDnqAh7UzquKBEnFi1NKw+wmXkKLcrivaTdEfApavYb3
23
+ AfHKoGue907jC3Y5Mcquq81ds2J7qTEwz1eKLzfo1yjj32ShvrmwALIuhDn1GjUC
24
+ 6qtx938CgYEApEqvu0nocR1jmVVlLe5uKQBj949dh6NGq0R5Lztz6xufaTYzMC3d
25
+ AZG9XPPjRqSLs+ylSXJpwHEwoeyLFDaJcO+GgW1/ut4MC2HppOx6aImwDdXMHUWR
26
+ KYGIFF4AU/IYoBcanAm4s078EH/Oz01B2c7tR2TqabisPgLYe7PXSCw=
27
+ -----END RSA PRIVATE KEY-----
@@ -0,0 +1,40 @@
1
+ require 'bundler'
2
+ require 'rubygems'
3
+ require 'buff/ruby_engine'
4
+
5
+ def setup_rspec
6
+ require 'rspec'
7
+ require 'webmock/rspec'
8
+
9
+ Dir[File.join(File.expand_path("../../spec/support/**/*.rb", __FILE__))].each { |f| require f }
10
+
11
+ RSpec.configure do |config|
12
+ config.include Ridley::SpecHelpers
13
+
14
+ config.before(:suite) do
15
+ WebMock.disable_net_connect!(allow_localhost: true, net_http_connect_on_start: true)
16
+ end
17
+
18
+ config.before(:all) { Ridley.logger = Celluloid.logger = nil }
19
+
20
+ config.before(:each) do
21
+ Celluloid.shutdown
22
+ Celluloid.boot
23
+ end
24
+ end
25
+ end
26
+
27
+ if Buff::RubyEngine.mri? && ENV['CI'] != 'true'
28
+ require 'spork'
29
+
30
+ Spork.prefork do
31
+ setup_rspec
32
+ end
33
+
34
+ Spork.each_run do
35
+ require 'ridley-connectors'
36
+ end
37
+ else
38
+ require 'ridley-connectors'
39
+ setup_rspec
40
+ end
@@ -0,0 +1,9 @@
1
+ RSpec.configuration.before(:each) do
2
+ class Celluloid::ActorProxy
3
+ unless @rspec_compatible
4
+ @rspec_compatible = true
5
+ undef_method :should_receive if method_defined?(:should_receive)
6
+ undef_method :stub if method_defined?(:stub)
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,20 @@
1
+ module Ridley
2
+ module SpecHelpers
3
+ def app_root_path
4
+ Pathname.new(File.expand_path('../../../', __FILE__))
5
+ end
6
+
7
+ def clean_tmp_path
8
+ FileUtils.rm_rf(tmp_path)
9
+ FileUtils.mkdir_p(tmp_path)
10
+ end
11
+
12
+ def fixtures_path
13
+ app_root_path.join('spec/fixtures')
14
+ end
15
+
16
+ def tmp_path
17
+ app_root_path.join('spec/tmp')
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,22 @@
1
+ require 'spec_helper'
2
+
3
+ describe Ridley::NodeObject do
4
+ let(:resource) { double('resource') }
5
+ let(:instance) { described_class.new(resource) }
6
+ subject { instance }
7
+
8
+ describe "#chef_run" do
9
+ it "sends the message #chef_run to the resource with the public_hostname of this instance" do
10
+ resource.should_receive(:chef_run).with(instance.public_hostname)
11
+ subject.chef_run
12
+ end
13
+ end
14
+
15
+ describe "#put_secret" do
16
+ it "sends the message #put_secret to the resource with the public_hostname of this instance" do
17
+ resource.should_receive(:put_secret).with(instance.public_hostname)
18
+
19
+ subject.put_secret
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,32 @@
1
+ require 'spec_helper'
2
+
3
+ describe Ridley::Client do
4
+ let(:server_url) { "https://api.opscode.com" }
5
+ let(:client_name) { "fake" }
6
+ let(:client_key) { fixtures_path.join("my-fake.pem").to_s }
7
+ let(:ssh) { {user: "fake", password: "password1", port: "222"} }
8
+ let(:winrm) { {user: "fake", password: "password2", port: "5986"} }
9
+ let(:config) do
10
+ {
11
+ server_url: server_url,
12
+ client_name: client_name,
13
+ client_key: client_key,
14
+ ssh: ssh,
15
+ winrm: winrm
16
+ }
17
+ end
18
+
19
+ describe "ClassMethods" do
20
+ describe "::initialize" do
21
+ subject { described_class.new(options) }
22
+
23
+ it "assigns a 'ssh' attribute from the given 'ssh' option" do
24
+ described_class.new(config).ssh.should eql({user: "fake", password: "password1", port: "222"})
25
+ end
26
+
27
+ it "assigns a 'winrm' attribute from the given 'winrm' option" do
28
+ described_class.new(config).winrm.should eql({user: "fake", password: "password2", port: "5986"})
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,173 @@
1
+ require 'spec_helper'
2
+
3
+ describe Ridley::HostCommander do
4
+ subject { described_class.new }
5
+
6
+ describe "#run" do
7
+ let(:host) { "fake.riotgames.com" }
8
+ let(:command) { "ls" }
9
+ let(:options) do
10
+ { ssh: { port: 22 }, winrm: { port: 5985 } }
11
+ end
12
+
13
+ context "when communicating to a unix node" do
14
+ before do
15
+ subject.stub(:connector_port_open?).with(host, options[:winrm][:port]).and_return(false)
16
+ subject.stub(:connector_port_open?).with(host, options[:ssh][:port], anything).and_return(true)
17
+ end
18
+
19
+ it "sends a #run message to the ssh host connector" do
20
+ subject.send(:ssh).should_receive(:run).with(host, command, options)
21
+
22
+ subject.run(host, command, options)
23
+ end
24
+ end
25
+
26
+ context "when communicating to a windows node" do
27
+ before do
28
+ subject.stub(:connector_port_open?).with(host, options[:winrm][:port]).and_return(true)
29
+ subject.stub(:connector_port_open?).with(host, options[:ssh][:port], anything).and_return(false)
30
+ end
31
+
32
+ it "sends a #run message to the ssh host connector" do
33
+ subject.send(:winrm).should_receive(:run).with(host, command, options)
34
+
35
+ subject.run(host, command, options)
36
+ end
37
+ end
38
+ end
39
+
40
+ describe "#bootstrap" do
41
+ let(:host) { "fake.riotgames.com" }
42
+ let(:options) do
43
+ { ssh: { port: 22 }, winrm: { port: 5985 } }
44
+ end
45
+
46
+ context "when communicating to a unix node" do
47
+ before do
48
+ subject.stub(:connector_port_open?).with(host, options[:winrm][:port]).and_return(false)
49
+ subject.stub(:connector_port_open?).with(host, options[:ssh][:port], anything).and_return(true)
50
+ end
51
+
52
+ it "sends a #bootstrap message to the ssh host connector" do
53
+ subject.send(:ssh).should_receive(:bootstrap).with(host, options)
54
+
55
+ subject.bootstrap(host, options)
56
+ end
57
+ end
58
+
59
+ context "when communicating to a windows node" do
60
+ before do
61
+ subject.stub(:connector_port_open?).with(host, options[:winrm][:port]).and_return(true)
62
+ subject.stub(:connector_port_open?).with(host, options[:ssh][:port], anything).and_return(false)
63
+ end
64
+
65
+ it "sends a #bootstrap message to the winrm host connector" do
66
+ subject.send(:winrm).should_receive(:bootstrap).with(host, options)
67
+
68
+ subject.bootstrap(host, options)
69
+ end
70
+ end
71
+ end
72
+
73
+ describe "#chef_client" do
74
+ let(:host) { "fake.riotgames.com" }
75
+ let(:options) do
76
+ { ssh: { port: 22 }, winrm: { port: 5985 } }
77
+ end
78
+
79
+ context "when communicating to a unix node" do
80
+ before do
81
+ subject.stub(:connector_port_open?).with(host, options[:winrm][:port]).and_return(false)
82
+ subject.stub(:connector_port_open?).with(host, options[:ssh][:port], anything).and_return(true)
83
+ end
84
+
85
+ it "sends a #chef_client message to the ssh host connector" do
86
+ subject.send(:ssh).should_receive(:chef_client).with(host, options)
87
+
88
+ subject.chef_client(host, options)
89
+ end
90
+ end
91
+
92
+ context "when communicating to a windows node" do
93
+ before do
94
+ subject.stub(:connector_port_open?).with(host, options[:winrm][:port]).and_return(true)
95
+ subject.stub(:connector_port_open?).with(host, options[:ssh][:port], anything).and_return(false)
96
+ end
97
+
98
+ it "sends a #chef_client message to the ssh host connector" do
99
+ subject.send(:winrm).should_receive(:chef_client).with(host, options)
100
+
101
+ subject.chef_client(host, options)
102
+ end
103
+ end
104
+ end
105
+
106
+ describe "#put_secret" do
107
+ let(:host) { "fake.riotgames.com" }
108
+ let(:secret) { "something_secret" }
109
+ let(:options) do
110
+ { ssh: { port: 22 }, winrm: { port: 5985 } }
111
+ end
112
+
113
+ context "when communicating to a unix node" do
114
+ before do
115
+ subject.stub(:connector_port_open?).with(host, options[:winrm][:port]).and_return(false)
116
+ subject.stub(:connector_port_open?).with(host, options[:ssh][:port], anything).and_return(true)
117
+ end
118
+
119
+ it "sends a #put_secret message to the ssh host connector" do
120
+ subject.send(:ssh).should_receive(:put_secret).with(host, secret, options)
121
+
122
+ subject.put_secret(host, secret, options)
123
+ end
124
+ end
125
+
126
+ context "when communicating to a windows node" do
127
+ before do
128
+ subject.stub(:connector_port_open?).with(host, options[:winrm][:port]).and_return(true)
129
+ subject.stub(:connector_port_open?).with(host, options[:ssh][:port], anything).and_return(false)
130
+ end
131
+
132
+ it "sends a #put_secret message to the ssh host connector" do
133
+ subject.send(:winrm).should_receive(:put_secret).with(host, secret, options)
134
+
135
+ subject.put_secret(host, secret, options)
136
+ end
137
+ end
138
+ end
139
+
140
+ describe "#ruby_script" do
141
+ let(:host) { "fake.riotgames.com" }
142
+ let(:command_lines) { ["line one"] }
143
+ let(:options) do
144
+ { ssh: { port: 22 }, winrm: { port: 5985 } }
145
+ end
146
+
147
+ context "when communicating to a unix node" do
148
+ before do
149
+ subject.stub(:connector_port_open?).with(host, options[:winrm][:port]).and_return(false)
150
+ subject.stub(:connector_port_open?).with(host, options[:ssh][:port], anything).and_return(true)
151
+ end
152
+
153
+ it "sends a #ruby_script message to the ssh host connector" do
154
+ subject.send(:ssh).should_receive(:ruby_script).with(host, command_lines, options)
155
+
156
+ subject.ruby_script(host, command_lines, options)
157
+ end
158
+ end
159
+
160
+ context "when communicating to a windows node" do
161
+ before do
162
+ subject.stub(:connector_port_open?).with(host, options[:winrm][:port]).and_return(true)
163
+ subject.stub(:connector_port_open?).with(host, options[:ssh][:port], anything).and_return(false)
164
+ end
165
+
166
+ it "sends a #ruby_script message to the ssh host connector" do
167
+ subject.send(:winrm).should_receive(:ruby_script).with(host, command_lines, options)
168
+
169
+ subject.ruby_script(host, command_lines, options)
170
+ end
171
+ end
172
+ end
173
+ end
@@ -0,0 +1,57 @@
1
+ require 'spec_helper'
2
+
3
+ describe Ridley::HostConnector::SSH do
4
+ subject { connector }
5
+ let(:connector) { described_class.new }
6
+
7
+ let(:host) { 'fake.riotgames.com' }
8
+ let(:options) do
9
+ {
10
+ server_url: double('server_url'),
11
+ validator_path: fixtures_path.join('my-fake.pem'),
12
+ validator_client: double('validator_client'),
13
+ encrypted_data_bag_secret: 'encrypted_data_bag_secret',
14
+ ssh: Hash.new,
15
+ chef_version: double('chef_version')
16
+ }
17
+ end
18
+
19
+ describe "#bootstrap" do
20
+ it "sends a #run message to self to bootstrap a node" do
21
+ connector.should_receive(:run).with(host, anything, options)
22
+ connector.bootstrap(host, options)
23
+ end
24
+ end
25
+
26
+ describe "#chef_client" do
27
+ it "sends a #run message to self to execute chef-client" do
28
+ connector.should_receive(:run).with(host, "chef-client", options)
29
+ connector.chef_client(host, options)
30
+ end
31
+ end
32
+
33
+ describe "#put_secret" do
34
+ let(:encrypted_data_bag_secret_path) { fixtures_path.join("encrypted_data_bag_secret").to_s }
35
+ let(:secret) { File.read(encrypted_data_bag_secret_path).chomp }
36
+
37
+ it "receives a run command with echo" do
38
+ connector.should_receive(:run).with(host,
39
+ "echo '#{secret}' > /etc/chef/encrypted_data_bag_secret; chmod 0600 /etc/chef/encrypted_data_bag_secret",
40
+ options
41
+ )
42
+ connector.put_secret(host, secret, options)
43
+ end
44
+ end
45
+
46
+ describe "#ruby_script" do
47
+ let(:command_lines) { ["puts 'hello'", "puts 'there'"] }
48
+
49
+ it "receives a ruby call with the command" do
50
+ connector.should_receive(:run).with(host,
51
+ "#{described_class::EMBEDDED_RUBY_PATH} -e \"puts 'hello';puts 'there'\"",
52
+ options
53
+ )
54
+ connector.ruby_script(host, command_lines, options)
55
+ end
56
+ end
57
+ end