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
@@ -41,7 +41,13 @@ class Chef
41
41
  build_report_dir
42
42
  savetime = Time.now.strftime("%Y%m%d%H%M%S")
43
43
  File.open(File.join(config[:path], "chef-run-report-#{savetime}.json"), "w") do |file|
44
- file.puts Chef::JSONCompat.to_json_pretty(data)
44
+
45
+ #ensure start time and end time are output in the json properly in the event activesupport happens to be on the system
46
+ run_data = data
47
+ run_data[:start_time] = run_data[:start_time].to_s
48
+ run_data[:end_time] = run_data[:end_time].to_s
49
+
50
+ file.puts Chef::JSONCompat.to_json_pretty(run_data)
45
51
  end
46
52
  end
47
53
 
@@ -21,6 +21,7 @@ require 'forwardable'
21
21
  require 'chef/version'
22
22
  require 'mixlib/cli'
23
23
  require 'chef/mixin/convert_to_class_name'
24
+ require 'chef/mixin/path_sanity'
24
25
  require 'chef/knife/core/subcommand_loader'
25
26
  require 'chef/knife/core/ui'
26
27
  require 'chef/rest'
@@ -32,6 +33,7 @@ class Chef
32
33
  Chef::REST::RESTRequest.user_agent = "Chef Knife#{Chef::REST::RESTRequest::UA_COMMON}"
33
34
 
34
35
  include Mixlib::CLI
36
+ include Chef::Mixin::PathSanity
35
37
  extend Chef::Mixin::ConvertToClassName
36
38
  extend Forwardable
37
39
 
@@ -160,7 +162,7 @@ class Chef
160
162
  load_commands
161
163
  subcommand_class = subcommand_class_from(args)
162
164
  subcommand_class.options = options.merge!(subcommand_class.options)
163
- subcommand_class.load_deps unless want_help?(args)
165
+ subcommand_class.load_deps
164
166
  instance = subcommand_class.new(args)
165
167
  instance.configure_chef
166
168
  instance.run_with_pretty_exceptions
@@ -210,9 +212,7 @@ class Chef
210
212
  # Error out and print usage. probably becuase the arguments given by the
211
213
  # user could not be resolved to a subcommand.
212
214
  def self.subcommand_not_found!(args)
213
- unless want_help?(args)
214
- ui.fatal("Cannot find sub command for: '#{args.join(' ')}'")
215
- end
215
+ ui.fatal("Cannot find sub command for: '#{args.join(' ')}'")
216
216
 
217
217
  if category_commands = guess_category(args)
218
218
  list_commands(category_commands)
@@ -226,13 +226,6 @@ class Chef
226
226
  exit 10
227
227
  end
228
228
 
229
- # :nodoc:
230
- # TODO: duplicated with chef/application/knife
231
- # all logic should be removed from that and Chef::Knife should own it.
232
- def self.want_help?(args)
233
- (args.any? { |arg| arg =~ /^(:?(:?\-\-)?help|\-h)$/})
234
- end
235
-
236
229
  @@chef_config_dir = nil
237
230
 
238
231
  # search upward from current_dir until .chef directory is found
@@ -241,9 +234,9 @@ class Chef
241
234
  @@chef_config_dir = false
242
235
  full_path = Dir.pwd.split(File::SEPARATOR)
243
236
  (full_path.length - 1).downto(0) do |i|
244
- canidate_directory = File.join(full_path[0..i] + [".chef" ])
245
- if File.exist?(canidate_directory) && File.directory?(canidate_directory)
246
- @@chef_config_dir = canidate_directory
237
+ candidate_directory = File.join(full_path[0..i] + [".chef" ])
238
+ if File.exist?(candidate_directory) && File.directory?(candidate_directory)
239
+ @@chef_config_dir = candidate_directory
247
240
  break
248
241
  end
249
242
  end
@@ -304,11 +297,11 @@ class Chef
304
297
  read_config_file(config[:config_file])
