chef 12.4.0 → 12.4.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (133) hide show
  1. checksums.yaml +4 -4
  2. data/lib/chef/api_client.rb +31 -129
  3. data/lib/chef/api_client_v1.rb +325 -0
  4. data/lib/chef/chef_class.rb +15 -7
  5. data/lib/chef/chef_fs/file_system/chef_server_root_dir.rb +2 -2
  6. data/lib/chef/dsl/resources.rb +6 -4
  7. data/lib/chef/exceptions.rb +2 -2
  8. data/lib/chef/guard_interpreter/resource_guard_interpreter.rb +2 -1
  9. data/lib/chef/knife/bootstrap/templates/chef-full.erb +4 -4
  10. data/lib/chef/knife/client_bulk_delete.rb +2 -2
  11. data/lib/chef/knife/client_create.rb +4 -4
  12. data/lib/chef/knife/client_delete.rb +3 -3
  13. data/lib/chef/knife/client_edit.rb +10 -2
  14. data/lib/chef/knife/client_list.rb +2 -2
  15. data/lib/chef/knife/client_reregister.rb +2 -2
  16. data/lib/chef/knife/client_show.rb +2 -2
  17. data/lib/chef/knife/osc_user_create.rb +3 -3
  18. data/lib/chef/knife/osc_user_delete.rb +2 -2
  19. data/lib/chef/knife/osc_user_edit.rb +3 -3
  20. data/lib/chef/knife/osc_user_list.rb +2 -2
  21. data/lib/chef/knife/osc_user_reregister.rb +2 -2
  22. data/lib/chef/knife/osc_user_show.rb +2 -2
  23. data/lib/chef/knife/user_create.rb +3 -3
  24. data/lib/chef/knife/user_delete.rb +4 -4
  25. data/lib/chef/knife/user_edit.rb +3 -3
  26. data/lib/chef/knife/user_list.rb +2 -2
  27. data/lib/chef/knife/user_reregister.rb +2 -2
  28. data/lib/chef/knife/user_show.rb +2 -2
  29. data/lib/chef/node_map.rb +14 -18
  30. data/lib/chef/platform/handler_map.rb +45 -0
  31. data/lib/chef/platform/priority_map.rb +19 -32
  32. data/lib/chef/platform/provider_handler_map.rb +29 -0
  33. data/lib/chef/platform/provider_mapping.rb +3 -2
  34. data/lib/chef/platform/resource_handler_map.rb +29 -0
  35. data/lib/chef/platform/resource_priority_map.rb +0 -6
  36. data/lib/chef/provider.rb +1 -1
  37. data/lib/chef/provider/dsc_resource.rb +2 -2
  38. data/lib/chef/provider/dsc_script.rb +1 -1
  39. data/lib/chef/provider/mount/aix.rb +1 -1
  40. data/lib/chef/provider/package.rb +0 -31
  41. data/lib/chef/provider/package/aix.rb +1 -0
  42. data/lib/chef/provider/package/apt.rb +1 -0
  43. data/lib/chef/provider/package/homebrew.rb +1 -0
  44. data/lib/chef/provider/package/ips.rb +1 -0
  45. data/lib/chef/provider/package/macports.rb +1 -0
  46. data/lib/chef/provider/package/openbsd.rb +1 -0
  47. data/lib/chef/provider/package/pacman.rb +1 -0
  48. data/lib/chef/provider/package/paludis.rb +1 -0
  49. data/lib/chef/provider/package/portage.rb +2 -0
  50. data/lib/chef/provider/package/smartos.rb +1 -0
  51. data/lib/chef/provider/package/solaris.rb +2 -0
  52. data/lib/chef/provider/package/yum.rb +1 -0
  53. data/lib/chef/provider/package/zypper.rb +1 -0
  54. data/lib/chef/provider/service.rb +4 -22
  55. data/lib/chef/provider/service/debian.rb +2 -0
  56. data/lib/chef/provider/service/insserv.rb +2 -0
  57. data/lib/chef/provider/service/invokercd.rb +2 -0
  58. data/lib/chef/provider/service/openbsd.rb +1 -1
  59. data/lib/chef/provider/service/redhat.rb +2 -0
  60. data/lib/chef/provider/service/upstart.rb +3 -0
  61. data/lib/chef/provider_resolver.rb +59 -53
  62. data/lib/chef/resource.rb +22 -73
  63. data/lib/chef/resource/dsc_script.rb +1 -1
  64. data/lib/chef/resource/ips_package.rb +1 -0
  65. data/lib/chef/resource/mount.rb +8 -0
  66. data/lib/chef/resource/openbsd_package.rb +0 -11
  67. data/lib/chef/resource/solaris_package.rb +1 -4
  68. data/lib/chef/resource_resolver.rb +54 -26
  69. data/lib/chef/run_list/versioned_recipe_list.rb +6 -5
  70. data/lib/chef/user.rb +52 -188
  71. data/lib/chef/user_v1.rb +335 -0
  72. data/lib/chef/version.rb +1 -1
  73. data/spec/data/trusted_certs/opscode.pem +53 -56
  74. data/spec/functional/provider/whyrun_safe_ruby_block_spec.rb +1 -1
  75. data/spec/functional/resource/package_spec.rb +0 -2
  76. data/spec/integration/recipes/recipe_dsl_spec.rb +661 -126
  77. data/spec/spec_helper.rb +19 -13
  78. data/spec/support/shared/unit/api_versioning.rb +2 -2
  79. data/spec/unit/api_client_spec.rb +22 -201
  80. data/spec/unit/api_client_v1_spec.rb +457 -0
  81. data/spec/unit/knife/client_bulk_delete_spec.rb +4 -4
  82. data/spec/unit/knife/client_create_spec.rb +1 -1
  83. data/spec/unit/knife/client_delete_spec.rb +3 -3
  84. data/spec/unit/knife/client_edit_spec.rb +14 -1
  85. data/spec/unit/knife/client_list_spec.rb +1 -1
  86. data/spec/unit/knife/client_reregister_spec.rb +2 -2
  87. data/spec/unit/knife/client_show_spec.rb +2 -2
  88. data/spec/unit/knife/osc_user_create_spec.rb +5 -5
  89. data/spec/unit/knife/osc_user_delete_spec.rb +1 -1
  90. data/spec/unit/knife/osc_user_edit_spec.rb +1 -1
  91. data/spec/unit/knife/osc_user_list_spec.rb +1 -1
  92. data/spec/unit/knife/osc_user_reregister_spec.rb +1 -1
  93. data/spec/unit/knife/osc_user_show_spec.rb +1 -1
  94. data/spec/unit/knife/user_create_spec.rb +1 -1
  95. data/spec/unit/knife/user_delete_spec.rb +2 -2
  96. data/spec/unit/knife/user_edit_spec.rb +2 -2
  97. data/spec/unit/knife/user_list_spec.rb +1 -1
  98. data/spec/unit/knife/user_reregister_spec.rb +1 -1
  99. data/spec/unit/knife/user_show_spec.rb +2 -2
  100. data/spec/unit/lwrp_spec.rb +146 -134
  101. data/spec/unit/node_map_spec.rb +12 -0
  102. data/spec/unit/platform_spec.rb +1 -1
  103. data/spec/unit/provider/deploy_spec.rb +1 -1
  104. data/spec/unit/provider/dsc_resource_spec.rb +3 -3
  105. data/spec/unit/provider/dsc_script_spec.rb +2 -2
  106. data/spec/unit/provider_resolver_spec.rb +170 -135
  107. data/spec/unit/recipe_spec.rb +3 -3
  108. data/spec/unit/resource/breakpoint_spec.rb +1 -1
  109. data/spec/unit/resource/cron_spec.rb +1 -1
  110. data/spec/unit/resource/directory_spec.rb +1 -1
  111. data/spec/unit/resource/dsc_resource_spec.rb +1 -1
  112. data/spec/unit/resource/dsc_script_spec.rb +2 -2
  113. data/spec/unit/resource/env_spec.rb +1 -1
  114. data/spec/unit/resource/erl_call_spec.rb +1 -1
  115. data/spec/unit/resource/file_spec.rb +1 -1
  116. data/spec/unit/resource/group_spec.rb +1 -1
  117. data/spec/unit/resource/link_spec.rb +1 -1
  118. data/spec/unit/resource/mdadm_spec.rb +1 -1
  119. data/spec/unit/resource/mount_spec.rb +1 -1
  120. data/spec/unit/resource/ohai_spec.rb +1 -1
  121. data/spec/unit/resource/registry_key_spec.rb +1 -1
  122. data/spec/unit/resource/route_spec.rb +1 -1
  123. data/spec/unit/resource/ruby_block_spec.rb +3 -3
  124. data/spec/unit/resource/user_spec.rb +1 -1
  125. data/spec/unit/resource/windows_service_spec.rb +1 -1
  126. data/spec/unit/resource_resolver_spec.rb +8 -4
  127. data/spec/unit/resource_spec.rb +89 -3
  128. data/spec/unit/run_list/versioned_recipe_list_spec.rb +115 -48
  129. data/spec/unit/user_spec.rb +97 -405
  130. data/spec/unit/user_v1_spec.rb +584 -0
  131. metadata +11 -6
  132. data/lib/chef/osc_user.rb +0 -194
  133. data/spec/unit/osc_user_spec.rb +0 -276
