chef 0.7.16 → 0.8.2

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 (180) hide show
  1. data/README.rdoc +11 -10
  2. data/bin/chef-client +2 -2
  3. data/bin/chef-solo +1 -1
  4. data/bin/knife +27 -0
  5. data/bin/shef +49 -0
  6. data/distro/README +2 -0
  7. data/distro/{debian → common}/man/man1/chef-indexer.1 +0 -0
  8. data/distro/{debian → common}/man/man1/chef-server.1 +0 -0
  9. data/distro/{debian → common}/man/man8/chef-client.8 +0 -0
  10. data/distro/{debian → common}/man/man8/chef-solo.8 +0 -0
  11. data/distro/common/man/man8/knife.8 +375 -0
  12. data/distro/redhat/etc/init.d/chef-client +8 -4
  13. data/distro/redhat/etc/init.d/chef-server +16 -15
  14. data/distro/redhat/etc/init.d/chef-server-webui +78 -0
  15. data/distro/redhat/etc/init.d/chef-solr +76 -0
  16. data/distro/redhat/etc/init.d/chef-solr-indexer +75 -0
  17. data/distro/redhat/etc/sysconfig/chef-client +10 -0
  18. data/distro/redhat/etc/sysconfig/chef-server +10 -0
  19. data/distro/redhat/etc/sysconfig/chef-server-webui +10 -0
  20. data/distro/redhat/etc/sysconfig/chef-solr +9 -0
  21. data/distro/redhat/etc/sysconfig/chef-solr-indexer +7 -0
  22. data/distro/suse/etc/init.d/chef-client +121 -0
  23. data/lib/chef.rb +1 -1
  24. data/lib/chef/api_client.rb +263 -0
  25. data/lib/chef/application.rb +1 -1
  26. data/lib/chef/application/client.rb +21 -3
  27. data/lib/chef/application/knife.rb +144 -0
  28. data/lib/chef/application/server.rb +2 -1
  29. data/lib/chef/application/solo.rb +9 -2
  30. data/lib/chef/cache.rb +61 -0
  31. data/lib/chef/cache/checksum.rb +70 -0
  32. data/lib/chef/certificate.rb +154 -0
  33. data/lib/chef/client.rb +123 -220
  34. data/lib/chef/compile.rb +9 -21
  35. data/lib/chef/config.rb +67 -10
  36. data/lib/chef/cookbook.rb +49 -22
  37. data/lib/chef/cookbook/metadata.rb +85 -5
  38. data/lib/chef/cookbook_loader.rb +4 -4
  39. data/lib/chef/couchdb.rb +99 -30
  40. data/lib/chef/daemon.rb +1 -1
  41. data/lib/chef/data_bag.rb +215 -0
  42. data/lib/chef/data_bag_item.rb +219 -0
  43. data/lib/chef/exceptions.rb +3 -0
  44. data/lib/chef/index_queue.rb +29 -0
  45. data/lib/chef/index_queue/amqp_client.rb +106 -0
  46. data/lib/chef/index_queue/consumer.rb +76 -0
  47. data/lib/chef/index_queue/indexable.rb +74 -0
  48. data/lib/chef/knife.rb +309 -0
  49. data/lib/chef/knife/client_bulk_delete.rb +40 -0
  50. data/lib/chef/knife/client_create.rb +62 -0
  51. data/lib/chef/knife/client_delete.rb +37 -0
  52. data/lib/chef/knife/client_edit.rb +37 -0
  53. data/lib/chef/knife/client_list.rb +40 -0
  54. data/lib/chef/knife/client_reregister.rb +48 -0
  55. data/lib/chef/knife/client_show.rb +42 -0
  56. data/lib/chef/knife/configure.rb +123 -0
  57. data/lib/chef/knife/cookbook_bulk_delete.rb +46 -0
  58. data/lib/chef/knife/cookbook_delete.rb +41 -0
  59. data/lib/chef/knife/cookbook_download.rb +57 -0
  60. data/lib/chef/knife/cookbook_list.rb +41 -0
  61. data/lib/chef/knife/cookbook_metadata.rb +87 -0
  62. data/lib/chef/knife/cookbook_show.rb +75 -0
  63. data/lib/chef/knife/cookbook_upload.rb +179 -0
  64. data/lib/chef/knife/data_bag_create.rb +43 -0
  65. data/lib/chef/knife/data_bag_delete.rb +43 -0
  66. data/lib/chef/knife/data_bag_edit.rb +49 -0
  67. data/lib/chef/knife/data_bag_list.rb +42 -0
  68. data/lib/chef/knife/data_bag_show.rb +40 -0
  69. data/lib/chef/knife/ec2_instance_data.rb +46 -0
  70. data/lib/chef/knife/index_rebuild.rb +51 -0
  71. data/lib/chef/knife/node_bulk_delete.rb +43 -0
  72. data/lib/chef/knife/node_create.rb +39 -0
  73. data/lib/chef/knife/node_delete.rb +36 -0
  74. data/lib/chef/knife/node_edit.rb +36 -0
  75. data/lib/chef/knife/node_from_file.rb +42 -0
  76. data/lib/chef/knife/node_list.rb +41 -0
  77. data/lib/chef/knife/node_run_list_add.rb +64 -0
  78. data/lib/chef/knife/node_run_list_remove.rb +45 -0
  79. data/lib/chef/knife/node_show.rb +46 -0
  80. data/lib/chef/knife/role_bulk_delete.rb +44 -0
  81. data/lib/chef/knife/role_create.rb +44 -0
  82. data/lib/chef/knife/role_delete.rb +36 -0
  83. data/lib/chef/knife/role_edit.rb +37 -0
  84. data/lib/chef/knife/role_from_file.rb +46 -0
  85. data/lib/chef/knife/role_list.rb +40 -0
  86. data/lib/chef/knife/role_show.rb +43 -0
  87. data/lib/chef/knife/search.rb +94 -0
  88. data/lib/chef/knife/ssh.rb +170 -0
  89. data/lib/chef/log.rb +30 -8
  90. data/lib/chef/mixin/checksum.rb +2 -7
  91. data/lib/chef/mixin/command.rb +32 -13
  92. data/lib/chef/mixin/convert_to_class_name.rb +15 -0
  93. data/lib/chef/mixin/deep_merge.rb +199 -11
  94. data/lib/chef/mixin/generate_url.rb +18 -9
  95. data/lib/chef/mixin/language.rb +29 -1
  96. data/lib/chef/mixin/language_include_attribute.rb +56 -0
  97. data/lib/chef/mixin/language_include_recipe.rb +53 -0
  98. data/lib/chef/mixin/params_validate.rb +25 -12
  99. data/lib/chef/mixin/recipe_definition_dsl_core.rb +2 -0
  100. data/lib/chef/mixin/template.rb +11 -1
  101. data/lib/chef/mixin/xml_escape.rb +87 -0
  102. data/lib/chef/node.rb +144 -122
  103. data/lib/chef/openid_registration.rb +12 -5
  104. data/lib/chef/platform.rb +89 -47
  105. data/lib/chef/provider/breakpoint.rb +36 -0
  106. data/lib/chef/provider/cron.rb +5 -6
  107. data/lib/chef/provider/deploy.rb +43 -10
  108. data/lib/chef/provider/deploy/revision.rb +2 -3
  109. data/lib/chef/provider/erl_call.rb +72 -0
  110. data/lib/chef/provider/file.rb +8 -4
  111. data/lib/chef/provider/git.rb +10 -5
  112. data/lib/chef/provider/group/dscl.rb +128 -0
  113. data/lib/chef/provider/http_request.rb +6 -2
  114. data/lib/chef/provider/ifconfig.rb +1 -0
  115. data/lib/chef/provider/link.rb +1 -1
  116. data/lib/chef/provider/log.rb +53 -0
  117. data/lib/chef/provider/mdadm.rb +88 -0
  118. data/lib/chef/provider/mount/mount.rb +1 -1
  119. data/lib/chef/provider/package.rb +1 -1
  120. data/lib/chef/provider/package/easy_install.rb +106 -0
  121. data/lib/chef/provider/package/pacman.rb +101 -0
  122. data/lib/chef/provider/package/portage.rb +1 -1
  123. data/lib/chef/provider/package/rpm.rb +10 -8
  124. data/lib/chef/provider/package/yum-dump.py +22 -3
  125. data/lib/chef/provider/package/yum.rb +32 -8
  126. data/lib/chef/provider/package/zypper.rb +132 -0
  127. data/lib/chef/provider/remote_directory.rb +58 -49
  128. data/lib/chef/provider/remote_file.rb +1 -1
  129. data/lib/chef/provider/route.rb +136 -80
  130. data/lib/chef/provider/ruby_block.rb +18 -1
  131. data/lib/chef/provider/service/arch.rb +109 -0
  132. data/lib/chef/provider/service/freebsd.rb +0 -1
  133. data/lib/chef/provider/service/simple.rb +2 -3
  134. data/lib/chef/provider/service/upstart.rb +191 -0
  135. data/lib/chef/provider/subversion.rb +12 -4
  136. data/lib/chef/provider/template.rb +85 -53
  137. data/lib/chef/provider/user.rb +1 -1
  138. data/lib/chef/provider/user/dscl.rb +277 -0
  139. data/lib/chef/provider/user/useradd.rb +1 -0
  140. data/lib/chef/recipe.rb +2 -41
  141. data/lib/chef/resource.rb +9 -3
  142. data/lib/chef/resource/breakpoint.rb +35 -0
  143. data/lib/chef/resource/deploy.rb +16 -2
  144. data/lib/chef/resource/easy_install_package.rb +41 -0
  145. data/lib/chef/resource/erl_call.rb +83 -0
  146. data/lib/chef/resource/freebsd_package.rb +35 -0
  147. data/lib/chef/resource/log.rb +62 -0
  148. data/lib/chef/resource/mdadm.rb +82 -0
  149. data/lib/chef/resource/pacman_package.rb +33 -0
  150. data/lib/chef/resource/ruby_block.rb +21 -2
  151. data/lib/chef/resource/scm.rb +8 -0
  152. data/lib/chef/resource/subversion.rb +1 -0
  153. data/lib/chef/resource/user.rb +5 -2
  154. data/lib/chef/resource/yum_package.rb +36 -0
  155. data/lib/chef/resource_collection.rb +17 -9
  156. data/lib/chef/resource_collection/stepable_iterator.rb +124 -0
  157. data/lib/chef/rest.rb +166 -81
  158. data/lib/chef/role.rb +114 -38
  159. data/lib/chef/run_list.rb +15 -6
  160. data/lib/chef/runner.rb +13 -11
  161. data/lib/chef/search/query.rb +60 -0
  162. data/lib/chef/shef.rb +220 -0
  163. data/lib/chef/shef/ext.rb +297 -0
  164. data/lib/chef/shef/shef_session.rb +175 -0
  165. data/lib/chef/streaming_cookbook_uploader.rb +187 -0
  166. data/lib/chef/tasks/chef_repo.rake +53 -155
  167. data/lib/chef/util/file_edit.rb +94 -96
  168. data/lib/chef/webui_user.rb +233 -0
  169. metadata +219 -63
  170. data/distro/debian/etc/init.d/chef-indexer +0 -175
  171. data/distro/redhat/etc/chef/client.rb +0 -16
  172. data/distro/redhat/etc/chef/indexer.rb +0 -10
  173. data/distro/redhat/etc/chef/server.rb +0 -22
  174. data/distro/redhat/etc/init.d/chef-indexer +0 -76
  175. data/lib/chef/application/indexer.rb +0 -141
  176. data/lib/chef/queue.rb +0 -145
  177. data/lib/chef/search.rb +0 -88
  178. data/lib/chef/search/result.rb +0 -64
  179. data/lib/chef/search_index.rb +0 -77
  180. data/lib/chef/util/fileedit.rb +0 -121