305
298
  else
306
299
  # ...but do log a message if no config was found.
307
- Chef::Config[:color] = config[:color] && !config[:no_color]
300
+ Chef::Config[:color] = config[:color]
308
301
  ui.warn("No knife configuration file found")
309
302
  end
310
303
 
311
- Chef::Config[:color] = config[:color] && !config[:no_color]
304
+ Chef::Config[:color] = config[:color]
312
305
 
313
306
  case config[:verbosity]
314
307
  when 0
@@ -388,6 +381,7 @@ class Chef
388
381
  unless self.respond_to?(:run)
389
382
  ui.error "You need to add a #run method to your knife command before you can use it"
390
383
  end
384
+ enforce_path_sanity
391
385
  run
392
386
  rescue Exception => e
393
387
  raise if config[:verbosity] == 2
@@ -53,6 +53,12 @@ class Chef
53
53
  :default => "22",
54
54
  :proc => Proc.new { |key| Chef::Config[:knife][:ssh_port] = key }
55
55
 
56
+ option :ssh_gateway,
57
+ :short => "-G GATEWAY",
58
+ :long => "--ssh-gateway GATEWAY",
59
+ :description => "The ssh gateway",
60
+ :proc => Proc.new { |key| Chef::Config[:knife][:ssh_gateway] = key }
61
+
56
62
  option :identity_file,
57
63
  :short => "-i IDENTITY_FILE",
58
64
  :long => "--identity-file IDENTITY_FILE",
@@ -81,7 +87,7 @@ class Chef
81
87
  :short => "-d DISTRO",
82
88
  :long => "--distro DISTRO",
83
89
  :description => "Bootstrap a distro using a template",
84
- :default => "ubuntu10.04-gems"
90
+ :default => "chef-full"
85
91
 
86
92
  option :use_sudo,
87
93
  :long => "--sudo",
@@ -100,11 +106,11 @@ class Chef
100
106
  :proc => lambda { |o| o.split(/[\s,]+/) },
101
107
  :default => []
102
108
 
103
- option :no_host_key_verify,
104
- :long => "--no-host-key-verify",
105
- :description => "Disable host key verification",
109
+ option :host_key_verify,
110
+ :long => "--[no-]host-key-verify",
111
+ :description => "Verify host key, enabled by default.",
106
112
  :boolean => true,
107
- :default => false
113
+ :default => true
108
114
 
109
115
  def load_template(template=nil)
110
116
  # Are we bootstrapping using an already shipped template?
@@ -113,8 +119,8 @@ class Chef
113
119
  else
114
120
  bootstrap_files = []
115
121
  bootstrap_files << File.join(File.dirname(__FILE__), 'bootstrap', "#{config[:distro]}.erb")
116
- bootstrap_files << File.join(@@chef_config_dir, "bootstrap", "#{config[:distro]}.erb")
117
- bootstrap_files << File.join(ENV['HOME'], '.chef', 'bootstrap', "#{config[:distro]}.erb")
122
+ bootstrap_files << File.join(Knife.chef_config_dir, "bootstrap", "#{config[:distro]}.erb") if Knife.chef_config_dir
123
+ bootstrap_files << File.join(ENV['HOME'], '.chef', 'bootstrap', "#{config[:distro]}.erb") if ENV['HOME']
118
124
  bootstrap_files << Gem.find_files(File.join("chef","knife","bootstrap","#{config[:distro]}.erb"))
119
125
  bootstrap_files.flatten!
120
126
  end
@@ -178,9 +184,10 @@ class Chef
178
184
  ssh.config[:ssh_user] = config[:ssh_user]
179
185
  ssh.config[:ssh_password] = config[:ssh_password]
180
186
  ssh.config[:ssh_port] = Chef::Config[:knife][:ssh_port] || config[:ssh_port]
