chef 0.10.8 → 0.10.10.beta.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (197) hide show
  1. data/distro/arch/etc/rc.d/chef-client +15 -1
  2. data/distro/common/html/chef-client.8.html +4 -4
  3. data/distro/common/html/chef-expander.8.html +4 -4
  4. data/distro/common/html/chef-expanderctl.8.html +4 -4
  5. data/distro/common/html/chef-server-webui.8.html +4 -4
  6. data/distro/common/html/chef-server.8.html +4 -4
  7. data/distro/common/html/chef-solo.8.html +4 -4
  8. data/distro/common/html/chef-solr.8.html +4 -4
  9. data/distro/common/html/knife-bootstrap.1.html +6 -10
  10. data/distro/common/html/knife-client.1.html +4 -4
  11. data/distro/common/html/knife-configure.1.html +4 -4
  12. data/distro/common/html/knife-cookbook-site.1.html +6 -6
  13. data/distro/common/html/knife-cookbook.1.html +4 -4
  14. data/distro/common/html/knife-data-bag.1.html +4 -4
  15. data/distro/common/html/knife-environment.1.html +4 -4
  16. data/distro/common/html/knife-exec.1.html +4 -4
  17. data/distro/common/html/knife-index.1.html +4 -4
  18. data/distro/common/html/knife-node.1.html +5 -5
  19. data/distro/common/html/knife-role.1.html +4 -4
  20. data/distro/common/html/knife-search.1.html +4 -4
  21. data/distro/common/html/knife-ssh.1.html +5 -6
  22. data/distro/common/html/knife-status.1.html +4 -4
  23. data/distro/common/html/knife-tag.1.html +4 -4
  24. data/distro/common/html/knife.1.html +7 -8
  25. data/distro/common/html/shef.1.html +4 -4
  26. data/distro/common/man/man1/knife-bootstrap.1 +4 -4
  27. data/distro/common/man/man1/knife-client.1 +1 -1
  28. data/distro/common/man/man1/knife-configure.1 +1 -1
  29. data/distro/common/man/man1/knife-cookbook-site.1 +4 -4
  30. data/distro/common/man/man1/knife-cookbook.1 +1 -1
  31. data/distro/common/man/man1/knife-data-bag.1 +1 -1
  32. data/distro/common/man/man1/knife-environment.1 +1 -1
  33. data/distro/common/man/man1/knife-exec.1 +1 -1
  34. data/distro/common/man/man1/knife-index.1 +1 -1
  35. data/distro/common/man/man1/knife-node.1 +2 -2
  36. data/distro/common/man/man1/knife-role.1 +1 -1
  37. data/distro/common/man/man1/knife-search.1 +1 -1
  38. data/distro/common/man/man1/knife-ssh.1 +3 -7
  39. data/distro/common/man/man1/knife-status.1 +1 -1
  40. data/distro/common/man/man1/knife-tag.1 +1 -1
  41. data/distro/common/man/man1/knife.1 +5 -9
  42. data/distro/common/man/man1/shef.1 +1 -1
  43. data/distro/common/man/man8/chef-client.8 +1 -1
  44. data/distro/common/man/man8/chef-expander.8 +1 -1
  45. data/distro/common/man/man8/chef-expanderctl.8 +1 -1
  46. data/distro/common/man/man8/chef-server-webui.8 +1 -1
  47. data/distro/common/man/man8/chef-server.8 +1 -1
  48. data/distro/common/man/man8/chef-solo.8 +1 -1
  49. data/distro/common/man/man8/chef-solr.8 +1 -1
  50. data/distro/common/markdown/man1/knife-bootstrap.mkd +3 -7
  51. data/distro/common/markdown/man1/knife-cookbook-site.mkd +3 -3
  52. data/distro/common/markdown/man1/knife-node.mkd +2 -2
  53. data/distro/common/markdown/man1/knife-ssh.mkd +2 -5
  54. data/distro/common/markdown/man1/knife.mkd +7 -9
  55. data/distro/debian/etc/init.d/chef-client +22 -1
  56. data/distro/redhat/etc/init.d/chef-client +12 -1
  57. data/distro/windows/service_manager.rb +164 -0
  58. data/lib/chef/application.rb +12 -6
  59. data/lib/chef/application/client.rb +4 -3
  60. data/lib/chef/application/knife.rb +7 -12
  61. data/lib/chef/application/solo.rb +2 -1
  62. data/lib/chef/application/windows_service.rb +224 -0
  63. data/lib/chef/checksum_cache.rb +1 -0
  64. data/lib/chef/client.rb +3 -16
  65. data/lib/chef/config.rb +42 -13
  66. data/lib/chef/cookbook/metadata.rb +1 -1
  67. data/lib/chef/cookbook/syntax_check.rb +2 -2
  68. data/lib/chef/cookbook_version.rb +5 -0
  69. data/lib/chef/daemon.rb +1 -1
  70. data/lib/chef/exceptions.rb +7 -1
  71. data/lib/chef/file_access_control.rb +13 -87
  72. data/lib/chef/file_access_control/unix.rb +119 -0
  73. data/lib/chef/file_access_control/windows.rb +257 -0
  74. data/lib/chef/handler/json_file.rb +7 -1
  75. data/lib/chef/knife.rb +10 -16
  76. data/lib/chef/knife/bootstrap.rb +15 -8
  77. data/lib/chef/knife/bootstrap/centos5-gems.erb +1 -1
  78. data/lib/chef/knife/bootstrap/chef-full.erb +59 -0
  79. data/lib/chef/knife/bootstrap/ubuntu10.04-apt.erb +1 -0
  80. data/lib/chef/knife/configure.rb +2 -2
  81. data/lib/chef/knife/cookbook_site_download.rb +60 -21
  82. data/lib/chef/knife/cookbook_site_install.rb +16 -21
  83. data/lib/chef/knife/cookbook_upload.rb +77 -48
  84. data/lib/chef/knife/core/bootstrap_context.rb +3 -1
  85. data/lib/chef/knife/core/cookbook_scm_repo.rb +1 -1
  86. data/lib/chef/knife/core/node_editor.rb +1 -1
  87. data/lib/chef/knife/core/subcommand_loader.rb +1 -1
  88. data/lib/chef/knife/core/ui.rb +3 -2
  89. data/lib/chef/knife/help_topics.rb +1 -1
  90. data/lib/chef/knife/node_run_list_add.rb +14 -6
  91. data/lib/chef/knife/node_run_list_remove.rb +3 -3
  92. data/lib/chef/knife/ssh.rb +32 -13
  93. data/lib/chef/mash.rb +14 -0
  94. data/lib/chef/mixin/command.rb +1 -0
  95. data/lib/chef/mixin/command/unix.rb +5 -0
  96. data/lib/chef/mixin/convert_to_class_name.rb +2 -0
  97. data/lib/chef/mixin/deep_merge.rb +40 -18
  98. data/lib/chef/mixin/enforce_ownership_and_permissions.rb +39 -0
  99. data/lib/chef/mixin/language.rb +89 -3
  100. data/lib/chef/mixin/language_include_recipe.rb +8 -4
  101. data/lib/chef/mixin/path_sanity.rb +67 -0
  102. data/lib/chef/mixin/recipe_definition_dsl_core.rb +19 -11
  103. data/lib/chef/mixin/securable.rb +152 -0
  104. data/lib/chef/mixin/shell_out.rb +1 -1
  105. data/lib/chef/mixin/template.rb +8 -3
  106. data/lib/chef/mixins.rb +3 -0
  107. data/lib/chef/monkey_patches/moneta.rb +50 -0
  108. data/lib/chef/monkey_patches/string.rb +1 -1
  109. data/lib/chef/node.rb +2 -1
  110. data/lib/chef/platform.rb +34 -0
  111. data/lib/chef/provider.rb +23 -21
  112. data/lib/chef/provider/cron.rb +17 -12
  113. data/lib/chef/provider/cron/solaris.rb +6 -18
  114. data/lib/chef/provider/deploy.rb +14 -15
  115. data/lib/chef/provider/deploy/timestamped.rb +0 -1
  116. data/lib/chef/provider/directory.rb +1 -3
  117. data/lib/chef/provider/execute.rb +2 -2
  118. data/lib/chef/provider/file.rb +1 -75
  119. data/lib/chef/provider/git.rb +11 -9
  120. data/lib/chef/provider/group/gpasswd.rb +14 -9
  121. data/lib/chef/provider/link.rb +28 -59
  122. data/lib/chef/provider/mdadm.rb +2 -2
  123. data/lib/chef/provider/mount/mount.rb +1 -1
  124. data/lib/chef/provider/package.rb +10 -6
  125. data/lib/chef/provider/package/apt.rb +3 -1
  126. data/lib/chef/provider/package/dpkg.rb +1 -1
  127. data/lib/chef/provider/package/portage.rb +6 -3
  128. data/lib/chef/provider/package/rubygems.rb +75 -6
  129. data/lib/chef/provider/package/smartos.rb +84 -0
  130. data/lib/chef/provider/package/yum-dump.py +3 -2
  131. data/lib/chef/provider/package/yum.rb +51 -10
  132. data/lib/chef/provider/remote_directory.rb +24 -3
  133. data/lib/chef/provider/remote_file.rb +0 -6
  134. data/lib/chef/provider/route.rb +3 -3
  135. data/lib/chef/provider/service/debian.rb +2 -2
  136. data/lib/chef/provider/service/freebsd.rb +1 -1
  137. data/lib/chef/provider/service/macosx.rb +125 -0
  138. data/lib/chef/provider/service/windows.rb +5 -1
  139. data/lib/chef/provider/subversion.rb +10 -7
  140. data/lib/chef/providers.rb +3 -0
  141. data/lib/chef/resource.rb +181 -87
  142. data/lib/chef/resource/apt_package.rb +10 -1
  143. data/lib/chef/resource/chef_gem.rb +53 -0
  144. data/lib/chef/resource/conditional.rb +3 -0
  145. data/lib/chef/resource/cookbook_file.rb +12 -6
  146. data/lib/chef/resource/cron.rb +9 -0
  147. data/lib/chef/resource/directory.rb +14 -31
  148. data/lib/chef/resource/execute.rb +11 -9
  149. data/lib/chef/resource/file.rb +9 -33
  150. data/lib/chef/resource/link.rb +13 -8
  151. data/lib/chef/resource/mdadm.rb +10 -1
  152. data/lib/chef/resource/remote_directory.rb +13 -2
  153. data/lib/chef/resource/remote_file.rb +14 -7
  154. data/lib/chef/resource/smartos_package.rb +36 -0
  155. data/lib/chef/resource/template.rb +12 -5
  156. data/lib/chef/resource_platform_map.rb +153 -0
  157. data/lib/chef/resources.rb +2 -0
  158. data/lib/chef/rest.rb +55 -10
  159. data/lib/chef/rest/auth_credentials.rb +1 -0
  160. data/lib/chef/rest/rest_request.rb +24 -8
  161. data/lib/chef/role.rb +8 -2
  162. data/lib/chef/run_list.rb +1 -1
  163. data/lib/chef/run_list/run_list_expansion.rb +2 -2
  164. data/lib/chef/run_list/run_list_item.rb +7 -0
  165. data/lib/chef/runner.rb +4 -0
  166. data/lib/chef/shef.rb +2 -2
  167. data/lib/chef/shef/shef_session.rb +4 -5
  168. data/lib/chef/shell_out.rb +2 -245
  169. data/lib/chef/util/file_edit.rb +99 -89
  170. data/lib/chef/version.rb +1 -1
  171. data/lib/chef/win32/api.rb +349 -0
  172. data/lib/chef/win32/api/error.rb +921 -0
  173. data/lib/chef/win32/api/file.rb +289 -0
  174. data/lib/chef/win32/api/memory.rb +105 -0
  175. data/lib/chef/win32/api/process.rb +40 -0
  176. data/lib/chef/win32/api/psapi.rb +51 -0
  177. data/lib/chef/win32/api/security.rb +341 -0
  178. data/lib/chef/win32/api/system.rb +192 -0
  179. data/lib/chef/win32/api/unicode.rb +178 -0
  180. data/lib/chef/win32/error.rb +73 -0
  181. data/lib/chef/win32/file.rb +117 -0
  182. data/lib/chef/win32/file/info.rb +100 -0
  183. data/lib/chef/win32/handle.rb +48 -0
  184. data/lib/chef/win32/memory.rb +101 -0
  185. data/lib/chef/win32/process.rb +84 -0
  186. data/lib/chef/win32/security.rb +489 -0
  187. data/lib/chef/win32/security/ace.rb +125 -0
  188. data/lib/chef/win32/security/acl.rb +101 -0
  189. data/lib/chef/win32/security/securable_object.rb +109 -0
  190. data/lib/chef/win32/security/security_descriptor.rb +93 -0
  191. data/lib/chef/win32/security/sid.rb +199 -0
  192. data/lib/chef/win32/security/token.rb +64 -0
  193. data/lib/chef/win32/unicode.rb +43 -0
  194. data/lib/chef/win32/version.rb +119 -0
  195. metadata +104 -158
  196. data/lib/chef/shell_out/unix.rb +0 -223
  197. data/lib/chef/shell_out/windows.rb +0 -588