@@ -87,12 +87,14 @@ Dir["spec/support/**/*.rb"].
87
87
  OHAI_SYSTEM = Ohai::System.new
88
88
  OHAI_SYSTEM.all_plugins("platform")
89
89
 
90
- TEST_PLATFORM =
91
- (OHAI_SYSTEM['platform'] ||
92
- 'unknown_test_platform').dup.freeze
93
- TEST_PLATFORM_VERSION =
94
- (OHAI_SYSTEM['platform_version'] ||
95
- 'unknown_platform_version').dup.freeze
90
+ test_node = Chef::Node.new
91
+ test_node.automatic['os'] = (OHAI_SYSTEM['os'] || 'unknown_os').dup.freeze
92
+ test_node.automatic['platform_family'] = (OHAI_SYSTEM['platform_family'] || 'unknown_platform_family').dup.freeze
93
+ test_node.automatic['platform'] = (OHAI_SYSTEM['platform'] || 'unknown_platform').dup.freeze
94
+ test_node.automatic['platform_version'] = (OHAI_SYSTEM['platform_version'] || 'unknown_platform_version').dup.freeze
95
+ TEST_NODE = test_node.freeze
96
+ TEST_PLATFORM = TEST_NODE['platform']
97
+ TEST_PLATFORM_VERSION = TEST_NODE['platform_version']
96
98
 