187
+ ssh.config[:ssh_gateway] = Chef::Config[:knife][:ssh_gateway] || config[:ssh_gateway]
181
188
  ssh.config[:identity_file] = config[:identity_file]
182
189
  ssh.config[:manual] = true
183
- ssh.config[:no_host_key_verify] = config[:no_host_key_verify]
190
+ ssh.config[:host_key_verify] = config[:host_key_verify]
184
191
  ssh.config[:on_error] = :raise
185
192
  ssh
186
193
  end
@@ -2,7 +2,7 @@ bash -c '
2
2
  <%= "export http_proxy=\"#{knife_config[:bootstrap_proxy]}\"" if knife_config[:bootstrap_proxy] -%>
3
3
 
4
4
  if [ ! -f /usr/bin/chef-client ]; then
5
- wget <%= "--proxy=on " if knife_config[:bootstrap_proxy] %>http://download.fedora.redhat.com/pub/epel/5/i386/epel-release-5-4.noarch.rpm
5
+ wget <%= "--proxy=on " if knife_config[:bootstrap_proxy] %>http://dl.fedoraproject.org/pub/epel/5/i386/epel-release-5-4.noarch.rpm
6
6
  rpm -Uvh epel-release-5-4.noarch.rpm
7
7
  wget <%= "--proxy=on " if knife_config[:bootstrap_proxy] %>http://rpm.aegisco.com/aegisco/rhel/aegisco-rhel.rpm
8
8
  rpm -Uvh aegisco-rhel.rpm
@@ -0,0 +1,59 @@
1
+ bash -c '
2
+ <%= "export http_proxy=\"#{knife_config[:bootstrap_proxy]}\"" if knife_config[:bootstrap_proxy] -%>
3
+
4
+ exists() {
5
+ if command -v $1 &>/dev/null
6
+ then
7
+ return 0
8
+ else
9
+ return 1
10
+ fi
11
+ }
12
+
13
+ install_sh="http://opscode.com/chef/install.sh"
14
+ version_string="<%= "-v #{knife_config[:bootstrap_version]}" if knife_config[:bootstrap_version] %>"
15
+
16
+ if ! exists /usr/bin/chef-client; then
17
+ if exists wget; then
18
+ bash <(wget <%= "--proxy=on " if knife_config[:bootstrap_proxy] %> ${install_sh} -O -) ${version_string}
19
+ else
20
+ if exists curl; then
21
+ bash <(curl -L <%= "--proxy=on " if knife_config[:bootstrap_proxy] %> ${install_sh}) ${version_string}
22
+ fi
23
+ fi
24
+ fi
25
+
26
+ mkdir -p /etc/chef
27
+
28
+ (
29
+ cat <<'EOP'
30
+ <%= validation_key %>
31
+ EOP
32
+ ) > /tmp/validation.pem
33
+ awk NF /tmp/validation.pem > /etc/chef/validation.pem
34
+ rm /tmp/validation.pem
35
+
36
+
37
+ <% if @chef_config[:encrypted_data_bag_secret] -%>
38
+ (
39
+ cat <<'EOP'
40
+ <%= encrypted_data_bag_secret %>
41
+ EOP
42
+ ) > /tmp/encrypted_data_bag_secret
43
+ awk NF /tmp/encrypted_data_bag_secret > /etc/chef/encrypted_data_bag_secret
44
+ rm /tmp/encrypted_data_bag_secret
45
+ <% end -%>
46
+
47
+ (
48
+ cat <<'EOP'
49
+ <%= config_content %>
50
+ EOP
51
+ ) > /etc/chef/client.rb
52
+
53
+ (
54
+ cat <<'EOP'
55
+ <%= { "run_list" => @run_list }.to_json %>
56
+ EOP
57
+ ) > /etc/chef/first-boot.json
58
+
59
+ <%= start_chef %>'
@@ -2,6 +2,7 @@ bash -c '
2
2
  <%= "export http_proxy=\"#{knife_config[:bootstrap_proxy]}\"" if knife_config[:bootstrap_proxy] -%>
