ridley 0.12.4 → 1.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. data/Gemfile +1 -1
  2. data/lib/ridley.rb +3 -3
  3. data/lib/ridley/bootstrap_context.rb +100 -0
  4. data/lib/ridley/bootstrap_context/unix.rb +74 -0
  5. data/lib/ridley/bootstrap_context/windows.rb +120 -0
  6. data/lib/ridley/chef_objects/node_object.rb +8 -5
  7. data/lib/ridley/host_commander.rb +207 -0
  8. data/lib/ridley/host_connector.rb +49 -87
  9. data/lib/ridley/host_connector/ssh.rb +153 -39
  10. data/lib/ridley/host_connector/winrm.rb +164 -39
  11. data/lib/ridley/resources/node_resource.rb +52 -56
  12. data/lib/ridley/version.rb +1 -1
  13. data/ridley.gemspec +0 -2
  14. data/spec/spec_helper.rb +4 -4
  15. data/spec/support/chef_server.rb +9 -3
  16. data/spec/unit/ridley/{bootstrap_bindings/unix_template_binding_spec.rb → bootstrap_context/unix_spec.rb} +2 -2
  17. data/spec/unit/ridley/{bootstrap_bindings/windows_template_binding_spec.rb → bootstrap_context/windows_spec.rb} +2 -2
  18. data/spec/unit/ridley/{mixin/bootstrap_binding_spec.rb → bootstrap_context_spec.rb} +2 -6
  19. data/spec/unit/ridley/host_commander_spec.rb +208 -0
  20. data/spec/unit/ridley/host_connector/ssh_spec.rb +37 -31
  21. data/spec/unit/ridley/host_connector/winrm_spec.rb +124 -31
  22. data/spec/unit/ridley/host_connector_spec.rb +23 -147
  23. data/spec/unit/ridley/resources/node_resource_spec.rb +55 -115
  24. metadata +17 -66
  25. data/lib/ridley/bootstrap_bindings.rb +0 -3
  26. data/lib/ridley/bootstrap_bindings/unix_template_binding.rb +0 -108
  27. data/lib/ridley/bootstrap_bindings/windows_template_binding.rb +0 -163
  28. data/lib/ridley/bootstrapper.rb +0 -89
  29. data/lib/ridley/bootstrapper/context.rb +0 -81
  30. data/lib/ridley/host_connector/response_set.rb +0 -98
  31. data/lib/ridley/host_connector/ssh/worker.rb +0 -135
  32. data/lib/ridley/host_connector/winrm/worker.rb +0 -159
  33. data/lib/ridley/log.rb +0 -10
  34. data/lib/ridley/mixin/bootstrap_binding.rb +0 -77
  35. data/spec/unit/ridley/bootstrapper/context_spec.rb +0 -45
  36. data/spec/unit/ridley/bootstrapper_spec.rb +0 -96
  37. data/spec/unit/ridley/host_connector/response_set_spec.rb +0 -112
  38. data/spec/unit/ridley/host_connector/ssh/worker_spec.rb +0 -57
  39. data/spec/unit/ridley/host_connector/winrm/worker_spec.rb +0 -139
@@ -1,51 +1,57 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Ridley::HostConnector::SSH do
4
- let(:resource) { double('resource') }
5
-
6
- let(:node_one) do
7
- Ridley::NodeObject.new(resource, automatic: { cloud: { public_hostname: "33.33.33.10" } })
8
- end
9
-
10
- let(:node_two) do
11
- Ridley::NodeObject.new(resource, automatic: { cloud: { public_hostname: "33.33.33.11" } })
12
- end
4
+ subject { connector }
5
+ let(:connector) { described_class.new }
13
6
 
7
+ let(:host) { 'reset.riotgames.com' }
14
8
  let(:options) do
15
9
  {
16
- user: "vagrant",
17
- password: "vagrant",
18
- timeout: 1
10
+ server_url: double('server_url'),
11
+ validator_path: fixtures_path.join('reset.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')
19
16
  }
20
17
  end
21
18
 
22
- describe "ClassMethods" do
23
- subject { described_class }
24
-
25
- describe "::start" do
26
- it "raises a LocalJumpError if a block is not provided" do
27
- expect {
28
- subject.start([node_one, node_two], options)
29
- }.to raise_error(LocalJumpError)
30
- end
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)
31
23
  end
32
24
  end
33
25
 
34
- subject do
35
- Ridley::HostConnector::SSH.new([node_one, node_two], ssh: { user: "vagrant", password: "vagrant", timeout: 1 })
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
36
31
  end
37
32
 
38
- describe "#run" do
39
- let(:worker) { double('worker', terminate: nil) }
40
- let(:response) { Ridley::HostConnector::Response.new("host") }
41
- before { Ridley::HostConnector::SSH::Worker.stub(:new).and_return(worker) }
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 }
42
36
 