@@ -0,0 +1,187 @@
1
+ require 'net/http'
2
+ require 'mixlib/authentication/signedheaderauth'
3
+ require 'openssl'
4
+
5
+ # inspired by/cargo-culted from http://stanislavvitvitskiy.blogspot.com/2008/12/multipart-post-in-ruby.html
6
+ # TODO: confirm that code is public domain
7
+ class Chef
8
+ class StreamingCookbookUploader
9
+
10
+ DefaultHeaders = { 'accept' => 'application/json' }
11
+
12
+ class << self
13
+
14
+ def post(to_url, user_id, secret_key_filename, params = {}, headers = {})
15
+ make_request(:post, to_url, user_id, secret_key_filename, params, headers)
16
+ end
17
+
18
+ def put(to_url, user_id, secret_key_filename, params = {}, headers = {})
19
+ make_request(:put, to_url, user_id, secret_key_filename, params, headers)
20
+ end
21
+
22
+ def make_request(http_verb, to_url, user_id, secret_key_filename, params = {}, headers = {})
23
+ boundary = '----RubyMultipartClient' + rand(1000000).to_s + 'ZZZZZ'
24
+ parts = []
25
+ content_file = nil
26
+ content_body = nil
27
+
28
+ timestamp = Time.now.utc.iso8601
29
+ secret_key = OpenSSL::PKey::RSA.new(File.read(secret_key_filename))
30
+
31
+ unless params.nil? || params.empty?
32
+ params.each do |key, value|
33
+ if value.kind_of?(File)
34
+ content_file = value
35
+ filepath = value.path
36
+ filename = File.basename(filepath)
37
+ parts << StringPart.new( "--" + boundary + "\r\n" +
38
+ "Content-Disposition: form-data; name=\"" + key.to_s + "\"; filename=\"" + filename + "\"\r\n" +
39
+ "Content-Type: application/octet-stream\r\n\r\n")
40
+ parts << StreamPart.new(value, File.size(filepath))
41
+ parts << StringPart.new("\r\n")
42
+ else
43
+ content_body = value.to_s
44
+ parts << StringPart.new( "--" + boundary + "\r\n" +
45
+ "Content-Disposition: form-data; name=\"" + key.to_s + "\"\r\n\r\n")
46
+ parts << StringPart.new(content_body + "\r\n")
47
+ end
48
+ end
49
+ parts << StringPart.new("--" + boundary + "--\r\n")
50
+ end
51
+
52
+ body_stream = MultipartStream.new(parts)
53
+
54
+ timestamp = Time.now.utc.iso8601
55
+
56
+ url = URI.parse(to_url)
57
+
58
+ Chef::Log.logger.debug("Signing: method: #{http_verb}, path: #{url.path}, file: #{content_file}, User-id: #{user_id}, Timestamp: #{timestamp}")
59
+
60
+ signing_options = {
61
+ :http_method=>http_verb,
62
+ :path=>url.path,
63
+ :user_id=>user_id,
64
+ :timestamp=>timestamp}
65
+ (content_file && signing_options[:file] = content_file) || (signing_options[:body] = (content_body || ""))
66
+
67
+ headers.merge!(Mixlib::Authentication::SignedHeaderAuth.signing_object(signing_options).sign(secret_key))
68
+
69
+ content_file.rewind if content_file
70
+
71
+ # net/http doesn't like symbols for header keys, so we'll to_s each one just in case
72
+ headers = DefaultHeaders.merge(Hash[*headers.map{ |k,v| [k.to_s, v] }.flatten])
73
+
74
+ req = case http_verb
75
+ when :put
76
+ Net::HTTP::Put.new(url.path, headers)
77
+ when :post
78
+ Net::HTTP::Post.new(url.path, headers)
79
+ end
80
+ req.content_length = body_stream.size
81
+ req.content_type = 'multipart/form-data; boundary=' + boundary unless parts.empty?
82
+ req.body_stream = body_stream
83
+
84
+ http = Net::HTTP.new(url.host, url.port)
85
+ if url.scheme == "https"
86
+ http.use_ssl = true
87
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
88
+ end
89
+ res = http.request(req)
90
+ #res = http.start {|http_proc| http_proc.request(req) }
91
+
92
+ # alias status to code and to_s to body for test purposes
93
+ # TODO: stop the following madness!
94
+ class << res
95
+ alias :to_s :body
96
+
97
+ # BUGBUG this makes the response compatible with what respsonse_steps expects to test headers (response.headers[] -> response[])
98
+ def headers
99
+ self
100
+ end
101
+
102
+ def status
103
+ code.to_i
104
+ end
105
+ end
106
+ res
107
+ end
108
+
109
+ end
110
+
111
+ class StreamPart
112
+ def initialize(stream, size)
113
+ @stream, @size = stream, size
114
+ end
115
+
116
+ def size
117
+ @size
118
+ end
119
+
120
+ # read the specified amount from the stream
121
+ def read(offset, how_much)
122
+ @stream.read(how_much)
123
+ end
124
+ end
125
+
126
+ class StringPart
127
+ def initialize(str)
128
+ @str = str
129
+ end
130
+
131
+ def size
132
+ @str.length
133
+ end
134
+
135
+ # read the specified amount from the string startiung at the offset
136
+ def read(offset, how_much)
137
+ @str[offset, how_much]
138
+ end
139
+ end
140
+
141
+ class MultipartStream
142
+ def initialize(parts)
143
+ @parts = parts
144
+ @part_no = 0
145
+ @part_offset = 0
146
+ end
147
+
148
+ def size
149
+ @parts.inject(0) {|size, part| size + part.size}
150
+ end
151
+
152
+ def read(how_much)
153
+ return nil if @part_no >= @parts.size
154
+
155
+ how_much_current_part = @parts[@part_no].size - @part_offset
156
+
157
+ how_much_current_part = if how_much_current_part > how_much
158
+ how_much
159
+ else
160
+ how_much_current_part
161
+ end
162
+
163
+ how_much_next_part = how_much - how_much_current_part
164
+
165
+ current_part = @parts[@part_no].read(@part_offset, how_much_current_part)
166
+
167
+ # recurse into the next part if the current one was not large enough
168
+ if how_much_next_part > 0
169
+ @part_no += 1
170
+ @part_offset = 0
171
+ next_part = read(how_much_next_part)
172
+ current_part + if next_part
173
+ next_part
174
+ else
175
+ ''
176
+ end
177
+ else
178
+ @part_offset += how_much_current_part
179
+ current_part
180
+ end
181
+ end
182
+ end
183
+
184
+ end
185
+
186
+
187
+ end
@@ -24,6 +24,20 @@ require 'chef/cookbook/metadata'
24
24
  require 'tempfile'