97
99
  RSpec.configure do |config|
98
100
  config.include(Matchers)
@@ -162,13 +164,17 @@ RSpec.configure do |config|
162
164
  config.filter_run_excluding :provider => lambda {|criteria|
163
165
  type, target_provider = criteria.first
164
166
 
165
- platform = TEST_PLATFORM.dup
166
- platform_version = TEST_PLATFORM_VERSION.dup
167
-
168
- begin
169
- provider_for_running_platform = Chef::Platform.find_provider(platform, platform_version, type)
170
- provider_for_running_platform != target_provider
171
- rescue ArgumentError # no provider for platform
167
+ node = TEST_NODE.dup
168
+ resource_class = Chef::ResourceResolver.resolve(type, node: node)
169
+ if resource_class
170
+ resource = resource_class.new('test', Chef::RunContext.new(node, nil, nil))
171
+ begin
172
+ provider = resource.provider_for_action(Array(resource_class.default_action).first)
173
+ provider.class != target_provider
174
+ rescue Chef::Exceptions::ProviderNotFound # no provider for platform
175
+ true
176
+ end
177
+ else
172
178
  true
173
179
  end
174
180
  }
@@ -26,7 +26,7 @@ shared_examples_for "version handling" do
26
26
  allow(rest_v1).to receive(http_verb).and_raise(exception_406)
27
27
  end
28
28
 
29
- context "when the server does not support the min or max server API version that Chef::User supports" do
29
+ context "when the server does not support the min or max server API version that Chef::UserV1 supports" do
30
30
  before do
31
31
  allow(object).to receive(:server_client_api_version_intersection).and_return([])
32
32
  end
@@ -34,7 +34,7 @@ shared_examples_for "version handling" do
34
34
  it "raises the original exception" do
35
35
  expect{ object.send(method) }.to raise_error(exception_406)
36
36
  end
37
- end # when the server does not support the min or max server API version that Chef::User supports
37
+ end # when the server does not support the min or max server API version that Chef::UserV1 supports
38
38
  end # version handling
39
39
 
40
40
  shared_examples_for "user and client reregister" do
@@ -21,6 +21,11 @@ require 'spec_helper'
21
21
  require 'chef/api_client'
22
22
  require 'tempfile'
23
23
 
24
+ # DEPRECATION NOTE
25
+ #
26
+ # This code will be removed in Chef 13 in favor of the code in Chef::ApiClientV1,
27
+ # which will be moved to this namespace. New development should occur in
28
+ # Chef::ApiClientV1 until the time before Chef 13.
24
29
  describe Chef::ApiClient do
25
30
  before(:each) do
26
31
  @client = Chef::ApiClient.new
@@ -53,20 +58,6 @@ describe Chef::ApiClient do
53
58
  expect { @client.admin(Hash.new) }.to raise_error(ArgumentError)
54
59
  end
55
60
 
56
- it "has an create_key flag attribute" do
57
- @client.create_key(true)
58
- expect(@client.create_key).to be_truthy
59
- end
60
-
61
- it "create_key defaults to false" do
62
- expect(@client.create_key).to be_falsey
63
- end
64
-
65
- it "allows only boolean values for the create_key flag" do
66
- expect { @client.create_key(false) }.not_to raise_error
67
- expect { @client.create_key(Hash.new) }.to raise_error(ArgumentError)
68
- end
69
-
70
61
  it "has a 'validator' flag attribute" do
71
62
  @client.validator(true)
72
63
  expect(@client.validator).to be_truthy
@@ -129,12 +120,6 @@ describe Chef::ApiClient do
129
120
  expect(@json).to include(%q{"validator":false})
130
121
  end
131
122
 
132
- it "includes the 'create_key' flag when present" do
133
- @client.create_key(true)
134
- @json = @client.to_json
135
- expect(@json).to include(%q{"create_key":true})
136
- end
137
-
138
123
  it "includes the private key when present" do
139
124
  @client.private_key("monkeypants")
140
125
  expect(@client.to_json).to include(%q{"private_key":"monkeypants"})
@@ -143,15 +128,11 @@ describe Chef::ApiClient do
143
128
  it "does not include the private key if not present" do
144
129
  expect(@json).not_to include("private_key")
145
130
  end
146
-
147
- include_examples "to_json equivalent to Chef::JSONCompat.to_json" do
148
- let(:jsonable) { @client }
149
- end
150
131
  end
151
132
 
152
133
  describe "when deserializing from JSON (string) using ApiClient#from_json" do
153
134
  let(:client_string) do
154
- "{\"name\":\"black\",\"public_key\":\"crowes\",\"private_key\":\"monkeypants\",\"admin\":true,\"validator\":true,\"create_key\":true}"
135
+ "{\"name\":\"black\",\"public_key\":\"crowes\",\"private_key\":\"monkeypants\",\"admin\":true,\"validator\":true}"
155
136
  end
156
137
 
157
138
  let(:client) do
@@ -178,10 +159,6 @@ describe Chef::ApiClient do
178
159
  expect(client.admin).to be_truthy
179
160
  end
180
161
 