43
- before do
44
- worker.stub_chain(:future, :run).and_return(double(value: [:ok, response]))
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)
45
43
  end
44
+ end
45
+
46
+ describe "#ruby_script" do
47
+ let(:command_lines) { ["puts 'hello'", "puts 'there'"] }
46
48
 
47
- it "returns an SSH::ResponseSet" do
48
- subject.run("ls").should be_a(Ridley::HostConnector::ResponseSet)
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)
49
55
  end
50
56
  end
51
57
  end
@@ -1,52 +1,145 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Ridley::HostConnector::WinRM do
4
- let(:resource) { double('resource') }
5
-
6
- let(:node_one) do
7
- Ridley::NodeObject.new(resource, automatic: { cloud: { public_hostname: "33.33.33.10" } })
4
+ subject { connector }
5
+ let(:connector) { described_class.new }
6
+ let(:host) { 'reset.riotgames.com' }
7
+ let(:options) do
8
+ {
9
+ server_url: double('server_url'),
10
+ validator_path: fixtures_path.join('reset.pem'),
11
+ validator_client: double('validator_client'),
12
+ encrypted_data_bag_secret: 'encrypted_data_bag_secret',
13
+ winrm: Hash.new,
14
+ chef_version: double('chef_version')
15
+ }
8
16
  end
9
17
 
10
- let(:node_two) do
11
- Ridley::NodeObject.new(resource, automatic: { cloud: { public_hostname: "33.33.33.11" } })
12
- end
13
- let(:command_uploader) { double('command_uploader', cleanup: nil) }
18
+ before { described_class::CommandUploader.stub(:new).and_return(double('command_uploader')) }
19
+
20
+ describe "#get_command" do
21
+ subject(:get_command) { connector.get_command(command, command_uploader_stub) }
22
+
23
+ let(:command) { "echo %TEMP%" }
24
+ let(:command_uploader_stub) { double('CommandUploader') }
25
+
26
+ it { should eq(command) }
14
27
 
15
- before do
16
- Ridley::HostConnector::WinRM::CommandUploader.stub(:new).and_return(command_uploader)
28
+ context "when a command is more than 2047 characters" do
29
+ let(:command) { "a" * 2048 }
30
+
31
+ it "uploads and returns a command" do
32
+ described_class::CommandUploader.stub(new: command_uploader_stub)
33
+
34
+ command_uploader_stub.should_receive :upload
35
+ command_uploader_stub.stub command: "my command"
36
+ command_uploader_stub.stub(:cleanup)
37
+
38
+ get_command.should eq("my command")
39
+ end
40
+ end
17
41
  end
18
42
 
19
- describe "ClassMethods" do
20
- subject { Ridley::HostConnector::WinRM }
43
+ describe "#run" do
44
+ subject(:result) { connector.run(host, command, options) }
45
+ let(:command) { "dir" }
46
+ let(:command_uploader_stub) { double('CommandUploader', cleanup: true) }
47
+ let(:stdout) { "stdout" }
48
+ let(:stderr) { nil }
49
+ let(:winrm_stub) { double }
50
+
51
+ before do
52
+ described_class::CommandUploader.stub(:new).and_return(command_uploader_stub)
53
+ connector.stub(:winrm).and_return(winrm_stub)
54
+ winrm_stub.stub(:run_cmd).and_yield(stdout, stderr).and_return(exitcode: 0)
55
+ end
56
+
57
+ context "when the exit_code is 0" do
58
+ it "returns a non-error HostConnector::Response" do
59
+ expect(result).to be_a(Ridley::HostConnector::Response)
60
+ expect(result).to_not be_error
61
+ end
62
+
63
+ it "sets the response's stdout message" do
64
+ expect(result.stdout).to eq("stdout")
65
+ end
66
+ end
67
+
68
+ context "when the exit_code is not 0" do
69
+ let(:stderr) { "stderr" }
70
+
71
+ before do
72
+ winrm_stub.stub(:run_cmd).and_yield(stdout, stderr).and_return(exitcode: 1)
73
+ end
74
+
75
+ it "returns an error HostConnector::Response with an error" do
76
+ expect(result).to be_a(Ridley::HostConnector::Response)
77
+ expect(result).to be_error
78
+ end
21
79
 
22
- describe "::start" do
23
- let(:options) do
24
- {
25
- user: "Administrator",
26
- password: "password1"
27
- }
80
+ it "sets the response's stderr message" do
81
+ expect(result.stderr).to eq("stderr")
28
82
  end
83
+ end
84
+
85
+ context "when a WinRM::WinRMHTTPTransportError error is raised" do
86
+ let(:stderr) { "error" }
87
+ before { winrm_stub.stub(:run_cmd).and_yield(stdout, stderr).and_raise(::WinRM::WinRMHTTPTransportError) }
29
88
 