@@ -91,7 +91,7 @@ class Chef
91
91
  #
92
92
  # === Returns
93
93
  # metadata<Chef::Cookbook::Metadata>
94
- def initialize(cookbook=nil, maintainer='Your Name', maintainer_email='youremail@example.com', license='Apache v2.0')
94
+ def initialize(cookbook=nil, maintainer='YOUR_COMPANY_NAME', maintainer_email='YOUR_EMAIL', license='none')
95
95
  @cookbook = cookbook
96
96
  @name = cookbook ? cookbook.name : ""
97
97
  @long_description = ""
@@ -112,7 +112,7 @@ class Chef
112
112
  result = shell_out("erubis -x #{erb_file} | ruby -c")
113
113
  result.error!
114
114
  true
115
- rescue Chef::Exceptions::ShellCommandFailed
115
+ rescue Mixlib::ShellOut::ShellCommandFailed
116
116
  file_relative_path = erb_file[/^#{Regexp.escape(cookbook_path+File::Separator)}(.*)/, 1]
117
117
  Chef::Log.fatal("Erb template #{file_relative_path} has a syntax error:")
118
118
  result.stderr.each_line { |l| Chef::Log.fatal(l.chomp) }
@@ -124,7 +124,7 @@ class Chef
124
124
  result = shell_out("ruby -c #{ruby_file}")
125
125
  result.error!
126
126
  true
127
- rescue Chef::Exceptions::ShellCommandFailed
127
+ rescue Mixlib::ShellOut::ShellCommandFailed
128
128
  file_relative_path = ruby_file[/^#{Regexp.escape(cookbook_path+File::Separator)}(.*)/, 1]
129
129
  Chef::Log.fatal("Cookbook file #{file_relative_path} has a ruby syntax error:")
130
130
  result.stderr.each_line { |l| Chef::Log.fatal(l.chomp) }
@@ -875,10 +875,15 @@ class Chef
875
875
  chef_server_rest.get_rest("cookbooks/#{name}/#{version}")
876
876
  end
877
877
 
878
+ # The API returns only a single version of each cookbook in the result from the cookbooks method
878
879
  def self.list
879
880
  chef_server_rest.get_rest('cookbooks')
880
881
  end
881
882
 
883
+ def self.list_all_versions
884
+ chef_server_rest.get_rest('cookbooks?num_versions=all')
885
+ end
886
+
882
887
  ##
883
888
  # Given a +cookbook_name+, get a list of all versions that exist on the
884
889
  # server.
@@ -40,7 +40,7 @@ class Chef
40
40
  exit if fork
41
41
  Process.setsid
42
42
  exit if fork
43
- Chef::Log.info("Forked, in #{Process.pid}. Priveleges: #{Process.euid} #{Process.egid}")
43
+ Chef::Log.info("Forked, in #{Process.pid}. Privileges: #{Process.euid} #{Process.egid}")
44
44
  File.umask Chef::Config[:umask]
45
45
  $stdin.reopen("/dev/null")
46
46
  $stdout.reopen("/dev/null", "a")
@@ -49,6 +49,7 @@ class Chef
49
49
  class ConfigurationError < ArgumentError; end
50
50
  class RedirectLimitExceeded < RuntimeError; end
51
51
  class AmbiguousRunlistSpecification < ArgumentError; end
52
+ class CookbookFrozen < ArgumentError; end
52
53
  class CookbookNotFound < RuntimeError; end
53
54
  # Cookbook loader used to raise an argument error when cookbook not found.
54
55
  # for back compat, need to raise an error that inherits from ArgumentError
@@ -56,7 +57,6 @@ class Chef
56
57
  class AttributeNotFound < RuntimeError; end
57
58
  class InvalidCommandOption < RuntimeError; end
58
59
  class CommandTimeout < RuntimeError; end
59
- class ShellCommandFailed < RuntimeError; end
60
60
  class RequestedUIDUnavailable < RuntimeError; end
61
61
  class InvalidHomeDirectory < ArgumentError; end
62
62
  class DsclCommandFailed < RuntimeError; end
@@ -74,6 +74,8 @@ class Chef
74
74
  class InvalidDataBagItemID < ArgumentError; end
75
75
  class InvalidDataBagName < ArgumentError; end
76
76
  class EnclosingDirectoryDoesNotExist < ArgumentError; end
77
+ # Errors originating from calls to the Win32 API
78
+ class Win32APIError < RuntimeError; end
77
79
 
78
80
  class ObsoleteDependencySyntax < ArgumentError; end
79
81
  class InvalidDataBagPath < ArgumentError; end
@@ -89,6 +91,10 @@ class Chef
89
91
  # match OP VERSION. ArgumentError?
90
92
  class InvalidVersionConstraint < ArgumentError; end
91
93
 
94
+ # Backcompat with Chef::ShellOut code:
95
+ require 'mixlib/shellout/exceptions'
96
+ class ShellCommandFailed < Mixlib::ShellOut::ShellCommandFailed; end
97
+
92
98
  class CookbookVersionSelection
93
99
 
94
100
  # Compound exception: In run_list expansion and resolution,
@@ -25,13 +25,18 @@ class Chef
25
25
  # FileAccessControl objects set the owner, group and mode of +file+ to
26
26
  # the values specified by a value object, usually a Chef::Resource.
27
27
  class FileAccessControl
28
- UINT = (1 << 32)
29
- UID_MAX = (1 << 32) - 10
30
-
28
+
29
+ if RUBY_PLATFORM =~ /mswin|mingw|windows/
30
+ require 'chef/file_access_control/windows'
31
+ include FileAccessControl::Windows
32
+ else
33
+ require 'chef/file_access_control/unix'
34
+ include FileAccessControl::Unix
35
+ end
36
+
31
37
  attr_reader :resource
32
-
33
38
  attr_reader :file
34
-
39
+
35
40
  # FileAccessControl objects set the owner, group and mode of +file+ to
36
41
  # the values specified by +resource+. +file+ is completely independent
37
42
  # of any file or path attribute on +resource+, so it is possible to set
@@ -46,92 +51,13 @@ class Chef
46
51
  @resource, @file = resource, file
47
52
  @modified = false
48
53
  end
49
-
54
+
50
55
  def modified?
51
56
  @modified
52
57
  end
53
-
54
- def set_all
55
- set_owner
56
- set_group
57
- set_mode
58
- end
59
-
60
- # Workaround the fact that Ruby's Etc module doesn't believe in negative
61
- # uids, so negative uids show up as the diminished radix complement of
62
- # a uint. For example, a uid of -2 is reported as 4294967294
63
- def diminished_radix_complement(int)
64
- if int > UID_MAX
65
- int - UINT
66
- else
67
- int
68
- end
69
- end
70
-
71
- def target_uid
72
- return nil if resource.owner.nil?
73
- if resource.owner.kind_of?(String)
74
- diminished_radix_complement( Etc.getpwnam(resource.owner).uid )
75
- elsif resource.owner.kind_of?(Integer)
76
- resource.owner
77
- else
78
- Chef::Log.error("The `owner` parameter of the #@resource resource is set to an invalid value (#{resource.owner.inspect})")
79
- raise ArgumentError, "cannot resolve #{resource.owner.inspect} to uid, owner must be a string or integer"
80
- end
81
- rescue ArgumentError
82
- raise Chef::Exceptions::UserIDNotFound, "cannot determine user id for '#{resource.owner}', does the user exist on this system?"
83
- end
84
-
85
- def set_owner
86
- if (uid = target_uid) && (uid != stat.uid)
87
- File.chown(uid, nil, file)
88
- Chef::Log.info("#{log_string} owner changed to #{uid}")
89
- modified
90
- end
91
- end
92
-
93
- def target_gid
94
- return nil if resource.group.nil?
95
- if resource.group.kind_of?(String)
96
- diminished_radix_complement( Etc.getgrnam(resource.group).gid )
97
- elsif resource.group.kind_of?(Integer)
98
- resource.group
99
- else
100
- Chef::Log.error("The `group` parameter of the #@resource resource is set to an invalid value (#{resource.owner.inspect})")
101
- raise ArgumentError, "cannot resolve #{resource.group.inspect} to gid, group must be a string or integer"
102
- end
103
- rescue ArgumentError
104
- raise Chef::Exceptions::GroupIDNotFound, "cannot determine group id for '#{resource.group}', does the group exist on this system?"
105
- end
106
-
107
- def set_group
108
- if (gid = target_gid) && (gid != stat.gid)
109
- File.chown(nil, gid, file)
110
- Chef::Log.info("#{log_string} group changed to #{gid}")
111
- modified
112
- end
113
- end
114
58
 
115
- def target_mode
116
- return nil if resource.mode.nil?
117
- (resource.mode.respond_to?(:oct) ? resource.mode.oct : resource.mode.to_i) & 007777
118
- end
119
-
120
- def set_mode
121
- if (mode = target_mode) && (mode != (stat.mode & 007777))
122
- File.chmod(target_mode, file)
123
- Chef::Log.info("#{log_string} mode changed to #{mode.to_s(8)}")
124
- modified
125
- end
126
- end
127
-
128
-
129
- def stat
130
- @stat ||= ::File.stat(file)
131
- end
132
-
133
59
  private
134
-
60
+
135
61
  def modified
136
62
  @modified = true
137
63
  end
@@ -139,6 +65,6 @@ class Chef
139
65
  def log_string
140
66
  @resource || @file
141
67
  end
142
-
68
+
143
69
  end
144
70
  end
@@ -0,0 +1,119 @@
1
+ #
2
+ # Author:: Adam Jacob (<adam@opscode.com>)
3
+ # Author:: Daniel DeLeo (<dan@opscode.com>)
4
+ # Author:: Seth Chisamore (<schisamo@opscode.com>)
5
+ # Copyright:: Copyright (c) 2008-2011 Opscode, Inc.
6
+ # License:: Apache License, Version 2.0
7
+ #
8
+ # Licensed under the Apache License, Version 2.0 (the "License");
9
+ # you may not use this file except in compliance with the License.
10
+ # You may obtain a copy of the License at
11
+ #
12
+ # http://www.apache.org/licenses/LICENSE-2.0
13
+ #
14
+ # Unless required by applicable law or agreed to in writing, software
15
+ # distributed under the License is distributed on an "AS IS" BASIS,
16
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
+ # See the License for the specific language governing permissions and
18
+ # limitations under the License.
19
+ #
20
+
21
+ require 'chef/log'
22
+
23
+ class Chef
24
+ class FileAccessControl
25
+ module Unix
26
+ UINT = (1 << 32)
27
+ UID_MAX = (1 << 32) - 10
28
+
29
+ def set_all
30
+ set_owner
31
+ set_group
32
+ set_mode unless resource.instance_of?(Chef::Resource::Link)
33
+ end
34
+
35
+ # Workaround the fact that Ruby's Etc module doesn't believe in negative
36
+ # uids, so negative uids show up as the diminished radix complement of
37
+ # a uint. For example, a uid of -2 is reported as 4294967294
38
+ def diminished_radix_complement(int)
39
+ if int > UID_MAX
40
+ int - UINT
41
+ else
42
+ int
43
+ end
44
+ end
45
+
46
+ def target_uid
47
+ return nil if resource.owner.nil?
48
+ if resource.owner.kind_of?(String)
49
+ diminished_radix_complement( Etc.getpwnam(resource.owner).uid )
50
+ elsif resource.owner.kind_of?(Integer)
51
+ resource.owner
52
+ else
53
+ Chef::Log.error("The `owner` parameter of the #@resource resource is set to an invalid value (#{resource.owner.inspect})")
54
+ raise ArgumentError, "cannot resolve #{resource.owner.inspect} to uid, owner must be a string or integer"
55
+ end
56
+ rescue ArgumentError
57
+ raise Chef::Exceptions::UserIDNotFound, "cannot determine user id for '#{resource.owner}', does the user exist on this system?"
58
+ end
59
+
60
+ def set_owner
61
+ if (uid = target_uid) && (uid != stat.uid)
62
+ chown(uid, nil, file)
63
+ Chef::Log.info("#{log_string} owner changed to #{uid}")
64
+ modified
65
+ end
66
+ end
67
+
68
+ def target_gid
69
+ return nil if resource.group.nil?
70
+ if resource.group.kind_of?(String)
71
+ diminished_radix_complement( Etc.getgrnam(resource.group).gid )
72
+ elsif resource.group.kind_of?(Integer)
73
+ resource.group
74
+ else
75
+ Chef::Log.error("The `group` parameter of the #@resource resource is set to an invalid value (#{resource.owner.inspect})")
76
+ raise ArgumentError, "cannot resolve #{resource.group.inspect} to gid, group must be a string or integer"
77
+ end
78
+ rescue ArgumentError
79
+ raise Chef::Exceptions::GroupIDNotFound, "cannot determine group id for '#{resource.group}', does the group exist on this system?"
80
+ end
81
+
82
+ def set_group
83
+ if (gid = target_gid) && (gid != stat.gid)
84
+ chown(nil, gid, file)
85
+ Chef::Log.info("#{log_string} group changed to #{gid}")
86
+ modified
87
+ end
88
+ end
89
+
90
+ # TODO rename this to a more generic target_permissions
91
+ def target_mode
92
+ return nil if resource.mode.nil?
93
+ (resource.mode.respond_to?(:oct) ? resource.mode.oct : resource.mode.to_i) & 007777
94
+ end
95
+
96
+ # TODO rename this to a more generic set_permissions
97
+ def set_mode
98
+ if (mode = target_mode) && (mode != (stat.mode & 007777))
99
+ File.chmod(target_mode, file)
100
+ Chef::Log.info("#{log_string} mode changed to #{mode.to_s(8)}")
101
+ modified
102
+ end
103
+ end
104
+
105
+ def stat
106
+ @stat ||= ::File.stat(file)
107
+ end
108
+
109
+ private
110
+ def chown(uid, gid, file)
111
+ if resource.instance_of?(Chef::Resource::Link)
112
+ File.lchown(uid, gid, file)
113
+ else
114
+ File.chown(uid, gid, file)
115
+ end
116
+ end
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,257 @@
1
+ #
2
+ # Author:: John Keiser (<jkeiser@opscode.com>)
3
+ # Author:: Seth Chisamore (<schisamo@opscode.com>)
4
+ # Copyright:: Copyright 2011 Opscode, Inc.
5
+ # License:: Apache License, Version 2.0
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+ #
19
+
20
+ require 'chef/win32/security'
21
+
22
+ class Chef
23
+ class FileAccessControl
24
+ module Windows
25
+ include Chef::Win32::API::Security
26
+
27
+ Security = Chef::Win32::Security
28
+ ACL = Security::ACL
29
+ ACE = Security::ACE
30
+ SID = Security::SID
31
+
32
+ def set_all
33
+ set_owner
34
+ set_group
35
+ set_dacl
36
+ end
37
+
38
+ private
39
+
40
+ # Compare the actual ACL on a resource with the ACL we want. This
41
+ # ignores explicit ACLs on the target, and does mask prediction (if you
42
+ # set GENERIC_WRITE, Windows will flip on a whole bunch of other rights
43
+ # on the file when you save the ACL)
44
+ def acls_equal(target_acl, actual_acl)
45
+ if actual_acl.nil?
46
+ return target_acl.nil?
47
+ end
48
+
49
+ actual_acl = actual_acl.select { |ace| !ace.inherited? }
50
+ # When ACLs apply to children, Windows splits them on the file system into two ACLs:
51
+ # one specific applying to this container, and one generic applying to children.
52
+ new_target_acl = []
53
+ target_acl.each do |target_ace|
54
+ if target_ace.flags & INHERIT_ONLY_ACE == 0
55
+ self_ace = target_ace.dup
56
+ self_ace.flags = 0
57
+ self_ace.mask = securable_object.predict_rights_mask(target_ace.mask)
58
+ new_target_acl << self_ace
59
+ end
60
+ if target_ace.flags & (CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE) != 0
61
+ children_ace = target_ace.dup
62
+ children_ace.flags |= INHERIT_ONLY_ACE
63
+ new_target_acl << children_ace
64
+ end
65
+ end
66
+ return actual_acl == new_target_acl
67
+ end
68
+
69
+ def existing_descriptor
70
+ securable_object.security_descriptor
71
+ end
72
+
73
+ def get_sid(value)
74
+ if value.kind_of?(String)
75
+ SID.from_account(value)
76
+ elsif value.kind_of?(SID)
77
+ value
78
+ else
79
+ raise "Must specify username, group or SID: #{value}"
80
+ end
81
+ end
82
+
83
+ def securable_object
84
+ @securable_object ||= begin
85
+ if file.kind_of?(String)
86
+ so = Chef::Win32::Security::SecurableObject.new(file.dup)
87
+ end
88
+ raise ArgumentError, "'file' must be a valid path or object of type 'Chef::Win32::Security::SecurableObject'" unless so.kind_of? Chef::Win32::Security::SecurableObject
89
+ so
90
+ end
91
+ end
92
+
93
+ def set_dacl
94
+ dacl = target_dacl
95
+ existing_dacl = existing_descriptor.dacl
96
+ inherits = target_inherits
97
+ if ! inherits.nil? && inherits != existing_descriptor.dacl_inherits?
98
+ # We have to set DACL along with inherits. If rights were not
99
+ # specified, we need to change only inherited ACLs and leave
100
+ # explicit ACLs alone.
101
+ if dacl.nil? && !existing_dacl.nil?
102
+ dacl = ACL.create(existing_dacl.select { |ace| !ace.inherited? })
103
+ end
104
+ securable_object.set_dacl(dacl, inherits)
105
+ Chef::Log.info("#{log_string} permissions changed to #{dacl} with inherits of #{inherits}")
106
+ modified
107
+ elsif dacl && !acls_equal(dacl, existing_dacl)
108
+ securable_object.dacl = dacl
109
+ Chef::Log.info("#{log_string} permissions changed to #{dacl}")
110
+ modified
111
+ end
112
+ end
113
+
114
+ def set_group
115
+ if (group = target_group) && (group != existing_descriptor.group)
116
+ Chef::Log.info("#{log_string} group changed to #{group}")
117
+ securable_object.group = group
118
+ modified
119
+ end
120
+ end
121
+
122
+ def set_owner
123
+ if (owner = target_owner) && (owner != existing_descriptor.owner)
124
+ Chef::Log.info("#{log_string} owner changed to #{owner}")
125
+ securable_object.owner = owner
126
+ modified
127
+ end
128
+ end
129
+
130
+ def mode_ace(sid, mode)
131
+ mask = 0
132
+ mask |= GENERIC_READ if mode & 4 != 0
133
+ mask |= (GENERIC_WRITE | DELETE) if mode & 2 != 0
134
+ mask |= GENERIC_EXECUTE if mode & 1 != 0
135
+ return [] if mask == 0
136
+ [ ACE.access_allowed(sid, mask) ]
137
+ end
138
+
139
+ def calculate_mask(permissions)
140
+ mask = 0
141
+ [ permissions ].flatten.each do |permission|
142
+ case permission
143
+ when :full_control
144
+ mask |= GENERIC_ALL
145
+ when :modify
146
+ mask |= GENERIC_WRITE | GENERIC_READ | GENERIC_EXECUTE | DELETE
147
+ when :read
148
+ mask |= GENERIC_READ
149
+ when :read_execute
150
+ mask |= GENERIC_READ | GENERIC_EXECUTE
151
+ when :write
152
+ mask |= GENERIC_WRITE
153
+ else
154
+ # Otherwise, assume it's an integer specifying the actual flags
155
+ mask |= permission
156
+ end
157
+ end
158
+ mask
159
+ end
160
+
161
+ def calculate_flags(rights)
162
+ # Handle inheritance flags
163
+ flags = 0
164
+ case rights[:applies_to_children]
165
+ when :containers_only
166
+ flags |= CONTAINER_INHERIT_ACE
167
+ when :objects_only
168
+ flags |= OBJECT_INHERIT_ACE
169
+ when true
170
+ flags |= CONTAINER_INHERIT_ACE
171
+ flags |= OBJECT_INHERIT_ACE
172
+ when nil
173
+ flags |= CONTAINER_INHERIT_ACE
174
+ flags |= OBJECT_INHERIT_ACE
175
+ end
176
+
177
+ if rights[:applies_to_self] == false
178
+ flags |= INHERIT_ONLY_ACE
179
+ end
180
+
181
+ if rights[:one_level_deep]
182
+ flags |= NO_PROPAGATE_INHERIT_ACE
183
+ end
184
+ flags
185
+ end
186
+
187
+ def target_dacl
188
+ return nil if resource.rights.nil? && resource.deny_rights.nil? && resource.mode.nil?
189
+ acls = nil
190
+
191
+ if !resource.deny_rights.nil?
192
+ acls = [] if acls.nil?
193
+
194
+ resource.deny_rights.each do |rights|
195
+ mask = calculate_mask(rights[:permissions])
196
+ [ rights[:principals] ].flatten.each do |principal|
197
+ sid = get_sid(principal)
198
+ flags = calculate_flags(rights)
199
+ acls.push ACE.access_denied(sid, mask, flags)
200
+ end
201
+ end
202
+ end
203
+
204
+ if !resource.rights.nil?
205
+ acls = [] if acls.nil?
206
+
207
+ resource.rights.each do |rights|
208
+ mask = calculate_mask(rights[:permissions])
209
+ [ rights[:principals] ].flatten.each do |principal|
210
+ sid = get_sid(principal)
211
+ flags = calculate_flags(rights)
212
+ acls.push ACE.access_allowed(sid, mask, flags)
213
+ end
214
+ end
215
+ end
216
+
217
+ if !resource.mode.nil?
218
+ acls = [] if acls.nil?
219
+
220
+ mode = (resource.mode.respond_to?(:oct) ? resource.mode.oct : resource.mode.to_i) & 0777
221
+
222
+ owner = target_owner
223
+ if owner
224
+ acls += mode_ace(owner, (mode & 0700) >> 6)
225
+ elsif mode & 0700 != 0
226
+ raise "Mode #{mode.to_s(8)} includes bits for the owner, but owner is not specified"
227
+ end
228
+
229
+ group = target_group
230
+ if group
231
+ acls += mode_ace(group, (mode & 070) >> 3)
232
+ elsif mode & 070 != 0
233
+ raise "Mode #{mode.to_s(8)} includes bits for the group, but group is not specified"
234
+ end
235
+
236
+ acls += mode_ace(SID.Everyone, (mode & 07))
237
+ end
238
+
239
+ acls.nil? ? nil : Chef::Win32::Security::ACL.create(acls)
240
+ end
241
+
242
+ def target_group
243
+ return nil if resource.group.nil?
244
+ sid = get_sid(resource.group)
245
+ end
246
+
247
+ def target_inherits
248
+ resource.inherits
249
+ end
250
+
251
+ def target_owner
252
+ return nil if resource.owner.nil?
253
+ sid = get_sid(resource.owner)
254
+ end
255
+ end
256
+ end
257
+ end