chef 0.8.16 → 0.9.0.a3

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 (185) hide show
  1. data/bin/shef +1 -0
  2. data/distro/common/man/man1/chef-server-webui.1 +106 -0
  3. data/distro/common/man/man1/chef-server.1 +0 -1
  4. data/distro/common/man/man1/chef-solr-indexer.1 +55 -0
  5. data/distro/common/man/man1/chef-solr.1 +55 -0
  6. data/distro/common/man/man8/chef-client.8 +4 -2
  7. data/distro/common/man/man8/chef-solo.8 +1 -2
  8. data/distro/common/man/man8/chef-solr-rebuild.8 +37 -0
  9. data/distro/common/man/man8/knife.8 +668 -266
  10. data/distro/common/man/man8/shef.8 +45 -0
  11. data/distro/common/markdown/README +3 -0
  12. data/distro/common/markdown/knife.mkd +520 -0
  13. data/distro/debian/etc/default/chef-client +4 -0
  14. data/distro/debian/etc/default/chef-server +6 -0
  15. data/distro/debian/etc/default/chef-server-webui +6 -0
  16. data/distro/debian/etc/default/chef-solr +4 -0
  17. data/distro/debian/etc/default/chef-solr-indexer +4 -0
  18. data/distro/debian/etc/init.d/chef-client +41 -41
  19. data/distro/debian/etc/init.d/chef-server +10 -10
  20. data/distro/debian/etc/init.d/chef-server-webui +121 -0
  21. data/distro/debian/etc/init.d/chef-solr +177 -0
  22. data/distro/debian/etc/init.d/chef-solr-indexer +176 -0
  23. data/distro/redhat/etc/init.d/chef-client +76 -48
  24. data/distro/redhat/etc/init.d/chef-server +85 -51
  25. data/distro/redhat/etc/init.d/chef-server-webui +85 -51
  26. data/distro/redhat/etc/init.d/chef-solr +77 -49
  27. data/distro/redhat/etc/init.d/chef-solr-indexer +77 -48
  28. data/distro/redhat/etc/logrotate.d/chef-client +8 -0
  29. data/distro/redhat/etc/logrotate.d/chef-server +8 -0
  30. data/distro/redhat/etc/logrotate.d/chef-server-webui +8 -0
  31. data/distro/redhat/etc/logrotate.d/chef-solr +8 -0
  32. data/distro/redhat/etc/logrotate.d/chef-solr-indexer +8 -0
  33. data/distro/redhat/etc/sysconfig/chef-client +9 -4
  34. data/distro/redhat/etc/sysconfig/chef-server +10 -6
  35. data/distro/redhat/etc/sysconfig/chef-server-webui +10 -6
  36. data/distro/redhat/etc/sysconfig/chef-solr +3 -4
  37. data/distro/redhat/etc/sysconfig/chef-solr-indexer +3 -3
  38. data/lib/chef.rb +16 -5
  39. data/lib/chef/application/knife.rb +2 -2
  40. data/lib/chef/application/solo.rb +1 -7
  41. data/lib/chef/cache/checksum.rb +12 -5
  42. data/lib/chef/cache/file_cache_by_checksum.rb +52 -0
  43. data/lib/chef/checksum.rb +115 -0
  44. data/lib/chef/client.rb +193 -185
  45. data/lib/chef/config.rb +9 -1
  46. data/lib/chef/cookbook/cookbook_collection.rb +43 -0
  47. data/lib/chef/cookbook/file_system_file_vendor.rb +53 -0
  48. data/lib/chef/cookbook/file_vendor.rb +47 -0
  49. data/lib/chef/cookbook/metadata.rb +34 -35
  50. data/lib/chef/cookbook/metadata/version.rb +1 -1
  51. data/lib/chef/cookbook_loader.rb +70 -45
  52. data/lib/chef/cookbook_version.rb +760 -0
  53. data/lib/chef/couchdb.rb +8 -5
  54. data/lib/chef/data_bag_item.rb +5 -5
  55. data/lib/chef/exceptions.rb +10 -0
  56. data/lib/chef/file_access_control.rb +134 -0
  57. data/lib/chef/handler.rb +62 -0
  58. data/lib/chef/handler/json_file.rb +47 -0
  59. data/lib/chef/knife.rb +14 -2
  60. data/lib/chef/knife/bootstrap.rb +126 -0
  61. data/lib/chef/knife/cookbook_bulk_delete.rb +1 -1
  62. data/lib/chef/knife/cookbook_delete.rb +4 -4
  63. data/lib/chef/knife/cookbook_download.rb +57 -26
  64. data/lib/chef/knife/cookbook_metadata.rb +2 -2
  65. data/lib/chef/knife/cookbook_show.rb +30 -11
  66. data/lib/chef/knife/cookbook_upload.rb +113 -86
  67. data/lib/chef/knife/ec2_server_create.rb +146 -0
  68. data/lib/chef/knife/ec2_server_delete.rb +84 -0
  69. data/lib/chef/knife/ec2_server_list.rb +82 -0
  70. data/lib/chef/knife/status.rb +51 -0
  71. data/lib/chef/mixin/language_include_attribute.rb +16 -11
  72. data/lib/chef/mixin/language_include_recipe.rb +15 -16
  73. data/lib/chef/mixin/recipe_definition_dsl_core.rb +17 -20
  74. data/lib/chef/mixin/shell_out.rb +38 -0
  75. data/lib/chef/mixins.rb +1 -1
  76. data/lib/chef/node.rb +190 -63
  77. data/lib/chef/node/attribute.rb +92 -78
  78. data/lib/chef/platform.rb +24 -4
  79. data/lib/chef/provider.rb +28 -10
  80. data/lib/chef/provider/breakpoint.rb +2 -2
  81. data/lib/chef/provider/cookbook_file.rb +96 -0
  82. data/lib/chef/provider/cron.rb +2 -2
  83. data/lib/chef/provider/deploy.rb +12 -10
  84. data/lib/chef/provider/env.rb +152 -0
  85. data/lib/chef/provider/env/windows.rb +75 -0
  86. data/lib/chef/provider/file.rb +10 -14
  87. data/lib/chef/provider/group.rb +15 -2
  88. data/lib/chef/provider/group/dscl.rb +17 -25
  89. data/lib/chef/provider/group/gpasswd.rb +6 -3
  90. data/lib/chef/provider/group/pw.rb +3 -7
  91. data/lib/chef/provider/group/windows.rb +79 -0
  92. data/lib/chef/provider/link.rb +4 -5
  93. data/lib/chef/provider/mdadm.rb +25 -18
  94. data/lib/chef/provider/mount/mount.rb +28 -27
  95. data/lib/chef/provider/package.rb +35 -35
  96. data/lib/chef/provider/package/dpkg.rb +13 -10
  97. data/lib/chef/provider/package/easy_install.rb +6 -6
  98. data/lib/chef/provider/package/freebsd.rb +17 -51
  99. data/lib/chef/provider/package/rpm.rb +1 -1
  100. data/lib/chef/provider/package/rubygems.rb +391 -74
  101. data/lib/chef/provider/package/yum.rb +2 -2
  102. data/lib/chef/provider/package/zypper.rb +2 -1
  103. data/lib/chef/provider/remote_directory.rb +60 -83
  104. data/lib/chef/provider/remote_file.rb +17 -66
  105. data/lib/chef/provider/script.rb +20 -9
  106. data/lib/chef/provider/service.rb +23 -30
  107. data/lib/chef/provider/service/arch.rb +3 -3
  108. data/lib/chef/provider/service/debian.rb +22 -17
  109. data/lib/chef/provider/service/freebsd.rb +4 -4
  110. data/lib/chef/provider/service/init.rb +2 -2
  111. data/lib/chef/provider/service/redhat.rb +14 -16
  112. data/lib/chef/provider/service/simple.rb +7 -3
  113. data/lib/chef/provider/service/solaris.rb +85 -0
  114. data/lib/chef/provider/service/upstart.rb +12 -7
  115. data/lib/chef/provider/service/windows.rb +2 -2
  116. data/lib/chef/provider/template.rb +133 -118
  117. data/lib/chef/provider/user.rb +34 -17
  118. data/lib/chef/provider/user/dscl.rb +117 -114
  119. data/lib/chef/provider/user/windows.rb +124 -0
  120. data/lib/chef/providers.rb +7 -0
  121. data/lib/chef/recipe.rb +39 -20
  122. data/lib/chef/resource.rb +47 -52
  123. data/lib/chef/resource/apt_package.rb +4 -4
  124. data/lib/chef/resource/bash.rb +4 -4
  125. data/lib/chef/resource/cookbook_file.rb +45 -0
  126. data/lib/chef/resource/cron.rb +3 -3
  127. data/lib/chef/resource/csh.rb +4 -4
  128. data/lib/chef/resource/deploy.rb +3 -3
  129. data/lib/chef/resource/directory.rb +4 -4
  130. data/lib/chef/resource/dpkg_package.rb +4 -4
  131. data/lib/chef/resource/easy_install_package.rb +3 -3
  132. data/lib/chef/resource/env.rb +58 -0
  133. data/lib/chef/resource/erl_call.rb +3 -3
  134. data/lib/chef/resource/execute.rb +3 -3
  135. data/lib/chef/resource/file.rb +3 -3
  136. data/lib/chef/resource/freebsd_package.rb +3 -3
  137. data/lib/chef/resource/gem_package.rb +17 -9
  138. data/lib/chef/resource/git.rb +3 -3
  139. data/lib/chef/resource/group.rb +3 -3
  140. data/lib/chef/resource/http_request.rb +4 -4
  141. data/lib/chef/resource/ifconfig.rb +3 -3
  142. data/lib/chef/resource/link.rb +3 -3
  143. data/lib/chef/resource/log.rb +2 -2
  144. data/lib/chef/resource/macports_package.rb +2 -2
  145. data/lib/chef/resource/mdadm.rb +3 -3
  146. data/lib/chef/resource/mount.rb +2 -2
  147. data/lib/chef/resource/package.rb +4 -4
  148. data/lib/chef/resource/pacman_package.rb +4 -4
  149. data/lib/chef/resource/perl.rb +4 -4
  150. data/lib/chef/resource/portage_package.rb +4 -4
  151. data/lib/chef/resource/python.rb +4 -4
  152. data/lib/chef/resource/remote_directory.rb +3 -3
  153. data/lib/chef/resource/remote_file.rb +26 -3
  154. data/lib/chef/resource/route.rb +3 -3
  155. data/lib/chef/resource/ruby.rb +3 -3
  156. data/lib/chef/resource/ruby_block.rb +3 -2
  157. data/lib/chef/resource/scm.rb +7 -5
  158. data/lib/chef/resource/script.rb +4 -4
  159. data/lib/chef/resource/service.rb +3 -3
  160. data/lib/chef/resource/subversion.rb +4 -2
  161. data/lib/chef/resource/template.rb +3 -3
  162. data/lib/chef/resource/user.rb +3 -3
  163. data/lib/chef/resource/yum_package.rb +3 -3
  164. data/lib/chef/resource_collection.rb +9 -5
  165. data/lib/chef/resources.rb +2 -0
  166. data/lib/chef/rest.rb +4 -0
  167. data/lib/chef/role.rb +2 -0
  168. data/lib/chef/run_context.rb +108 -0
  169. data/lib/chef/run_list.rb +75 -98
  170. data/lib/chef/run_list/run_list_expansion.rb +156 -0
  171. data/lib/chef/run_list/run_list_item.rb +71 -0
  172. data/lib/chef/runner.rb +58 -61
  173. data/lib/chef/sandbox.rb +147 -0
  174. data/lib/chef/shef.rb +4 -3
  175. data/lib/chef/shef/ext.rb +12 -4
  176. data/lib/chef/shef/shef_session.rb +27 -23
  177. data/lib/chef/shell_out.rb +375 -0
  178. data/lib/chef/util/windows.rb +56 -0
  179. data/lib/chef/util/windows/net_group.rb +101 -0
  180. data/lib/chef/util/windows/net_user.rb +198 -0
  181. data/lib/chef/version.rb +20 -0
  182. metadata +112 -22
  183. data/lib/chef/compile.rb +0 -158
  184. data/lib/chef/cookbook.rb +0 -201
  185. data/lib/chef/mixin/generate_url.rb +0 -58