30
- it "evaluates within the context of a new WinRM and returns the last item in the block" do
31
- result = subject.start([node_one, node_two], options) do |winrm|
32
- winrm.run("dir")
33
- end
34
- result.should be_a(Ridley::HostConnector::ResponseSet)
89
+ it "returns an error HostConnector::Response with an error" do
90
+ expect(result).to be_a(Ridley::HostConnector::Response)
91
+ expect(result).to be_error
35
92
  end
36
93
 
37
- it "raises a LocalJumpError if a block is not provided" do
38
- expect {
39
- subject.start([node_one, node_two], options)
40
- }.to raise_error(LocalJumpError)
94
+ it "sets the response's stderr message to the exception's message" do
95
+ expect(result.stderr).to eql("WinRM::WinRMHTTPTransportError")
41
96
  end
42
97
  end
43
98
  end
44
99
 
45
- subject { Ridley::HostConnector::WinRM.new([node_one, node_two], user: 'Administrator', password: 'password1') }
100
+ describe "#bootstrap" do
101
+ it "sends a #run message to self to bootstrap a node" do
102
+ connector.should_receive(:run).with(host, anything, options)
103
+ connector.bootstrap(host, options)
104
+ end
105
+ end
46
106
 
47
- describe "#run" do
48
- it "returns a ResponseSet" do
49
- subject.run("dir").should be_a(Ridley::HostConnector::ResponseSet)
107
+ describe "#chef_client" do
108
+ subject(:chef_client) { connector.chef_client(host, options) }
109
+
110
+ it "receives a command to run chef-client" do
111
+ connector.should_receive(:run).with(host, "chef-client", options)
112
+
113
+ chef_client
114
+ end
115
+ end
116
+
117
+ describe "#put_secret" do
118
+ subject(:put_secret) { connector.put_secret(host, secret, options) }
119
+ let(:encrypted_data_bag_secret_path) { fixtures_path.join("encrypted_data_bag_secret").to_s }
120
+ let(:secret) { File.read(encrypted_data_bag_secret_path).chomp }
121
+
122
+ it "receives a command to copy the secret" do
123
+ connector.should_receive(:run).with(host,
124
+ "echo #{secret} > C:\\chef\\encrypted_data_bag_secret",
125
+ options
126
+ )
127
+
128
+ put_secret
129
+ end
130
+ end
131
+
132
+ describe "#ruby_script" do
133
+ subject(:ruby_script) { connector.ruby_script(host, command_lines, options) }
134
+ let(:command_lines) { ["puts 'hello'", "puts 'there'"] }
135
+
136
+ it "receives a ruby call with the command" do
137
+ connector.should_receive(:run).with(host,
138
+ "#{described_class::EMBEDDED_RUBY_PATH} -e \"puts 'hello';puts 'there'\"",
139
+ options
140
+ )
141
+
142
+ ruby_script
50
143
  end
51
144
  end
52
145
  end
@@ -1,168 +1,44 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe Ridley::HostConnector do
4
- subject do
5
- described_class
6
- end
7
-
8
- it "returns 22 as the default SSH port" do
9
- described_class::DEFAULT_SSH_PORT.should eq(22)
10
- end
11
-
12
- it "returns 5985 as the default WinRM port" do
13
- described_class::DEFAULT_WINRM_PORT.should eq(5985)
14
- end
15
-
16
- describe "::new" do
17
- let(:host) { "192.168.1.1" }
18
- let(:options) do
19
- {
20
- ssh: {
21
- user: "reset",
22
- password: "lol"
23
- },
24
- winrm: {
25
- user: "Administrator",
26
- password: "secret"
27
- }
28
- }
29
- end
30
-
31
- subject { described_class.new(host, options) }
3
+ describe Ridley::HostConnector::Base do
4
+ subject { Class.new(Ridley::HostConnector::Base).new }
32
5
 
33
- context "when the best connector is SSH" do
34
- before do
35
- described_class.stub(:best_connector_for).and_yield(Ridley::HostConnector::SSH)
36
- end
6
+ let(:host) { double('host') }
7
+ let(:options) { Hash.new }
37
8
 
38
- it { should be_a(Ridley::HostConnector::SSH::Worker) }
39
- its(:user) { should eq("reset") }
40
- end
41
-
42
- context "when the best connector is WinRM" do
43
- before do
44
- described_class.stub(:best_connector_for).and_yield(Ridley::HostConnector::WinRM)
45
- end
9
+ describe "#run" do
10
+ let(:command) { double('command') }
46
11
 
