ridley 0.12.4 → 1.0.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.
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