cheffish 1.5.0 → 1.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +10 -0
  3. data/LICENSE +201 -201
  4. data/README.md +120 -120
  5. data/Rakefile +23 -23
  6. data/cheffish.gemspec +26 -0
  7. data/lib/chef/provider/chef_acl.rb +446 -439
  8. data/lib/chef/provider/chef_client.rb +53 -53
  9. data/lib/chef/provider/chef_container.rb +55 -55
  10. data/lib/chef/provider/chef_data_bag.rb +55 -55
  11. data/lib/chef/provider/chef_data_bag_item.rb +278 -278
  12. data/lib/chef/provider/chef_environment.rb +83 -83
  13. data/lib/chef/provider/chef_group.rb +83 -83
  14. data/lib/chef/provider/chef_mirror.rb +169 -169
  15. data/lib/chef/provider/chef_node.rb +87 -87
  16. data/lib/chef/provider/chef_organization.rb +155 -155
  17. data/lib/chef/provider/chef_resolved_cookbooks.rb +46 -46
  18. data/lib/chef/provider/chef_role.rb +84 -84
  19. data/lib/chef/provider/chef_user.rb +59 -59
  20. data/lib/chef/provider/private_key.rb +225 -225
  21. data/lib/chef/provider/public_key.rb +88 -88
  22. data/lib/chef/resource/chef_acl.rb +69 -69
  23. data/lib/chef/resource/chef_client.rb +48 -48
  24. data/lib/chef/resource/chef_container.rb +22 -22
  25. data/lib/chef/resource/chef_data_bag.rb +22 -22
  26. data/lib/chef/resource/chef_data_bag_item.rb +121 -121
  27. data/lib/chef/resource/chef_environment.rb +77 -77
  28. data/lib/chef/resource/chef_group.rb +53 -53
  29. data/lib/chef/resource/chef_mirror.rb +52 -52
  30. data/lib/chef/resource/chef_node.rb +22 -22
  31. data/lib/chef/resource/chef_organization.rb +69 -69
  32. data/lib/chef/resource/chef_resolved_cookbooks.rb +35 -35
  33. data/lib/chef/resource/chef_role.rb +110 -110
  34. data/lib/chef/resource/chef_user.rb +56 -56
  35. data/lib/chef/resource/private_key.rb +48 -48
  36. data/lib/chef/resource/public_key.rb +25 -25
  37. data/lib/cheffish.rb +235 -235
  38. data/lib/cheffish/actor_provider_base.rb +131 -131
  39. data/lib/cheffish/basic_chef_client.rb +184 -184
  40. data/lib/cheffish/chef_provider_base.rb +246 -246
  41. data/lib/cheffish/chef_run.rb +162 -162
  42. data/lib/cheffish/chef_run_data.rb +19 -19
  43. data/lib/cheffish/chef_run_listener.rb +30 -30
  44. data/lib/cheffish/key_formatter.rb +113 -113
  45. data/lib/cheffish/merged_config.rb +98 -94
  46. data/lib/cheffish/recipe_dsl.rb +157 -157
  47. data/lib/cheffish/rspec.rb +8 -8
  48. data/lib/cheffish/rspec/chef_run_support.rb +83 -83
  49. data/lib/cheffish/rspec/matchers.rb +4 -4
  50. data/lib/cheffish/rspec/matchers/be_idempotent.rb +16 -16
  51. data/lib/cheffish/rspec/matchers/emit_no_warnings_or_errors.rb +15 -15
  52. data/lib/cheffish/rspec/matchers/have_updated.rb +37 -37
  53. data/lib/cheffish/rspec/matchers/partially_match.rb +63 -63
  54. data/lib/cheffish/rspec/recipe_run_wrapper.rb +78 -78
  55. data/lib/cheffish/rspec/repository_support.rb +108 -108
  56. data/lib/cheffish/server_api.rb +52 -52
  57. data/lib/cheffish/version.rb +3 -3
  58. data/lib/cheffish/with_pattern.rb +21 -21
  59. data/spec/functional/fingerprint_spec.rb +64 -64
  60. data/spec/functional/merged_config_spec.rb +19 -19
  61. data/spec/functional/server_api_spec.rb +13 -13
  62. data/spec/integration/chef_acl_spec.rb +892 -879
  63. data/spec/integration/chef_client_spec.rb +105 -105
  64. data/spec/integration/chef_container_spec.rb +33 -33
  65. data/spec/integration/chef_group_spec.rb +309 -309
  66. data/spec/integration/chef_mirror_spec.rb +491 -491
  67. data/spec/integration/chef_node_spec.rb +786 -786
  68. data/spec/integration/chef_organization_spec.rb +226 -226
  69. data/spec/integration/chef_role_spec.rb +78 -78
  70. data/spec/integration/chef_user_spec.rb +85 -85
  71. data/spec/integration/private_key_spec.rb +399 -399
  72. data/spec/integration/recipe_dsl_spec.rb +28 -28
  73. data/spec/integration/rspec/converge_spec.rb +183 -183
  74. data/spec/support/key_support.rb +29 -29
  75. data/spec/support/spec_support.rb +15 -15
  76. data/spec/unit/get_private_key_spec.rb +131 -131
  77. data/spec/unit/recipe_run_wrapper_spec.rb +37 -37
  78. metadata +7 -5