@@ -29,7 +29,7 @@ class Chef
29
29
  Chef::Log.fatal("You must supply a regular expression to match the results against")
30
30
  exit 42
31
31
  else
32
- bulk_delete(Chef::Cookbook, "cookbook", "cookbook", rest.get_rest("cookbooks"), @name_args[0]) do |name, cookbook|
32
+ bulk_delete(Chef::CookbookVersion, "cookbook", "cookbook", rest.get_rest("cookbooks"), @name_args[0]) do |name, cookbook|
33
33
  rest.delete_rest(cookbook)
34
34
  end
35
35
  end
@@ -22,11 +22,11 @@ class Chef
22
22
  class Knife
23
23
  class CookbookDelete < Knife
24
24
 
25
- banner "Sub-Command: cookbook delete COOKBOOK (options)"
25
+ banner "Sub-Command: cookbook delete COOKBOOK VERSION (options)"
26
26
 
27
- def run
28
- delete_object(Chef::Cookbook, @name_args[0], "cookbook") do
29
- rest.delete_rest("cookbooks/#{@name_args[0]}")
27
+ def run
28
+ delete_object(Chef::CookbookVersion, "#{@name_args[0]} #{@name_args[1]}", "cookbook") do
29
+ rest.delete_rest("cookbooks/#{@name_args[0]}/#{@name_args[1]}")
30
30
  end