181
- it "preserves the create_key status" do
182
- expect(client.create_key).to be_truthy
183
- end
184
-
185
162
  it "preserves the 'validator' status" do
186
163
  expect(client.validator).to be_truthy
187
164
  end
@@ -199,7 +176,6 @@ describe Chef::ApiClient do
199
176
  "private_key" => "monkeypants",
200
177
  "admin" => true,
201
178
  "validator" => true,
202
- "create_key" => true,
203
179
  "json_class" => "Chef::ApiClient"
204
180
  }
205
181
  end
@@ -224,10 +200,6 @@ describe Chef::ApiClient do
224
200
  expect(client.admin).to be_truthy
225
201
  end
226
202
 
227
- it "preserves the create_key status" do
228
- expect(client.create_key).to be_truthy
229
- end
230
-
231
203
  it "preserves the 'validator' status" do
232
204
  expect(client.validator).to be_truthy
233
205
  end
@@ -243,18 +215,16 @@ describe Chef::ApiClient do
243
215
 
244
216
  before(:each) do
245
217
  client = {
246
- "name" => "black",
247
- "clientname" => "black",
248
- "public_key" => "crowes",
249
- "private_key" => "monkeypants",
250
- "admin" => true,
251
- "create_key" => true,
252
- "validator" => true,
253
- "json_class" => "Chef::ApiClient"
218
+ "name" => "black",
219
+ "clientname" => "black",
220
+ "public_key" => "crowes",
221
+ "private_key" => "monkeypants",
222
+ "admin" => true,
223
+ "validator" => true,
224
+ "json_class" => "Chef::ApiClient"
254
225
  }
255
-
256
- @http_client = double("Chef::REST mock")
257
- allow(Chef::REST).to receive(:new).and_return(@http_client)
226
+ @http_client = double("Chef::ServerAPI mock")
227
+ allow(Chef::ServerAPI).to receive(:new).and_return(@http_client)
258
228
  expect(@http_client).to receive(:get).with("clients/black").and_return(client)
259
229
  @client = Chef::ApiClient.load(client['name'])
260
230
  end
@@ -275,10 +245,6 @@ describe Chef::ApiClient do
275
245
  expect(@client.admin).to be_a_kind_of(TrueClass)
276
246
  end
277
247
 
278
- it "preserves the create_key status" do
279
- expect(@client.create_key).to be_a_kind_of(TrueClass)
280
- end
281
-
282
248
  it "preserves the 'validator' status" do
283
249
  expect(@client.validator).to be_a_kind_of(TrueClass)
284
250
  end
@@ -304,18 +270,13 @@ describe Chef::ApiClient do
304
270
  File.open(Chef::Config[:client_key], "r") {|f| f.read.chomp }
305
271
  end
306
272
 
307
- it "has an HTTP client configured with default credentials" do
308
- expect(@client.http_api).to be_a_kind_of(Chef::REST)
309
- expect(@client.http_api.client_name).to eq("silent-bob")
310
- expect(@client.http_api.signing_key.to_s).to eq(private_key_data)
311
- end
312
273
  end
313
274
 
314
275
 
315
276
  describe "when requesting a new key" do
316
277
  before do
317
278
  @http_client = double("Chef::REST mock")
318
- allow(Chef::REST).to receive(:new).and_return(@http_client)
279
+ allow(Chef::ServerAPI).to receive(:new).and_return(@http_client)
319
280
  end
320
281
 
321
282
  context "and the client does not exist on the server" do
@@ -332,34 +293,24 @@ describe Chef::ApiClient do
332
293
  end
333
294
 
334
295
  context "and the client exists" do
335
- let(:chef_rest_v0_mock) { double('chef rest root v0 object') }
336
- let(:payload) {
337
- {:name => "lost-my-key", :admin => false, :validator => false, :private_key => true}
338
- }
339
-
340
296
  before do
341
297
  @api_client_without_key = Chef::ApiClient.new
342
298
  @api_client_without_key.name("lost-my-key")
343
- allow(@api_client_without_key).to receive(:chef_rest_v0).and_return(chef_rest_v0_mock)
344
- #allow(@api_client_with_key).to receive(:http_api).and_return(_api_mock)
345
-
346
- allow(chef_rest_v0_mock).to receive(:put).with("clients/lost-my-key", payload).and_return(@api_client_with_key)
347
- allow(chef_rest_v0_mock).to receive(:get).with("clients/lost-my-key").and_return(@api_client_without_key)
348
- allow(@http_client).to receive(:get).with("clients/lost-my-key").and_return(@api_client_without_key)
299
+ expect(@http_client).to receive(:get).with("clients/lost-my-key").and_return(@api_client_without_key)
349
300
  end
350
301
 
302
+
351
303
  context "and the client exists on a Chef 11-like server" do
352
304
  before do
353
305
  @api_client_with_key = Chef::ApiClient.new
354
306
  @api_client_with_key.name("lost-my-key")
355
307
  @api_client_with_key.private_key("the new private key")
356
- allow(@api_client_with_key).to receive(:chef_rest_v0).and_return(chef_rest_v0_mock)
308
+ expect(@http_client).to receive(:put).
309
+ with("clients/lost-my-key", :name => "lost-my-key", :admin => false, :validator => false, :private_key => true).
310
+ and_return(@api_client_with_key)
357
311
  end
358
312
 
359
313
  it "returns an ApiClient with a private key" do