3
3
 
4
4
  if [ ! -f /usr/bin/chef-client ]; then
5
+ apt-get install -y wget
5
6
  echo "chef chef/chef_server_url string <%= @chef_config[:chef_server_url] %>" | debconf-set-selections
6
7
  [ -f /etc/apt/sources.list.d/opscode.list ] || echo "deb http://apt.opscode.com <%= chef_version.to_f == 0.10 ? "lucid-0.10" : "lucid" %> main" > /etc/apt/sources.list.d/opscode.list
7
8
  wget <%= "--proxy=on " if knife_config[:bootstrap_proxy] %>-O- http://apt.opscode.com/packages@opscode.com.gpg.key | apt-key add -
@@ -83,7 +83,7 @@ EOH
83
83
  client_create.config[:admin] = true
84
84
  client_create.config[:file] = new_client_key
85
85
  client_create.config[:yes] = true
86
- client_create.config[:no_editor] = true
86
+ client_create.config[:disable_editing] = true
87
87
  client_create.run
88
88
  else
89
89
  ui.msg("*****")
@@ -105,7 +105,7 @@ EOH
105
105
  end
106
106
 
107
107
  def ask_user_for_config_path
108
- config[:config_file] ||= ask_question("Where should I put the config file? ", :default => '~/.chef/knife.rb')
108
+ config[:config_file] ||= ask_question("Where should I put the config file? ", :default => "#{Chef::Config[:user_home]}/.chef/knife.rb")
109
109
  # have to use expand path to expand the tilde character to the user's home
110
110
  config[:config_file] = File.expand_path(config[:config_file])
111
111
  if File.exists?(config[:config_file])
@@ -21,7 +21,9 @@ class Chef
21
21
  class Knife
22
22
  class CookbookSiteDownload < Knife
23
23
 
24
- attr_reader :version
24
+ deps do
25
+ require 'fileutils'
26
+ end
25
27
 
26
28
  banner "knife cookbook site download COOKBOOK [VERSION] (options)"
27
29
  category "cookbook site"
@@ -36,35 +38,72 @@ class Chef
36
38
  :description => "Force download deprecated version"
37
39
 
38
40
  def run
39
- current = noauth_rest.get_rest("http://cookbooks.opscode.com/api/v1/cookbooks/#{name_args[0]}")
40
- if current["deprecated"] == true
41
- replacement = File.basename(current["replacement"])
42
- ui.warn("DEPRECATION: This cookbook has been deprecated. It has been replaced by #{replacement}.")
41
+ if current_cookbook_deprecated?
42
+ message = 'DEPRECATION: This cookbook has been deprecated. '
43
+ message << "It has been replaced by #{replacement_cookbook}."
44
+ ui.warn message
45
+
43
46
  unless config[:force]
44
- ui.warn("Use --force to force download deprecated cookbook.")
47
+ ui.warn 'Use --force to force download deprecated cookbook.'
45
48
  return
46
49
  end
47
50
  end
48
- cookbook_data = if @name_args.length == 1
49
- noauth_rest.get_rest(current["latest_version"])
50
- else
51
- noauth_rest.get_rest("http://cookbooks.opscode.com/api/v1/cookbooks/#{name_args[0]}/versions/#{name_args[1].gsub('.', '_')}")
52
- end
53
-
54
- @version = cookbook_data['version']
55
- unless config[:file]
56
- config[:file] = File.join(Dir.pwd, "#{@name_args[0]}-#{cookbook_data['version']}.tar.gz")
51
+
52
+ download_cookbook
53
+ end
54
+
55
+ def version
56
+ @version = desired_cookbook_data['version']
57
+ end
58
+
59
+ private
60
+ def cookbooks_api_url
61
+ 'http://cookbooks.opscode.com/api/v1/cookbooks'
62
+ end
63
+
64
+ def current_cookbook_data
65
+ @current_cookbook_data ||= begin
66
+ noauth_rest.get_rest "#{cookbooks_api_url}/#{@name_args[0]}"
57
67
  end
