cheffish 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 (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
+