31
31
  end
32
32
 
@@ -1,6 +1,7 @@
1
1
  #
2
2
  # Author:: Adam Jacob (<adam@opscode.com>)
3
- # Copyright:: Copyright (c) 2009 Opscode, Inc.
3
+ # Author:: Christopher Walters (<cw@opscode.com>)
4
+ # Copyright:: Copyright (c) 2009, 2010 Opscode, Inc.
4
5
  # License:: Apache License, Version 2.0
5
6
  #
6
7
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -22,36 +23,66 @@ class Chef
22
23
  class Knife
23
24
  class CookbookDownload < Knife
24
25
 
25
- banner "Sub-Command: cookbook download COOKBOOK (options)"
26
-
27
- option :file,
28
- :short => "-f FILE",
29
- :long => "--file FILE",
30
- :description => "The filename to write to"
31
-
32
- def run
33
- cookbook = rest.get_rest("cookbooks/#{@name_args[0]}")
34
- version = cookbook["metadata"]["version"]
35
- Chef::Log.info("Downloading #{@name_args[0]} cookbook version #{version}")
36
- rest.sign_on_redirect = false
37
- tf = rest.get_rest("cookbooks/#{@name_args[0]}/_content", true)
38
- rest.sign_on_redirect = true
39
- unless config[:file]
40
- if version
41
- config[:file] = File.join(Dir.pwd, "#{@name_args[0]}-#{version}.tar.gz")
26
+ banner "Sub-Command: cookbook download COOKBOOK VERSION (options)"
27
+
28
+ option :version,
29
+ :short => "-v VERSION",
30
+ :long => "--version VERSION",
31
+ :description => "The version of the cookbook to download"
32
+
33
+ option :download_directory,
34
+ :short => "-d DOWNLOAD_DIRECTORY",
35
+ :long => "--dir DOWNLOAD_DIRECTORY",
36
+ :description => "The directory to download the cookbook into",
37
+ :default => Dir.pwd
38
+
39
+ option :force,
40
+ :short => "-f",
41
+ :long => "--force",
42
+ :description => "Force download over the download directory if it exists"
43
+
44
+ # TODO: tim/cw: 5-23-2010: need to implement knife-side
45
+ # specificity for downloads - need to implement --platform and
46
+ # --fqdn here
47
+ def run
48
+ if @name_args.length != 2
49
+ Chef::Log.fatal("You must supply a cookbook name and version to download!")
50
+ exit 42
51
+ end
52
+
53
+ cookbook_name = @name_args[0]
54
+ cookbook_version = @name_args[1] == 'latest' ? '_latest' : @name_args[1]
55
+ Chef::Log.info("Downloading #{cookbook_name} cookbook version #{cookbook_version}")
56
+
57
+ cookbook = rest.get_rest("cookbooks/#{cookbook_name}/#{cookbook_version}")
58
+ manifest = cookbook.manifest
59
+
60
+ basedir = File.join(config[:download_directory], "#{cookbook_name}-#{cookbook.version}")
61
+ if File.exists?(basedir)
62
+ if config[:force]
63
+ Chef::Log.debug("Deleting #{basedir}")
64
+ FileUtils.rm_rf(basedir)
42
65
  else