@@ -1,3 +1,3 @@
1
- module Cheffish
2
- VERSION = '1.5.0'
3
- end
1
+ module Cheffish
2
+ VERSION = '1.6.0'
3
+ end
@@ -1,21 +1,21 @@
1
- module Cheffish
2
- module WithPattern
3
- def with(symbol)
4
- class_eval <<EOM
5
- attr_accessor :current_#{symbol}
6
-
7
- def with_#{symbol}(value)
8
- old_value = self.current_#{symbol}
9
- self.current_#{symbol} = value
10
- if block_given?
11
- begin
12
- yield
13
- ensure
14
- self.current_#{symbol} = old_value
15
- end
16
- end
17
- end
18
- EOM
19
- end
20
- end
21
- end
1
+ module Cheffish
2
+ module WithPattern
3
+ def with(symbol)
4
+ class_eval <<EOM
5
+ attr_accessor :current_#{symbol}
6
+
7
+ def with_#{symbol}(value)
8
+ old_value = self.current_#{symbol}
9
+ self.current_#{symbol} = value
10
+ if block_given?
11
+ begin
12
+ yield
13
+ ensure
14
+ self.current_#{symbol} = old_value
15
+ end
16
+ end
17
+ end
18
+ EOM
19
+ end
20
+ end
21
+ end
@@ -1,64 +1,64 @@
1
- require 'cheffish/key_formatter'
2
- require 'support/key_support'
3
-
4
- describe 'Cheffish fingerprint key formatter' do
5
-
6
- # Sample key: 0x9a6fa4c43b328c3d04c1fbc0498539218b6728e41cd35f6d27d491ef705f0b2083dc1ac977da19f54ba82b044773f20667e9627c543abb3b41b6eb9e4318ca3c68f487bbd0f1c9eea9a3101b7d1d180983c5440ac4183e78e9e256fa687d8aac63b21617a4b02b35bf5e307a3b76961a16cd8493e923536b34cc2b2da8d45220d57ef2243b081b555b84f1da0ade0e896c2aa96911b41430b59eaf75dbffb7eaa7c5b3a686f2d47a24e3b7f1acb0844f84a2fedc63660ae366b800cd9448093d6b1d96503ebb7807b48257e16c3d8a7c9a8cc5dd63116aa673bd9e09754de09358486e743e34c6a3642eeb64b2208efc96df39151572557a75638bd059c21a55 = 0xd6e92677d4e1d2aa6d14f87b5f49ee6916c6b92411536254fae4a21e82eebb0a40600247c701c1c938b21ca9f25b7b330c35fded57b4de3a951e83329a80bdbf2ba138fe2f190bffce43967b5fa93b179367bcd15cb1db7f9e3ab62caca95dc9489b62bc0a10b53841b932455a43409f96eed90dc80abc8cce5593ead8f0a26d * 0xb7f68cd427045788d5e315375f71d3a416784ec2597776a60ed77c821294d9bd66e96658bdcb43072cee0c849d297bd9f94991738f1a0df313ceb51b093a9372f12a61987f40e7a03d773911deb270916a574962ae8ff4f2d8bfcedee1c885e9c3e54212471636a6330b05b78c3a7ddf96b013be389a08ab7971db2f68fb2689
7
-
8
- sample_private_key = <<EOF
9
- -----BEGIN RSA PRIVATE KEY-----
10
- MIIEowIBAAKCAQEAmm+kxDsyjD0EwfvASYU5IYtnKOQc019tJ9SR73BfCyCD3BrJd9oZ9UuoKwRH
11
- c/IGZ+lifFQ6uztBtuueQxjKPGj0h7vQ8cnuqaMQG30dGAmDxUQKxBg+eOniVvpofYqsY7IWF6Sw
12
- KzW/XjB6O3aWGhbNhJPpI1NrNMwrLajUUiDVfvIkOwgbVVuE8doK3g6JbCqpaRG0FDC1nq912/+3
13
- 6qfFs6aG8tR6JOO38aywhE+Eov7cY2YK42a4AM2USAk9ax2WUD67eAe0glfhbD2KfJqMxd1jEWqm
14
- c72eCXVN4JNYSG50PjTGo2Qu62SyII78lt85FRVyVXp1Y4vQWcIaVQIDAQABAoIBABY+JC37FLGs
15
- DCZgOvab0HmrWUVDbX9oDBGjhQ1GUvoISdWGqiOv7vMsXWEssZnabt/CdmPPwdG7nCBbWSTyyhXf
16
- S/DMtTBN1CjsimJbJ7iRjj/4J9DMaRsDHI1IbYo/UcreGF55YsImcJSBSOmNj9rcE+eXYgmrdxJY
17
- oZNm8IWPaZ1/8KdPHSq6/HfTzRxXhcGOMGnf3lGfzkzIbV9Ee88Lv9sSV3bYrOsWMNabOe2TeTpC
18
- UTfFkC++0RkFjEDINSCnoCi+ybzHLUDnurANCwnRWLTVEAeffwNVmiDfgimuqFtzCInW5/5bOTPz
19
- rBmcC6QAFbyk2WKAlY8Zd4SBYqECgYEA1ukmd9Th0qptFPh7X0nuaRbGuSQRU2JU+uSiHoLuuwpA
20
- YAJHxwHByTiyHKnyW3szDDX97Ve03jqVHoMymoC9vyuhOP4vGQv/zkOWe1+pOxeTZ7zRXLHbf546
21
- tiysqV3JSJtivAoQtThBuTJFWkNAn5bu2Q3ICryMzlWT6tjwom0CgYEAt/aM1CcEV4jV4xU3X3HT
22
- pBZ4TsJZd3amDtd8ghKU2b1m6WZYvctDByzuDISdKXvZ+UmRc48aDfMTzrUbCTqTcvEqYZh/QOeg
23
- PXc5Ed6ycJFqV0liro/08ti/zt7hyIXpw+VCEkcWNqYzCwW3jDp935awE744mgireXHbL2j7JokC
24
- gYAOHErRTWHyYgw9dz8qd4E21y7/EvYsQmWP/5kBZdlk4HxvkVbDI0NlAdr39NSb2w/z+kuM3Nhc
25
- Sv5lfXnCGTfcKHIyesX+4AHQujFUMmi7H4YnJoecjXT7ARmbwn0ntae0o7cs34BPVb1C+qEBFy9U
26
- CyXtjHEY+15HYekPX2UVVQKBgBT8Nwxsdv5VSbDh1rM4lN//ADJb0UDjdAX1ZuqfnANKq9asKitc
27
- aIUFBxK+ff8hdbgOQF1iUaKNvBC0cCUZXYCbKi5/6uRIh+r7ErOLJ+fXbr4OTQeEvHiHaTn8Ct2J
28
- CSWjnWngWhRZ2TDEsi947Kr40ZUu+d34ZzcvWcWKwDuhAoGBAJzCRoGOu6YGy+rBPxaIg0vB+Grx
29
- rxs0NeNqGdrzmyAPN35OHXYclPwfp+DbtbJHgGMRc/9VFPqW9PeTKjIByeEsXyrcdreR35AR/fwR
30
- AUcSSKTvw+PobCpXhdkiw4TgJhFNuZnoC63FOjNqA5mu1ICZYBb4ZVlgUAgSmDQxSIgK
31
- -----END RSA PRIVATE KEY-----
32
- EOF
33
- sample_public_key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCab6TEOzKMPQTB+8BJhTkhi2co5BzTX20n1JHvcF8LIIPcGsl32hn1S6grBEdz8gZn6WJ8VDq7O0G2655DGMo8aPSHu9Dxye6poxAbfR0YCYPFRArEGD546eJW+mh9iqxjshYXpLArNb9eMHo7dpYaFs2Ek+kjU2s0zCstqNRSINV+8iQ7CBtVW4Tx2greDolsKqlpEbQUMLWer3Xb/7fqp8Wzpoby1Hok47fxrLCET4Si/txjZgrjZrgAzZRICT1rHZZQPrt4B7SCV+FsPYp8mozF3WMRaqZzvZ4JdU3gk1hIbnQ+NMajZC7rZLIgjvyW3zkVFXJVenVji9BZwhpV"
34
-
35
- def key_to_format(key, format)
36
- keyobj, f = Cheffish::KeyFormatter.decode(key)
37
- Cheffish::KeyFormatter.encode(keyobj, {:format => format})
38
- end
39
-
40
- context 'when computing key fingperprints' do
41
-
42
- it 'computes the PKCS#8 SHA1 private key fingerprint correctly', :pending => (RUBY_VERSION.to_f >= 2.0) do
43
- expect(key_to_format(sample_private_key, :pkcs8sha1fingerprint)).to eq(
44
- '88:7e:3a:bd:26:9f:b5:c5:d8:ae:52:f9:df:0b:64:a4:5c:17:0a:87')
45
- end
46
-
47
- it 'computes the PKCS#1 MD5 public key fingerprint correctly' do
48
- expect(key_to_format(sample_public_key, :pkcs1md5fingerprint)).to eq(
49
- '1f:e8:da:c1:16:c3:72:7d:90:e2:b7:64:c4:b4:55:20')
50
- end
51
-
52
- it 'computes the RFC4716 MD5 public key fingerprint correctly' do
53
- expect(key_to_format(sample_public_key, :rfc4716md5fingerprint)).to eq(
54
- 'b0:13:4f:da:cf:8c:dc:a7:4a:1f:d2:3a:51:92:cf:6b')
55
- end
56
-
57
- it 'defaults to the PKCS#1 MD5 public key fingerprint' do
58
- expect(key_to_format(sample_public_key, :fingerprint)).to eq(
59
- key_to_format(sample_public_key, :pkcs1md5fingerprint))
60
- end
61
-
62
- end
63
-
64
- end
1
+ require 'cheffish/key_formatter'
2
+ require 'support/key_support'
3
+
4
+ describe 'Cheffish fingerprint key formatter' do
5
+
6
+ # Sample key: 0x9a6fa4c43b328c3d04c1fbc0498539218b6728e41cd35f6d27d491ef705f0b2083dc1ac977da19f54ba82b044773f20667e9627c543abb3b41b6eb9e4318ca3c68f487bbd0f1c9eea9a3101b7d1d180983c5440ac4183e78e9e256fa687d8aac63b21617a4b02b35bf5e307a3b76961a16cd8493e923536b34cc2b2da8d45220d57ef2243b081b555b84f1da0ade0e896c2aa96911b41430b59eaf75dbffb7eaa7c5b3a686f2d47a24e3b7f1acb0844f84a2fedc63660ae366b800cd9448093d6b1d96503ebb7807b48257e16c3d8a7c9a8cc5dd63116aa673bd9e09754de09358486e743e34c6a3642eeb64b2208efc96df39151572557a75638bd059c21a55 = 0xd6e92677d4e1d2aa6d14f87b5f49ee6916c6b92411536254fae4a21e82eebb0a40600247c701c1c938b21ca9f25b7b330c35fded57b4de3a951e83329a80bdbf2ba138fe2f190bffce43967b5fa93b179367bcd15cb1db7f9e3ab62caca95dc9489b62bc0a10b53841b932455a43409f96eed90dc80abc8cce5593ead8f0a26d * 0xb7f68cd427045788d5e315375f71d3a416784ec2597776a60ed77c821294d9bd66e96658bdcb43072cee0c849d297bd9f94991738f1a0df313ceb51b093a9372f12a61987f40e7a03d773911deb270916a574962ae8ff4f2d8bfcedee1c885e9c3e54212471636a6330b05b78c3a7ddf96b013be389a08ab7971db2f68fb2689
7
+
8
+ sample_private_key = <<EOF
9
+ -----BEGIN RSA PRIVATE KEY-----
10
+ MIIEowIBAAKCAQEAmm+kxDsyjD0EwfvASYU5IYtnKOQc019tJ9SR73BfCyCD3BrJd9oZ9UuoKwRH
11
+ c/IGZ+lifFQ6uztBtuueQxjKPGj0h7vQ8cnuqaMQG30dGAmDxUQKxBg+eOniVvpofYqsY7IWF6Sw
12
+ KzW/XjB6O3aWGhbNhJPpI1NrNMwrLajUUiDVfvIkOwgbVVuE8doK3g6JbCqpaRG0FDC1nq912/+3
13
+ 6qfFs6aG8tR6JOO38aywhE+Eov7cY2YK42a4AM2USAk9ax2WUD67eAe0glfhbD2KfJqMxd1jEWqm
14
+ c72eCXVN4JNYSG50PjTGo2Qu62SyII78lt85FRVyVXp1Y4vQWcIaVQIDAQABAoIBABY+JC37FLGs
15
+ DCZgOvab0HmrWUVDbX9oDBGjhQ1GUvoISdWGqiOv7vMsXWEssZnabt/CdmPPwdG7nCBbWSTyyhXf
16
+ S/DMtTBN1CjsimJbJ7iRjj/4J9DMaRsDHI1IbYo/UcreGF55YsImcJSBSOmNj9rcE+eXYgmrdxJY
17
+ oZNm8IWPaZ1/8KdPHSq6/HfTzRxXhcGOMGnf3lGfzkzIbV9Ee88Lv9sSV3bYrOsWMNabOe2TeTpC
18
+ UTfFkC++0RkFjEDINSCnoCi+ybzHLUDnurANCwnRWLTVEAeffwNVmiDfgimuqFtzCInW5/5bOTPz
19
+ rBmcC6QAFbyk2WKAlY8Zd4SBYqECgYEA1ukmd9Th0qptFPh7X0nuaRbGuSQRU2JU+uSiHoLuuwpA
20
+ YAJHxwHByTiyHKnyW3szDDX97Ve03jqVHoMymoC9vyuhOP4vGQv/zkOWe1+pOxeTZ7zRXLHbf546
21
+ tiysqV3JSJtivAoQtThBuTJFWkNAn5bu2Q3ICryMzlWT6tjwom0CgYEAt/aM1CcEV4jV4xU3X3HT
22
+ pBZ4TsJZd3amDtd8ghKU2b1m6WZYvctDByzuDISdKXvZ+UmRc48aDfMTzrUbCTqTcvEqYZh/QOeg
23
+ PXc5Ed6ycJFqV0liro/08ti/zt7hyIXpw+VCEkcWNqYzCwW3jDp935awE744mgireXHbL2j7JokC
24
+ gYAOHErRTWHyYgw9dz8qd4E21y7/EvYsQmWP/5kBZdlk4HxvkVbDI0NlAdr39NSb2w/z+kuM3Nhc
25
+ Sv5lfXnCGTfcKHIyesX+4AHQujFUMmi7H4YnJoecjXT7ARmbwn0ntae0o7cs34BPVb1C+qEBFy9U
26
+ CyXtjHEY+15HYekPX2UVVQKBgBT8Nwxsdv5VSbDh1rM4lN//ADJb0UDjdAX1ZuqfnANKq9asKitc
27
+ aIUFBxK+ff8hdbgOQF1iUaKNvBC0cCUZXYCbKi5/6uRIh+r7ErOLJ+fXbr4OTQeEvHiHaTn8Ct2J
28
+ CSWjnWngWhRZ2TDEsi947Kr40ZUu+d34ZzcvWcWKwDuhAoGBAJzCRoGOu6YGy+rBPxaIg0vB+Grx
29
+ rxs0NeNqGdrzmyAPN35OHXYclPwfp+DbtbJHgGMRc/9VFPqW9PeTKjIByeEsXyrcdreR35AR/fwR
30
+ AUcSSKTvw+PobCpXhdkiw4TgJhFNuZnoC63FOjNqA5mu1ICZYBb4ZVlgUAgSmDQxSIgK
31
+ -----END RSA PRIVATE KEY-----
32
+ EOF
33
+ sample_public_key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCab6TEOzKMPQTB+8BJhTkhi2co5BzTX20n1JHvcF8LIIPcGsl32hn1S6grBEdz8gZn6WJ8VDq7O0G2655DGMo8aPSHu9Dxye6poxAbfR0YCYPFRArEGD546eJW+mh9iqxjshYXpLArNb9eMHo7dpYaFs2Ek+kjU2s0zCstqNRSINV+8iQ7CBtVW4Tx2greDolsKqlpEbQUMLWer3Xb/7fqp8Wzpoby1Hok47fxrLCET4Si/txjZgrjZrgAzZRICT1rHZZQPrt4B7SCV+FsPYp8mozF3WMRaqZzvZ4JdU3gk1hIbnQ+NMajZC7rZLIgjvyW3zkVFXJVenVji9BZwhpV"
34
+
35
+ def key_to_format(key, format)
36
+ keyobj, f = Cheffish::KeyFormatter.decode(key)
37
+ Cheffish::KeyFormatter.encode(keyobj, {:format => format})
38
+ end
39
+
40
+ context 'when computing key fingperprints' do
41
+
42
+ it 'computes the PKCS#8 SHA1 private key fingerprint correctly', :pending => (RUBY_VERSION.to_f >= 2.0) do
43
+ expect(key_to_format(sample_private_key, :pkcs8sha1fingerprint)).to eq(
44
+ '88:7e:3a:bd:26:9f:b5:c5:d8:ae:52:f9:df:0b:64:a4:5c:17:0a:87')
45
+ end
46
+
47
+ it 'computes the PKCS#1 MD5 public key fingerprint correctly' do
48
+ expect(key_to_format(sample_public_key, :pkcs1md5fingerprint)).to eq(
49
+ '1f:e8:da:c1:16:c3:72:7d:90:e2:b7:64:c4:b4:55:20')
50
+ end
51
+
52
+ it 'computes the RFC4716 MD5 public key fingerprint correctly' do
53
+ expect(key_to_format(sample_public_key, :rfc4716md5fingerprint)).to eq(
54
+ 'b0:13:4f:da:cf:8c:dc:a7:4a:1f:d2:3a:51:92:cf:6b')
55
+ end
56
+
57
+ it 'defaults to the PKCS#1 MD5 public key fingerprint' do
58
+ expect(key_to_format(sample_public_key, :fingerprint)).to eq(
59
+ key_to_format(sample_public_key, :pkcs1md5fingerprint))
60
+ end
61
+
62
+ end
63
+
64
+ end
@@ -1,20 +1,20 @@
1
- require 'cheffish/merged_config'
2
-
3
- describe "merged_config" do
4
-
5
- let(:config) do
6
- Cheffish::MergedConfig.new({:test=>'val'})
7
- end
8
-
9
- it "returns value in config" do
10
- expect(config.test).to eq('val')
11
- end
12
-
13
- it "raises a NoMethodError if calling an unknown method with arguments" do
14
- expect{config.merge({:some => 'hash'})}.to raise_error(NoMethodError)
15
- end
16
-
17
- it "has an informative string representation" do
18
- expect("#{config}").to eq("{:test=>\"val\"}")
19
- end
1
+ require 'cheffish/merged_config'
2
+
3
+ describe "merged_config" do
4
+
5
+ let(:config) do
6
+ Cheffish::MergedConfig.new({:test=>'val'})
7
+ end
8
+
9
+ it "returns value in config" do
10
+ expect(config.test).to eq('val')
11
+ end
12
+
13
+ it "raises a NoMethodError if calling an unknown method with arguments" do
14
+ expect{config.merge({:some => 'hash'})}.to raise_error(NoMethodError)
15
+ end
16
+
17
+ it "has an informative string representation" do
18
+ expect("#{config}").to eq("{:test=>\"val\"}")
19
+ end
20
20
  end