360
- expect(chef_rest_v0_mock).to receive(:put).with("clients/lost-my-key", payload).
361
- and_return(@api_client_with_key)
362
-
363
314
  response = Chef::ApiClient.reregister("lost-my-key")
364
315
  # no sane == method for ApiClient :'(
365
316
  expect(response).to eq(@api_client_without_key)
@@ -372,7 +323,7 @@ describe Chef::ApiClient do
372
323
  context "and the client exists on a Chef 10-like server" do
373
324
  before do
374
325
  @api_client_with_key = {"name" => "lost-my-key", "private_key" => "the new private key"}
375
- expect(chef_rest_v0_mock).to receive(:put).
326
+ expect(@http_client).to receive(:put).
376
327
  with("clients/lost-my-key", :name => "lost-my-key", :admin => false, :validator => false, :private_key => true).
377
328
  and_return(@api_client_with_key)
378
329
  end
@@ -390,134 +341,4 @@ describe Chef::ApiClient do
390
341
 
391
342
  end
392
343
  end
393
-
394
- describe "Versioned API Interactions" do
395
- let(:response_406) { OpenStruct.new(:code => '406') }
396
- let(:exception_406) { Net::HTTPServerException.new("406 Not Acceptable", response_406) }
397
- let(:payload) {
398
- {
399
- :name => "some_name",
400
- :validator => true,
401
- :admin => true
402
- }
403
- }
404
-
405
- before do
406
- @client = Chef::ApiClient.new
407
- allow(@client).to receive(:chef_rest_v0).and_return(double('chef rest root v0 object'))
408
- allow(@client).to receive(:chef_rest_v1).and_return(double('chef rest root v1 object'))
409
- @client.name "some_name"
410
- @client.validator true
411
- @client.admin true
412
- end
413
-
414
- describe "create" do
415
-
416
- # from spec/support/shared/unit/user_and_client_shared.rb
417
- it_should_behave_like "user or client create" do
418
- let(:object) { @client }
419
- let(:error) { Chef::Exceptions::InvalidClientAttribute }
420
- let(:rest_v0) { @client.chef_rest_v0 }
421
- let(:rest_v1) { @client.chef_rest_v1 }
422
- let(:url) { "clients" }
423
- end
424
-
425
- context "when API V1 is not supported by the server" do
426
- # from spec/support/shared/unit/api_versioning.rb
427
- it_should_behave_like "version handling" do
428
- let(:object) { @client }
429
- let(:method) { :create }
430
- let(:http_verb) { :post }
431
- let(:rest_v1) { @client.chef_rest_v1 }
432
- end
433
- end
434
-
435
- end # create
436
-
437
- describe "update" do
438
- context "when a valid client is defined" do
439
-
440
- shared_examples_for "client updating" do
441
- it "updates the client" do
442
- expect(rest). to receive(:put).with("clients/some_name", payload)
443
- @client.update
444
- end
445
-
446
- context "when only the name field exists" do
447
-
448
- before do
449
- # needed since there is no way to set to nil via code
450
- @client.instance_variable_set(:@validator, nil)
451
- @client.instance_variable_set(:@admin, nil)
452
- end
453
-
454
- after do
455
- @client.validator true
456
- @client.admin true
457
- end
458
-
459
- it "updates the client with only the name" do
460
- expect(rest). to receive(:put).with("clients/some_name", {:name => "some_name"})
461
- @client.update
462
- end
463
- end
464
-
465
- end
466
-
467
- context "when API V1 is supported by the server" do
468
-
469
- it_should_behave_like "client updating" do
470
- let(:rest) { @client.chef_rest_v1 }
471
- end
472
-
473
- end # when API V1 is supported by the server
474
-
475
- context "when API V1 is not supported by the server" do
476
- context "when no version is supported" do
477
- # from spec/support/shared/unit/api_versioning.rb
478
- it_should_behave_like "version handling" do
479
- let(:object) { @client }
480
- let(:method) { :create }
481
- let(:http_verb) { :post }
482
- let(:rest_v1) { @client.chef_rest_v1 }
483
- end
484
- end # when no version is supported
485
-
486
- context "when API V0 is supported" do
487
-
488
- before do
489
- allow(@client.chef_rest_v1).to receive(:put).and_raise(exception_406)
490
- allow(@client).to receive(:server_client_api_version_intersection).and_return([0])
491
- end
492
-
493
- it_should_behave_like "client updating" do
494
- let(:rest) { @client.chef_rest_v0 }
495
- end
496
-
497
- end
498
-
499
- end # when API V1 is not supported by the server
500
- end # when a valid client is defined
501
- end # update
502
-
503
- # DEPRECATION
504
- # This can be removed after API V0 support is gone
505
- describe "reregister" do
506
- context "when server API V0 is valid on the Chef Server receiving the request" do
507
- it "creates a new object via the API" do
508
- expect(@client.chef_rest_v0).to receive(:put).with("clients/#{@client.name}", payload.merge({:private_key => true})).and_return({})
509
- @client.reregister
510
- end
511
- end # when server API V0 is valid on the Chef Server receiving the request
512
-
513
- context "when server API V0 is not supported by the Chef Server" do
514
- # from spec/support/shared/unit/api_versioning.rb
515
- it_should_behave_like "user and client reregister" do
516
- let(:object) { @client }
517
- let(:rest_v0) { @client.chef_rest_v0 }
518
- end
519
- end # when server API V0 is not supported by the Chef Server
520
- end # reregister
521
-
522
- end
523
344
  end