25
25
  require 'rake'
26
26
 
27
+ # Allow REMOTE options to be overridden on the command line
28
+ REMOTE_HOST = ENV["REMOTE_HOST"] if ENV["REMOTE_HOST"] != nil
29
+ REMOTE_SUDO = ENV["REMOTE_SUDO"] if ENV["REMOTE_SUDO"] != nil
30
+ if defined? REMOTE_HOST
31
+ REMOTE_PATH_PREFIX = "#{REMOTE_HOST}:"
32
+ REMOTE_EXEC_PREFIX = "ssh #{REMOTE_HOST}"
33
+ REMOTE_EXEC_PREFIX += " sudo" if defined? REMOTE_SUDO
34
+ LOCAL_EXEC_PREFIX = ""
35
+ else
36
+ REMOTE_PATH_PREFIX = ""
37
+ REMOTE_EXEC_PREFIX = ""
38
+ LOCAL_EXEC_PREFIX = "sudo"
39
+ end
40
+
27
41
  desc "Update your repository from source control"
28
42
  task :update do
29
43
  puts "** Updating your repository"
@@ -33,7 +47,6 @@ task :update do
33
47
  sh %{svn up}
34
48
  when :git
35
49
  pull = false
36
- pull = true if File.join(TOPDIR, ".git", "remotes", "origin")
37
50
  IO.foreach(File.join(TOPDIR, ".git", "config")) do |line|
