cheffish 0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +201 -0
  3. data/README.md +4 -0
  4. data/Rakefile +23 -0
  5. data/lib/chef/provider/chef_client.rb +44 -0
  6. data/lib/chef/provider/chef_data_bag.rb +50 -0
  7. data/lib/chef/provider/chef_data_bag_item.rb +273 -0
  8. data/lib/chef/provider/chef_environment.rb +78 -0
  9. data/lib/chef/provider/chef_node.rb +82 -0
  10. data/lib/chef/provider/chef_role.rb +79 -0
  11. data/lib/chef/provider/chef_user.rb +48 -0
  12. data/lib/chef/provider/private_key.rb +160 -0
  13. data/lib/chef/provider/public_key.rb +83 -0
  14. data/lib/chef/resource/chef_client.rb +44 -0
  15. data/lib/chef/resource/chef_data_bag.rb +18 -0
  16. data/lib/chef/resource/chef_data_bag_item.rb +114 -0
  17. data/lib/chef/resource/chef_environment.rb +71 -0
  18. data/lib/chef/resource/chef_node.rb +18 -0
  19. data/lib/chef/resource/chef_role.rb +104 -0
  20. data/lib/chef/resource/chef_user.rb +51 -0
  21. data/lib/chef/resource/in_parallel.rb +6 -0
  22. data/lib/chef/resource/private_key.rb +39 -0
  23. data/lib/chef/resource/public_key.rb +16 -0
  24. data/lib/cheffish.rb +245 -0
  25. data/lib/cheffish/actor_provider_base.rb +120 -0
  26. data/lib/cheffish/chef_provider_base.rb +222 -0
  27. data/lib/cheffish/cheffish_server_api.rb +21 -0
  28. data/lib/cheffish/inline_resource.rb +88 -0
  29. data/lib/cheffish/key_formatter.rb +93 -0
  30. data/lib/cheffish/recipe_dsl.rb +98 -0
  31. data/lib/cheffish/version.rb +4 -0
  32. data/spec/integration/chef_client_spec.rb +48 -0
  33. data/spec/integration/chef_node_spec.rb +75 -0
  34. data/spec/integration/chef_user_spec.rb +48 -0
  35. data/spec/integration/private_key_spec.rb +356 -0
  36. data/spec/integration/recipe_dsl_spec.rb +29 -0
  37. data/spec/support/key_support.rb +29 -0
  38. data/spec/support/spec_support.rb +148 -0
  39. metadata +124 -0