43
- config[:file] = File.join(Dir.pwd, "#{@name_args[0]}.tar.gz")
66
+ Chef::Log.fatal("Directory #{basedir} exists, use --force to overwrite")
67
+ exit
68
+ end
69
+ end
70
+
71
+ Chef::CookbookVersion::COOKBOOK_SEGMENTS.each do |segment|
72
+ next unless manifest.has_key?(segment)
73
+ Chef::Log.info("Downloading #{segment}")
74
+ manifest[segment].each do |segment_file|
75
+ dest = File.join(basedir, segment_file['path'].gsub('/', File::SEPARATOR))
76
+ Chef::Log.debug("Downloading #{segment_file['path']} to #{dest}")
77
+ FileUtils.mkdir_p(File.dirname(dest))
78
+ rest.sign_on_redirect = false
79
+ tempfile = rest.get_rest(segment_file['url'], true)
80
+ FileUtils.mv(tempfile.path, dest)
44
81
  end
45
82
  end
46
- FileUtils.cp(tf.path, config[:file])
47
- Chef::Log.info("Cookbook saved: #{config[:file]}")
83
+ Chef::Log.info("Cookbook downloaded to #{basedir}")
48
84
  end
49
85
 
50
86
  end
51
87
  end
52
88
  end
53
-
54
-
55
-
56
-
57
-
@@ -45,8 +45,8 @@ class Chef
45
45
 