58
- ui.info("Downloading #{@name_args[0]} from the cookbooks site at version #{cookbook_data['version']} to #{config[:file]}")
68
+ end
69
+
70
+ def current_cookbook_deprecated?
71
+ current_cookbook_data['deprecated'] == true
72
+ end
73
+
74
+ def desired_cookbook_data
75
+ @desired_cookbook_data ||= begin
76
+ uri = if @name_args.length == 1
77
+ current_cookbook_data['latest_version']
78
+ else
79
+ specific_cookbook_version_url
80
+ end
81
+
82
+ noauth_rest.get_rest uri
83
+ end
84
+ end
85
+
86
+ def download_cookbook
87
+ ui.info "Downloading #{@name_args[0]} from the cookbooks site at version #{version} to #{download_location}"
59
88
  noauth_rest.sign_on_redirect = false
60
- tf = noauth_rest.get_rest(cookbook_data["file"], true)
89
+ tf = noauth_rest.get_rest desired_cookbook_data["file"], true
90
+
91
+ ::FileUtils.cp tf.path, download_location
92
+ ui.info "Cookbook saved: #{download_location}"
93
+ end
94
+
95
+ def download_location
96
+ config[:file] ||= File.join Dir.pwd, "#{@name_args[0]}-#{version}.tar.gz"
97
+ config[:file]
98
+ end
61
99
 
62
- FileUtils.cp(tf.path, config[:file])
63
- ui.info("Cookbook saved: #{config[:file]}")
100
+ def replacement_cookbook
101
+ replacement = File.basename(current_cookbook_data['replacement'])
64
102
  end
65
103
 
104
+ def specific_cookbook_version_url
105
+ "#{cookbooks_api_url}/#{@name_args[0]}/versions/#{@name_args[1].gsub('.', '_')}"
106
+ end
66
107
  end
67
108
  end
68
109
  end
69
-
70
-
@@ -17,6 +17,7 @@
17
17
  #
18
18
 
19
19
  require 'chef/knife'
20
+ require 'shellwords'
20
21
 
21
22
  class Chef
22
23
  class Knife
@@ -34,9 +35,10 @@ class Chef
34
35
 
35
36
  option :no_deps,
36
37
  :short => "-D",
37
- :long => "--no-dependencies",
38
+ :long => "--skip-dependencies",
38
39
  :boolean => true,
39
- :description => "Do not install dependencies automatically"
40
+ :default => false,
41
+ :description => "Skips automatic dependency installation."
40
42
 
41
43
  option :cookbook_path,
42
44
  :short => "-o PATH:PATH",
@@ -65,7 +67,7 @@ class Chef
65
67
  @cookbook_name = parse_name_args!
66
68
  # Check to ensure we have a valid source of cookbooks before continuing
67
69
  #
68
- @install_path = config[:cookbook_path].first
70
+ @install_path = File.expand_path(config[:cookbook_path].first)
69
71
  ui.info "Installing #@cookbook_name to #{@install_path}"
70
72
 
71
73
  @repo = CookbookSCMRepo.new(@install_path, ui, config)
@@ -78,12 +80,12 @@ class Chef
78
80
 
79
81
  downloader = download_cookbook_to(upstream_file)
80
82
  clear_existing_files(File.join(@install_path, @cookbook_name))
81
- extract_cookbook(upstream_file, @install_path)
83
+ extract_cookbook(upstream_file, downloader.version)
82
84
 
83
85
  # TODO: it'd be better to store these outside the cookbook repo and
84
86
  # keep them around, e.g., in ~/Library/Caches on OS X.
85
87
  ui.info("removing downloaded tarball")
86
- shell_out!("rm #{upstream_file}", :cwd => vendor_path)
88
+ File.unlink(upstream_file)
87
89
 