47
- it { should be_a(Ridley::HostConnector::WinRM::Worker) }
48
- its(:user) { should eq("Administrator") }
49
- its(:password) { should eq("secret") }
12
+ it "raises a RuntimeError" do
13
+ expect { subject.run(host, command, options) }.to raise_error(RuntimeError)
50
14
  end
51
15
  end
52
16
 
53
- describe "::connector_port_open?" do
54
- let(:host) { "127.0.0.1" }
55
- let(:port) { 22 }
56
- let(:socket) { double(:new => true, :close => nil) }
57
-
58
- context "when a port is open" do
59
- before do
60
- TCPSocket.stub(:new).and_return(socket)
61
- end
62
-
63
- it "returns true" do
64
- subject.connector_port_open?(host, port).should eql(true)
65
- end
66
-
67
- it "closes the opened socket" do
68
- socket.should_receive(:close)
69
- subject.connector_port_open?(host, port)
70
- end
71
- end
72
-
73
- context "when a port is closed" do
74
- before do
75
- TCPSocket.stub(:new).and_raise(Errno::ECONNREFUSED)
76
- end
77
-
78
- it "returns false" do
79
- subject.connector_port_open?(host, port).should eq(false)
80
- end
81
- end
82
-
83
- context "when host is unreachable" do
84
- before do
85
- TCPSocket.stub(:new).and_raise(SocketError)
86
- end
87
-
88
- it "returns false" do
89
- subject.connector_port_open?(host, port).should eql(false)
90
- end
17
+ describe "#bootstrap" do
18
+ it "raises a RuntimeError" do
19
+ expect { subject.bootstrap(host, options) }.to raise_error(RuntimeError)
91
20
  end
92
21
  end
93
22
 
94
- describe "::best_connector_for" do
95
- let(:host) {"127.0.0.1"}
96
-
97
- context "when an SSH port is open" do
98
- it "returns Ridley::HostConnector::SSH" do
99
- subject.stub(:connector_port_open?).and_return(false, true)
100
- expect(subject.best_connector_for(host)).to eq(Ridley::HostConnector::SSH)
101
- end
102
- end
103
-
104
- context "when an SSH port isnt open and a WinRM port is open" do
105
- it "retrns Ridley::HostConnector::WinRM" do
106
- subject.stub(:connector_port_open?).and_return(true, false)
107
- expect(subject.best_connector_for(host)).to eq(Ridley::HostConnector::WinRM)
108
- end
109
- end
110
-
111
- context "when no useable ports are open" do
112
- it "raises an exception" do
113
- subject.stub(:connector_port_open?).and_return(false, false)
114
- expect {
115
- subject.best_connector_for(host)
116
- }.to raise_error(Ridley::Errors::HostConnectionError)
117
- end
118
- end
119
-
120
- context "when a block is provided" do
121
- it "yields the best HostConnector to the block" do
122
- subject.stub(:connector_port_open?).and_return(false, true)
123
- subject.best_connector_for(host) do |yielded|
124
- expect(yielded).to eq(Ridley::HostConnector::SSH)
125
- end
126
- end
23
+ describe "#chef_client" do
24
+ it "raises a RuntimeError" do
25
+ expect { subject.chef_client(host, options) }.to raise_error(RuntimeError)
127
26
  end
128
27
  end
129
28
 
130
- describe "::parse_port_options" do
131
- let(:options) do
132
- {
133
- ssh: {
134
- port: 1234
135
- },
136
- winrm: {
137
- port: 5678
138
- }
139
- }
140
- end
29
+ describe "#put_secret" do
30
+ let(:secret) { double('secret') }
141
31
 
142
- context "when :ssh has a key for :port" do
143
- it "returns the value of port instead of the default" do
144
- subject.parse_port_options(options).should include(1234)
145
- end
146
- end
147
-
148
- context "when there is no :ssh key" do
149
- it "returns the default value for port" do
150
- options.delete(:ssh)
151
- subject.parse_port_options(options).should include(22)
152
- end
32
+ it "raises a RuntimeError" do
33
+ expect { subject.put_secret(host, secret, options) }.to raise_error(RuntimeError)
153
34
  end
35
+ end
154
36
 
155
- context "when :winrm has a key for :port" do
156
- it "returns the value of port instead of the default" do
157
- subject.parse_port_options(options).should include(5678)
158
- end
159
- end
37
+ describe "#ruby_script" do
38
+ let(:command_lines) { double('command-lines') }
160
39
 
161
- context "when there is no :ssh key" do
162
- it "returns the default value for port" do
163
- options.delete(:winrm)
164
- subject.parse_port_options(options).should include(5985)
165
- end
40
+ it "raises a RuntimeError" do
41
+ expect { subject.ruby_script(host, command_lines, options) }.to raise_error(RuntimeError)
166
42
  end
167
43
  end
168
44
  end