46
46
  if config[:all]
47
47
  cl = Chef::CookbookLoader.new
48
- cl.each do |cookbook|
49
- generate_metadata(cookbook.name.to_s)
48
+ cl.each do |cname, cookbook|
49
+ generate_metadata(cname.to_s)
50
50
  end
51
51
  else
52
52
  generate_metadata(@name_args[0])
@@ -24,7 +24,7 @@ class Chef
24
24
  class Knife
25
25
  class CookbookShow < Knife
26
26
 
27
- banner "Sub-Command: cookbook show COOKBOOK [PART] [FILENAME] (options)"
27
+ banner "Sub-Command: cookbook show COOKBOOK [VERSION] [PART] [FILENAME] (options)"
28
28
 
29
29
  option :fqdn,
30
30
  :short => "-f FQDN",
@@ -43,17 +43,36 @@ class Chef
43
43
 
44
44
  def run
45
45
  case @name_args.length
46
- when 3 # We are showing a specific file
47
- arguments = { :id => @name_args[2] }
48
- arguments[:fqdn] = config[:fqdn] if config.has_key?(:fqdn)
49
- arguments[:platform] = config[:platform] if config.has_key?(:platform)
50
- arguments[:version] = config[:platform_version] if config.has_key?(:platform_version)
51
- result = rest.get_rest("cookbooks/#{@name_args[0]}/#{@name_args[1]}?#{make_query_params(arguments)}")
46
+ when 4 # We are showing a specific file
47
+ node = Hash.new
48
+ node[:fqdn] = config[:fqdn] if config.has_key?(:fqdn)
49
+ node[:platform] = config[:platform] if config.has_key?(:platform)
50
+ node[:platform_version] = config[:platform_version] if config.has_key?(:platform_version)
51
+
52
+ class << node
53
+ def attribute?(name)
54
+ has_key?(name)
55
+ end
56
+ end
57
+
58
+ cookbook_name, cookbook_version, segment, filename = @name_args[0..3]
59
+
60
+ manifest = rest.get_rest("cookbooks/#{cookbook_name}/#{cookbook_version}")
61
+ cookbook = Chef::CookbookVersion.new(cookbook_name)
62
+ cookbook.manifest = manifest
63
+
64
+ manifest_entry = cookbook.preferred_manifest_record(node, segment, filename)
65
+ result = rest.get_rest("cookbooks/#{cookbook_name}/#{cookbook_version}/files/#{manifest_entry[:checksum]}")
66
+
52
67
  pretty_print(result)
53
- when 2 # We are showing a specific part of the cookbook
54
- result = rest.get_rest("cookbooks/#{@name_args[0]}")
55
- output(result[@name_args[1]])
56
- when 1 # We are showing the whole cookbook data
68
+ when 3 # We are showing a specific part of the cookbook
69
+ cookbook_version = @name_args[1] == 'latest' ? '_latest' : @name_args[1]
70
+ result = rest.get_rest("cookbooks/#{@name_args[0]}/#{cookbook_version}")
71
+ output(result.manifest[@name_args[2]])
72
+ when 2 # We are showing the whole cookbook data
73
+ cookbook_version = @name_args[1] == 'latest' ? '_latest' : @name_args[1]
74
+ output(rest.get_rest("cookbooks/#{@name_args[0]}/#{cookbook_version}"))
75
+ when 1 # We are showing the cookbook versions
57
76
  output(rest.get_rest("cookbooks/#{@name_args[0]}"))
