chef 0.7.10

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of chef might be problematic. Click here for more details.

Files changed (120) hide show
  1. data/LICENSE +201 -0
  2. data/README.rdoc +135 -0
  3. data/bin/chef-client +26 -0
  4. data/bin/chef-solo +26 -0
  5. data/lib/chef.rb +49 -0
  6. data/lib/chef/application.rb +98 -0
  7. data/lib/chef/application/agent.rb +18 -0
  8. data/lib/chef/application/client.rb +209 -0
  9. data/lib/chef/application/indexer.rb +141 -0
  10. data/lib/chef/application/server.rb +18 -0
  11. data/lib/chef/application/solo.rb +214 -0
  12. data/lib/chef/client.rb +396 -0
  13. data/lib/chef/compile.rb +138 -0
  14. data/lib/chef/config.rb +141 -0
  15. data/lib/chef/cookbook.rb +144 -0
  16. data/lib/chef/cookbook/metadata.rb +407 -0
  17. data/lib/chef/cookbook/metadata/version.rb +87 -0
  18. data/lib/chef/cookbook_loader.rb +168 -0
  19. data/lib/chef/couchdb.rb +172 -0
  20. data/lib/chef/daemon.rb +170 -0
  21. data/lib/chef/exceptions.rb +36 -0
  22. data/lib/chef/file_cache.rb +205 -0
  23. data/lib/chef/log.rb +39 -0
  24. data/lib/chef/mixin/check_helper.rb +31 -0
  25. data/lib/chef/mixin/checksum.rb +37 -0
  26. data/lib/chef/mixin/command.rb +351 -0
  27. data/lib/chef/mixin/create_path.rb +56 -0
  28. data/lib/chef/mixin/deep_merge.rb +36 -0
  29. data/lib/chef/mixin/find_preferred_file.rb +99 -0
  30. data/lib/chef/mixin/from_file.rb +36 -0
  31. data/lib/chef/mixin/generate_url.rb +48 -0
  32. data/lib/chef/mixin/language.rb +79 -0
  33. data/lib/chef/mixin/params_validate.rb +197 -0
  34. data/lib/chef/mixin/template.rb +84 -0
  35. data/lib/chef/node.rb +406 -0
  36. data/lib/chef/node/attribute.rb +412 -0
  37. data/lib/chef/openid_registration.rb +181 -0
  38. data/lib/chef/platform.rb +253 -0
  39. data/lib/chef/provider.rb +40 -0
  40. data/lib/chef/provider/cron.rb +137 -0
  41. data/lib/chef/provider/directory.rb +72 -0
  42. data/lib/chef/provider/execute.rb +58 -0
  43. data/lib/chef/provider/file.rb +191 -0
  44. data/lib/chef/provider/group.rb +120 -0
  45. data/lib/chef/provider/group/groupadd.rb +92 -0
  46. data/lib/chef/provider/group/pw.rb +88 -0
  47. data/lib/chef/provider/http_request.rb +102 -0
  48. data/lib/chef/provider/ifconfig.rb +131 -0
  49. data/lib/chef/provider/link.rb +157 -0
  50. data/lib/chef/provider/mount.rb +121 -0
  51. data/lib/chef/provider/mount/mount.rb +208 -0
  52. data/lib/chef/provider/package.rb +160 -0
  53. data/lib/chef/provider/package/apt.rb +110 -0
  54. data/lib/chef/provider/package/dpkg.rb +113 -0
  55. data/lib/chef/provider/package/freebsd.rb +153 -0
  56. data/lib/chef/provider/package/macports.rb +105 -0
  57. data/lib/chef/provider/package/portage.rb +124 -0
  58. data/lib/chef/provider/package/rpm.rb +99 -0
  59. data/lib/chef/provider/package/rubygems.rb +130 -0
  60. data/lib/chef/provider/package/yum-dump.py +104 -0
  61. data/lib/chef/provider/package/yum.rb +175 -0
  62. data/lib/chef/provider/remote_directory.rb +126 -0
  63. data/lib/chef/provider/remote_file.rb +134 -0
  64. data/lib/chef/provider/route.rb +118 -0
  65. data/lib/chef/provider/ruby_block.rb +15 -0
  66. data/lib/chef/provider/script.rb +42 -0
  67. data/lib/chef/provider/service.rb +129 -0
  68. data/lib/chef/provider/service/debian.rb +64 -0
  69. data/lib/chef/provider/service/freebsd.rb +157 -0
  70. data/lib/chef/provider/service/gentoo.rb +54 -0
  71. data/lib/chef/provider/service/init.rb +126 -0
  72. data/lib/chef/provider/service/redhat.rb +62 -0
  73. data/lib/chef/provider/template.rb +141 -0
  74. data/lib/chef/provider/user.rb +170 -0
  75. data/lib/chef/provider/user/pw.rb +113 -0
  76. data/lib/chef/provider/user/useradd.rb +107 -0
  77. data/lib/chef/queue.rb +145 -0
  78. data/lib/chef/recipe.rb +210 -0
  79. data/lib/chef/resource.rb +256 -0
  80. data/lib/chef/resource/apt_package.rb +34 -0
  81. data/lib/chef/resource/bash.rb +33 -0
  82. data/lib/chef/resource/cron.rb +143 -0
  83. data/lib/chef/resource/csh.rb +33 -0
  84. data/lib/chef/resource/directory.rb +76 -0
  85. data/lib/chef/resource/dpkg_package.rb +34 -0
  86. data/lib/chef/resource/execute.rb +127 -0
  87. data/lib/chef/resource/file.rb +84 -0
  88. data/lib/chef/resource/gem_package.rb +41 -0
  89. data/lib/chef/resource/group.rb +68 -0
  90. data/lib/chef/resource/http_request.rb +52 -0
  91. data/lib/chef/resource/ifconfig.rb +134 -0
  92. data/lib/chef/resource/link.rb +78 -0
  93. data/lib/chef/resource/macports_package.rb +29 -0
  94. data/lib/chef/resource/mount.rb +135 -0
  95. data/lib/chef/resource/package.rb +80 -0
  96. data/lib/chef/resource/perl.rb +33 -0
  97. data/lib/chef/resource/portage_package.rb +33 -0
  98. data/lib/chef/resource/python.rb +33 -0
  99. data/lib/chef/resource/remote_directory.rb +91 -0
  100. data/lib/chef/resource/remote_file.rb +60 -0
  101. data/lib/chef/resource/route.rb +135 -0
  102. data/lib/chef/resource/ruby.rb +33 -0
  103. data/lib/chef/resource/ruby_block.rb +20 -0
  104. data/lib/chef/resource/script.rb +51 -0
  105. data/lib/chef/resource/service.rb +134 -0
  106. data/lib/chef/resource/template.rb +60 -0
  107. data/lib/chef/resource/user.rb +98 -0
  108. data/lib/chef/resource_collection.rb +176 -0
  109. data/lib/chef/resource_definition.rb +67 -0
  110. data/lib/chef/rest.rb +238 -0
  111. data/lib/chef/role.rb +231 -0
  112. data/lib/chef/run_list.rb +156 -0
  113. data/lib/chef/runner.rb +123 -0
  114. data/lib/chef/search.rb +88 -0
  115. data/lib/chef/search/result.rb +64 -0
  116. data/lib/chef/search_index.rb +77 -0
  117. data/lib/chef/tasks/chef_repo.rake +345 -0
  118. data/lib/chef/util/file_edit.rb +125 -0
  119. data/lib/chef/util/fileedit.rb +121 -0
  120. metadata +262 -0