88
90
  if @repo.finalize_updates_to(@cookbook_name, downloader.version)
89
91
  @repo.reset_to_default_state
@@ -108,14 +110,15 @@ class Chef
108
110
 
109
111
  def parse_name_args!
110
112
  if name_args.empty?
111
- ui.error("please specify a cookbook to download and install")
113
+ ui.error("Please specify a cookbook to download and install.")
112
114
  exit 1
113
- elsif name_args.size > 1
114
- ui.error("Installing multiple cookbooks at once is not supported")
115
- exit 1
116
- else
117
- name_args.first
115
+ elsif name_args.size >= 2
116
+ unless name_args.last.match(/^(\d+)(\.\d+){1,2}$/) and name_args.size == 2
117
+ ui.error("Installing multiple cookbooks at once is not supported.")
118
+ exit 1
119
+ end
118
120
  end
121
+ name_args.first
119
122
  end
120
123
 
121
124
  def download_cookbook_to(download_path)
@@ -128,21 +131,13 @@ class Chef
128
131
 
129
132
  def extract_cookbook(upstream_file, version)
130
133
  ui.info("Uncompressing #{@cookbook_name} version #{version}.")
131
- shell_out!("tar zxvf #{upstream_file}", :cwd => @install_path)
134
+ shell_out!("tar zxvf #{Shellwords.escape upstream_file}", :cwd => @install_path)
132
135
  end
133
136
 
134
137
  def clear_existing_files(cookbook_path)
135
138
  ui.info("Removing pre-existing version.")
136
- shell_out!("rm -r #{cookbook_path}", :cwd => @install_path) if File.directory?(cookbook_path)
139
+ FileUtils.rmtree(cookbook_path) if File.directory?(cookbook_path)
137
140
  end
138
-
139
-
140
141
  end
141
142
  end
142
143
  end
143
-
144
-
145
-
146
-
147
-
148
-
@@ -68,49 +68,85 @@ class Chef
68
68
  :description => "Also upload cookbook dependencies"
69
69
 
70
70
  def run
71
+ # Sanity check before we load anything from the server
72
+ unless config[:all]
73
+ if @name_args.empty?
74
+ show_usage
75
+ ui.fatal("You must specify the --all flag or at least one cookbook name")
76
+ exit 1
77
+ end
78
+ end
79
+
71
80
  config[:cookbook_path] ||= Chef::Config[:cookbook_path]
72
81
 
82
+ if @name_args.empty? and ! config[:all]
83
+ show_usage
84
+ ui.fatal("You must specify the --all flag or at least one cookbook name")
85
+ exit 1
86
+ end
87
+
73
88
  assert_environment_valid!
74
89
  warn_about_cookbook_shadowing
75
90
  version_constraints_to_update = {}
91
+ upload_failures = 0
92
+ upload_ok = 0
93
+
76
94
  # Get a list of cookbooks and their versions from the server
77
- # for checking existence of dependending cookbooks.
78
- @server_side_cookbooks = Chef::CookbookVersion.list
95
+ # to check for the existence of a cookbook's dependencies.
96
+ @server_side_cookbooks = Chef::CookbookVersion.list_all_versions
97
+
98
+ justify_width = cookbooks_to_upload.map {|name, cookbook| name.size}.max.to_i + 2
79
99
 
80
- if config[:all]
81
- justify_width = cookbook_repo.cookbook_names.map {|name| name.size}.max.to_i + 2
82
- cookbook_repo.each do |cookbook_name, cookbook|
83
- cookbook.freeze_version if config[:freeze]
100
+ cookbooks_to_upload.each do |cookbook_name, cookbook|
101
+ cookbook.freeze_version if config[:freeze]
102
+ begin
84
103
  upload(cookbook, justify_width)
104
+ upload_ok += 1
85
105
  version_constraints_to_update[cookbook_name] = cookbook.version