@@ -0,0 +1,4 @@
1
+ module Cheffish
2
+ VERSION = '0.1'
3
+ end
4
+
@@ -0,0 +1,48 @@
1
+ require 'support/spec_support'
2
+ require 'support/key_support'
3
+ require 'chef/resource/chef_client'
4
+ require 'chef/provider/chef_client'
5
+
6
+ repo_path = Dir.mktmpdir('chef_repo')
7
+
8
+ describe Chef::Resource::ChefClient do
9
+ extend SpecSupport
10
+
11
+ when_the_chef_server 'is empty' do
12
+ context 'and we have a private key' do
13
+ with_recipe do
14
+ private_key "#{repo_path}/blah.pem"
15
+ end
16
+
17
+ context 'and we run a recipe that creates client "blah"' do
18
+ with_recipe do
19
+ chef_client 'blah' do
20
+ source_key_path "#{repo_path}/blah.pem"
21
+ end
22
+ end
23
+
24
+ it 'the client gets created' do
25
+ chef_run.should have_updated 'chef_client[blah]', :create
26
+ client = get('/clients/blah')
27
+ client['name'].should == 'blah'
28
+ key, format = Cheffish::KeyFormatter.decode(client['public_key'])
29
+ key.should be_public_key_for("#{repo_path}/blah.pem")
30
+ end
31
+ end
32
+
33
+ context 'and we run a recipe that creates client "blah" with output_key_path' do
34
+ with_recipe do
35
+ chef_client 'blah' do
36
+ source_key_path "#{repo_path}/blah.pem"
37
+ output_key_path "#{repo_path}/blah.pub"
38
+ end
39
+ end
40
+
41
+ it 'the output public key gets created' do
42
+ IO.read("#{repo_path}/blah.pub").should start_with('ssh-rsa ')
43
+ "#{repo_path}/blah.pub".should be_public_key_for("#{repo_path}/blah.pem")
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,75 @@
1
+ require 'support/spec_support'
2
+ require 'chef/resource/chef_node'
3
+ require 'chef/provider/chef_node'
4
+
5
+ describe Chef::Resource::ChefNode do
6
+ extend SpecSupport
7
+
8
+ when_the_chef_server 'is empty' do
9
+ context 'and we run a recipe that creates node "blah"' do
10
+ with_recipe do
11
+ chef_node 'blah'
12
+ end
13
+
14
+ it 'the node gets created' do
15
+ chef_run.should have_updated 'chef_node[blah]', :create
16
+ get('/nodes/blah')['name'].should == 'blah'
17
+ end
18
+ end
19
+
20
+ # TODO why-run mode
21
+
22
+ context 'and another chef server is running on port 8899' do
23
+ before :each do
24
+ @server = ChefZero::Server.new(:port => 8899)
25
+ @server.start_background
26
+ end
27
+
28
+ after :each do
29
+ @server.stop
30
+ end
31
+
32
+ context 'and a recipe is run that creates node "blah" on the second chef server using with_chef_server' do
33
+
34
+ with_recipe do
35
+ with_chef_server 'http://127.0.0.1:8899'
36
+ chef_node 'blah'
37
+ end
38
+
39
+ it 'the node is created on the second chef server but not the first' do
40
+ chef_run.should have_updated 'chef_node[blah]', :create
41
+ lambda { get('/nodes/blah') }.should raise_error(Net::HTTPServerException)
42
+ get('http://127.0.0.1:8899/nodes/blah')['name'].should == 'blah'
43
+ end
44
+ end
45
+
46
+ context 'and a recipe is run that creates node "blah" on the second chef server using chef_server' do
47
+
48
+ with_recipe do
49
+ chef_node 'blah' do
50
+ chef_server({ :chef_server_url => 'http://127.0.0.1:8899' })
51
+ end
52
+ end
53
+
54
+ it 'the node is created on the second chef server but not the first' do
55
+ chef_run.should have_updated 'chef_node[blah]', :create
56
+ lambda { get('/nodes/blah') }.should raise_error(Net::HTTPServerException)
57
+ get('http://127.0.0.1:8899/nodes/blah')['name'].should == 'blah'
58
+ end
59
+ end
60
+
61
+ end
62
+ end
63
+
64
+ when_the_chef_server 'has a node named "blah"' do
65
+ node 'blah', {}
66
+
67
+ with_recipe do
68
+ chef_node 'blah'
69
+ end
70
+
71
+ it 'the node "blah" does not get created or updated' do
72
+ chef_run.should_not have_updated 'chef_node[blah]', :create
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,48 @@
1
+ require 'support/spec_support'
2
+ require 'support/key_support'
3
+ require 'chef/resource/chef_user'
4
+ require 'chef/provider/chef_user'
5
+
6
+ repo_path = Dir.mktmpdir('chef_repo')
7
+
8
+ describe Chef::Resource::ChefUser do
9
+ extend SpecSupport
10
+
11
+ when_the_chef_server 'is empty' do
12
+ context 'and we have a private key' do
13
+ with_recipe do
14
+ private_key "#{repo_path}/blah.pem"
15
+ end
16
+
17
+ context 'and we run a recipe that creates user "blah"'do
18
+ with_recipe do
19
+ chef_user 'blah' do
20
+ source_key_path "#{repo_path}/blah.pem"
21
+ end
22
+ end
23
+
24
+ it 'the user gets created' do
25
+ chef_run.should have_updated 'chef_user[blah]', :create
26
+ user = get('/users/blah')
27
+ user['name'].should == 'blah'
28
+ key, format = Cheffish::KeyFormatter.decode(user['public_key'])
29
+ key.should be_public_key_for("#{repo_path}/blah.pem")
30
+ end
31
+ end
32
+
33
+ context 'and we run a recipe that creates client "blah" with output_key_path' do
34
+ with_recipe do
35
+ chef_client 'blah' do
36
+ source_key_path "#{repo_path}/blah.pem"
37
+ output_key_path "#{repo_path}/blah.pub"
38
+ end
39
+ end
40
+
41
+ it 'the output public key gets created' do
42
+ IO.read("#{repo_path}/blah.pub").should start_with('ssh-rsa ')
43
+ "#{repo_path}/blah.pub".should be_public_key_for("#{repo_path}/blah.pem")
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,356 @@
1
+ require 'support/spec_support'
2
+ require 'chef/resource/private_key'
3
+ require 'chef/provider/private_key'
4
+ require 'chef/resource/public_key'
5
+ require 'chef/provider/public_key'
6
+ require 'support/key_support'
7
+
8
+ repo_path = Dir.mktmpdir('chef_repo')
9
+
10
+ describe Chef::Resource::PrivateKey do
11
+ extend SpecSupport
12
+
13
+ before :each do
14
+ FileUtils.remove_entry_secure(repo_path)
15
+ Dir.mkdir(repo_path)
16
+ end
17
+
18
+ context 'with a recipe with a private_key' do
19
+ with_recipe do
20
+ private_key "#{repo_path}/blah"
21
+ end
22
+
23
+ it 'the private_key is created in pem format' do
24
+ chef_run.should have_updated "private_key[#{repo_path}/blah]", :create
25
+ IO.read("#{repo_path}/blah").should start_with('-----BEGIN')
26
+ OpenSSL::PKey.read(IO.read("#{repo_path}/blah")).kind_of?(OpenSSL::PKey::RSA).should be_true
27
+ end
28
+
29
+ context 'and a private_key that copies it in der format' do
30
+ with_recipe do
31
+ private_key "#{repo_path}/blah.der" do
32
+ source_key_path "#{repo_path}/blah"
33
+ format :der
34
+ end
35
+ end
36
+
37
+ it 'the private_key is copied in der format and is identical' do
38
+ chef_run.should have_updated "private_key[#{repo_path}/blah.der]", :create
39
+ key_str = IO.read("#{repo_path}/blah.der")
40
+ key_str.should_not start_with('-----BEGIN')
41
+ key_str.should_not start_with('ssh-')
42
+ "#{repo_path}/blah.der".should match_private_key("#{repo_path}/blah")
43
+ end
44
+ end
45
+
46
+ it 'a private_key that copies it from in-memory as a string succeeds' do
47
+ run_recipe do
48
+ private_key "#{repo_path}/blah.der" do
49
+ source_key IO.read("#{repo_path}/blah")
50
+ format :der
51
+ end
52
+ end
53
+
54
+ chef_run.should have_updated "private_key[#{repo_path}/blah.der]", :create
55
+ key_str = IO.read("#{repo_path}/blah.der")
56
+ key_str.should_not start_with('-----BEGIN')
57
+ key_str.should_not start_with('ssh-')
58
+ "#{repo_path}/blah.der".should match_private_key("#{repo_path}/blah")
59
+ end
60
+
61
+ it 'a private_key that copies it from in-memory as a key succeeds' do
62
+ key = OpenSSL::PKey.read(IO.read("#{repo_path}/blah"))
63
+ run_recipe do
64
+ private_key "#{repo_path}/blah.der" do
65
+ source_key key
66
+ format :der
67
+ end
68
+ end
69
+
70
+ chef_run.should have_updated "private_key[#{repo_path}/blah.der]", :create
71
+ key_str = IO.read("#{repo_path}/blah.der")
72
+ key_str.should_not start_with('-----BEGIN')
73
+ key_str.should_not start_with('ssh-')
74
+ "#{repo_path}/blah.der".should match_private_key("#{repo_path}/blah")
75
+ end
76
+
77
+ context 'and a public_key' do
78
+ with_recipe do
79
+ public_key "#{repo_path}/blah.pub" do
80
+ source_key_path "#{repo_path}/blah"
81
+ end
82
+ end
83
+
84
+ it 'the public_key is created' do
85
+ chef_run.should have_updated "private_key[#{repo_path}/blah]", :create
86
+ chef_run.should have_updated "public_key[#{repo_path}/blah.pub]", :create
87
+ IO.read("#{repo_path}/blah.pub").should start_with('ssh-rsa ')
88
+ "#{repo_path}/blah.pub".should be_public_key_for "#{repo_path}/blah"
89
+ end
90
+
91
+ context 'and another public_key based off the first public_key' do
92
+ with_recipe do
93
+ public_key "#{repo_path}/blah.pub2" do
94
+ source_key_path "#{repo_path}/blah.pub"
95
+ end
96
+ end
97
+
98
+ it 'the second public_key is created' do
99
+ chef_run.should have_updated "public_key[#{repo_path}/blah.pub2]", :create
100
+ IO.read("#{repo_path}/blah.pub").should start_with('ssh-rsa ')
101
+ "#{repo_path}/blah.pub".should be_public_key_for "#{repo_path}/blah"
102
+ end
103
+ end
104
+
105
+ context 'and another public_key based off the first public_key in-memory in a string' do
106
+ with_recipe do
107
+ public_key "#{repo_path}/blah.pub2" do
108
+ source_key IO.read("#{repo_path}/blah.pub")
109
+ end
110
+ end
111
+
112
+ it 'the second public_key is created' do
113
+ chef_run.should have_updated "public_key[#{repo_path}/blah.pub2]", :create
114
+ IO.read("#{repo_path}/blah.pub").should start_with('ssh-rsa ')
115
+ "#{repo_path}/blah.pub".should be_public_key_for "#{repo_path}/blah"
116
+ end
117
+ end
118
+
119
+ it 'and another public_key based off the first public_key in-memory in a key, the second public_key is created' do
120
+ key, format = Cheffish::KeyFormatter.decode(IO.read("#{repo_path}/blah.pub"))
121
+
122
+ run_recipe do
123
+ public_key "#{repo_path}/blah.pub2" do
124
+ source_key key
125
+ end
126
+ end
127
+
128
+ chef_run.should have_updated "public_key[#{repo_path}/blah.pub2]", :create
129
+ IO.read("#{repo_path}/blah.pub").should start_with('ssh-rsa ')
130
+ "#{repo_path}/blah.pub".should be_public_key_for "#{repo_path}/blah"
131
+ end
132
+
133
+ context 'and another public_key in :pem format based off the first public_key' do
134
+ with_recipe do
135
+ public_key "#{repo_path}/blah.pub2" do
136
+ source_key_path "#{repo_path}/blah.pub"
137
+ format :pem
138
+ end
139
+ end
140
+
141
+ it 'the second public_key is created' do
142
+ chef_run.should have_updated "public_key[#{repo_path}/blah.pub2]", :create
143
+ IO.read("#{repo_path}/blah.pub").should start_with('ssh-rsa ')
144
+ "#{repo_path}/blah.pub".should be_public_key_for "#{repo_path}/blah"
145
+ end
146
+ end
147
+
148
+ context 'and another public_key in :der format based off the first public_key' do
149
+ with_recipe do
150
+ public_key "#{repo_path}/blah.pub2" do
151
+ source_key_path "#{repo_path}/blah.pub"
152
+ format :pem
153
+ end
154
+ end
155
+
156
+ it 'the second public_key is created' do
157
+ chef_run.should have_updated "public_key[#{repo_path}/blah.pub2]", :create
158
+ IO.read("#{repo_path}/blah.pub").should start_with('ssh-rsa ')
159
+ "#{repo_path}/blah.pub".should be_public_key_for "#{repo_path}/blah"
160
+ end
161
+ end
162
+ end
163
+
164
+ context 'and a public key in pem format' do
165
+ with_recipe do
166
+ public_key "#{repo_path}/blah.pub" do
167
+ source_key_path "#{repo_path}/blah"
168
+ format :pem
169
+ end
170
+ end
171
+
172
+ it 'the public_key is created' do
173
+ chef_run.should have_updated "private_key[#{repo_path}/blah]", :create
174
+ chef_run.should have_updated "public_key[#{repo_path}/blah.pub]", :create
175
+ IO.read("#{repo_path}/blah.pub").should start_with('-----BEGIN')
176
+ "#{repo_path}/blah.pub".should be_public_key_for "#{repo_path}/blah"
177
+ end
178
+ end
179
+
180
+ context 'and a public key in der format' do
181
+ with_recipe do
182
+ public_key "#{repo_path}/blah.pub" do
183
+ source_key_path "#{repo_path}/blah"
184
+ format :der
185
+ end
186
+ end
187
+
188
+ it 'the public_key is created in openssh format' do
189
+ chef_run.should have_updated "private_key[#{repo_path}/blah]", :create
190
+ chef_run.should have_updated "public_key[#{repo_path}/blah.pub]", :create
191
+ IO.read("#{repo_path}/blah.pub").should_not start_with('-----BEGIN')
192
+ IO.read("#{repo_path}/blah.pub").should_not start_with('ssh-rsa')
193
+ "#{repo_path}/blah.pub".should be_public_key_for "#{repo_path}/blah"
194
+ end
195
+ end
196
+ end
197
+
198
+ context 'with a recipe with a private_key in der format' do
199
+ with_recipe do
200
+ private_key "#{repo_path}/blah" do
201
+ format :der
202
+ end
203
+ end
204
+
205
+ it 'the private_key is created' do
206
+ chef_run.should have_updated "private_key[#{repo_path}/blah]", :create
207
+ IO.read("#{repo_path}/blah").should_not start_with('-----BEGIN')
208
+ OpenSSL::PKey.read(IO.read("#{repo_path}/blah")).kind_of?(OpenSSL::PKey::RSA).should be_true
209
+ end
210
+
211
+ context 'and a public_key' do
212
+ with_recipe do
213
+ public_key "#{repo_path}/blah.pub" do
214
+ source_key_path "#{repo_path}/blah"
215
+ end
216
+ end
217
+
218
+ it 'the public_key is created in openssh format' do
219
+ chef_run.should have_updated "private_key[#{repo_path}/blah]", :create
220
+ chef_run.should have_updated "public_key[#{repo_path}/blah.pub]", :create
221
+ IO.read("#{repo_path}/blah.pub").should start_with('ssh-rsa ')
222
+ "#{repo_path}/blah.pub".should be_public_key_for "#{repo_path}/blah"
223
+ end
224
+ end
225
+ end
226
+
227
+ context 'with a recipe with a private_key with a pass_phrase' do
228
+ with_recipe do
229
+ private_key "#{repo_path}/blah" do
230
+ pass_phrase 'hello'
231
+ end
232
+ end
233
+
234
+ it 'the private_key is created' do
235
+ chef_run.should have_updated "private_key[#{repo_path}/blah]", :create
236
+ IO.read("#{repo_path}/blah").should start_with('-----BEGIN')
237
+ OpenSSL::PKey.read(IO.read("#{repo_path}/blah"), 'hello').kind_of?(OpenSSL::PKey::RSA).should be_true
238
+ end
239
+
240
+ context 'and a private_key that copies it in der format' do
241
+ with_recipe do
242
+ private_key "#{repo_path}/blah.der" do
243
+ source_key_path "#{repo_path}/blah"
244
+ source_key_pass_phrase 'hello'
245
+ format :der
246
+ end
247
+ end
248
+
249
+ it 'the private_key is copied in der format and is identical' do
250
+ chef_run.should have_updated "private_key[#{repo_path}/blah.der]", :create
251
+ key_str = IO.read("#{repo_path}/blah.der")
252
+ key_str.should_not start_with('-----BEGIN')
253
+ key_str.should_not start_with('ssh-')
254
+ "#{repo_path}/blah.der".should match_private_key("#{repo_path}/blah", 'hello')
255
+ end
256
+ end
257
+
258
+ it 'a private_key that copies it from in-memory as a string succeeds' do
259
+ run_recipe do
260
+ private_key "#{repo_path}/blah.der" do
261
+ source_key IO.read("#{repo_path}/blah")
262
+ source_key_pass_phrase 'hello'
263
+ format :der
264
+ end
265
+ end
266
+
267
+ chef_run.should have_updated "private_key[#{repo_path}/blah.der]", :create
268
+ key_str = IO.read("#{repo_path}/blah.der")
269
+ key_str.should_not start_with('-----BEGIN')
270
+ key_str.should_not start_with('ssh-')
271
+ "#{repo_path}/blah.der".should match_private_key("#{repo_path}/blah", 'hello')
272
+ end
273
+
274
+ context 'and a public_key' do
275
+ with_recipe do
276
+ public_key "#{repo_path}/blah.pub" do
277
+ source_key_path "#{repo_path}/blah"
278
+ source_key_pass_phrase 'hello'
279
+ end
280
+ end
281
+
282
+ it 'the public_key is created in openssh format' do
283
+ chef_run.should have_updated "private_key[#{repo_path}/blah]", :create
284
+ chef_run.should have_updated "public_key[#{repo_path}/blah.pub]", :create
285
+ IO.read("#{repo_path}/blah.pub").should start_with('ssh-rsa ')
286
+ "#{repo_path}/blah.pub".should be_public_key_for "#{repo_path}/blah", 'hello'
287
+ end
288
+ end
289
+
290
+ context 'and a public_key derived from the private key in an in-memory string' do
291
+ with_recipe do
292
+ public_key "#{repo_path}/blah.pub" do
293
+ source_key IO.read("#{repo_path}/blah")
294
+ source_key_pass_phrase 'hello'
295
+ end
296
+ end
297
+
298
+ it 'the public_key is created in openssh format' do
299
+ chef_run.should have_updated "private_key[#{repo_path}/blah]", :create
300
+ chef_run.should have_updated "public_key[#{repo_path}/blah.pub]", :create
301
+ IO.read("#{repo_path}/blah.pub").should start_with('ssh-rsa ')
302
+ "#{repo_path}/blah.pub".should be_public_key_for "#{repo_path}/blah", 'hello'
303
+ end
304
+ end
305
+ end
306
+
307
+ context 'with a recipe with a private_key and public_key_path' do
308
+ with_recipe do
309
+ private_key "#{repo_path}/blah" do
310
+ public_key_path "#{repo_path}/blah.pub"
311
+ end
312
+ end
313
+
314
+ it 'the private_key and public_key are created' do
315
+ chef_run.should have_updated "private_key[#{repo_path}/blah]", :create
316
+ IO.read("#{repo_path}/blah").should start_with('-----BEGIN')
317
+ OpenSSL::PKey.read(IO.read("#{repo_path}/blah")).kind_of?(OpenSSL::PKey::RSA).should be_true
318
+ IO.read("#{repo_path}/blah.pub").should start_with('ssh-rsa ')
319
+ "#{repo_path}/blah.pub".should be_public_key_for("#{repo_path}/blah")
320
+ end
321
+ end
322
+
323
+ context 'with a recipe with a private_key and public_key_path and public_key_format' do
324
+ with_recipe do
325
+ private_key "#{repo_path}/blah" do
326
+ public_key_path "#{repo_path}/blah.pub.der"
327
+ public_key_format :der
328
+ end
329
+ end
330
+
331
+ it 'the private_key and public_key are created' do
332
+ chef_run.should have_updated "private_key[#{repo_path}/blah]", :create
333
+ IO.read("#{repo_path}/blah").should start_with('-----BEGIN')
334
+ OpenSSL::PKey.read(IO.read("#{repo_path}/blah")).kind_of?(OpenSSL::PKey::RSA).should be_true
335
+ IO.read("#{repo_path}/blah.pub.der").should_not start_with('ssh-rsa ')
336
+ "#{repo_path}/blah.pub.der".should be_public_key_for("#{repo_path}/blah")
337
+ end
338
+ end
339
+
340
+ context 'with a recipe with a private_key with path :none' do
341
+ it 'the private_key is created' do
342
+ got_private_key = nil
343
+ run_recipe do
344
+ private_key 'in_memory' do
345
+ path :none
346
+ after { |resource, private_key| got_private_key = private_key }
347
+ end
348
+ end
349
+
350
+ chef_run.should have_updated "private_key[in_memory]", :create
351
+ got_private_key.kind_of?(OpenSSL::PKey::RSA).should be_true
352
+ end
353
+ end
354
+
355
+ end
356
+