@@ -0,0 +1,87 @@
1
+ #
2
+ # Author:: AJ Christensen (<aj@opscode.com>)
3
+ # Copyright:: Copyright (c) 2008 Opscode, Inc.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ require 'chef/cookbook'
20
+ require 'chef/cookbook/metadata'
21
+
22
+ class Chef::Cookbook::Metadata
23
+ class Version
24
+ include Comparable
25
+
26
+ attr_accessor :major,
27
+ :minor,
28
+ :patch
29
+
30
+ def initialize(str="")
31
+ @major, @minor, @patch = _parse(str)
32
+ end
33
+
34
+ def _parse(str="")
35
+ @major, @minor, @patch = case str
36
+ when /^(\d+)\.(\d+)\.(\d+)$/
37
+ [ $1.to_i, $2.to_i, $3.to_i ]
38
+ when /^(\d+)\.(\d+)$/
39
+ [ $1.to_i, $2.to_i, 0 ]
40
+ else
41
+ raise "Metadata version does not match 'x.y.z' or 'x.y'"
42
+ end
43
+ end
44
+
45
+ def inspect
46
+ "#{@major}.#{@minor}.#{@patch}"
47
+ end
48
+
49
+ def to_s
50
+ "#{@major}.#{@minor}.#{@patch}"
51
+ end
52
+
53
+ def <=>(v)
54
+ major, minor, patch = (
55
+ [ :major, :minor, :patch ].collect do |method|
56
+ self.send(method) <=> v.send(method)
57
+ end
58
+ )
59
+
60
+ Chef::Log.debug "(#{self.to_s}/#{v.to_s}) major,minor,patch: #{[major,minor,patch].join(',')}"
61
+
62
+ # all these returns feels like C, surely there is a better way!
63
+
64
+ if major == 0 && minor == 0 && patch == 0
65
+ comp = 0
66
+ end
67
+
68
+ if major == 1
69
+ comp = 1
70
+ end
71
+
72
+ if major == 0 && minor == 1 && patch == -1
73
+ comp = 1
74
+ end
75
+
76
+ if minor == 1 && major == 0 && patch == 0
77
+ comp = 1
78
+ end
79
+
80
+ if patch == 1 && major == 0 && minor == 0
81
+ comp = 1
82
+ end
83
+
84
+ return (comp || -1)
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,168 @@
1
+ #
2
+ # Author:: Adam Jacob (<adam@opscode.com>)
3
+ # Copyright:: Copyright (c) 2008 Opscode, Inc.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+
18
+ require 'chef/config'
19
+ require 'chef/cookbook'
20
+ require 'chef/cookbook/metadata'
21
+
22
+ class Chef
23
+ class CookbookLoader
24
+
25
+ attr_accessor :cookbook, :metadata
26
+
27
+ include Enumerable
28
+
29
+ def initialize()
30
+ @cookbook = Hash.new
31
+ @metadata = Hash.new
32
+ load_cookbooks
33
+ end
34
+
35
+ def load_cookbooks
36
+ cookbook_settings = Hash.new
37
+ Chef::Config.cookbook_path.each do |cb_path|
38
+ Dir[File.join(cb_path, "*")].each do |cookbook|
39
+ next unless File.directory?(cookbook)
40
+ cookbook_name = File.basename(cookbook).to_sym
41
+ unless cookbook_settings.has_key?(cookbook_name)
42
+ cookbook_settings[cookbook_name] = {
43
+ :ignore_regexes => Array.new,
44
+ :attribute_files => Array.new,
45
+ :definition_files => Array.new,
46
+ :recipe_files => Array.new,
47
+ :template_files => Array.new,
48
+ :remote_files => Array.new,
49
+ :lib_files => Array.new,
50
+ :metadata_files => Array.new
51
+ }
52
+ end
53
+ ignore_regexes = load_ignore_file(File.join(cookbook, "ignore"))
54
+ cookbook_settings[cookbook_name][:ignore_regexes].concat(ignore_regexes)
55
+ load_files_unless_basename(
56
+ File.join(cookbook, "attributes", "*.rb"),
57
+ cookbook_settings[cookbook_name][:attribute_files],
58
+ cookbook_settings[cookbook_name][:ignore_regexes]
59
+ )
60
+ load_files_unless_basename(
61
+ File.join(cookbook, "definitions", "*.rb"),
62
+ cookbook_settings[cookbook_name][:definition_files],
63
+ cookbook_settings[cookbook_name][:ignore_regexes]
64
+ )
65
+ load_files_unless_basename(
66
+ File.join(cookbook, "recipes", "*.rb"),
67
+ cookbook_settings[cookbook_name][:recipe_files],
68
+ cookbook_settings[cookbook_name][:ignore_regexes]
69
+ )
70
+ load_files_unless_basename(
71
+ File.join(cookbook, "libraries", "*.rb"),
72
+ cookbook_settings[cookbook_name][:lib_files],
73
+ cookbook_settings[cookbook_name][:ignore_regexes]
74
+ )
75
+ load_cascading_files(
76
+ "*.erb",
77
+ File.join(cookbook, "templates"),
78
+ cookbook_settings[cookbook_name][:template_files],
79
+ cookbook_settings[cookbook_name][:ignore_regexes]
80
+ )
81
+ load_cascading_files(
82
+ "*",
83
+ File.join(cookbook, "files"),
84
+ cookbook_settings[cookbook_name][:remote_files],
85
+ cookbook_settings[cookbook_name][:ignore_regexes]
86
+ )
87
+ if File.exists?(File.join(cookbook, "metadata.json"))
88
+ cookbook_settings[cookbook_name][:metadata_files] << File.join(cookbook, "metadata.json")
89
+ end
90
+ end
91
+ end
92
+ cookbook_settings.each_key do |cookbook|
93
+ @cookbook[cookbook] = Chef::Cookbook.new(cookbook)
94
+ @cookbook[cookbook].attribute_files = cookbook_settings[cookbook][:attribute_files]
95
+ @cookbook[cookbook].definition_files = cookbook_settings[cookbook][:definition_files]
96
+ @cookbook[cookbook].recipe_files = cookbook_settings[cookbook][:recipe_files]
97
+ @cookbook[cookbook].template_files = cookbook_settings[cookbook][:template_files]
98
+ @cookbook[cookbook].remote_files = cookbook_settings[cookbook][:remote_files]
99
+ @cookbook[cookbook].lib_files = cookbook_settings[cookbook][:lib_files]
100
+ @metadata[cookbook] = Chef::Cookbook::Metadata.new(@cookbook[cookbook])
101
+ cookbook_settings[cookbook][:metadata_files].each do |meta_json|
102
+ @metadata[cookbook].from_json(IO.read(meta_json))
103
+ end
104
+ end
105
+ end
106
+
107
+ def [](cookbook)
108
+ if @cookbook.has_key?(cookbook.to_sym)
109
+ @cookbook[cookbook.to_sym]
110
+ else
111
+ raise ArgumentError, "Cannot find a cookbook named #{cookbook.to_s}; did you forget to add metadata to a cookbook? (http://wiki.opscode.com/display/chef/Metadata)"
112
+ end
113
+ end
114
+
115
+ def each
116
+ @cookbook.each_value do |cobject|
117
+ yield cobject
118
+ end
119
+ end
120
+
121
+ private
122
+
123
+ def load_ignore_file(ignore_file)
124
+ results = Array.new
125
+ if File.exists?(ignore_file) && File.readable?(ignore_file)
126
+ IO.foreach(ignore_file) do |line|
127
+ next if line =~ /^#/
128
+ next if line =~ /^\w*$/
129
+ line.chomp!
130
+ results << Regexp.new(line)
131
+ end
132
+ end
133
+ results
134
+ end
135
+
136
+ def load_cascading_files(file_glob, base_path, result_array, ignore_regexes)
137
+ # To handle dotfiles like .ssh
138
+ Dir.glob(File.join(base_path, "**/#{file_glob}"), File::FNM_DOTMATCH).each do |file|
139
+ next if skip_file(file, ignore_regexes)
140
+ file =~ /^#{base_path}\/(.+)$/
141
+ singlecopy = $1
142
+ unless result_array.detect { |f| f =~ /#{singlecopy}$/ }
143
+ result_array << file
144
+ end
145
+ end
146
+ end
147
+
148
+ def load_files_unless_basename(file_glob, result_array, ignore_regexes)
149
+ Dir[file_glob].each do |file|
150
+ next if skip_file(file, ignore_regexes)
151
+ file_basename = File.basename(file)
152
+ # If we've seen a file with this basename before, skip it.
153
+ unless result_array.detect { |f| File.basename(f) == file_basename }
154
+ result_array << file
155
+ end
156
+ end
157
+ end
158
+
159
+ def skip_file(file, ignore_regexes)
160
+ skip = false
161
+ ignore_regexes.each do |exp|
162
+ skip = true if exp.match(file)
163
+ end
164
+ skip
165
+ end
166
+
167
+ end
168
+ end
@@ -0,0 +1,172 @@
1
+ #
2
+ # Author:: Adam Jacob (<adam@opscode.com>)
3
+ # Copyright:: Copyright (c) 2008 Opscode, Inc.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+
18
+ require 'chef/mixin/params_validate'
19
+ require 'chef/config'
20
+ require 'chef/rest'
21
+ require 'chef/log'
22
+ require 'digest/sha2'
23
+ require 'json'
24
+
25
+ class Chef
26
+ class CouchDB
27
+ include Chef::Mixin::ParamsValidate
28
+
29
+ def initialize(url=nil)
30
+ url ||= Chef::Config[:couchdb_url]
31
+ @rest = Chef::REST.new(url)
32
+ end
33
+
34
+ def create_db
35
+ @database_list = @rest.get_rest("_all_dbs")
36
+ unless @database_list.detect { |db| db == Chef::Config[:couchdb_database] }
37
+ response = @rest.put_rest(Chef::Config[:couchdb_database], Hash.new)
38
+ end
39
+ Chef::Config[:couchdb_database]
40
+ end
41
+
42
+ def create_design_document(name, data)
43
+ create_db
44
+ to_update = true
45
+ begin
46
+ old_doc = @rest.get_rest("#{Chef::Config[:couchdb_database]}/_design%2F#{name}")
47
+ if data["version"] != old_doc["version"]
48
+ data["_rev"] = old_doc["_rev"]
49
+ Chef::Log.debug("Updating #{name} views")
50
+ else
51
+ to_update = false
52
+ end
53
+ rescue
54
+ Chef::Log.debug("Creating #{name} views for the first time")
55
+ end
56
+ if to_update
57
+ @rest.put_rest("#{Chef::Config[:couchdb_database]}/_design%2F#{name}", data)
58
+ end
59
+ true
60
+ end
61
+
62
+ def store(obj_type, name, object)
63
+ validate(
64
+ {
65
+ :obj_type => obj_type,
66
+ :name => name,
67
+ :object => object,
68
+ },
69
+ {
70
+ :object => { :respond_to => :to_json },
71
+ }
72
+ )
73
+ @rest.put_rest("#{Chef::Config[:couchdb_database]}/#{obj_type}_#{safe_name(name)}", object)
74
+ end
75
+
76
+ def load(obj_type, name)
77
+ validate(
78
+ {
79
+ :obj_type => obj_type,
80
+ :name => name,
81
+ },
82
+ {
83
+ :obj_type => { :kind_of => String },
84
+ :name => { :kind_of => String },
85
+ }
86
+ )
87
+ @rest.get_rest("#{Chef::Config[:couchdb_database]}/#{obj_type}_#{safe_name(name)}")
88
+ end
89
+
90
+ def delete(obj_type, name, rev=nil)
91
+ validate(
92
+ {
93
+ :obj_type => obj_type,
94
+ :name => name,
95
+ },
96
+ {
97
+ :obj_type => { :kind_of => String },
98
+ :name => { :kind_of => String },
99
+ }
100
+ )
101
+ unless rev
102
+ last_obj = @rest.get_rest("#{Chef::Config[:couchdb_database]}/#{obj_type}_#{safe_name(name)}")
103
+ if last_obj.respond_to?(:couchdb_rev)
104
+ rev = last_obj.couchdb_rev
105
+ else
106
+ rev = last_obj['_rev']
107
+ end
108
+ end
109
+ @rest.delete_rest("#{Chef::Config[:couchdb_database]}/#{obj_type}_#{safe_name(name)}?rev=#{rev}")
110
+ end
111
+
112
+ def list(view, inflate=false)
113
+ validate(
114
+ {
115
+ :view => view,
116
+ },
117
+ {
118
+ :view => { :kind_of => String }
119
+ }
120
+ )
121
+ if inflate
122
+ @rest.get_rest(view_uri(view, "all"))
123
+ else
124
+ @rest.get_rest(view_uri(view, "all_id"))
125
+ end
126
+ end
127
+
128
+ def has_key?(obj_type, name)
129
+ validate(
130
+ {
131
+ :obj_type => obj_type,
132
+ :name => name,
133
+ },
134
+ {
135
+ :obj_type => { :kind_of => String },
136
+ :name => { :kind_of => String },
137
+ }
138
+ )
139
+ begin
140
+ @rest.get_rest("#{Chef::Config[:couchdb_database]}/#{obj_type}_#{safe_name(name)}")
141
+ true
142
+ rescue
143
+ false
144
+ end
145
+ end
146
+
147
+ def get_view(design, view, options={})
148
+ view_string = view_uri(design, view)
149
+ view_string << "?" if options.length != 0
150
+ first = true;
151
+ options.each { |k,v| view_string << "#{first ? '' : '&'}#{k}=#{URI.escape(v.to_json)}"; first = false }
152
+ @rest.get_rest(view_string)
153
+ end
154
+
155
+ def view_uri(design, view)
156
+ Chef::Config[:couchdb_version] ||= @rest.run_request(:GET, URI.parse(@rest.url + "/"), false, 10, false)["version"].gsub(/-.+/,"").to_f
157
+ case Chef::Config[:couchdb_version]
158
+ when 0.9, 0.10
159
+ "#{Chef::Config[:couchdb_database]}/_design/#{design}/_view/#{view}"
160
+ when 0.8
161
+ "#{Chef::Config[:couchdb_database]}/_view/#{design}/#{view}"
162
+ end
163
+ end
164
+
165
+ private
166
+
167
+ def safe_name(name)
168
+ name.gsub(/\./, "_")
169
+ end
170
+
171
+ end
172
+ end
@@ -0,0 +1,170 @@
1
+ #
2
+ # Author:: AJ Christensen (<aj@junglist.gen.nz>)
3
+ # Copyright:: Copyright (c) 2008 Opscode, Inc.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+
18
+ # I love you Merb (lib/merb-core/server.rb)
19
+
20
+ require 'chef/config'
21
+ require 'etc'
22
+
23
+ class Chef
24
+ class Daemon
25
+ class << self
26
+ attr_accessor :name
27
+
28
+ # Daemonize the current process, managing pidfiles and process uid/gid
29
+ #
30
+ # === Parameters
31
+ # name<String>:: The name to be used for the pid file
32
+ #
33
+ def daemonize(name)
34
+ @name = name
35
+ pid = pid_from_file
36
+ unless running?
37
+ remove_pid_file()
38
+ Chef::Log.info("Daemonizing..")
39
+ begin
40
+ exit if fork
41
+ Process.setsid
42
+ exit if fork
43
+ Chef::Log.info("Forked, in #{Process.pid}. Priveleges: #{Process.euid} #{Process.egid}")
44
+ File.umask 0000
45
+ $stdin.reopen("/dev/null")
46
+ $stdout.reopen("/dev/null", "a")
47
+ $stdout.reopen($stdout)
48
+ save_pid_file
49
+ at_exit { remove_pid_file }
50
+ rescue NotImplementedError => e
51
+ Chef::Application.fatal!("There is no fork: #{e.message}")
52
+ end
53
+ else
54
+ Chef::Application.fatal!("Chef is already running pid #{pid}")
55
+ end
56
+ end
57
+
58
+ # Check if Chef is running based on the pid_file
59
+ # ==== Returns
60
+ # Boolean::
61
+ # True if Chef is running
62
+ # False if Chef is not running
63
+ #
64
+ def running?
65
+ if pid_from_file.nil?
66
+ false
67
+ else
68
+ Process.kill(0, pid_from_file)
69
+ true
70
+ end
71
+ rescue Errno::ESRCH, Errno::ENOENT
72
+ false
73
+ rescue Errno::EACCES => e
74
+ Chef::Application.fatal!("You don't have access to the PID file at #{pid_file}: #{e.message}")
75
+ end
76
+
77
+ # Gets the pid file for @name
78
+ # ==== Returns
79
+ # String::
80
+ # Location of the pid file for @name
81
+ def pid_file
82
+ Chef::Config[:pid_file] or "/tmp/#{@name}.pid"
83
+ end
84
+
85
+ # Suck the pid out of pid_file
86
+ # ==== Returns
87
+ # Integer::
88
+ # The PID from pid_file
89
+ # nil::
90
+ # Returned if the pid_file does not exist.
91
+ #
92
+ def pid_from_file
93
+ File.read(pid_file).chomp.to_i
94
+ rescue Errno::ENOENT, Errno::EACCES
95
+ nil
96
+ end
97
+
98
+ # Store the PID on the filesystem
99
+ # This uses the Chef::Config[:pid_file] option, or "/tmp/name.pid" otherwise
100
+ #
101
+ def save_pid_file
102
+ file = pid_file
103
+ begin
104
+ FileUtils.mkdir_p(File.dirname(file))
105
+ rescue Errno::EACCES => e
106
+ Chef::Application.fatal!("Failed store pid in #{File.dirname(file)}, permission denied: #{e.message}")
107
+ end
108
+
109
+ begin
110
+ File.open(file, "w") { |f| f.write(Process.pid.to_s) }
111
+ rescue Errno::EACCES => e
112
+ Chef::Application.fatal!("Couldn't write to pidfile #{file}, permission denied: #{e.message}")
113
+ end
114
+ end
115
+
116
+ # Delete the PID from the filesystem
117
+ def remove_pid_file
118
+ FileUtils.rm(pid_file) if File.exists?(pid_file)
119
+ end
120
+
121
+ # Change process user/group to those specified in Chef::Config
122
+ #
123
+ def change_privilege
124
+ if Chef::Config[:user] and Chef::Config[:group]
125
+ Chef::Log.info("About to change privilege to #{Chef::Config[:user]}:#{Chef::Config[:group]}")
126
+ _change_privilege(Chef::Config[:user], Chef::Config[:group])
127
+ elsif Chef::Config[:user]
128
+ Chef::Log.info("About to change privilege to #{Chef::Config[:user]}")
129
+ _change_privilege(Chef::Config[:user])
130
+ end
131
+ end
132
+
133
+ # Change privileges of the process to be the specified user and group
134
+ #
135
+ # ==== Parameters
136
+ # user<String>:: The user to change the process to.
137
+ # group<String>:: The group to change the process to.
138
+ #
139
+ # ==== Alternatives
140
+ # If group is left out, the user will be used (changing to user:user)
141
+ #
142
+ def _change_privilege(user, group=user)
143
+ uid, gid = Process.euid, Process.egid
144
+
145
+ begin
146
+ target_uid = Etc.getpwnam(user).uid
147
+ rescue ArgumentError => e
148
+ Chef::Application.fatal!("Failed to get UID for user #{user}, does it exist? #{e.message}")
149
+ return false
150
+ end
151
+
152
+ begin
153
+ target_gid = Etc.getgrnam(group).gid
154
+ rescue ArgumentError => e
155
+ Chef::Application.fatal!("Failed to get GID for group #{group}, does it exist? #{e.message}")
156
+ return false
157
+ end
158
+
159
+ if (uid != target_uid) or (gid != target_gid)
160
+ Process.initgroups(user, target_gid)
161
+ Process::GID.change_privilege(target_gid)
162
+ Process::UID.change_privilege(target_uid)
163
+ end
164
+ true
165
+ rescue Errno::EPERM => e
166
+ Chef::Application.fatal!("Permission denied when trying to change #{uid}:#{gid} to #{target_uid}:#{target_gid}. #{e.message}")
167
+ end
168
+ end
169
+ end
170
+ end