106
+ rescue Exceptions::CookbookFrozen
107
+ upload_failures += 1
108
+ ui.warn("Not updating version constraints for #{cookbook_name} in the environment as the cookbook is frozen.") if config[:environment]
86
109
  end
87
- else
88
- if @name_args.empty?
89
- show_usage
90
- ui.error("You must specify the --all flag or at least one cookbook name")
91
- exit 1
92
- end
93
- justify_width = @name_args.map {|name| name.size }.max.to_i + 2
94
- @name_args.each do |cookbook_name|
110
+ end
111
+
112
+ upload_failures += config[:all] ? 0 : @name_args.length - @cookbooks_to_upload.length
113
+
114
+ if upload_failures == 0
115
+ ui.info "Uploaded #{upload_ok} cookbook#{upload_ok > 1 ? "s" : ""}."
116
+ elsif upload_failures > 0 && upload_ok > 0
117
+ ui.warn "Uploaded #{upload_ok} cookbook#{upload_ok > 1 ? "s" : ""} ok but #{upload_failures} " +
118
+ "cookbook#{upload_failures > 1 ? "s" : ""} upload failed."
119
+ elsif upload_failures > 0 && upload_ok == 0
120
+ ui.error "Failed to upload #{upload_failures} cookbook#{upload_failures > 1 ? "s" : ""}."
121
+ exit 1
122
+ end
123
+
124
+ unless version_constraints_to_update.empty?
125
+ update_version_constraints(version_constraints_to_update) if config[:environment]
126
+ end
127
+ end
128
+
129
+ def cookbooks_to_upload
130
+ @cookbooks_to_upload ||=
131
+ if config[:all]
132
+ cookbook_repo
133
+ else
134
+ upload_set = {}
135
+ @name_args.each do |cookbook_name|
95
136
  begin
96
- cookbook = cookbook_repo[cookbook_name]
97
- if config[:depends]
98
- cookbook.metadata.dependencies.each do |dep, versions|
99
- @name_args.push dep
137
+ if ! upload_set.has_key?(cookbook_name)
138
+ upload_set[cookbook_name] = cookbook_repo[cookbook_name]
139
+ if config[:depends]
140
+ upload_set[cookbook_name].metadata.dependencies.each { |dep, ver| @name_args << dep }
100
141
  end
101
142
  end
102
- cookbook.freeze_version if config[:freeze]
103
- upload(cookbook, justify_width)
104
- version_constraints_to_update[cookbook_name] = cookbook.version
105
143
  rescue Exceptions::CookbookNotFoundInRepo => e
106
144
  ui.error("Could not find cookbook #{cookbook_name} in your cookbook path, skipping it")
107
145
  Log.debug(e)
108
146
  end
109
147
  end
110
- end
111
-
112
- ui.info "upload complete"
113
- update_version_constraints(version_constraints_to_update) if config[:environment]
148
+ upload_set
149
+ end
114
150
  end
115
151
 
116
152
  def cookbook_repo
@@ -127,7 +163,6 @@ class Chef
127
163
  environment.save
128
164
  end
129
165
 
130
-
131
166
  def environment
132
167
  @environment ||= config[:environment] ? Environment.load(config[:environment]) : nil
133
168
  end
@@ -164,23 +199,21 @@ WARNING
164
199
 
165
200
  def upload(cookbook, justify_width)
166
201
  ui.info("Uploading #{cookbook.name.to_s.ljust(justify_width + 10)} [#{cookbook.version}]")
167
-
168
- check_for_broken_links(cookbook)
169
- check_dependencies(cookbook)
202
+ check_for_broken_links!(cookbook)
203
+ check_for_dependencies!(cookbook)
170
204
  Chef::CookbookUploader.new(cookbook, config[:cookbook_path], :force => config[:force]).upload_cookbook
171
205
  rescue Net::HTTPServerException => e
172
206
  case e.response.code
173
207
  when "409"