58
77
  end
59
78
  end
@@ -1,7 +1,7 @@
1
1
  #
2
- #
3
2
  # Author:: Adam Jacob (<adam@opscode.com>)
4
- # Copyright:: Copyright (c) 2009 Opscode, Inc.
3
+ # Author:: Christopher Walters (<cw@opscode.com>)
4
+ # Copyright:: Copyright (c) 2009, 2010 Opscode, Inc.
5
5
  # License:: Apache License, Version 2.0
6
6
  #
7
7
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,8 +17,14 @@
17
17
  # limitations under the License.
18
18
  #
19
19
 
20
+ require 'rest_client'
21
+
20
22
  require 'chef/knife'
21
23
  require 'chef/streaming_cookbook_uploader'
24
+ require 'chef/cache/checksum'
25
+ require 'chef/sandbox'
26
+ require 'chef/cookbook_version'
27
+ require 'chef/cookbook/file_system_file_vendor'
22
28
 
23
29
  class Chef
24
30
  class Knife
@@ -37,130 +43,151 @@ class Chef
37
43
  :long => "--all",
38
44
  :description => "Upload all cookbooks, rather than just a single cookbook"
39
45
 
40
- def run
41
- Chef::Log.debug "Uploading cookbooks from #{config[:cookbook_path]}"
42
-
46
+ def run
43
47
  if config[:cookbook_path]
44
48
  Chef::Config[:cookbook_path] = config[:cookbook_path]
45
49
  else
46
50
  config[:cookbook_path] = Chef::Config[:cookbook_path]
47
51
  end
48
52
 
53
+ Chef::Cookbook::FileVendor.on_create { |manifest| Chef::Cookbook::FileSystemFileVendor.new(manifest) }
54
+
55
+ cl = Chef::CookbookLoader.new
49
56
  if config[:all]
50
- cl = Chef::CookbookLoader.new
51
- cl.each do |cookbook|
57
+ cl.each do |cookbook_name, cookbook|
52
58
  Chef::Log.info("** #{cookbook.name.to_s} **")
53
- upload_cookbook(cookbook.name.to_s)
59
+ upload_cookbook(cookbook)
54
60
  end
55
61
  else
56
- @name_args.each do |cb|
57
- Chef::Log.info("** #{cb} **")
58
- upload_cookbook(cb)
59
- end
62
+ @name_args.each{|cookbook_name| upload_cookbook(cl[cookbook_name]) }
63
+ end
64
+ end
65
+
66
+ def test_ruby(cookbook_dir)
67
+ Chef::Log.info("Validating ruby files")
68
+ Dir[File.join(cookbook_dir, '**', '*.rb')].each do |ruby_file|
69
+ Chef::Log.info("Testing #{ruby_file} for syntax errors...")
70
+ Chef::Mixin::Command.run_command(:command => "ruby -c #{ruby_file}")
60
71
  end
61
72
  end
73
+
74
+ def test_templates(cookbook_dir)
75
+ Chef::Log.info("Validating templates")
76
+ Dir[File.join(cookbook_dir, '**', '*.erb')].each do |erb_file|
77
+ Chef::Log.info("Testing template #{erb_file} for syntax errors...")
78
+ Chef::Mixin::Command.run_command(:command => "sh -c 'erubis -x #{erb_file} | ruby -c'")
79
+ end
80
+ end
81
+
82
+ def upload_cookbook(cookbook)
83
+ Chef::Log.info("Saving #{cookbook.name}")
84
+
85
+ # create build directory
86
+ tmp_cookbook_dir = create_build_dir(cookbook)
87
+
88
+ # create a CookbookLoader that loads a Cookbook from the build directory
89
+ orig_cookbook_path = nil
90
+ build_dir_cookbook = nil
91
+ begin
92
+ orig_cookbook_path = Chef::Config.cookbook_path
93
+ Chef::Config.cookbook_path = tmp_cookbook_dir
94
+ build_dir_cookbook = Chef::CookbookLoader.new[cookbook.name]
95
+ Chef::Log.debug("Staged cookbook manifest:\n#{JSON.pretty_generate(build_dir_cookbook)}")
96
+ ensure
97
+ Chef::Config.cookbook_path = orig_cookbook_path
98
+ end
62
99
 