@@ -0,0 +1,457 @@
1
+ #
2
+ # Author:: Adam Jacob (<adam@opscode.com>)
3
+ # Copyright:: Copyright (c) 2008 Opscode, Inc.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ require 'spec_helper'
20
+
21
+ require 'chef/api_client_v1'
22
+ require 'tempfile'
23
+
24
+ describe Chef::ApiClientV1 do
25
+ before(:each) do
26
+ @client = Chef::ApiClientV1.new
27
+ end
28
+
29
+ it "has a name attribute" do
30
+ @client.name("ops_master")
31
+ expect(@client.name).to eq("ops_master")
32
+ end
33
+
34
+ it "does not allow spaces in the name" do
35
+ expect { @client.name "ops master" }.to raise_error(ArgumentError)
36
+ end
37
+
38
+ it "only allows string values for the name" do
39
+ expect { @client.name Hash.new }.to raise_error(ArgumentError)
40
+ end
41
+
42
+ it "has an admin flag attribute" do
43
+ @client.admin(true)
44
+ expect(@client.admin).to be_truthy
45
+ end
46
+
47
+ it "defaults to non-admin" do
48
+ expect(@client.admin).to be_falsey
49
+ end
50
+
51
+ it "allows only boolean values for the admin flag" do
52
+ expect { @client.admin(false) }.not_to raise_error
53
+ expect { @client.admin(Hash.new) }.to raise_error(ArgumentError)
54
+ end
55
+
56
+ it "has an create_key flag attribute" do
57
+ @client.create_key(true)
58
+ expect(@client.create_key).to be_truthy
59
+ end
60
+
61
+ it "create_key defaults to false" do
62
+ expect(@client.create_key).to be_falsey
63
+ end
64
+
65
+ it "allows only boolean values for the create_key flag" do
66
+ expect { @client.create_key(false) }.not_to raise_error
67
+ expect { @client.create_key(Hash.new) }.to raise_error(ArgumentError)
68
+ end
69
+
70
+ it "has a 'validator' flag attribute" do
71
+ @client.validator(true)
72
+ expect(@client.validator).to be_truthy
73
+ end
74
+
75
+ it "defaults to non-validator" do
76
+ expect(@client.validator).to be_falsey
77
+ end
78
+
79
+ it "allows only boolean values for the 'validator' flag" do
80
+ expect { @client.validator(false) }.not_to raise_error
81
+ expect { @client.validator(Hash.new) }.to raise_error(ArgumentError)
82
+ end
83
+
84
+ it "has a public key attribute" do
85
+ @client.public_key("super public")
86
+ expect(@client.public_key).to eq("super public")
87
+ end
88
+
89
+ it "accepts only String values for the public key" do
90
+ expect { @client.public_key "" }.not_to raise_error
91
+ expect { @client.public_key Hash.new }.to raise_error(ArgumentError)
92
+ end
93
+
94
+
95
+ it "has a private key attribute" do
96
+ @client.private_key("super private")
97
+ expect(@client.private_key).to eq("super private")
98
+ end
99
+
100
+ it "accepts only String values for the private key" do
101
+ expect { @client.private_key "" }.not_to raise_error
102
+ expect { @client.private_key Hash.new }.to raise_error(ArgumentError)
103
+ end
104
+
105
+ describe "when serializing to JSON" do
106
+ before(:each) do
107
+ @client.name("black")
108
+ @client.public_key("crowes")
109
+ @json = @client.to_json
110
+ end
111
+
112
+ it "serializes as a JSON object" do
113
+ expect(@json).to match(/^\{.+\}$/)
114
+ end
115
+
116
+ it "includes the name value" do
117
+ expect(@json).to include(%q{"name":"black"})
118
+ end
119
+
120
+ it "includes the public key value" do
121
+ expect(@json).to include(%{"public_key":"crowes"})
122
+ end
123
+
124
+ it "includes the 'admin' flag" do
125
+ expect(@json).to include(%q{"admin":false})
126
+ end
127
+
128
+ it "includes the 'validator' flag" do
129
+ expect(@json).to include(%q{"validator":false})
130
+ end
131
+
132
+ it "includes the 'create_key' flag when present" do
133
+ @client.create_key(true)
134
+ @json = @client.to_json
135
+ expect(@json).to include(%q{"create_key":true})
136
+ end
137
+
138
+ it "includes the private key when present" do
139
+ @client.private_key("monkeypants")
140
+ expect(@client.to_json).to include(%q{"private_key":"monkeypants"})
141
+ end
142
+
143
+ it "does not include the private key if not present" do
144
+ expect(@json).not_to include("private_key")
145
+ end
146
+
147
+ include_examples "to_json equivalent to Chef::JSONCompat.to_json" do
148
+ let(:jsonable) { @client }
149
+ end
150
+ end
151
+
152
+ describe "when deserializing from JSON (string) using ApiClient#from_json" do
153
+ let(:client_string) do
154
+ "{\"name\":\"black\",\"public_key\":\"crowes\",\"private_key\":\"monkeypants\",\"admin\":true,\"validator\":true,\"create_key\":true}"
155
+ end
156
+
157
+ let(:client) do
158
+ Chef::ApiClientV1.from_json(client_string)
159
+ end
160
+
161
+ it "does not require a 'json_class' string" do
162
+ expect(Chef::JSONCompat.parse(client_string)["json_class"]).to eq(nil)
163
+ end
164
+
165
+ it "should deserialize to a Chef::ApiClientV1 object" do
166
+ expect(client).to be_a_kind_of(Chef::ApiClientV1)
167
+ end
168
+
169
+ it "preserves the name" do
170
+ expect(client.name).to eq("black")
171
+ end
172
+
173
+ it "preserves the public key" do
174
+ expect(client.public_key).to eq("crowes")
175
+ end
176
+
177
+ it "preserves the admin status" do
178
+ expect(client.admin).to be_truthy
179
+ end
180
+
181
+ it "preserves the create_key status" do
182
+ expect(client.create_key).to be_truthy
183
+ end
184
+
185
+ it "preserves the 'validator' status" do
186
+ expect(client.validator).to be_truthy
187
+ end
188
+
189
+ it "includes the private key if present" do
190
+ expect(client.private_key).to eq("monkeypants")
191
+ end
192
+ end
193
+
194
+ describe "when deserializing from JSON (hash) using ApiClientV1#from_json" do
195
+ let(:client_hash) do
196
+ {
197
+ "name" => "black",
198
+ "public_key" => "crowes",
199
+ "private_key" => "monkeypants",
200
+ "admin" => true,
201
+ "validator" => true,
202
+ "create_key" => true
203
+ }
204
+ end
205
+
206
+ let(:client) do
207
+ Chef::ApiClientV1.from_json(Chef::JSONCompat.to_json(client_hash))
208
+ end
209
+
210
+ it "should deserialize to a Chef::ApiClientV1 object" do
211
+ expect(client).to be_a_kind_of(Chef::ApiClientV1)
212
+ end
213
+
214
+ it "preserves the name" do
215
+ expect(client.name).to eq("black")
216
+ end
217
+
218
+ it "preserves the public key" do
219
+ expect(client.public_key).to eq("crowes")
220
+ end
221
+
222
+ it "preserves the admin status" do
223
+ expect(client.admin).to be_truthy
224
+ end
225
+
226
+ it "preserves the create_key status" do
227
+ expect(client.create_key).to be_truthy
228
+ end
229
+
230
+ it "preserves the 'validator' status" do
231
+ expect(client.validator).to be_truthy
232
+ end
233
+
234
+ it "includes the private key if present" do
235
+ expect(client.private_key).to eq("monkeypants")
236
+ end
237
+ end
238
+
239
+ describe "when loading from JSON" do
240
+ before do
241
+ end
242
+
243
+ before(:each) do
244
+ client = {
245
+ "name" => "black",
246
+ "clientname" => "black",
247
+ "public_key" => "crowes",
248
+ "private_key" => "monkeypants",
249
+ "admin" => true,
250
+ "create_key" => true,
251
+ "validator" => true
252
+ }
253
+
254
+ @http_client = double("Chef::ServerAPI mock")
255
+ allow(Chef::ServerAPI).to receive(:new).and_return(@http_client)
256
+ expect(@http_client).to receive(:get).with("clients/black").and_return(client)
257
+ @client = Chef::ApiClientV1.load(client['name'])
258
+ end
259
+
260
+ it "should deserialize to a Chef::ApiClientV1 object" do
261
+ expect(@client).to be_a_kind_of(Chef::ApiClientV1)
262
+ end
263
+
264
+ it "preserves the name" do
265
+ expect(@client.name).to eq("black")
266
+ end
267
+
268
+ it "preserves the public key" do
269
+ expect(@client.public_key).to eq("crowes")
270
+ end
271
+
272
+ it "preserves the admin status" do
273
+ expect(@client.admin).to be_a_kind_of(TrueClass)
274
+ end
275
+
276
+ it "preserves the create_key status" do
277
+ expect(@client.create_key).to be_a_kind_of(TrueClass)
278
+ end
279
+
280
+ it "preserves the 'validator' status" do
281
+ expect(@client.validator).to be_a_kind_of(TrueClass)
282
+ end
283
+
284
+ it "includes the private key if present" do
285
+ expect(@client.private_key).to eq("monkeypants")
286
+ end
287
+
288
+ end
289
+
290
+ describe "with correctly configured API credentials" do
291
+ before do
292
+ Chef::Config[:node_name] = "silent-bob"
293
+ Chef::Config[:client_key] = File.expand_path('ssl/private_key.pem', CHEF_SPEC_DATA)
294
+ end
295
+
296
+ after do
297
+ Chef::Config[:node_name] = nil
298
+ Chef::Config[:client_key] = nil
299
+ end
300
+
301
+ let :private_key_data do
302
+ File.open(Chef::Config[:client_key], "r") {|f| f.read.chomp }
303
+ end
304
+
305
+ end
306
+
307
+
308
+ describe "when requesting a new key" do
309
+ before do
310
+ @http_client = double("Chef::ServerAPI mock")
311
+ allow(Chef::ServerAPI).to receive(:new).and_return(@http_client)
312
+ end
313
+
314
+ context "and the client does not exist on the server" do
315
+ before do
316
+ @a_404_response = Net::HTTPNotFound.new("404 not found and such", nil, nil)
317
+ @a_404_exception = Net::HTTPServerException.new("404 not found exception", @a_404_response)
318
+
319
+ expect(@http_client).to receive(:get).with("clients/lost-my-key").and_raise(@a_404_exception)
320
+ end
321
+
322
+ it "raises a 404 error" do
323
+ expect { Chef::ApiClientV1.reregister("lost-my-key") }.to raise_error(Net::HTTPServerException)
324
+ end
325
+ end
326
+ end
327
+
328
+ describe "Versioned API Interactions" do
329
+ let(:response_406) { OpenStruct.new(:code => '406') }
330
+ let(:exception_406) { Net::HTTPServerException.new("406 Not Acceptable", response_406) }
331
+ let(:payload) {
332
+ {
333
+ :name => "some_name",
334
+ :validator => true,
335
+ :admin => true
336
+ }
337
+ }
338
+
339
+ before do
340
+ @client = Chef::ApiClientV1.new
341
+ allow(@client).to receive(:chef_rest_v0).and_return(double('chef rest root v0 object'))
342
+ allow(@client).to receive(:chef_rest_v1).and_return(double('chef rest root v1 object'))
343
+ @client.name "some_name"
344
+ @client.validator true
345
+ @client.admin true
346
+ end
347
+
348
+ describe "create" do
349
+
350
+ # from spec/support/shared/unit/user_and_client_shared.rb
351
+ it_should_behave_like "user or client create" do
352
+ let(:object) { @client }
353
+ let(:error) { Chef::Exceptions::InvalidClientAttribute }
354
+ let(:rest_v0) { @client.chef_rest_v0 }
355
+ let(:rest_v1) { @client.chef_rest_v1 }
356
+ let(:url) { "clients" }
357
+ end
358
+
359
+ context "when API V1 is not supported by the server" do
360
+ # from spec/support/shared/unit/api_versioning.rb
361
+ it_should_behave_like "version handling" do
362
+ let(:object) { @client }
363
+ let(:method) { :create }
364
+ let(:http_verb) { :post }
365
+ let(:rest_v1) { @client.chef_rest_v1 }
366
+ end
367
+ end
368
+
369
+ end # create
370
+
371
+ describe "update" do
372
+ context "when a valid client is defined" do
373
+
374
+ shared_examples_for "client updating" do
375
+ it "updates the client" do
376
+ expect(rest). to receive(:put).with("clients/some_name", payload).and_return(payload)
377
+ @client.update
378
+ end
379
+
380
+ context "when only the name field exists" do
381
+
382
+ before do
383
+ # needed since there is no way to set to nil via code
384
+ @client.instance_variable_set(:@validator, nil)
385
+ @client.instance_variable_set(:@admin, nil)
386
+ end
387
+
388
+ after do
389
+ @client.validator true
390
+ @client.admin true
391
+ end
392
+
393
+ it "updates the client with only the name" do
394
+ expect(rest). to receive(:put).with("clients/some_name", {:name => "some_name"}).and_return({:name => "some_name"})
395
+ @client.update
396
+ end
397
+ end
398
+
399
+ end
400
+
401
+ context "when API V1 is supported by the server" do
402
+
403
+ it_should_behave_like "client updating" do
404
+ let(:rest) { @client.chef_rest_v1 }
405
+ end
406
+
407
+ end # when API V1 is supported by the server
408
+
409
+ context "when API V1 is not supported by the server" do
410
+ context "when no version is supported" do
411
+ # from spec/support/shared/unit/api_versioning.rb
412
+ it_should_behave_like "version handling" do
413
+ let(:object) { @client }
414
+ let(:method) { :create }
415
+ let(:http_verb) { :post }
416
+ let(:rest_v1) { @client.chef_rest_v1 }
417
+ end
418
+ end # when no version is supported
419
+
420
+ context "when API V0 is supported" do
421
+
422
+ before do
423
+ allow(@client.chef_rest_v1).to receive(:put).and_raise(exception_406)
424
+ allow(@client).to receive(:server_client_api_version_intersection).and_return([0])
425
+ end
426
+
427
+ it_should_behave_like "client updating" do
428
+ let(:rest) { @client.chef_rest_v0 }
429
+ end
430
+
431
+ end
432
+
433
+ end # when API V1 is not supported by the server
434
+ end # when a valid client is defined
435
+ end # update
436
+
437
+ # DEPRECATION
438
+ # This can be removed after API V0 support is gone
439
+ describe "reregister" do
440
+ context "when server API V0 is valid on the Chef Server receiving the request" do
441
+ it "creates a new object via the API" do
442
+ expect(@client.chef_rest_v0).to receive(:put).with("clients/#{@client.name}", payload.merge({:private_key => true})).and_return({})
443
+ @client.reregister
444
+ end
445
+ end # when server API V0 is valid on the Chef Server receiving the request
446
+
447
+ context "when server API V0 is not supported by the Chef Server" do
448
+ # from spec/support/shared/unit/api_versioning.rb
449
+ it_should_behave_like "user and client reregister" do
450
+ let(:object) { @client }
451
+ let(:rest_v0) { @client.chef_rest_v0 }
452
+ end
453
+ end # when server API V0 is not supported by the Chef Server
454
+ end # reregister
455
+
456
+ end
457
+ end