174
208
  ui.error "Version #{cookbook.version} of cookbook #{cookbook.name} is frozen. Use --force to override."
175
209
  Log.debug(e)
210
+ raise Exceptions::CookbookFrozen
176
211
  else
177
212
  raise
178
213
  end
179
214
  end
180
215
 
181
- # if only you people wouldn't put broken symlinks in your cookbooks in
182
- # the first place. ;)
183
- def check_for_broken_links(cookbook)
216
+ def check_for_broken_links!(cookbook)
184
217
  # MUST!! dup the cookbook version object--it memoizes its
185
218
  # manifest object, but the manifest becomes invalid when you
186
219
  # regenerate the metadata
@@ -190,18 +223,17 @@ WARNING
190
223
  unless broken_files.empty?
191
224
  broken_filenames = Array(broken_files).map {|path, info| path}
192
225
  ui.error "The cookbook #{cookbook.name} has one or more broken files"
193
- ui.info "This is probably caused by broken symlinks in the cookbook directory"
194
- ui.info "The broken file(s) are: #{broken_filenames.join(' ')}"
226
+ ui.error "This is probably caused by broken symlinks in the cookbook directory"
227
+ ui.error "The broken file(s) are: #{broken_filenames.join(' ')}"
195
228
  exit 1
196
229
  end
197
230
  end
198
231
 
199
- def check_dependencies(cookbook)
232
+ def check_for_dependencies!(cookbook)
200
233
  # for each dependency, check if the version is on the server, or
201
234
  # the version is in the cookbooks being uploaded. If not, exit and warn the user.
202
235
  cookbook.metadata.dependencies.each do |cookbook_name, version|
203
236
  unless check_server_side_cookbooks(cookbook_name, version) || check_uploading_cookbooks(cookbook_name, version)
204
- # warn the user and exit
205
237
  ui.error "Cookbook #{cookbook.name} depends on cookbook #{cookbook_name} version #{version},"
206
238
  ui.error "which is not currently being uploaded and cannot be found on the server."
207
239
  exit 1
@@ -213,28 +245,25 @@ WARNING
213
245
  if @server_side_cookbooks[cookbook_name].nil?
214
246
  false
215
247
  else
248
+ versions = @server_side_cookbooks[cookbook_name]['versions'].collect {|versions| versions["version"]}
249
+ Log.debug "Versions of cookbook '#{cookbook_name}' returned by the server: #{versions.join(", ")}"
216
250
  @server_side_cookbooks[cookbook_name]["versions"].each do |versions_hash|
217
- return true if Chef::VersionConstraint.new(version).include?(versions_hash["version"])
251
+ if Chef::VersionConstraint.new(version).include?(versions_hash["version"])
252
+ Log.debug "Matched cookbook '#{cookbook_name}' with constraint '#{version}' to cookbook version '#{versions_hash['version']}' on the server"
253
+ return true
254
+ end
218
255
  end
219
256
  false
220
257
  end
221
258
  end
222
259
 
223
260
  def check_uploading_cookbooks(cookbook_name, version)
224
- if config[:all]
225
- # check from all local cookbooks in the path
226
- unless cookbook_repo[cookbook_name].nil?
227
- return Chef::VersionConstraint.new(version).include?(cookbook_repo[cookbook_name].version)
228
- end
229
- else
230
- # check from only those in the command argument
231
- if @name_args.include?(cookbook_name)
232
- return Chef::VersionConstraint.new(version).include?(cookbook_repo[cookbook_name].version)
233
- end
261
+ if (! cookbooks_to_upload[cookbook_name].nil?) && Chef::VersionConstraint.new(version).include?(cookbooks_to_upload[cookbook_name].version)
262
+ Log.debug "Matched cookbook '#{cookbook_name}' with constraint '#{version}' to a local cookbook."
263
+ return true
234
264
  end
235
265
  false
236
266
  end
237
-
238
267
  end
239
268
  end
240
269
  end