63
- def upload_cookbook(cookbook_name)
64
- # Syntax check all cookbook paths rather than tmp_cookbook_dir as to
65
- # take advantage of the existing cache used/generated by knife cookbook
66
- # test.
67
- check = Chef::Knife::CookbookTest.new
68
- check.config[:cookbook_path] = config[:cookbook_path]
69
- check.name_args = [ cookbook_name ]
70
- check.run
71
-
72
- if cookbook_name =~ /^#{File::SEPARATOR}/
73
- child_folders = cookbook_name
74
- cookbook_name = File.basename(cookbook_name)
75
- else
76
- child_folders = config[:cookbook_path].inject([]) do |r, e|
77
- r << File.join(e, cookbook_name)
78
- r
100
+ # generate checksums of cookbook files and create a sandbox
101
+ checksum_files = build_dir_cookbook.checksums
102
+ checksums = checksum_files.inject({}){|memo,elt| memo[elt.first]=nil ; memo}
103
+ new_sandbox = catch_auth_exceptions{ rest.post_rest("/sandboxes", { :checksums => checksums }) }
104
+
105
+ # upload the new checksums and commit the sandbox
106
+ new_sandbox['checksums'].each do |checksum, info|
107
+ if info['needs_upload'] == true
108
+ Chef::Log.debug("PUTting #{checksum_files[checksum]} (checksum hex = #{checksum}) to #{info['url']}")
109
+
110
+ # Checksum is the hexadecimal representation of the md5,
111
+ # but we need the base64 encoding for the content-md5
112
+ # header
113
+ checksum64 = Base64.encode64([checksum].pack("H*")).strip
114
+ timestamp = Time.now.utc.iso8601
115
+ file_contents = File.read(checksum_files[checksum])
116
+ # TODO - 5/28/2010, cw: make signing and sending the request streaming
117
+ sign_obj = Mixlib::Authentication::SignedHeaderAuth.signing_object(
118
+ :http_method => :put,
119
+ :path => URI.parse(info['url']).path,
120
+ :body => file_contents,
121
+ :timestamp => timestamp,
122
+ :user_id => rest.client_name
123
+ )
124
+ headers = { 'content-type' => 'application/x-binary', 'content-md5' => checksum64, :accept => 'application/json' }
125
+ headers.merge!(sign_obj.sign(OpenSSL::PKey::RSA.new(rest.signing_key)))
126
+ begin
127
+ RestClient::Request.execute(:method => :put, :url => info['url'], :headers => headers, :payload => file_contents)
128
+ rescue RestClient::RequestFailed => e
129
+ Chef::Log.error("Upload failed: #{e.message}\n#{e.response.body}")
130
+ raise
131
+ end
79
132
  end
80
133
  end
134
+ sandbox_url = new_sandbox['uri']
135
+ Chef::Log.debug("Committing sandbox")
136
+ catch_auth_exceptions{ rest.put_rest(sandbox_url, {:is_completed => true}) }
81
137
 
82
- tmp_cookbook_tarball = Tempfile.new("chef-#{cookbook_name}")
83
- tmp_cookbook_tarball.close
84
- tarball_name = "#{tmp_cookbook_tarball.path}.tar.gz"
85
- File.unlink(tmp_cookbook_tarball.path)
138
+ # files are uploaded, so save the manifest
139
+ catch_auth_exceptions{ build_dir_cookbook.save }
140
+
141
+ Chef::Log.info("Upload complete!")
142
+ Chef::Log.debug("Removing local staging directory at #{tmp_cookbook_dir}")
143
+ FileUtils.rm_rf tmp_cookbook_dir
144
+ end
86
145
 
87
- tmp_cookbook_path = Tempfile.new("chef-#{cookbook_name}-build")
146
+ def create_build_dir(cookbook)
147
+ tmp_cookbook_path = Tempfile.new("chef-#{cookbook.name}-build")
88
148
  tmp_cookbook_path.close
89
149
  tmp_cookbook_dir = tmp_cookbook_path.path