38
51
  pull = true if line =~ /\[remote "origin"\]/
39
52
  end
@@ -47,124 +60,15 @@ task :update do
47
60
  end
48
61
  end
49
62
 
50
- desc "Test your cookbooks for syntax errors"
51
- task :test_recipes do
52
- puts "** Testing your cookbooks for syntax errors"
53
-
54
- if File.exists?(TEST_CACHE)
55
- cache = JSON.load(open(TEST_CACHE).read)
56
- trap("INT") { puts "INT received, flushing test cache"; write_cache(cache) }
57
- else
58
- cache = {}
59
- end
60
-
61
- recipes = ["*cookbooks"].map { |folder|
62
- Dir[File.join(TOPDIR, folder, "**", "*.rb")]
63
- }.flatten
64
-
65
- recipes.each do |recipe|
66
- print "Testing recipe #{recipe}: "
67
-
68
- recipe_mtime = File.stat(recipe).mtime.to_s
69
- if cache.has_key?(recipe)
70
- if cache[recipe]["mtime"] == recipe_mtime
71
- puts "No modification since last test."
72
- next
73
- end
74
- else
75
- cache[recipe] = {}
76
- end
77
-
78
-
79
- sh %{ruby -c #{recipe}} do |ok, res|
80
- if ok
81
- cache[recipe]["mtime"] = recipe_mtime
82
- else
83
- write_cache(cache)
84
- raise "Syntax error in #{recipe}"
85
- end
86
- end
87
- end
88
-
89
- write_cache(cache)
90
- end
91
-
92
- desc "Test your templates for syntax errors"
93
- task :test_templates do
94
- puts "** Testing your cookbooks for syntax errors"
95
-
96
- if File.exists?(TEST_CACHE)
97
- cache = JSON.load(open(TEST_CACHE).read)
98
- trap("INT") { puts "INT received, flushing test cache"; write_cache(cache) }
99
- else
100
- cache = {}
101
- end
102
-
103
- templates = ["*cookbooks"].map { |folder|
104
- Dir[File.join(TOPDIR, folder, "**", "*.erb")]
105
- }.flatten
106
-
107
- templates.each do |template|
108
- print "Testing template #{template}: "
109
-
110
- template_mtime = File.stat(template).mtime.to_s
111
- if cache.has_key?(template)
112
- if cache[template]["mtime"] == template_mtime
113
- puts "No change since last test."
114
- next
115
- end
116
- else
117
- cache[template] = {}
118
- end
119
-
120
- sh %{erubis -x #{template} | ruby -c} do |ok, res|
121
- if ok
122
- cache[template]["mtime"] = template_mtime
123
- else
124
- write_cache(cache)
125
- raise "Syntax error in #{template}"
126
- end
127
- end
128
-
129
- end
130
-
131
- write_cache(cache)
132
- end
133
-
134
- desc "Test your cookbooks for syntax errors"
135
- task :test => [ :test_recipes , :test_templates ]
136
-
137
- def write_cache(cache)
138
- File.open(TEST_CACHE, "w") { |f| JSON.dump(cache, f) }
139
- end
140
-
141
63
  desc "Install the latest copy of the repository on this Chef Server"
142
- task :install => [ :update, :test, :metadata, :roles ] do
143
- puts "** Installing your cookbooks"
144
- directories = [
145
- COOKBOOK_PATH,
146
- SITE_COOKBOOK_PATH,
147
- CHEF_CONFIG_PATH
148
- ]
149
- puts "* Creating Directories"
150
- directories.each do |dir|
151
- sh "sudo mkdir -p #{dir}"
152
- sh "sudo chown root #{dir}"
153
- end
154
- puts "* Installing new Cookbooks"
155
- sh "sudo rsync -rlP --delete --exclude '.svn' --exclude '.git*' cookbooks/ #{COOKBOOK_PATH}"
156
- puts "* Installing new Site Cookbooks"
157
- sh "sudo rsync -rlP --delete --exclude '.svn' --exclude '.git*' site-cookbooks/ #{SITE_COOKBOOK_PATH}"
158
- puts "* Installing new Node Roles"
159
- sh "sudo rsync -rlP --delete --exclude '.svn' --exclude '.git*' roles/ #{ROLE_PATH}"
160
-
161
- if File.exists?(File.join(File.dirname(__FILE__), "config", "server.rb"))
64
+ task :install => [ :update, :roles, :upload_cookbooks ] do
65
+ if File.exists?(File.join(TOPDIR, "config", "server.rb"))
162
66
  puts "* Installing new Chef Server Config"
163
- sh "sudo cp config/server.rb #{CHEF_SERVER_CONFIG}"
67
+ sh "#{LOCAL_EXEC_PREFIX} rsync -rlt --delete --exclude '.svn' --exclude '.git*' config/server.rb #{REMOTE_PATH_PREFIX}#{CHEF_SERVER_CONFIG}"
164
68
  end
165
- if File.exists?(File.join(File.dirname(__FILE__), "config", "client.rb"))
69
+ if File.exists?(File.join(TOPDIR, "config", "client.rb"))
166
70
  puts "* Installing new Chef Client Config"
167
- sh "sudo cp config/client.rb #{CHEF_CLIENT_CONFIG}"
71
+ sh "#{LOCAL_EXEC_PREFIX} rsync -rlt --delete --exclude '.svn' --exclude '.git*' config/client.rb #{REMOTE_PATH_PREFIX}#{CHEF_CLIENT_CONFIG}"
168
72
  end
169
73
  end
170
74
 
@@ -279,12 +183,13 @@ task :ssl_cert do
279
183
  fqdn =~ /^(.+?)\.(.+)$/
280
184
  hostname = $1
281
185
  domain = $2
186
+ keyfile = fqdn.gsub("*", "wildcard")
282
187
  raise "Must provide FQDN!" unless fqdn && hostname && domain
283
188
  puts "** Creating self signed SSL Certificate for #{fqdn}"
284
- sh("(cd #{CADIR} && openssl genrsa 2048 > #{fqdn}.key)")
285
- sh("(cd #{CADIR} && chmod 644 #{fqdn}.key)")
189
+ sh("(cd #{CADIR} && openssl genrsa 2048 > #{keyfile}.key)")
190
+ sh("(cd #{CADIR} && chmod 644 #{keyfile}.key)")
286
191
  puts "* Generating Self Signed Certificate Request"
287
- tf = Tempfile.new("#{fqdn}.ssl-conf")
192
+ tf = Tempfile.new("#{keyfile}.ssl-conf")
288
193
  ssl_config = <<EOH
289
194
  [ req ]
290
195
  distinguished_name = req_distinguished_name
@@ -301,47 +206,40 @@ emailAddress = #{SSL_EMAIL_ADDRESS}
301
206
  EOH
302
207
  tf.puts(ssl_config)
303
208
  tf.close
304
- sh("(cd #{CADIR} && openssl req -config '#{tf.path}' -new -x509 -nodes -sha1 -days 3650 -key #{fqdn}.key > #{fqdn}.crt)")
305
- sh("(cd #{CADIR} && openssl x509 -noout -fingerprint -text < #{fqdn}.crt > #{fqdn}.info)")
306
- sh("(cd #{CADIR} && cat #{fqdn}.crt #{fqdn}.key > #{fqdn}.pem)")
307
- sh("(cd #{CADIR} && chmod 644 #{fqdn}.pem)")
209
+ sh("(cd #{CADIR} && openssl req -config '#{tf.path}' -new -x509 -nodes -sha1 -days 3650 -key #{keyfile}.key > #{keyfile}.crt)")
210
+ sh("(cd #{CADIR} && openssl x509 -noout -fingerprint -text < #{keyfile}.crt > #{keyfile}.info)")
211
+ sh("(cd #{CADIR} && cat #{keyfile}.crt #{keyfile}.key > #{keyfile}.pem)")
212
+ sh("(cd #{CADIR} && chmod 644 #{keyfile}.pem)")
213
+ end
214
+
215
+ rule(%r{\b(?:site-)?cookbooks/[^/]+/metadata\.json\Z} => [ proc { |task_name| task_name.sub(/\.[^.]+$/, '.rb') } ]) do |t|
216
+ system("knife cookbook metadata #{t.source}")
308
217
  end
309
218
 
310
219
  desc "Build cookbook metadata.json from metadata.rb"
311
- task :metadata do
312
- Chef::Config[:cookbook_path] = [ File.join(TOPDIR, 'cookbooks'), File.join(TOPDIR, 'site-cookbooks') ]
313
- cl = Chef::CookbookLoader.new
314
- cl.each do |cookbook|
315
- if ENV['COOKBOOK']
316
- next unless cookbook.name.to_s == ENV['COOKBOOK']
317
- end
318
- cook_meta = Chef::Cookbook::Metadata.new(cookbook)
319
- Chef::Config.cookbook_path.each do |cdir|
320
- metadata_rb_file = File.join(cdir, cookbook.name.to_s, 'metadata.rb')
321
- metadata_json_file = File.join(cdir, cookbook.name.to_s, 'metadata.json')
322
- if File.exists?(metadata_rb_file)
323
- puts "Generating metadata for #{cookbook.name}"
324
- cook_meta.from_file(metadata_rb_file)
325
- File.open(metadata_json_file, "w") do |f|
326
- f.write(JSON.pretty_generate(cook_meta))
327
- end
328
- end
329
- end
330
- end
220
+ task :metadata => FileList[File.join(TOPDIR, '*cookbooks', ENV['COOKBOOK'] || '*', 'metadata.rb')].pathmap('%X.json')
221
+
222
+ rule(%r{\broles/\S+\.json\Z} => [ proc { |task_name| task_name.sub(/\.[^.]+$/, '.rb') } ]) do |t|
223
+ system("knife role from file #{t.source}")
331
224
  end
332
225
 
333
- desc "Build roles from roles/role_name.json from role_name.rb"
334
- task :roles do
335
- Chef::Config[:role_path] = File.join(TOPDIR, 'roles')
336
- Dir[File.join(TOPDIR, 'roles', '**', '*.rb')].each do |role_file|
337
- short_name = File.basename(role_file, '.rb')
338
- puts "Generating role JSON for #{short_name}"
339
- role = Chef::Role.new
340
- role.name(short_name)
341
- role.from_file(role_file)
342
- File.open(File.join(TOPDIR, 'roles', "#{short_name}.json"), "w") do |f|
343
- f.write(JSON.pretty_generate(role))
344
- end
345
- end
226
+ desc "Update roles"
227
+ task :roles => FileList[File.join(TOPDIR, 'roles', '**', '*.rb')].pathmap('%X.json')
228
+
229
+ desc "Update a specific role"
230
+ task :role, :role_name do |t, args|
231
+ system("knife role from file #{args.cookbook}")
232
+ end
233
+
234
+ desc "Upload all cookbooks"
235
+ task :upload_cookbooks => [ :metadata ]
236
+ task :upload_cookbooks do
237
+ system("knife cookbook upload --all")
238
+ end
239
+
240
+ desc "Upload a single cookbook"
241
+ task :upload_cookbook => [ :metadata ]
242
+ task :upload_cookbook, :cookbook do |t, args|
243
+ system("knife cookbook upload #{args.cookbook}")
346
244
  end
347
245
 
@@ -20,106 +20,104 @@ require 'fileutils'
20
20
  require 'tempfile'
21
21
 
22
22
  class Chef
23
- class Util
24
- class FileEdit
23
+ class Util
24
+ class FileEdit
25
25
 
26
- private
27
-
28
- attr_accessor :original_pathname, :contents, :file_edited
26
+ private
27
+
28
+ attr_accessor :original_pathname, :contents, :file_edited
29
29
 
30
- public
31
-
32
- def initialize(filepath)
33
- @original_pathname = filepath
34
- @file_edited = false
35
-
36
- raise ArgumentError, "File doesn't exist" unless File.exist? @original_pathname
37
- raise ArgumentError, "File is blank" unless (@contents = File.new(@original_pathname).readlines).length > 0
38
- end
39
-
40
- #search the file line by line and match each line with the given regex
41
- #if matched, replace the whole line with newline.
42
- def search_file_replace_line(regex, newline)
43
- search_match(regex, newline, 'r', 1)
44
- end
30
+ public
31
+
32
+ def initialize(filepath)
33
+ @original_pathname = filepath
34
+ @file_edited = false
35
+
36
+ raise ArgumentError, "File doesn't exist" unless File.exist? @original_pathname
37
+ raise ArgumentError, "File is blank" unless (@contents = File.new(@original_pathname).readlines).length > 0
38
+ end
39
+
40
+ #search the file line by line and match each line with the given regex
41
+ #if matched, replace the whole line with newline.
42
+ def search_file_replace_line(regex, newline)
43
+ search_match(regex, newline, 'r', 1)
44
+ end
45
45
 
46
- #search the file line by line and match each line with the given regex
47
- #if matched, replace the match (all occurances) with the replace parameter
48
- def search_file_replace(regex, replace)
49
- search_match(regex, replace, 'r', 2)
50
- end
51
-
52
- #search the file line by line and match each line with the given regex
53
- #if matched, delete the line
54
- def search_file_delete_line(regex)
55
- search_match(regex, " ", 'd', 1)
56
- end
57
-
58
- #search the file line by line and match each line with the given regex
59
- #if matched, delete the match (all occurances) from the line
60
- def search_file_delete(regex)
61
- search_match(regex, " ", 'd', 2)
62
- end
46
+ #search the file line by line and match each line with the given regex
47
+ #if matched, replace the match (all occurances) with the replace parameter
48
+ def search_file_replace(regex, replace)
49
+ search_match(regex, replace, 'r', 2)
50
+ end
51
+
52
+ #search the file line by line and match each line with the given regex
53
+ #if matched, delete the line
54
+ def search_file_delete_line(regex)
55
+ search_match(regex, " ", 'd', 1)
56
+ end
57
+
58
+ #search the file line by line and match each line with the given regex
59
+ #if matched, delete the match (all occurances) from the line
60
+ def search_file_delete(regex)
61
+ search_match(regex, " ", 'd', 2)
62
+ end
63
63
 
64
- #search the file line by line and match each line with the given regex
65
- #if matched, insert newline after each matching line
66
- def insert_line_after_match(regex, newline)
67
- search_match(regex, newline, 'i', 0)
68
- end
69
-
70
- #Make a copy of old_file and write new file out (only if file changed)
71
- def write_file
72
-
73
- # file_edited is false when there was no match in the whole file and thus no contents have changed.
74
- if file_edited
75
- backup_pathname = original_pathname + ".old"
76
- File.copy(original_pathname, backup_pathname)
77
- Tempfile.open("w") do |newfile|
78
- contents.each do |line|
79
- newfile.puts(line)
80
- end
81
- newfile.flush
82
- FileUtils.mv(newfile.path, original_pathname)
83
- end
84
- end
85
- self.file_edited = false
64
+ #search the file line by line and match each line with the given regex
65
+ #if matched, insert newline after each matching line
66
+ def insert_line_after_match(regex, newline)
67
+ search_match(regex, newline, 'i', 0)
68
+ end
69
+
70
+ #Make a copy of old_file and write new file out (only if file changed)
71
+ def write_file
72
+
73
+ # file_edited is false when there was no match in the whole file and thus no contents have changed.
74
+ if file_edited
75
+ backup_pathname = original_pathname + ".old"
76
+ FileUtils.cp(original_pathname, backup_pathname, :preserve => true)
77
+ File.open(original_pathname, "w") do |newfile|
78
+ contents.each do |line|
79
+ newfile.puts(line)
80
+ end
81
+ newfile.flush
82
+ end
83
+ end
84
+ self.file_edited = false
85
+ end
86
+
87
+ private
88
+
89
+ #helper method to do the match, replace, delete, and insert operations
90
+ #command is the switch of delete, replace, and insert ('d', 'r', 'i')
91
+ #method is to control operation on whole line or only the match (1 for line, 2 for match)
92
+ def search_match(regex, replace, command, method)
93
+
94
+ #convert regex to a Regexp object (if not already is one) and store it in exp.
95
+ exp = Regexp.new(regex)
86
96
 
87
- end
88
-
89
- private
90
-
91
- #helper method to do the match, replace, delete, and insert operations
92
- #command is the switch of delete, replace, and insert ('d', 'r', 'i')
93
- #method is to control operation on whole line or only the match (1 for line, 2 for match)
94
- def search_match(regex, replace, command, method)
95
-
96
- #convert regex to a Regexp object (if not already is one) and store it in exp.
97
- exp = Regexp.new(regex)
97
+ #loop through contents and do the appropriate operation depending on 'command' and 'method'
98
+ new_contents = []
99
+
100
+ contents.each do |line|
101
+ if line.match(exp)
102
+ self.file_edited = true
103
+ case
104
+ when command == 'r'
105
+ new_contents << ((method == 1) ? replace : line.gsub!(exp, replace))
106
+ when command == 'd'
107
+ if method == 2
108
+ new_contents << line.gsub!(exp, "")
109
+ end
110
+ when command == 'i'
111
+ new_contents << line
112
+ new_contents << replace
113
+ end
114
+ else
115
+ new_contents << line
116
+ end
117
+ end
98
118
 
99
- #loop through contents and do the appropriate operation depending on 'command' and 'method'
100
- new_contents = []
101
-
102
- contents.each do |line|
103
- if line.match(exp)
104
- self.file_edited = true
105
- case
106
- when command == 'r'
107
- new_contents << ((method == 1) ? replace : line.gsub!(exp, replace))
108
- when command == 'd'
109
- if method == 2
110
- new_contents << line.gsub!(exp, "")
111
- end
112
- when command == 'i'
113
- new_contents << line
114
- new_contents << replace
115
- end
116
- else
117
- new_contents << line
118
- end
119
- end
120
-
121
- self.contents = new_contents
122
- end
123
- end
124
- end
119
+ self.contents = new_contents
120
+ end
121
+ end
122
+ end
125
123
  end