@@ -1,13 +1,13 @@
1
- require 'cheffish'
2
-
3
- describe "api version" do
4
-
5
- let(:server_api) do
6
- Cheffish.chef_server_api({:chef_server_url => "my.chef.server"})
7
- end
8
-
9
- it "is pinned to 0" do
10
- expect(Cheffish::ServerAPI).to receive(:new).with("my.chef.server", {api_version: "0"})
11
- server_api
12
- end
13
- end
1
+ require 'cheffish'
2
+
3
+ describe "api version" do
4
+
5
+ let(:server_api) do
6
+ Cheffish.chef_server_api({:chef_server_url => "my.chef.server"})
7
+ end
8
+
9
+ it "is pinned to 0" do
10
+ expect(Cheffish::ServerAPI).to receive(:new).with("my.chef.server", {api_version: "0"})
11
+ server_api
12
+ end
13
+ end
@@ -1,879 +1,892 @@
1
- require 'support/spec_support'
2
- require 'cheffish/rspec/chef_run_support'
3
- require 'chef/resource/chef_acl'
4
- require 'chef/provider/chef_acl'
5
- require 'chef_zero/version'
6
- require 'uri'
7
-
8
- if Gem::Version.new(ChefZero::VERSION) >= Gem::Version.new('3.1')
9
- describe Chef::Resource::ChefAcl do
10
- extend Cheffish::RSpec::ChefRunSupport
11
-
12
- # let(:chef_config) { super().merge(log_level: :debug, stdout: STDOUT, stderr: STDERR, log_location: STDOUT) }
13
-
14
- context "Rights attributes" do
15
- when_the_chef_server 'has a node named x', :osc_compat => false do
16
- node 'x', {}
17
-
18
- it 'Converging chef_acl "nodes/x" changes nothing' do
19
- expect_recipe {
20
- chef_acl 'nodes/x'
21
- }.to be_up_to_date
22
- expect(get('nodes/x/_acl')).to partially_match({})
23
- end
24
-
25
- it 'Converging chef_acl "nodes/x" with "complete true" and no rights raises an error' do
26
- expect_converge {
27
- chef_acl 'nodes/x' do
28
- complete true
29
- end
30
- }.to raise_error(RuntimeError)
31
- end
32
-
33
- it 'Removing all :grant rights from a node raises an error' do
34
- expect_converge {
35
- chef_acl 'nodes/x' do
36
- remove_rights :grant, users: %w(pivotal), groups: %w(admins users clients)
37
- end
38
- }.to raise_error(RuntimeError)
39
- end
40
-
41
- context 'and a user "blarghle"' do
42
- user 'blarghle', {}
43
-
44
- it 'Converging chef_acl "nodes/x" with user "blarghle" adds the user' do
45
- expect_recipe {
46
- chef_acl 'nodes/x' do
47
- rights :read, users: %w(blarghle)
48
- end
49
- }.to be_updated
50
- expect(get('nodes/x/_acl')).to partially_match('read' => { 'actors' => %w(blarghle) })
51
- end
52
-
53
- it 'Converging chef_acl "nodes/x" with "complete true" removes all ACLs except those specified' do
54
- expect_recipe {
55
- chef_acl 'nodes/x' do
56
- rights :grant, users: %w(blarghle)
57
- complete true
58
- end
59
- }.to be_updated
60
- expect(get('nodes/x/_acl')).to eq(
61
- "create"=>{"actors"=>[], "groups"=>[]},
62
- "read" =>{"actors"=>[], "groups"=>[]},
63
- "update"=>{"actors"=>[], "groups"=>[]},
64
- "delete"=>{"actors"=>[], "groups"=>[]},
65
- "grant" =>{"actors"=>["blarghle"], "groups"=>[]}
66
- )
67
- end
68
- end
69
-
70
- it 'Converging chef_acl "nodes/x" with "complete true" removes all ACLs except those specified in :all' do
71
- expect_recipe {
72
- chef_acl 'nodes/x' do
73
- rights :all, users: %w(blarghle)
74
- complete true
75
- end
76
- }.to be_updated
77
- expect(get('nodes/x/_acl')).to eq(
78
- "create"=>{"actors"=>["blarghle"], "groups"=>[]},
79
- "read" =>{"actors"=>["blarghle"], "groups"=>[]},
80
- "update"=>{"actors"=>["blarghle"], "groups"=>[]},
81
- "delete"=>{"actors"=>["blarghle"], "groups"=>[]},
82
- "grant" =>{"actors"=>["blarghle"], "groups"=>[]}
83
- )
84
- end
85
-
86
- context 'and a client "blarghle"' do
87
- user 'blarghle', {}
88
-
89
- it 'Converging chef_acl "nodes/x" with client "blarghle" adds the client' do
90
- expect_recipe {
91
- chef_acl 'nodes/x' do
92
- rights :read, clients: %w(blarghle)
93
- end
94
- }.to be_updated
95
- expect(get('nodes/x/_acl')).to partially_match('read' => { 'actors' => %w(blarghle) })
96
- end
97
- end
98
-
99
- context 'and a group "blarghle"' do
100
- group 'blarghle', {}
101
-
102
- it 'Converging chef_acl "nodes/x" with group "blarghle" adds the group' do
103
- expect_recipe {
104
- chef_acl 'nodes/x' do
105
- rights :read, groups: %w(blarghle)
106
- end
107
- }.to be_updated
108
- expect(get('nodes/x/_acl')).to partially_match('read' => { 'groups' => %w(blarghle) })
109
- end
110
- end
111
-
112
- context 'and multiple users and groups' do
113
- user 'u1', {}
114
- user 'u2', {}
115
- user 'u3', {}
116
- client 'c1', {}
117
- client 'c2', {}
118
- client 'c3', {}
119
- group 'g1', {}
120
- group 'g2', {}
121
- group 'g3', {}
122
-
123
- it 'Converging chef_acl "nodes/x" with multiple groups, users and clients in an acl makes the appropriate changes' do
124
- expect_recipe {
125
- chef_acl 'nodes/x' do
126
- rights :create, users: [ 'u1', 'u2', 'u3' ], clients: [ 'c1', 'c2', 'c3' ], groups: [ 'g1', 'g2', 'g3' ]
127
- end
128
- }.to be_updated
129
- expect(get('nodes/x/_acl')).to partially_match(
130
- 'create' => { 'groups' => %w(g1 g2 g3), 'actors' => %w(u1 u2 u3 c1 c2 c3) }
131
- )
132
- end
133
-
134
- it 'Converging chef_acl "nodes/x" with multiple groups, users and clients across multiple "rights" groups makes the appropriate changes' do
135
- expect_recipe {
136
- chef_acl 'nodes/x' do
137
- rights :create, users: %w(u1), clients: %w(c1), groups: %w(g1)
138
- rights :create, users: %w(u2 u3), clients: %w(c2 c3), groups: %w(g2)
139
- rights :read, users: %w(u1)
140
- rights :read, groups: %w(g1)
141
- end
142
- }.to be_updated
143
- expect(get('nodes/x/_acl')).to partially_match(
144
- 'create' => { 'groups' => %w(g1 g2), 'actors' => %w(u1 u2 u3 c1 c2 c3) },
145
- 'read' => { 'groups' => %w(g1), 'actors' => %w(u1) }
146
- )
147
- end
148
-
149
- it 'Converging chef_acl "nodes/x" with rights [ :read, :create, :update, :delete, :grant ] modifies all rights' do
150
- expect_recipe {
151
- chef_acl 'nodes/x' do
152
- rights [ :create, :read, :update, :delete, :grant ], users: %w(u1 u2), clients: %w(c1), groups: %w(g1)
153
- end
154
- }.to be_updated
155
- expect(get('nodes/x/_acl')).to partially_match(
156
- 'create' => { 'groups' => %w(g1), 'actors' => %w(u1 u2 c1) },
157
- 'read' => { 'groups' => %w(g1), 'actors' => %w(u1 u2 c1) },
158
- 'update' => { 'groups' => %w(g1), 'actors' => %w(u1 u2 c1) },
159
- 'delete' => { 'groups' => %w(g1), 'actors' => %w(u1 u2 c1) },
160
- 'grant' => { 'groups' => %w(g1), 'actors' => %w(u1 u2 c1) },
161
- )
162
- end
163
-
164
- it 'Converging chef_acl "nodes/x" with rights :all modifies all rights' do
165
- expect_recipe {
166
- chef_acl 'nodes/x' do
167
- rights :all, users: %w(u1 u2), clients: %w(c1), groups: %w(g1)
168
- end
169
- }.to be_updated
170
- expect(get('nodes/x/_acl')).to partially_match(
171
- 'create' => { 'groups' => %w(g1), 'actors' => %w(u1 u2 c1) },
172
- 'read' => { 'groups' => %w(g1), 'actors' => %w(u1 u2 c1) },
173
- 'update' => { 'groups' => %w(g1), 'actors' => %w(u1 u2 c1) },
174
- 'delete' => { 'groups' => %w(g1), 'actors' => %w(u1 u2 c1) },
175
- 'grant' => { 'groups' => %w(g1), 'actors' => %w(u1 u2 c1) },
176
- )
177
- end
178
- end
179
-
180
- it 'Converging chef_acl "nodes/y" throws a 404' do
181
- expect_converge {
182
- chef_acl 'nodes/y'
183
- }.to raise_error(Net::HTTPServerException)
184
- end
185
- end
186
-
187
- when_the_chef_server 'has a node named x with user blarghle in its acl', :osc_compat => false do
188
- user 'blarghle', {}
189
- node 'x', {} do
190
- acl 'read' => { 'actors' => %w(blarghle) }
191
- end
192
-
193
- it 'Converging chef_acl "nodes/x" with that user changes nothing' do
194
- expect_recipe {
195
- chef_acl 'nodes/x' do
196
- rights :read, users: %w(blarghle)
197
- end
198
- }.to be_up_to_date
199
- expect(get('nodes/x/_acl')).to partially_match({})
200
- end
201
- end
202
-
203
- when_the_chef_server 'has a node named x with users foo and bar in all its acls', :osc_compat => false do
204
- user 'foo', {}
205
- user 'bar', {}
206
- node 'x', {} do
207
- acl 'create' => { 'actors' => %w(foo bar) },
208
- 'read' => { 'actors' => %w(foo bar) },
209
- 'update' => { 'actors' => %w(foo bar) },
210
- 'delete' => { 'actors' => %w(foo bar) },
211
- 'grant' => { 'actors' => %w(foo bar) }
212
- end
213
-
214
- it 'Converging chef_acl "nodes/x" with remove_rights :all removes foo from everything' do
215
- expect_recipe {
216
- chef_acl 'nodes/x' do
217
- remove_rights :all, users: %w(foo)
218
- end
219
- }.to be_updated
220
- expect(get('nodes/x/_acl')).to partially_match(
221
- 'create' => { 'actors' => exclude('foo') },
222
- 'read' => { 'actors' => exclude('foo') },
223
- 'update' => { 'actors' => exclude('foo') },
224
- 'delete' => { 'actors' => exclude('foo') },
225
- 'grant' => { 'actors' => exclude('foo') },
226
- )
227
- end
228
- end
229
-
230
- ::RSpec::Matchers.define_negated_matcher :exclude, :include
231
-
232
- context 'recursive' do
233
- when_the_chef_server 'has a nodes container with user blarghle in its acl', :osc_compat => false do
234
- user 'blarghle', {}
235
- acl_for 'containers/nodes', 'read' => { 'actors' => %w(blarghle) }
236
- node 'x', {} do
237
- acl 'read' => { 'actors' => [] }
238
- end
239
-
240
- it 'Converging chef_acl "nodes" makes no changes' do
241
- expect {
242
- expect_recipe {
243
- chef_acl 'nodes' do
244
- rights :read, users: %w(blarghle)
245
- end
246
- }.to be_up_to_date
247
- }.to not_change { get('containers/nodes/_acl') }.
248
- and not_change { get('nodes/x/_acl') }
249
- end
250
-
251
- RSpec::Matchers.define_negated_matcher :not_change, :change
252
-
253
- it 'Converging chef_acl "nodes" with recursive :on_change makes no changes' do
254
- expect {
255
- expect_recipe {
256
- chef_acl 'nodes' do
257
- rights :read, users: %w(blarghle)
258
- recursive :on_change
259
- end
260
- }.to be_up_to_date
261
- }.to not_change { get('containers/nodes/_acl') }.
262
- and not_change { get('nodes/x/_acl') }
263
- end
264
-
265
- it 'Converging chef_acl "nodes" with recursive true changes nodes/x\'s acls' do
266
- expect_recipe {
267
- chef_acl 'nodes' do
268
- rights :read, users: %w(blarghle)
269
- recursive true
270
- end
271
- }.to be_updated
272
- expect(get('nodes/x/_acl')).to partially_match('read' => { 'actors' => %w(blarghle) })
273
- end
274
-
275
- it 'Converging chef_acl "" with recursive false does not change nodes/x\'s acls' do
276
- expect_recipe {
277
- chef_acl '' do
278
- rights :read, users: %w(blarghle)
279
- recursive false
280
- end
281
- }.to be_updated
282
- expect(get('containers/nodes/_acl')).to partially_match({})
283
- expect(get('nodes/x/_acl')).to partially_match({})
284
- end
285
-
286
- it 'Converging chef_acl "" with recursive :on_change does not change nodes/x\'s acls' do
287
- expect_recipe {
288
- chef_acl '' do
289
- rights :read, users: %w(blarghle)
290
- recursive :on_change
291
- end
292
- }.to be_updated
293
- expect(get('containers/nodes/_acl')).to partially_match({})
294
- expect(get('nodes/x/_acl')).to partially_match({})
295
- end
296
-
297
- it 'Converging chef_acl "" with recursive true changes nodes/x\'s acls' do
298
- expect_recipe {
299
- chef_acl '' do
300
- rights :read, users: %w(blarghle)
301
- recursive true
302
- end
303
- }.to be_updated
304
- expect(get('/organizations/_acl')).to partially_match('read' => { 'actors' => %w(blarghle) })
305
- expect(get('nodes/x/_acl')).to partially_match('read' => { 'actors' => %w(blarghle) })
306
- end
307
- end
308
- end
309
- end
310
-
311
- context 'ACLs on each type of thing' do
312
- when_the_chef_server 'has an organization named foo', :osc_compat => false, :single_org => false do
313
- organization 'foo' do
314
- user 'u', {}
315
- client 'x', {}
316
- container 'x', {}
317
- cookbook 'x', '1.0.0', {}
318
- data_bag 'x', { 'y' => {} }
319
- environment 'x', {}
320
- group 'x', {}
321
- node 'x', {}
322
- role 'x', {}
323
- sandbox 'x', {}
324
- user 'x', {}
325
- end
326
-
327
- organization 'bar' do
328
- user 'u', {}
329
- node 'x', {}
330
- end
331
-
332
- context 'and the chef server URL points at /organizations/foo' do
333
- before :each do
334
- Chef::Config.chef_server_url = URI.join(Chef::Config.chef_server_url, '/organizations/foo').to_s
335
- end
336
-
337
- context 'relative paths' do
338
- it "chef_acl 'nodes/x' changes the acls" do
339
- expect_recipe {
340
- chef_acl "nodes/x" do
341
- rights :read, users: %w(u)
342
- end
343
- }.to be_updated
344
- expect(get("nodes/x/_acl")).to partially_match('read' => { 'actors' => %w(u) })
345
- end
346
-
347
- it "chef_acl '*/*' changes the acls" do
348
- expect_recipe {
349
- chef_acl "*/*" do
350
- rights :read, users: %w(u)
351
- end
352
- }.to be_updated
353
- %w(clients containers cookbooks data environments groups nodes roles).each do |type|
354
- expect(get("/organizations/foo/#{type}/x/_acl")).to partially_match(
355
- 'read' => { 'actors' => %w(u) })
356
- end
357
- end
358
- end
359
-
360
- context 'absolute paths' do
361
- %w(clients containers cookbooks data environments groups nodes roles sandboxes).each do |type|
362
- it "chef_acl '/organizations/foo/#{type}/x' changes the acl" do
363
- expect_recipe {
364
- chef_acl "/organizations/foo/#{type}/x" do
365
- rights :read, users: %w(u)
366
- end
367
- }.to be_updated
368
- expect(get("/organizations/foo/#{type}/x/_acl")).to partially_match('read' => { 'actors' => %w(u) })
369
- end
370
- end
371
-
372
- %w(clients containers cookbooks data environments groups nodes roles sandboxes).each do |type|
373
- it "chef_acl '/organizations/foo/#{type}/x' changes the acl" do
374
- expect_recipe {
375
- chef_acl "/organizations/foo/#{type}/x" do
376
- rights :read, users: %w(u)
377
- end
378
- }.to be_updated
379
- expect(get("/organizations/foo/#{type}/x/_acl")).to partially_match('read' => { 'actors' => %w(u) })
380
- end
381
- end
382
-
383
- %w(clients containers cookbooks data environments groups nodes roles).each do |type|
384
- it "chef_acl '/*/*/#{type}/*' changes the acl" do
385
- expect_recipe {
386
- chef_acl "/*/*/#{type}/*" do
387
- rights :read, users: %w(u)
388
- end
389
- }.to be_updated
390
- expect(get("/organizations/foo/#{type}/x/_acl")).to partially_match('read' => { 'actors' => %w(u) })
391
- end
392
- end
393
-
394
- it "chef_acl '/*/*/*/x' changes the acls" do
395
- expect_recipe {
396
- chef_acl "/*/*/*/x" do
397
- rights :read, users: %w(u)
398
- end
399
- }.to be_updated
400
- %w(clients containers cookbooks data environments groups nodes roles sandboxes).each do |type|
401
- expect(get("/organizations/foo/#{type}/x/_acl")).to partially_match(
402
- 'read' => { 'actors' => %w(u) })
403
- end
404
- end
405
-
406
- it "chef_acl '/*/*/*/*' changes the acls" do
407
- expect_recipe {
408
- chef_acl "/*/*/*/*" do
409
- rights :read, users: %w(u)
410
- end
411
- }.to be_updated
412
- %w(clients containers cookbooks data environments groups nodes roles).each do |type|
413
- expect(get("/organizations/foo/#{type}/x/_acl")).to partially_match(
414
- 'read' => { 'actors' => %w(u) })
415
- end
416
- end
417
-
418
- it 'chef_acl "/organizations/foo/data_bags/x" changes the acl' do
419
- expect_recipe {
420
- chef_acl '/organizations/foo/data_bags/x' do
421
- rights :read, users: %w(u)
422
- end
423
- }.to be_updated
424
- expect(get('/organizations/foo/data/x/_acl')).to partially_match('read' => { 'actors' => %w(u) })
425
- end
426
-
427
- it 'chef_acl "/*/*/data_bags/*" changes the acl' do
428
- expect_recipe {
429
- chef_acl '/*/*/data_bags/*' do
430
- rights :read, users: %w(u)
431
- end
432
- }.to be_updated
433
- expect(get('/organizations/foo/data/x/_acl')).to partially_match('read' => { 'actors' => %w(u) })
434
- end
435
-
436
- it "chef_acl '/organizations/foo/cookbooks/x/1.0.0' raises an error" do
437
- expect_converge {
438
- chef_acl "/organizations/foo/cookbooks/x/1.0.0" do
439
- rights :read, users: %w(u)
440
- end
441
- }.to raise_error(/ACLs cannot be set on children of \/organizations\/foo\/cookbooks\/x/)
442
- end
443
-
444
- it "chef_acl '/organizations/foo/cookbooks/*/*' raises an error" do
445
- pending
446
- expect_converge {
447
- chef_acl "/organizations/foo/cookbooks/*/*" do
448
- rights :read, users: %w(u)
449
- end
450
- }.to raise_error(/ACLs cannot be set on children of \/organizations\/foo\/cookbooks\/*/)
451
- end
452
-
453
- it 'chef_acl "/organizations/foo/data/x/y" raises an error' do
454
- expect_converge {
455
- chef_acl '/organizations/foo/data/x/y' do
456
- rights :read, users: %w(u)
457
- end
458
- }.to raise_error(/ACLs cannot be set on children of \/organizations\/foo\/data\/x/)
459
- end
460
-
461
- it 'chef_acl "/organizations/foo/data/*/*" raises an error' do
462
- pending
463
- expect_converge {
464
- chef_acl '/organizations/foo/data/*/*' do
465
- rights :read, users: %w(u)
466
- end
467
- }.to raise_error(/ACLs cannot be set on children of \/organizations\/foo\/data\/*/)
468
- end
469
-
470
- it 'chef_acl "/organizations/foo" changes the acl' do
471
- expect_recipe {
472
- chef_acl '/organizations/foo' do
473
- rights :read, users: %w(u)
474
- end
475
- }.to be_updated
476
- expect(get('/organizations/foo/organizations/_acl')).to partially_match('read' => { 'actors' => %w(u) })
477
- expect(get('/organizations/foo/nodes/x/_acl')).to partially_match('read' => { 'actors' => %w(u) })
478
- end
479
-
480
- it 'chef_acl "/organizations/*" changes the acl' do
481
- expect_recipe {
482
- chef_acl '/organizations/*' do
483
- rights :read, users: %w(u)
484
- end
485
- }.to be_updated
486
- expect(get('/organizations/foo/organizations/_acl')).to partially_match('read' => { 'actors' => %w(u) })
487
- expect(get('/organizations/foo/nodes/x/_acl')).to partially_match('read' => { 'actors' => %w(u) })
488
- end
489
-
490
- it 'chef_acl "/users/x" changes the acl' do
491
- expect_recipe {
492
- chef_acl '/users/x' do
493
- rights :read, users: %w(u)
494
- end
495
- }.to be_updated
496
- expect(get('/users/x/_acl')).to partially_match('read' => { 'actors' => %w(u) })
497
- end
498
-
499
- it 'chef_acl "/users/*" changes the acl' do
500
- expect_recipe {
501
- chef_acl '/users/*' do
502
- rights :read, users: %w(u)
503
- end
504
- }.to be_updated
505
- expect(get('/users/x/_acl')).to partially_match('read' => { 'actors' => %w(u) })
506
- end
507
-
508
- it 'chef_acl "/*/x" changes the acl' do
509
- expect_recipe {
510
- chef_acl '/*/x' do
511
- rights :read, users: %w(u)
512
- end
513
- }.to be_updated
514
- expect(get('/users/x/_acl')).to partially_match('read' => { 'actors' => %w(u) })
515
- end
516
-
517
- it 'chef_acl "/*/*" changes the acl' do
518
- expect_recipe {
519
- chef_acl '/*/*' do
520
- rights :read, users: %w(u)
521
- end
522
- }.to be_updated
523
- expect(get('/organizations/foo/organizations/_acl')).to partially_match('read' => { 'actors' => %w(u) })
524
- expect(get('/users/x/_acl')).to partially_match('read' => { 'actors' => %w(u) })
525
- end
526
- end
527
- end
528
-
529
- context 'and the chef server URL points at /organizations/bar' do
530
- before :each do
531
- Chef::Config.chef_server_url = URI.join(Chef::Config.chef_server_url.to_s, '/organizations/bar').to_s
532
- end
533
-
534
- it "chef_acl '/organizations/foo/nodes/*' changes the acl" do
535
- expect_recipe {
536
- chef_acl "/organizations/foo/nodes/*" do
537
- rights :read, users: %w(u)
538
- end
539
- }.to be_updated
540
- expect(get("/organizations/foo/nodes/x/_acl")).to partially_match('read' => { 'actors' => %w(u) })
541
- end
542
- end
543
-
544
- context 'and the chef server URL points at /' do
545
- before :each do
546
- Chef::Config.chef_server_url = URI.join(Chef::Config.chef_server_url.to_s, '/').to_s
547
- end
548
-
549
- it "chef_acl '/organizations/foo/nodes/*' changes the acl" do
550
- expect_recipe {
551
- chef_acl "/organizations/foo/nodes/*" do
552
- rights :read, users: %w(u)
553
- end
554
- }.to be_updated
555
- expect(get("/organizations/foo/nodes/x/_acl")).to partially_match('read' => { 'actors' => %w(u) })
556
- end
557
- end
558
- end
559
-
560
- when_the_chef_server 'has a user "u" in single org mode', :osc_compat => false do
561
- user 'u', {}
562
- client 'x', {}
563
- container 'x', {}
564
- cookbook 'x', '1.0.0', {}
565
- data_bag 'x', { 'y' => {} }
566
- environment 'x', {}
567
- group 'x', {}
568
- node 'x', {}
569
- role 'x', {}
570
- sandbox 'x', {}
571
- user 'x', {}
572
-
573
- %w(clients containers cookbooks data environments groups nodes roles sandboxes).each do |type|
574
- it "chef_acl #{type}/x' changes the acl" do
575
- expect_recipe {
576
- chef_acl "#{type}/x" do
577
- rights :read, users: %w(u)
578
- end
579
- }.to be_updated
580
- expect(get("#{type}/x/_acl")).to partially_match('read' => { 'actors' => %w(u) })
581
- end
582
- end
583
-
584
- %w(clients containers cookbooks data environments groups nodes roles).each do |type|
585
- it "chef_acl '#{type}/*' changes the acl" do
586
- expect_recipe {
587
- chef_acl "#{type}/*" do
588
- rights :read, users: %w(u)
589
- end
590
- }.to be_updated
591
- expect(get("#{type}/x/_acl")).to partially_match('read' => { 'actors' => %w(u) })
592
- end
593
- end
594
-
595
- it "chef_acl '*/x' changes the acls" do
596
- expect_recipe {
597
- chef_acl "*/x" do
598
- rights :read, users: %w(u)
599
- end
600
- }.to be_updated
601
- %w(clients containers cookbooks data environments groups nodes roles sandboxes).each do |type|
602
- expect(get("#{type}/x/_acl")).to partially_match(
603
- 'read' => { 'actors' => %w(u) })
604
- end
605
- end
606
-
607
- it "chef_acl '*/*' changes the acls" do
608
- expect_recipe {
609
- chef_acl "*/*" do
610
- rights :read, users: %w(u)
611
- end
612
- }.to be_updated
613
- %w(clients containers cookbooks data environments groups nodes roles).each do |type|
614
- expect(get("#{type}/x/_acl")).to partially_match(
615
- 'read' => { 'actors' => %w(u) })
616
- end
617
- end
618
-
619
- it "chef_acl 'groups/*' changes the acl" do
620
- expect_recipe {
621
- chef_acl "groups/*" do
622
- rights :read, users: %w(u)
623
- end
624
- }.to be_updated
625
- %w(admins billing-admins clients users x).each do |n|
626
- expect(get("groups/#{n}/_acl")).to partially_match(
627
- 'read' => { 'actors' => %w(u) })
628
- end
629
- end
630
-
631
- it 'chef_acl "data_bags/x" changes the acl' do
632
- expect_recipe {
633
- chef_acl 'data_bags/x' do
634
- rights :read, users: %w(u)
635
- end
636
- }.to be_updated
637
- expect(get('data/x/_acl')).to partially_match('read' => { 'actors' => %w(u) })
638
- end
639
-
640
- it 'chef_acl "data_bags/*" changes the acl' do
641
- expect_recipe {
642
- chef_acl 'data_bags/*' do
643
- rights :read, users: %w(u)
644
- end
645
- }.to be_updated
646
- expect(get('data/x/_acl')).to partially_match('read' => { 'actors' => %w(u) })
647
- end
648
-
649
- it 'chef_acl "" changes the organization acl' do
650
- expect_recipe {
651
- chef_acl '' do
652
- rights :read, users: %w(u)
653
- end
654
- }.to be_updated
655
- expect(get('/organizations/_acl')).to partially_match('read' => { 'actors' => %w(u) })
656
- expect(get('nodes/x/_acl')).to partially_match('read' => { 'actors' => %w(u) })
657
- end
658
- end
659
- end
660
-
661
- context 'ACLs on each container type' do
662
- when_the_chef_server 'has an organization named foo', :osc_compat => false, :single_org => false do
663
- organization 'foo' do
664
- user 'u', {}
665
- client 'x', {}
666
- container 'x', {}
667
- cookbook 'x', '1.0.0', {}
668
- data_bag 'x', { 'y' => {} }
669
- environment 'x', {}
670
- group 'x', {}
671
- node 'x', {}
672
- role 'x', {}
673
- sandbox 'x', {}
674
- user 'x', {}
675
- end
676
-
677
- %w(clients containers cookbooks data environments groups nodes roles sandboxes).each do |type|
678
- it "chef_acl '/organizations/foo/#{type}' changes the acl" do
679
- expect_recipe {
680
- chef_acl "/organizations/foo/#{type}" do
681
- rights :read, users: %w(u)
682
- end
683
- }.to be_updated
684
- expect(get("/organizations/foo/containers/#{type}/_acl")).to partially_match('read' => { 'actors' => %w(u) })
685
- end
686
- end
687
-
688
- %w(clients containers cookbooks data environments groups nodes roles).each do |type|
689
- it "chef_acl '/*/*/#{type}' changes the acl" do
690
- expect_recipe {
691
- chef_acl "/*/*/#{type}" do
692
- rights :read, users: %w(u)
693
- end
694
- }.to be_updated
695
- expect(get("/organizations/foo/containers/#{type}/_acl")).to partially_match('read' => { 'actors' => %w(u) })
696
- end
697
- end
698
-
699
- it "chef_acl '/*/*/*' changes the acls" do
700
- expect_recipe {
701
- chef_acl "/*/*/*" do
702
- rights :read, users: %w(u)
703
- end
704
- }.to be_updated
705
- %w(clients containers cookbooks data environments groups nodes roles sandboxes).each do |type|
706
- expect(get("/organizations/foo/containers/#{type}/_acl")).to partially_match(
707
- 'read' => { 'actors' => %w(u) })
708
- end
709
- end
710
-
711
- it 'chef_acl "/organizations/foo/data_bags" changes the acl' do
712
- expect_recipe {
713
- chef_acl '/organizations/foo/data_bags' do
714
- rights :read, users: %w(u)
715
- end
716
- }.to be_updated
717
- expect(get('/organizations/foo/containers/data/_acl')).to partially_match('read' => { 'actors' => %w(u) })
718
- end
719
-
720
- it 'chef_acl "/*/*/data_bags" changes the acl' do
721
- expect_recipe {
722
- chef_acl '/*/*/data_bags' do
723
- rights :read, users: %w(u)
724
- end
725
- }.to be_updated
726
- expect(get('/organizations/foo/containers/data/_acl')).to partially_match('read' => { 'actors' => %w(u) })
727
- end
728
- end
729
-
730
- when_the_chef_server 'has a user "u" in single org mode', :osc_compat => false do
731
- user 'u', {}
732
- client 'x', {}
733
- container 'x', {}
734
- cookbook 'x', '1.0.0', {}
735
- data_bag 'x', { 'y' => {} }
736
- environment 'x', {}
737
- group 'x', {}
738
- node 'x', {}
739
- role 'x', {}
740
- sandbox 'x', {}
741
- user 'x', {}
742
-
743
- %w(clients containers cookbooks data environments groups nodes roles sandboxes).each do |type|
744
- it "chef_acl #{type}' changes the acl" do
745
- expect_recipe {
746
- chef_acl "#{type}" do
747
- rights :read, users: %w(u)
748
- end
749
- }.to be_updated
750
- expect(get("containers/#{type}/_acl")).to partially_match('read' => { 'actors' => %w(u) })
751
- end
752
- end
753
-
754
- it "chef_acl '*' changes the acls" do
755
- expect_recipe {
756
- chef_acl "*" do
757
- rights :read, users: %w(u)
758
- end
759
- }.to be_updated
760
- %w(clients containers cookbooks data environments groups nodes roles sandboxes).each do |type|
761
- expect(get("containers/#{type}/_acl")).to partially_match(
762
- 'read' => { 'actors' => %w(u) })
763
- end
764
- end
765
- end
766
- end
767
-
768
- context 'remove_rights' do
769
- when_the_chef_server 'has a node "x" with "u", "c" and "g" in its acl', :osc_compat => false do
770
- user 'u', {}
771
- user 'u2', {}
772
- client 'c', {}
773
- client 'c2', {}
774
- group 'g', {}
775
- group 'g2', {}
776
- node 'x', {} do
777
- acl 'create' => { 'actors' => [ 'u', 'c' ], 'groups' => [ 'g' ] },
778
- 'read' => { 'actors' => [ 'u', 'c' ], 'groups' => [ 'g' ] },
779
- 'update' => { 'actors' => [ 'u', 'c' ], 'groups' => [ 'g' ] }
780
- end
781
-
782
- it 'chef_acl with remove_rights "u" removes the user\'s rights' do
783
- expect_recipe {
784
- chef_acl "nodes/x" do
785
- remove_rights :read, users: %w(u)
786
- end
787
- }.to be_updated
788
- expect(get("nodes/x/_acl")).to partially_match('read' => { 'actors' => exclude('u') })
789
- end
790
-
791
- it 'chef_acl with remove_rights "c" removes the client\'s rights' do
792
- expect_recipe {
793
- chef_acl "nodes/x" do
794
- remove_rights :read, clients: %w(c)
795
- end
796
- }.to be_updated
797
- expect(get("nodes/x/_acl")).to partially_match('read' => { 'actors' => exclude('c') })
798
- end
799
-
800
- it 'chef_acl with remove_rights "g" removes the group\'s rights' do
801
- expect_recipe {
802
- chef_acl "nodes/x" do
803
- remove_rights :read, groups: %w(g)
804
- end
805
- }.to be_updated
806
- expect(get("nodes/x/_acl")).to partially_match(
807
- 'read' => { 'groups' => exclude('g') }
808
- )
809
- end
810
-
811
- it 'chef_acl with remove_rights [ :create, :read ], "u", "c", "g" removes all three' do
812
- expect_recipe {
813
- chef_acl "nodes/x" do
814
- remove_rights [ :create, :read ], users: %w(u), clients: %w(c), groups: %w(g)
815
- end
816
- }.to be_updated
817
- expect(get("nodes/x/_acl")).to partially_match(
818
- 'create' => { 'actors' => exclude('u').and(exclude('c')), 'groups' => exclude('g') },
819
- 'read' => { 'actors' => exclude('u').and(exclude('c')), 'groups' => exclude('g') }
820
- )
821
- end
822
-
823
- it 'chef_acl with remove_rights "u2", "c2", "g2" has no effect' do
824
- expect {
825
- expect_recipe {
826
- chef_acl "nodes/x" do
827
- remove_rights :read, users: %w(u2), clients: %w(c2), groups: %w(g2)
828
- end
829
- }.to be_up_to_date
830
- }.not_to change { get("nodes/x/_acl") }
831
- end
832
- end
833
- end
834
-
835
- when_the_chef_server 'has a node named data_bags', :osc_compat => false do
836
- user 'blarghle', {}
837
- node 'data_bags', {}
838
-
839
- it 'Converging chef_acl "nodes/data_bags" with user "blarghle" adds the user' do
840
- expect_recipe {
841
- chef_acl 'nodes/data_bags' do
842
- rights :read, users: %w(blarghle)
843
- end
844
- }.to be_updated
845
- expect(get('nodes/data_bags/_acl')).to partially_match('read' => { 'actors' => %w(blarghle) })
846
- end
847
- end
848
-
849
- when_the_chef_server 'has a node named data_bags in multi-org mode', :osc_compat => false, :single_org => false do
850
- user 'blarghle', {}
851
- organization 'foo' do
852
- node 'data_bags', {}
853
- end
854
-
855
- it 'Converging chef_acl "/organizations/foo/nodes/data_bags" with user "blarghle" adds the user' do
856
- expect_recipe {
857
- chef_acl '/organizations/foo/nodes/data_bags' do
858
- rights :read, users: %w(blarghle)
859
- end
860
- }.to be_updated
861
- expect(get('/organizations/foo/nodes/data_bags/_acl')).to partially_match('read' => { 'actors' => %w(blarghle) })
862
- end
863
- end
864
-
865
- when_the_chef_server 'has a user named data_bags in multi-org mode', :osc_compat => false, :single_org => false do
866
- user 'data_bags', {}
867
- user 'blarghle', {}
868
-
869
- it 'Converging chef_acl "/users/data_bags" with user "blarghle" adds the user' do
870
- expect_recipe {
871
- chef_acl '/users/data_bags' do
872
- rights :read, users: %w(blarghle)
873
- end
874
- }.to be_updated
875
- expect(get('/users/data_bags/_acl')).to partially_match('read' => { 'actors' => %w(blarghle) })
876
- end
877
- end
878
- end
879
- end
1
+ require 'support/spec_support'
2
+ require 'cheffish/rspec/chef_run_support'
3
+ require 'chef/resource/chef_acl'
4
+ require 'chef/provider/chef_acl'
5
+ require 'chef_zero/version'
6
+ require 'uri'
7
+
8
+ if Gem::Version.new(ChefZero::VERSION) >= Gem::Version.new('3.1')
9
+ describe Chef::Resource::ChefAcl do
10
+ extend Cheffish::RSpec::ChefRunSupport
11
+
12
+ # let(:chef_config) { super().merge(log_level: :debug, stdout: STDOUT, stderr: STDERR, log_location: STDOUT) }
13
+
14
+ context "Rights attributes" do
15
+ when_the_chef_server 'has a node named x', :osc_compat => false do
16
+ node 'x', {}
17
+
18
+ it 'Converging chef_acl "nodes/x" changes nothing' do
19
+ expect_recipe {
20
+ chef_acl 'nodes/x'
21
+ }.to be_up_to_date
22
+ expect(get('nodes/x/_acl')).to partially_match({})
23
+ end
24
+
25
+ it 'Converging chef_acl "nodes/x" with "complete true" and no rights raises an error' do
26
+ expect_converge {
27
+ chef_acl 'nodes/x' do
28
+ complete true
29
+ end
30
+ }.to raise_error(RuntimeError)
31
+ end
32
+
33
+ it 'Removing all :grant rights from a node raises an error' do
34
+ expect_converge {
35
+ chef_acl 'nodes/x' do
36
+ remove_rights :grant, users: %w(pivotal), groups: %w(admins users clients)
37
+ end
38
+ }.to raise_error(RuntimeError)
39
+ end
40
+
41
+ context 'and a user "blarghle"' do
42
+ user 'blarghle', {}
43
+
44
+ it 'Converging chef_acl "nodes/x" with user "blarghle" adds the user' do
45
+ expect_recipe {
46
+ chef_acl 'nodes/x' do
47
+ rights :read, users: %w(blarghle)
48
+ end
49
+ }.to be_updated
50
+ expect(get('nodes/x/_acl')).to partially_match('read' => { 'actors' => %w(blarghle) })
51
+ end
52
+
53
+ it 'Converging chef_acl "nodes/x" with "complete true" removes all ACLs except those specified' do
54
+ expect_recipe {
55
+ chef_acl 'nodes/x' do
56
+ rights :grant, users: %w(blarghle)
57
+ complete true
58
+ end
59
+ }.to be_updated
60
+ expect(get('nodes/x/_acl')).to eq(
61
+ "create"=>{"actors"=>[], "groups"=>[]},
62
+ "read" =>{"actors"=>[], "groups"=>[]},
63
+ "update"=>{"actors"=>[], "groups"=>[]},
64
+ "delete"=>{"actors"=>[], "groups"=>[]},
65
+ "grant" =>{"actors"=>["blarghle"], "groups"=>[]}
66
+ )
67
+ end
68
+ end
69
+
70
+ it 'Converging chef_acl "nodes/x" with "complete true" removes all ACLs except those specified in :all' do
71
+ expect_recipe {
72
+ chef_acl 'nodes/x' do
73
+ rights :all, users: %w(blarghle)
74
+ complete true
75
+ end
76
+ }.to be_updated
77
+ expect(get('nodes/x/_acl')).to eq(
78
+ "create"=>{"actors"=>["blarghle"], "groups"=>[]},
79
+ "read" =>{"actors"=>["blarghle"], "groups"=>[]},
80
+ "update"=>{"actors"=>["blarghle"], "groups"=>[]},
81
+ "delete"=>{"actors"=>["blarghle"], "groups"=>[]},
82
+ "grant" =>{"actors"=>["blarghle"], "groups"=>[]}
83
+ )
84
+ end
85
+
86
+ context 'and a client "blarghle"' do
87
+ user 'blarghle', {}
88
+
89
+ it 'Converging chef_acl "nodes/x" with client "blarghle" adds the client' do
90
+ expect_recipe {
91
+ chef_acl 'nodes/x' do
92
+ rights :read, clients: %w(blarghle)
93
+ end
94
+ }.to be_updated
95
+ expect(get('nodes/x/_acl')).to partially_match('read' => { 'actors' => %w(blarghle) })
96
+ end
97
+ end
98
+
99
+ context 'and a group "blarghle"' do
100
+ group 'blarghle', {}
101
+
102
+ it 'Converging chef_acl "nodes/x" with group "blarghle" adds the group' do
103
+ expect_recipe {
104
+ chef_acl 'nodes/x' do
105
+ rights :read, groups: %w(blarghle)
106
+ end
107
+ }.to be_updated
108
+ expect(get('nodes/x/_acl')).to partially_match('read' => { 'groups' => %w(blarghle) })
109
+ end
110
+ end
111
+
112
+ context 'and multiple users and groups' do
113
+ user 'u1', {}
114
+ user 'u2', {}
115
+ user 'u3', {}
116
+ client 'c1', {}
117
+ client 'c2', {}
118
+ client 'c3', {}
119
+ group 'g1', {}
120
+ group 'g2', {}
121
+ group 'g3', {}
122
+
123
+ it 'Converging chef_acls should ignore order of the values in the acls' do
124
+ expect_recipe {
125
+ chef_acl 'nodes/x' do
126
+ rights :create, users: [ 'u1', 'u2', 'u3' ], clients: [ 'c1', 'c2', 'c3' ], groups: [ 'g1', 'g2', 'g3' ]
127
+ end
128
+ }.to be_updated
129
+ expect_recipe {
130
+ chef_acl 'nodes/x' do
131
+ rights :create, users: [ 'u2', 'u3', 'u1' ], clients: [ 'c3', 'c2', 'c1' ], groups: [ 'g1', 'g2', 'g3' ]
132
+ end
133
+ }.to be_up_to_date
134
+ end
135
+
136
+ it 'Converging chef_acl "nodes/x" with multiple groups, users and clients in an acl makes the appropriate changes' do
137
+ expect_recipe {
138
+ chef_acl 'nodes/x' do
139
+ rights :create, users: [ 'u1', 'u2', 'u3' ], clients: [ 'c1', 'c2', 'c3' ], groups: [ 'g1', 'g2', 'g3' ]
140
+ end
141
+ }.to be_updated
142
+ expect(get('nodes/x/_acl')).to partially_match(
143
+ 'create' => { 'groups' => %w(g1 g2 g3), 'actors' => %w(u1 u2 u3 c1 c2 c3) }
144
+ )
145
+ end
146
+
147
+ it 'Converging chef_acl "nodes/x" with multiple groups, users and clients across multiple "rights" groups makes the appropriate changes' do
148
+ expect_recipe {
149
+ chef_acl 'nodes/x' do
150
+ rights :create, users: %w(u1), clients: %w(c1), groups: %w(g1)
151
+ rights :create, users: %w(u2 u3), clients: %w(c2 c3), groups: %w(g2)
152
+ rights :read, users: %w(u1)
153
+ rights :read, groups: %w(g1)
154
+ end
155
+ }.to be_updated
156
+ expect(get('nodes/x/_acl')).to partially_match(
157
+ 'create' => { 'groups' => %w(g1 g2), 'actors' => %w(u1 u2 u3 c1 c2 c3) },
158
+ 'read' => { 'groups' => %w(g1), 'actors' => %w(u1) }
159
+ )
160
+ end
161
+
162
+ it 'Converging chef_acl "nodes/x" with rights [ :read, :create, :update, :delete, :grant ] modifies all rights' do
163
+ expect_recipe {
164
+ chef_acl 'nodes/x' do
165
+ rights [ :create, :read, :update, :delete, :grant ], users: %w(u1 u2), clients: %w(c1), groups: %w(g1)
166
+ end
167
+ }.to be_updated
168
+ expect(get('nodes/x/_acl')).to partially_match(
169
+ 'create' => { 'groups' => %w(g1), 'actors' => %w(u1 u2 c1) },
170
+ 'read' => { 'groups' => %w(g1), 'actors' => %w(u1 u2 c1) },
171
+ 'update' => { 'groups' => %w(g1), 'actors' => %w(u1 u2 c1) },
172
+ 'delete' => { 'groups' => %w(g1), 'actors' => %w(u1 u2 c1) },
173
+ 'grant' => { 'groups' => %w(g1), 'actors' => %w(u1 u2 c1) },
174
+ )
175
+ end
176
+
177
+ it 'Converging chef_acl "nodes/x" with rights :all modifies all rights' do
178
+ expect_recipe {
179
+ chef_acl 'nodes/x' do
180
+ rights :all, users: %w(u1 u2), clients: %w(c1), groups: %w(g1)
181
+ end
182
+ }.to be_updated
183
+ expect(get('nodes/x/_acl')).to partially_match(
184
+ 'create' => { 'groups' => %w(g1), 'actors' => %w(u1 u2 c1) },
185
+ 'read' => { 'groups' => %w(g1), 'actors' => %w(u1 u2 c1) },
186
+ 'update' => { 'groups' => %w(g1), 'actors' => %w(u1 u2 c1) },
187
+ 'delete' => { 'groups' => %w(g1), 'actors' => %w(u1 u2 c1) },
188
+ 'grant' => { 'groups' => %w(g1), 'actors' => %w(u1 u2 c1) },
189
+ )
190
+ end
191
+ end
192
+
193
+ it 'Converging chef_acl "nodes/y" throws a 404' do
194
+ expect_converge {
195
+ chef_acl 'nodes/y'
196
+ }.to raise_error(Net::HTTPServerException)
197
+ end
198
+ end
199
+
200
+ when_the_chef_server 'has a node named x with user blarghle in its acl', :osc_compat => false do
201
+ user 'blarghle', {}
202
+ node 'x', {} do
203
+ acl 'read' => { 'actors' => %w(blarghle) }
204
+ end
205
+
206
+ it 'Converging chef_acl "nodes/x" with that user changes nothing' do
207
+ expect_recipe {
208
+ chef_acl 'nodes/x' do
209
+ rights :read, users: %w(blarghle)
210
+ end
211
+ }.to be_up_to_date
212
+ expect(get('nodes/x/_acl')).to partially_match({})
213
+ end
214
+ end
215
+
216
+ when_the_chef_server 'has a node named x with users foo and bar in all its acls', :osc_compat => false do
217
+ user 'foo', {}
218
+ user 'bar', {}
219
+ node 'x', {} do
220
+ acl 'create' => { 'actors' => %w(foo bar) },
221
+ 'read' => { 'actors' => %w(foo bar) },
222
+ 'update' => { 'actors' => %w(foo bar) },
223
+ 'delete' => { 'actors' => %w(foo bar) },
224
+ 'grant' => { 'actors' => %w(foo bar) }
225
+ end
226
+
227
+ it 'Converging chef_acl "nodes/x" with remove_rights :all removes foo from everything' do
228
+ expect_recipe {
229
+ chef_acl 'nodes/x' do
230
+ remove_rights :all, users: %w(foo)
231
+ end
232
+ }.to be_updated
233
+ expect(get('nodes/x/_acl')).to partially_match(
234
+ 'create' => { 'actors' => exclude('foo') },
235
+ 'read' => { 'actors' => exclude('foo') },
236
+ 'update' => { 'actors' => exclude('foo') },
237
+ 'delete' => { 'actors' => exclude('foo') },
238
+ 'grant' => { 'actors' => exclude('foo') },
239
+ )
240
+ end
241
+ end
242
+
243
+ ::RSpec::Matchers.define_negated_matcher :exclude, :include
244
+
245
+ context 'recursive' do
246
+ when_the_chef_server 'has a nodes container with user blarghle in its acl', :osc_compat => false do
247
+ user 'blarghle', {}
248
+ acl_for 'containers/nodes', 'read' => { 'actors' => %w(blarghle) }
249
+ node 'x', {} do
250
+ acl 'read' => { 'actors' => [] }
251
+ end
252
+
253
+ it 'Converging chef_acl "nodes" makes no changes' do
254
+ expect {
255
+ expect_recipe {
256
+ chef_acl 'nodes' do
257
+ rights :read, users: %w(blarghle)
258
+ end
259
+ }.to be_up_to_date
260
+ }.to not_change { get('containers/nodes/_acl') }.
261
+ and not_change { get('nodes/x/_acl') }
262
+ end
263
+
264
+ RSpec::Matchers.define_negated_matcher :not_change, :change
265
+
266
+ it 'Converging chef_acl "nodes" with recursive :on_change makes no changes' do
267
+ expect {
268
+ expect_recipe {
269
+ chef_acl 'nodes' do
270
+ rights :read, users: %w(blarghle)
271
+ recursive :on_change
272
+ end
273
+ }.to be_up_to_date
274
+ }.to not_change { get('containers/nodes/_acl') }.
275
+ and not_change { get('nodes/x/_acl') }
276
+ end
277
+
278
+ it 'Converging chef_acl "nodes" with recursive true changes nodes/x\'s acls' do
279
+ expect_recipe {
280
+ chef_acl 'nodes' do
281
+ rights :read, users: %w(blarghle)
282
+ recursive true
283
+ end
284
+ }.to be_updated
285
+ expect(get('nodes/x/_acl')).to partially_match('read' => { 'actors' => %w(blarghle) })
286
+ end
287
+
288
+ it 'Converging chef_acl "" with recursive false does not change nodes/x\'s acls' do
289
+ expect_recipe {
290
+ chef_acl '' do
291
+ rights :read, users: %w(blarghle)
292
+ recursive false
293
+ end
294
+ }.to be_updated
295
+ expect(get('containers/nodes/_acl')).to partially_match({})
296
+ expect(get('nodes/x/_acl')).to partially_match({})
297
+ end
298
+
299
+ it 'Converging chef_acl "" with recursive :on_change does not change nodes/x\'s acls' do
300
+ expect_recipe {
301
+ chef_acl '' do
302
+ rights :read, users: %w(blarghle)
303
+ recursive :on_change
304
+ end
305
+ }.to be_updated
306
+ expect(get('containers/nodes/_acl')).to partially_match({})
307
+ expect(get('nodes/x/_acl')).to partially_match({})
308
+ end
309
+
310
+ it 'Converging chef_acl "" with recursive true changes nodes/x\'s acls' do
311
+ expect_recipe {
312
+ chef_acl '' do
313
+ rights :read, users: %w(blarghle)
314
+ recursive true
315
+ end
316
+ }.to be_updated
317
+ expect(get('/organizations/_acl')).to partially_match('read' => { 'actors' => %w(blarghle) })
318
+ expect(get('nodes/x/_acl')).to partially_match('read' => { 'actors' => %w(blarghle) })
319
+ end
320
+ end
321
+ end
322
+ end
323
+
324
+ context 'ACLs on each type of thing' do
325
+ when_the_chef_server 'has an organization named foo', :osc_compat => false, :single_org => false do
326
+ organization 'foo' do
327
+ user 'u', {}
328
+ client 'x', {}
329
+ container 'x', {}
330
+ cookbook 'x', '1.0.0', {}
331
+ data_bag 'x', { 'y' => {} }
332
+ environment 'x', {}
333
+ group 'x', {}
334
+ node 'x', {}
335
+ role 'x', {}
336
+ sandbox 'x', {}
337
+ user 'x', {}
338
+ end
339
+
340
+ organization 'bar' do
341
+ user 'u', {}
342
+ node 'x', {}
343
+ end
344
+
345
+ context 'and the chef server URL points at /organizations/foo' do
346
+ before :each do
347
+ Chef::Config.chef_server_url = URI.join(Chef::Config.chef_server_url, '/organizations/foo').to_s
348
+ end
349
+
350
+ context 'relative paths' do
351
+ it "chef_acl 'nodes/x' changes the acls" do
352
+ expect_recipe {
353
+ chef_acl "nodes/x" do
354
+ rights :read, users: %w(u)
355
+ end
356
+ }.to be_updated
357
+ expect(get("nodes/x/_acl")).to partially_match('read' => { 'actors' => %w(u) })
358
+ end
359
+
360
+ it "chef_acl '*/*' changes the acls" do
361
+ expect_recipe {
362
+ chef_acl "*/*" do
363
+ rights :read, users: %w(u)
364
+ end
365
+ }.to be_updated
366
+ %w(clients containers cookbooks data environments groups nodes roles).each do |type|
367
+ expect(get("/organizations/foo/#{type}/x/_acl")).to partially_match(
368
+ 'read' => { 'actors' => %w(u) })
369
+ end
370
+ end
371
+ end
372
+
373
+ context 'absolute paths' do
374
+ %w(clients containers cookbooks data environments groups nodes roles sandboxes).each do |type|
375
+ it "chef_acl '/organizations/foo/#{type}/x' changes the acl" do
376
+ expect_recipe {
377
+ chef_acl "/organizations/foo/#{type}/x" do
378
+ rights :read, users: %w(u)
379
+ end
380
+ }.to be_updated
381
+ expect(get("/organizations/foo/#{type}/x/_acl")).to partially_match('read' => { 'actors' => %w(u) })
382
+ end
383
+ end
384
+
385
+ %w(clients containers cookbooks data environments groups nodes roles sandboxes).each do |type|
386
+ it "chef_acl '/organizations/foo/#{type}/x' changes the acl" do
387
+ expect_recipe {
388
+ chef_acl "/organizations/foo/#{type}/x" do
389
+ rights :read, users: %w(u)
390
+ end
391
+ }.to be_updated
392
+ expect(get("/organizations/foo/#{type}/x/_acl")).to partially_match('read' => { 'actors' => %w(u) })
393
+ end
394
+ end
395
+
396
+ %w(clients containers cookbooks data environments groups nodes roles).each do |type|
397
+ it "chef_acl '/*/*/#{type}/*' changes the acl" do
398
+ expect_recipe {
399
+ chef_acl "/*/*/#{type}/*" do
400
+ rights :read, users: %w(u)
401
+ end
402
+ }.to be_updated
403
+ expect(get("/organizations/foo/#{type}/x/_acl")).to partially_match('read' => { 'actors' => %w(u) })
404
+ end
405
+ end
406
+
407
+ it "chef_acl '/*/*/*/x' changes the acls" do
408
+ expect_recipe {
409
+ chef_acl "/*/*/*/x" do
410
+ rights :read, users: %w(u)
411
+ end
412
+ }.to be_updated
413
+ %w(clients containers cookbooks data environments groups nodes roles sandboxes).each do |type|
414
+ expect(get("/organizations/foo/#{type}/x/_acl")).to partially_match(
415
+ 'read' => { 'actors' => %w(u) })
416
+ end
417
+ end
418
+
419
+ it "chef_acl '/*/*/*/*' changes the acls" do
420
+ expect_recipe {
421
+ chef_acl "/*/*/*/*" do
422
+ rights :read, users: %w(u)
423
+ end
424
+ }.to be_updated
425
+ %w(clients containers cookbooks data environments groups nodes roles).each do |type|
426
+ expect(get("/organizations/foo/#{type}/x/_acl")).to partially_match(
427
+ 'read' => { 'actors' => %w(u) })
428
+ end
429
+ end
430
+
431
+ it 'chef_acl "/organizations/foo/data_bags/x" changes the acl' do
432
+ expect_recipe {
433
+ chef_acl '/organizations/foo/data_bags/x' do
434
+ rights :read, users: %w(u)
435
+ end
436
+ }.to be_updated
437
+ expect(get('/organizations/foo/data/x/_acl')).to partially_match('read' => { 'actors' => %w(u) })
438
+ end
439
+
440
+ it 'chef_acl "/*/*/data_bags/*" changes the acl' do
441
+ expect_recipe {
442
+ chef_acl '/*/*/data_bags/*' do
443
+ rights :read, users: %w(u)
444
+ end
445
+ }.to be_updated
446
+ expect(get('/organizations/foo/data/x/_acl')).to partially_match('read' => { 'actors' => %w(u) })
447
+ end
448
+
449
+ it "chef_acl '/organizations/foo/cookbooks/x/1.0.0' raises an error" do
450
+ expect_converge {
451
+ chef_acl "/organizations/foo/cookbooks/x/1.0.0" do
452
+ rights :read, users: %w(u)
453
+ end
454
+ }.to raise_error(/ACLs cannot be set on children of \/organizations\/foo\/cookbooks\/x/)
455
+ end
456
+
457
+ it "chef_acl '/organizations/foo/cookbooks/*/*' raises an error" do
458
+ pending
459
+ expect_converge {
460
+ chef_acl "/organizations/foo/cookbooks/*/*" do
461
+ rights :read, users: %w(u)
462
+ end
463
+ }.to raise_error(/ACLs cannot be set on children of \/organizations\/foo\/cookbooks\/*/)
464
+ end
465
+
466
+ it 'chef_acl "/organizations/foo/data/x/y" raises an error' do
467
+ expect_converge {
468
+ chef_acl '/organizations/foo/data/x/y' do
469
+ rights :read, users: %w(u)
470
+ end
471
+ }.to raise_error(/ACLs cannot be set on children of \/organizations\/foo\/data\/x/)
472
+ end
473
+
474
+ it 'chef_acl "/organizations/foo/data/*/*" raises an error' do
475
+ pending
476
+ expect_converge {
477
+ chef_acl '/organizations/foo/data/*/*' do
478
+ rights :read, users: %w(u)
479
+ end
480
+ }.to raise_error(/ACLs cannot be set on children of \/organizations\/foo\/data\/*/)
481
+ end
482
+
483
+ it 'chef_acl "/organizations/foo" changes the acl' do
484
+ expect_recipe {
485
+ chef_acl '/organizations/foo' do
486
+ rights :read, users: %w(u)
487
+ end
488
+ }.to be_updated
489
+ expect(get('/organizations/foo/organizations/_acl')).to partially_match('read' => { 'actors' => %w(u) })
490
+ expect(get('/organizations/foo/nodes/x/_acl')).to partially_match('read' => { 'actors' => %w(u) })
491
+ end
492
+
493
+ it 'chef_acl "/organizations/*" changes the acl' do
494
+ expect_recipe {
495
+ chef_acl '/organizations/*' do
496
+ rights :read, users: %w(u)
497
+ end
498
+ }.to be_updated
499
+ expect(get('/organizations/foo/organizations/_acl')).to partially_match('read' => { 'actors' => %w(u) })
500
+ expect(get('/organizations/foo/nodes/x/_acl')).to partially_match('read' => { 'actors' => %w(u) })
501
+ end
502
+
503
+ it 'chef_acl "/users/x" changes the acl' do
504
+ expect_recipe {
505
+ chef_acl '/users/x' do
506
+ rights :read, users: %w(u)
507
+ end
508
+ }.to be_updated
509
+ expect(get('/users/x/_acl')).to partially_match('read' => { 'actors' => %w(u) })
510
+ end
511
+
512
+ it 'chef_acl "/users/*" changes the acl' do
513
+ expect_recipe {
514
+ chef_acl '/users/*' do
515
+ rights :read, users: %w(u)
516
+ end
517
+ }.to be_updated
518
+ expect(get('/users/x/_acl')).to partially_match('read' => { 'actors' => %w(u) })
519
+ end
520
+
521
+ it 'chef_acl "/*/x" changes the acl' do
522
+ expect_recipe {
523
+ chef_acl '/*/x' do
524
+ rights :read, users: %w(u)
525
+ end
526
+ }.to be_updated
527
+ expect(get('/users/x/_acl')).to partially_match('read' => { 'actors' => %w(u) })
528
+ end
529
+
530
+ it 'chef_acl "/*/*" changes the acl' do
531
+ expect_recipe {
532
+ chef_acl '/*/*' do
533
+ rights :read, users: %w(u)
534
+ end
535
+ }.to be_updated
536
+ expect(get('/organizations/foo/organizations/_acl')).to partially_match('read' => { 'actors' => %w(u) })
537
+ expect(get('/users/x/_acl')).to partially_match('read' => { 'actors' => %w(u) })
538
+ end
539
+ end
540
+ end
541
+
542
+ context 'and the chef server URL points at /organizations/bar' do
543
+ before :each do
544
+ Chef::Config.chef_server_url = URI.join(Chef::Config.chef_server_url.to_s, '/organizations/bar').to_s
545
+ end
546
+
547
+ it "chef_acl '/organizations/foo/nodes/*' changes the acl" do
548
+ expect_recipe {
549
+ chef_acl "/organizations/foo/nodes/*" do
550
+ rights :read, users: %w(u)
551
+ end
552
+ }.to be_updated
553
+ expect(get("/organizations/foo/nodes/x/_acl")).to partially_match('read' => { 'actors' => %w(u) })
554
+ end
555
+ end
556
+
557
+ context 'and the chef server URL points at /' do
558
+ before :each do
559
+ Chef::Config.chef_server_url = URI.join(Chef::Config.chef_server_url.to_s, '/').to_s
560
+ end
561
+
562
+ it "chef_acl '/organizations/foo/nodes/*' changes the acl" do
563
+ expect_recipe {
564
+ chef_acl "/organizations/foo/nodes/*" do
565
+ rights :read, users: %w(u)
566
+ end
567
+ }.to be_updated
568
+ expect(get("/organizations/foo/nodes/x/_acl")).to partially_match('read' => { 'actors' => %w(u) })
569
+ end
570
+ end
571
+ end
572
+
573
+ when_the_chef_server 'has a user "u" in single org mode', :osc_compat => false do
574
+ user 'u', {}
575
+ client 'x', {}
576
+ container 'x', {}
577
+ cookbook 'x', '1.0.0', {}
578
+ data_bag 'x', { 'y' => {} }
579
+ environment 'x', {}
580
+ group 'x', {}
581
+ node 'x', {}
582
+ role 'x', {}
583
+ sandbox 'x', {}
584
+ user 'x', {}
585
+
586
+ %w(clients containers cookbooks data environments groups nodes roles sandboxes).each do |type|
587
+ it "chef_acl #{type}/x' changes the acl" do
588
+ expect_recipe {
589
+ chef_acl "#{type}/x" do
590
+ rights :read, users: %w(u)
591
+ end
592
+ }.to be_updated
593
+ expect(get("#{type}/x/_acl")).to partially_match('read' => { 'actors' => %w(u) })
594
+ end
595
+ end
596
+
597
+ %w(clients containers cookbooks data environments groups nodes roles).each do |type|
598
+ it "chef_acl '#{type}/*' changes the acl" do
599
+ expect_recipe {
600
+ chef_acl "#{type}/*" do
601
+ rights :read, users: %w(u)
602
+ end
603
+ }.to be_updated
604
+ expect(get("#{type}/x/_acl")).to partially_match('read' => { 'actors' => %w(u) })
605
+ end
606
+ end
607
+
608
+ it "chef_acl '*/x' changes the acls" do
609
+ expect_recipe {
610
+ chef_acl "*/x" do
611
+ rights :read, users: %w(u)
612
+ end
613
+ }.to be_updated
614
+ %w(clients containers cookbooks data environments groups nodes roles sandboxes).each do |type|
615
+ expect(get("#{type}/x/_acl")).to partially_match(
616
+ 'read' => { 'actors' => %w(u) })
617
+ end
618
+ end
619
+
620
+ it "chef_acl '*/*' changes the acls" do
621
+ expect_recipe {
622
+ chef_acl "*/*" do
623
+ rights :read, users: %w(u)
624
+ end
625
+ }.to be_updated
626
+ %w(clients containers cookbooks data environments groups nodes roles).each do |type|
627
+ expect(get("#{type}/x/_acl")).to partially_match(
628
+ 'read' => { 'actors' => %w(u) })
629
+ end
630
+ end
631
+
632
+ it "chef_acl 'groups/*' changes the acl" do
633
+ expect_recipe {
634
+ chef_acl "groups/*" do
635
+ rights :read, users: %w(u)
636
+ end
637
+ }.to be_updated
638
+ %w(admins billing-admins clients users x).each do |n|
639
+ expect(get("groups/#{n}/_acl")).to partially_match(
640
+ 'read' => { 'actors' => %w(u) })
641
+ end
642
+ end
643
+
644
+ it 'chef_acl "data_bags/x" changes the acl' do
645
+ expect_recipe {
646
+ chef_acl 'data_bags/x' do
647
+ rights :read, users: %w(u)
648
+ end
649
+ }.to be_updated
650
+ expect(get('data/x/_acl')).to partially_match('read' => { 'actors' => %w(u) })
651
+ end
652
+
653
+ it 'chef_acl "data_bags/*" changes the acl' do
654
+ expect_recipe {
655
+ chef_acl 'data_bags/*' do
656
+ rights :read, users: %w(u)
657
+ end
658
+ }.to be_updated
659
+ expect(get('data/x/_acl')).to partially_match('read' => { 'actors' => %w(u) })
660
+ end
661
+
662
+ it 'chef_acl "" changes the organization acl' do
663
+ expect_recipe {
664
+ chef_acl '' do
665
+ rights :read, users: %w(u)
666
+ end
667
+ }.to be_updated
668
+ expect(get('/organizations/_acl')).to partially_match('read' => { 'actors' => %w(u) })
669
+ expect(get('nodes/x/_acl')).to partially_match('read' => { 'actors' => %w(u) })
670
+ end
671
+ end
672
+ end
673
+
674
+ context 'ACLs on each container type' do
675
+ when_the_chef_server 'has an organization named foo', :osc_compat => false, :single_org => false do
676
+ organization 'foo' do
677
+ user 'u', {}
678
+ client 'x', {}
679
+ container 'x', {}
680
+ cookbook 'x', '1.0.0', {}
681
+ data_bag 'x', { 'y' => {} }
682
+ environment 'x', {}
683
+ group 'x', {}
684
+ node 'x', {}
685
+ role 'x', {}
686
+ sandbox 'x', {}
687
+ user 'x', {}
688
+ end
689
+
690
+ %w(clients containers cookbooks data environments groups nodes roles sandboxes).each do |type|
691
+ it "chef_acl '/organizations/foo/#{type}' changes the acl" do
692
+ expect_recipe {
693
+ chef_acl "/organizations/foo/#{type}" do
694
+ rights :read, users: %w(u)
695
+ end
696
+ }.to be_updated
697
+ expect(get("/organizations/foo/containers/#{type}/_acl")).to partially_match('read' => { 'actors' => %w(u) })
698
+ end
699
+ end
700
+
701
+ %w(clients containers cookbooks data environments groups nodes roles).each do |type|
702
+ it "chef_acl '/*/*/#{type}' changes the acl" do
703
+ expect_recipe {
704
+ chef_acl "/*/*/#{type}" do
705
+ rights :read, users: %w(u)
706
+ end
707
+ }.to be_updated
708
+ expect(get("/organizations/foo/containers/#{type}/_acl")).to partially_match('read' => { 'actors' => %w(u) })
709
+ end
710
+ end
711
+
712
+ it "chef_acl '/*/*/*' changes the acls" do
713
+ expect_recipe {
714
+ chef_acl "/*/*/*" do
715
+ rights :read, users: %w(u)
716
+ end
717
+ }.to be_updated
718
+ %w(clients containers cookbooks data environments groups nodes roles sandboxes).each do |type|
719
+ expect(get("/organizations/foo/containers/#{type}/_acl")).to partially_match(
720
+ 'read' => { 'actors' => %w(u) })
721
+ end
722
+ end
723
+
724
+ it 'chef_acl "/organizations/foo/data_bags" changes the acl' do
725
+ expect_recipe {
726
+ chef_acl '/organizations/foo/data_bags' do
727
+ rights :read, users: %w(u)
728
+ end
729
+ }.to be_updated
730
+ expect(get('/organizations/foo/containers/data/_acl')).to partially_match('read' => { 'actors' => %w(u) })
731
+ end
732
+
733
+ it 'chef_acl "/*/*/data_bags" changes the acl' do
734
+ expect_recipe {
735
+ chef_acl '/*/*/data_bags' do
736
+ rights :read, users: %w(u)
737
+ end
738
+ }.to be_updated
739
+ expect(get('/organizations/foo/containers/data/_acl')).to partially_match('read' => { 'actors' => %w(u) })
740
+ end
741
+ end
742
+
743
+ when_the_chef_server 'has a user "u" in single org mode', :osc_compat => false do
744
+ user 'u', {}
745
+ client 'x', {}
746
+ container 'x', {}
747
+ cookbook 'x', '1.0.0', {}
748
+ data_bag 'x', { 'y' => {} }
749
+ environment 'x', {}
750
+ group 'x', {}
751
+ node 'x', {}
752
+ role 'x', {}
753
+ sandbox 'x', {}
754
+ user 'x', {}
755
+
756
+ %w(clients containers cookbooks data environments groups nodes roles sandboxes).each do |type|
757
+ it "chef_acl #{type}' changes the acl" do
758
+ expect_recipe {
759
+ chef_acl "#{type}" do
760
+ rights :read, users: %w(u)
761
+ end
762
+ }.to be_updated
763
+ expect(get("containers/#{type}/_acl")).to partially_match('read' => { 'actors' => %w(u) })
764
+ end
765
+ end
766
+
767
+ it "chef_acl '*' changes the acls" do
768
+ expect_recipe {
769
+ chef_acl "*" do
770
+ rights :read, users: %w(u)
771
+ end
772
+ }.to be_updated
773
+ %w(clients containers cookbooks data environments groups nodes roles sandboxes).each do |type|
774
+ expect(get("containers/#{type}/_acl")).to partially_match(
775
+ 'read' => { 'actors' => %w(u) })
776
+ end
777
+ end
778
+ end
779
+ end
780
+
781
+ context 'remove_rights' do
782
+ when_the_chef_server 'has a node "x" with "u", "c" and "g" in its acl', :osc_compat => false do
783
+ user 'u', {}
784
+ user 'u2', {}
785
+ client 'c', {}
786
+ client 'c2', {}
787
+ group 'g', {}
788
+ group 'g2', {}
789
+ node 'x', {} do
790
+ acl 'create' => { 'actors' => [ 'u', 'c' ], 'groups' => [ 'g' ] },
791
+ 'read' => { 'actors' => [ 'u', 'c' ], 'groups' => [ 'g' ] },
792
+ 'update' => { 'actors' => [ 'u', 'c' ], 'groups' => [ 'g' ] }
793
+ end
794
+
795
+ it 'chef_acl with remove_rights "u" removes the user\'s rights' do
796
+ expect_recipe {
797
+ chef_acl "nodes/x" do
798
+ remove_rights :read, users: %w(u)
799
+ end
800
+ }.to be_updated
801
+ expect(get("nodes/x/_acl")).to partially_match('read' => { 'actors' => exclude('u') })
802
+ end
803
+
804
+ it 'chef_acl with remove_rights "c" removes the client\'s rights' do
805
+ expect_recipe {
806
+ chef_acl "nodes/x" do
807
+ remove_rights :read, clients: %w(c)
808
+ end
809
+ }.to be_updated
810
+ expect(get("nodes/x/_acl")).to partially_match('read' => { 'actors' => exclude('c') })
811
+ end
812
+
813
+ it 'chef_acl with remove_rights "g" removes the group\'s rights' do
814
+ expect_recipe {
815
+ chef_acl "nodes/x" do
816
+ remove_rights :read, groups: %w(g)
817
+ end
818
+ }.to be_updated
819
+ expect(get("nodes/x/_acl")).to partially_match(
820
+ 'read' => { 'groups' => exclude('g') }
821
+ )
822
+ end
823
+
824
+ it 'chef_acl with remove_rights [ :create, :read ], "u", "c", "g" removes all three' do
825
+ expect_recipe {
826
+ chef_acl "nodes/x" do
827
+ remove_rights [ :create, :read ], users: %w(u), clients: %w(c), groups: %w(g)
828
+ end
829
+ }.to be_updated
830
+ expect(get("nodes/x/_acl")).to partially_match(
831
+ 'create' => { 'actors' => exclude('u').and(exclude('c')), 'groups' => exclude('g') },
832
+ 'read' => { 'actors' => exclude('u').and(exclude('c')), 'groups' => exclude('g') }
833
+ )
834
+ end
835
+
836
+ it 'chef_acl with remove_rights "u2", "c2", "g2" has no effect' do
837
+ expect {
838
+ expect_recipe {
839
+ chef_acl "nodes/x" do
840
+ remove_rights :read, users: %w(u2), clients: %w(c2), groups: %w(g2)
841
+ end
842
+ }.to be_up_to_date
843
+ }.not_to change { get("nodes/x/_acl") }
844
+ end
845
+ end
846
+ end
847
+
848
+ when_the_chef_server 'has a node named data_bags', :osc_compat => false do
849
+ user 'blarghle', {}
850
+ node 'data_bags', {}
851
+
852
+ it 'Converging chef_acl "nodes/data_bags" with user "blarghle" adds the user' do
853
+ expect_recipe {
854
+ chef_acl 'nodes/data_bags' do
855
+ rights :read, users: %w(blarghle)
856
+ end
857
+ }.to be_updated
858
+ expect(get('nodes/data_bags/_acl')).to partially_match('read' => { 'actors' => %w(blarghle) })
859
+ end
860
+ end
861
+
862
+ when_the_chef_server 'has a node named data_bags in multi-org mode', :osc_compat => false, :single_org => false do
863
+ user 'blarghle', {}
864
+ organization 'foo' do
865
+ node 'data_bags', {}
866
+ end
867
+
868
+ it 'Converging chef_acl "/organizations/foo/nodes/data_bags" with user "blarghle" adds the user' do
869
+ expect_recipe {
870
+ chef_acl '/organizations/foo/nodes/data_bags' do
871
+ rights :read, users: %w(blarghle)
872
+ end
873
+ }.to be_updated
874
+ expect(get('/organizations/foo/nodes/data_bags/_acl')).to partially_match('read' => { 'actors' => %w(blarghle) })
875
+ end
876
+ end
877
+
878
+ when_the_chef_server 'has a user named data_bags in multi-org mode', :osc_compat => false, :single_org => false do
879
+ user 'data_bags', {}
880
+ user 'blarghle', {}
881
+
882
+ it 'Converging chef_acl "/users/data_bags" with user "blarghle" adds the user' do
883
+ expect_recipe {
884
+ chef_acl '/users/data_bags' do
885
+ rights :read, users: %w(blarghle)
886
+ end
887
+ }.to be_updated
888
+ expect(get('/users/data_bags/_acl')).to partially_match('read' => { 'actors' => %w(blarghle) })
889
+ end
890
+ end
891
+ end
892
+ end