90
150
  File.unlink(tmp_cookbook_dir)
91
151
  FileUtils.mkdir_p(tmp_cookbook_dir)
92
-
152
+
93
153
  Chef::Log.debug("Staging at #{tmp_cookbook_dir}")
94
154
 
95
- found_cookbook = false
155
+ checksums_to_on_disk_paths = cookbook.checksums
96
156
 
97
- child_folders.each do |file_path|
98
- if File.directory?(file_path)
99
- found_cookbook = true
100
- Chef::Log.info("Copying from #{file_path} to #{tmp_cookbook_dir}")
101
- FileUtils.cp_r(file_path, tmp_cookbook_dir, :remove_destination => true, :preserve => true)
102
- else
103
- Chef::Log.info("Nothing to copy from #{file_path}")
157
+ Chef::CookbookVersion::COOKBOOK_SEGMENTS.each do |segment|
158
+ cookbook.manifest[segment].each do |manifest_record|
159
+ path_in_cookbook = manifest_record[:path]
160
+ on_disk_path = checksums_to_on_disk_paths[manifest_record[:checksum]]
161
+ dest = File.join(tmp_cookbook_dir, cookbook.name.to_s, path_in_cookbook)
162
+ FileUtils.mkdir_p(File.dirname(dest))
163
+ FileUtils.cp(on_disk_path, dest)
104
164
  end
105
165
  end
106
-
107
- unless found_cookbook
108
- Chef::Log.fatal("Could not find cookbook #{cookbook_name}!")
109
- exit 17
110
- end
166
+
167
+ # Validate ruby files and templates
168
+ test_ruby(tmp_cookbook_dir)
169
+ test_templates(tmp_cookbook_dir)
111
170
 
112
171
  # First, generate metadata
172
+ Chef::Log.debug("Generating metadata")
113
173
  kcm = Chef::Knife::CookbookMetadata.new
114
174
  kcm.config[:cookbook_path] = [ tmp_cookbook_dir ]
115
- kcm.name_args = [ cookbook_name ]
175
+ kcm.name_args = [ cookbook.name.to_s ]
116
176
  kcm.run
177
+ end
117
178
 
118
- Chef::Log.info("Creating tarball at #{tarball_name}")
119
- Chef::Mixin::Command.run_command(
120
- :command => "tar -C #{tmp_cookbook_dir} -cvzf #{tarball_name} ./#{cookbook_name}"
121
- )
122
-
179
+ def catch_auth_exceptions
123
180
  begin
124
- cb = rest.get_rest("cookbooks/#{cookbook_name}")
125
- cookbook_uploaded = true
181
+ yield
126
182
  rescue Net::HTTPServerException => e
127
183
  case e.response.code
128
- when "404"
129
- cookbook_uploaded = false
130
184
  when "401"
131
- Chef::Log.fatal "Failed to fetch remote cookbook '#{cookbook_name}' due to authentication failure (#{e}), check your client configuration (username, key)"
185
+ Chef::Log.fatal "Request failed due to authentication (#{e}), check your client configuration (username, key)"
132
186
  exit 18
133
187
  end
134
188
  end
135
-
136
- if cookbook_uploaded
137
- Chef::StreamingCookbookUploader.put(
138
- "#{Chef::Config[:chef_server_url]}/cookbooks/#{cookbook_name}/_content",
139
- Chef::Config[:node_name],
140
- Chef::Config[:client_key],
141
- {
142
- :file => File.new(tarball_name),
143
- :name => cookbook_name
144
- }
145
- )
146
- else
147
- Chef::StreamingCookbookUploader.post(
148
- "#{Chef::Config[:chef_server_url]}/cookbooks",
149
- Chef::Config[:node_name],
150
- Chef::Config[:client_key],
151
- {
152
- :file => File.new(tarball_name),
153
- :name => cookbook_name
154
- }
155
- )
156
- end
157
- Chef::Log.info("Upload complete!")
158
- Chef::Log.debug("Removing local tarball at #{tarball_name}")
159
- FileUtils.rm_rf tarball_name
160
- Chef::Log.debug("Removing local staging directory at #{tmp_cookbook_dir}")
161
- FileUtils.rm_rf tmp_cookbook_dir
162
189
  end
163
-
190
+
164
191
  end
165
192
  end
166
193
  end