TrueCar-chef 0.10.0.beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/LICENSE +201 -0
- data/README.rdoc +171 -0
- data/bin/chef-client +26 -0
- data/bin/chef-solo +25 -0
- data/bin/knife +26 -0
- data/bin/shef +34 -0
- data/distro/README +2 -0
- data/distro/arch/etc/conf.d/chef-client.conf +5 -0
- data/distro/arch/etc/conf.d/chef-server-webui.conf +10 -0
- data/distro/arch/etc/conf.d/chef-server.conf +10 -0
- data/distro/arch/etc/conf.d/chef-solr-indexer.conf +8 -0
- data/distro/arch/etc/conf.d/chef-solr.conf +8 -0
- data/distro/arch/etc/rc.d/chef-client +76 -0
- data/distro/arch/etc/rc.d/chef-server +78 -0
- data/distro/arch/etc/rc.d/chef-server-webui +78 -0
- data/distro/arch/etc/rc.d/chef-solr +78 -0
- data/distro/arch/etc/rc.d/chef-solr-indexer +78 -0
- data/distro/common/man/man1/chef-indexer.1 +42 -0
- data/distro/common/man/man1/chef-server-webui.1 +106 -0
- data/distro/common/man/man1/chef-server.1 +107 -0
- data/distro/common/man/man1/chef-solr-indexer.1 +55 -0
- data/distro/common/man/man1/chef-solr.1 +55 -0
- data/distro/common/man/man8/chef-client.8 +63 -0
- data/distro/common/man/man8/chef-solo.8 +57 -0
- data/distro/common/man/man8/chef-solr-rebuild.8 +37 -0
- data/distro/common/man/man8/knife.8 +1349 -0
- data/distro/common/man/man8/shef.8 +45 -0
- data/distro/common/markdown/README +3 -0
- data/distro/common/markdown/knife.mkd +865 -0
- data/distro/debian/etc/default/chef-client +4 -0
- data/distro/debian/etc/default/chef-server +9 -0
- data/distro/debian/etc/default/chef-server-webui +9 -0
- data/distro/debian/etc/default/chef-solr +8 -0
- data/distro/debian/etc/default/chef-solr-indexer +7 -0
- data/distro/debian/etc/init.d/chef-client +175 -0
- data/distro/debian/etc/init.d/chef-server +122 -0
- data/distro/debian/etc/init.d/chef-server-webui +123 -0
- data/distro/debian/etc/init.d/chef-solr +176 -0
- data/distro/debian/etc/init.d/chef-solr-indexer +176 -0
- data/distro/debian/etc/init/chef-client.conf +17 -0
- data/distro/debian/etc/init/chef-server-webui.conf +17 -0
- data/distro/debian/etc/init/chef-server.conf +17 -0
- data/distro/debian/etc/init/chef-solr-indexer.conf +17 -0
- data/distro/debian/etc/init/chef-solr.conf +17 -0
- data/distro/redhat/etc/init.d/chef-client +106 -0
- data/distro/redhat/etc/init.d/chef-server +112 -0
- data/distro/redhat/etc/init.d/chef-server-webui +112 -0
- data/distro/redhat/etc/init.d/chef-solr +104 -0
- data/distro/redhat/etc/init.d/chef-solr-indexer +104 -0
- data/distro/redhat/etc/logrotate.d/chef-client +8 -0
- data/distro/redhat/etc/logrotate.d/chef-server +8 -0
- data/distro/redhat/etc/logrotate.d/chef-server-webui +8 -0
- data/distro/redhat/etc/logrotate.d/chef-solr +8 -0
- data/distro/redhat/etc/logrotate.d/chef-solr-indexer +8 -0
- data/distro/redhat/etc/sysconfig/chef-client +15 -0
- data/distro/redhat/etc/sysconfig/chef-server +14 -0
- data/distro/redhat/etc/sysconfig/chef-server-webui +14 -0
- data/distro/redhat/etc/sysconfig/chef-solr +8 -0
- data/distro/redhat/etc/sysconfig/chef-solr-indexer +7 -0
- data/lib/chef.rb +40 -0
- data/lib/chef/api_client.rb +264 -0
- data/lib/chef/application.rb +137 -0
- data/lib/chef/application/agent.rb +18 -0
- data/lib/chef/application/client.rb +242 -0
- data/lib/chef/application/knife.rb +169 -0
- data/lib/chef/application/solo.rb +217 -0
- data/lib/chef/applications.rb +4 -0
- data/lib/chef/certificate.rb +194 -0
- data/lib/chef/checksum.rb +182 -0
- data/lib/chef/checksum_cache.rb +189 -0
- data/lib/chef/client.rb +362 -0
- data/lib/chef/config.rb +244 -0
- data/lib/chef/cookbook/chefignore.rb +66 -0
- data/lib/chef/cookbook/cookbook_collection.rb +45 -0
- data/lib/chef/cookbook/cookbook_version_loader.rb +151 -0
- data/lib/chef/cookbook/file_system_file_vendor.rb +56 -0
- data/lib/chef/cookbook/file_vendor.rb +48 -0
- data/lib/chef/cookbook/metadata.rb +592 -0
- data/lib/chef/cookbook/remote_file_vendor.rb +87 -0
- data/lib/chef/cookbook/syntax_check.rb +136 -0
- data/lib/chef/cookbook_loader.rb +103 -0
- data/lib/chef/cookbook_site_streaming_uploader.rb +244 -0
- data/lib/chef/cookbook_uploader.rb +125 -0
- data/lib/chef/cookbook_version.rb +979 -0
- data/lib/chef/cookbook_version_selector.rb +163 -0
- data/lib/chef/couchdb.rb +247 -0
- data/lib/chef/daemon.rb +172 -0
- data/lib/chef/data_bag.rb +223 -0
- data/lib/chef/data_bag_item.rb +267 -0
- data/lib/chef/encrypted_data_bag_item.rb +126 -0
- data/lib/chef/environment.rb +386 -0
- data/lib/chef/exceptions.rb +153 -0
- data/lib/chef/file_access_control.rb +140 -0
- data/lib/chef/file_cache.rb +218 -0
- data/lib/chef/handler.rb +206 -0
- data/lib/chef/handler/json_file.rb +58 -0
- data/lib/chef/index_queue.rb +29 -0
- data/lib/chef/index_queue/amqp_client.rb +116 -0
- data/lib/chef/index_queue/consumer.rb +76 -0
- data/lib/chef/index_queue/indexable.rb +109 -0
- data/lib/chef/json_compat.rb +52 -0
- data/lib/chef/knife.rb +424 -0
- data/lib/chef/knife/bootstrap.rb +185 -0
- data/lib/chef/knife/bootstrap/archlinux-gems.erb +47 -0
- data/lib/chef/knife/bootstrap/centos5-gems.erb +41 -0
- data/lib/chef/knife/bootstrap/client-install.vbs +80 -0
- data/lib/chef/knife/bootstrap/fedora13-gems.erb +38 -0
- data/lib/chef/knife/bootstrap/ubuntu10.04-apt.erb +32 -0
- data/lib/chef/knife/bootstrap/ubuntu10.04-gems.erb +46 -0
- data/lib/chef/knife/bootstrap/windows-gems.erb +34 -0
- data/lib/chef/knife/client_bulk_delete.rb +43 -0
- data/lib/chef/knife/client_create.rb +73 -0
- data/lib/chef/knife/client_delete.rb +48 -0
- data/lib/chef/knife/client_edit.rb +48 -0
- data/lib/chef/knife/client_list.rb +43 -0
- data/lib/chef/knife/client_reregister.rb +59 -0
- data/lib/chef/knife/client_show.rb +53 -0
- data/lib/chef/knife/configure.rb +136 -0
- data/lib/chef/knife/configure_client.rb +52 -0
- data/lib/chef/knife/cookbook_bulk_delete.rb +61 -0
- data/lib/chef/knife/cookbook_create.rb +274 -0
- data/lib/chef/knife/cookbook_delete.rb +149 -0
- data/lib/chef/knife/cookbook_download.rb +134 -0
- data/lib/chef/knife/cookbook_list.rb +50 -0
- data/lib/chef/knife/cookbook_metadata.rb +102 -0
- data/lib/chef/knife/cookbook_metadata_from_file.rb +44 -0
- data/lib/chef/knife/cookbook_show.rb +101 -0
- data/lib/chef/knife/cookbook_site_download.rb +58 -0
- data/lib/chef/knife/cookbook_site_list.rb +56 -0
- data/lib/chef/knife/cookbook_site_search.rb +51 -0
- data/lib/chef/knife/cookbook_site_share.rb +114 -0
- data/lib/chef/knife/cookbook_site_show.rb +57 -0
- data/lib/chef/knife/cookbook_site_unshare.rb +56 -0
- data/lib/chef/knife/cookbook_site_vendor.rb +145 -0
- data/lib/chef/knife/cookbook_test.rb +82 -0
- data/lib/chef/knife/cookbook_upload.rb +146 -0
- data/lib/chef/knife/data_bag_create.rb +94 -0
- data/lib/chef/knife/data_bag_delete.rb +51 -0
- data/lib/chef/knife/data_bag_edit.rb +94 -0
- data/lib/chef/knife/data_bag_from_file.rb +85 -0
- data/lib/chef/knife/data_bag_list.rb +46 -0
- data/lib/chef/knife/data_bag_show.rb +81 -0
- data/lib/chef/knife/environment_create.rb +53 -0
- data/lib/chef/knife/environment_delete.rb +45 -0
- data/lib/chef/knife/environment_edit.rb +45 -0
- data/lib/chef/knife/environment_from_file.rb +39 -0
- data/lib/chef/knife/environment_list.rb +42 -0
- data/lib/chef/knife/environment_show.rb +46 -0
- data/lib/chef/knife/exec.rb +51 -0
- data/lib/chef/knife/index_rebuild.rb +50 -0
- data/lib/chef/knife/node_bulk_delete.rb +46 -0
- data/lib/chef/knife/node_create.rb +50 -0
- data/lib/chef/knife/node_delete.rb +47 -0
- data/lib/chef/knife/node_edit.rb +163 -0
- data/lib/chef/knife/node_from_file.rb +45 -0
- data/lib/chef/knife/node_list.rb +46 -0
- data/lib/chef/knife/node_run_list_add.rb +67 -0
- data/lib/chef/knife/node_run_list_remove.rb +48 -0
- data/lib/chef/knife/node_show.rb +62 -0
- data/lib/chef/knife/recipe_list.rb +33 -0
- data/lib/chef/knife/role_bulk_delete.rb +47 -0
- data/lib/chef/knife/role_create.rb +55 -0
- data/lib/chef/knife/role_delete.rb +47 -0
- data/lib/chef/knife/role_edit.rb +48 -0
- data/lib/chef/knife/role_from_file.rb +49 -0
- data/lib/chef/knife/role_list.rb +43 -0
- data/lib/chef/knife/role_show.rb +54 -0
- data/lib/chef/knife/search.rb +123 -0
- data/lib/chef/knife/ssh.rb +318 -0
- data/lib/chef/knife/status.rb +90 -0
- data/lib/chef/knife/subcommand_loader.rb +101 -0
- data/lib/chef/knife/tag_create.rb +31 -0
- data/lib/chef/knife/tag_delete.rb +31 -0
- data/lib/chef/knife/tag_list.rb +29 -0
- data/lib/chef/knife/ui.rb +227 -0
- data/lib/chef/knife/windows_bootstrap.rb +157 -0
- data/lib/chef/log.rb +39 -0
- data/lib/chef/mash.rb +211 -0
- data/lib/chef/mixin/check_helper.rb +31 -0
- data/lib/chef/mixin/checksum.rb +32 -0
- data/lib/chef/mixin/command.rb +221 -0
- data/lib/chef/mixin/command/unix.rb +215 -0
- data/lib/chef/mixin/command/windows.rb +76 -0
- data/lib/chef/mixin/convert_to_class_name.rb +63 -0
- data/lib/chef/mixin/create_path.rb +56 -0
- data/lib/chef/mixin/deep_merge.rb +225 -0
- data/lib/chef/mixin/deprecation.rb +65 -0
- data/lib/chef/mixin/from_file.rb +50 -0
- data/lib/chef/mixin/language.rb +165 -0
- data/lib/chef/mixin/language_include_attribute.rb +61 -0
- data/lib/chef/mixin/language_include_recipe.rb +52 -0
- data/lib/chef/mixin/params_validate.rb +225 -0
- data/lib/chef/mixin/recipe_definition_dsl_core.rb +81 -0
- data/lib/chef/mixin/shell_out.rb +40 -0
- data/lib/chef/mixin/template.rb +95 -0
- data/lib/chef/mixin/xml_escape.rb +140 -0
- data/lib/chef/mixins.rb +15 -0
- data/lib/chef/monkey_patches/dir.rb +36 -0
- data/lib/chef/monkey_patches/numeric.rb +7 -0
- data/lib/chef/monkey_patches/regexp.rb +34 -0
- data/lib/chef/monkey_patches/string.rb +28 -0
- data/lib/chef/monkey_patches/tempfile.rb +64 -0
- data/lib/chef/nil_argument.rb +3 -0
- data/lib/chef/node.rb +661 -0
- data/lib/chef/node/attribute.rb +487 -0
- data/lib/chef/openid_registration.rb +187 -0
- data/lib/chef/platform.rb +409 -0
- data/lib/chef/provider.rb +124 -0
- data/lib/chef/provider/breakpoint.rb +36 -0
- data/lib/chef/provider/cookbook_file.rb +101 -0
- data/lib/chef/provider/cron.rb +186 -0
- data/lib/chef/provider/cron/solaris.rb +195 -0
- data/lib/chef/provider/deploy.rb +320 -0
- data/lib/chef/provider/deploy/revision.rb +80 -0
- data/lib/chef/provider/deploy/timestamped.rb +33 -0
- data/lib/chef/provider/directory.rb +72 -0
- data/lib/chef/provider/env.rb +152 -0
- data/lib/chef/provider/env/windows.rb +75 -0
- data/lib/chef/provider/erl_call.rb +100 -0
- data/lib/chef/provider/execute.rb +60 -0
- data/lib/chef/provider/file.rb +222 -0
- data/lib/chef/provider/git.rb +221 -0
- data/lib/chef/provider/group.rb +133 -0
- data/lib/chef/provider/group/aix.rb +70 -0
- data/lib/chef/provider/group/dscl.rb +121 -0
- data/lib/chef/provider/group/gpasswd.rb +53 -0
- data/lib/chef/provider/group/groupadd.rb +81 -0
- data/lib/chef/provider/group/pw.rb +84 -0
- data/lib/chef/provider/group/usermod.rb +57 -0
- data/lib/chef/provider/group/windows.rb +79 -0
- data/lib/chef/provider/http_request.rb +122 -0
- data/lib/chef/provider/ifconfig.rb +132 -0
- data/lib/chef/provider/link.rb +161 -0
- data/lib/chef/provider/log.rb +54 -0
- data/lib/chef/provider/mdadm.rb +91 -0
- data/lib/chef/provider/mount.rb +117 -0
- data/lib/chef/provider/mount/mount.rb +232 -0
- data/lib/chef/provider/mount/windows.rb +80 -0
- data/lib/chef/provider/ohai.rb +41 -0
- data/lib/chef/provider/package.rb +160 -0
- data/lib/chef/provider/package/apt.rb +110 -0
- data/lib/chef/provider/package/dpkg.rb +112 -0
- data/lib/chef/provider/package/easy_install.rb +136 -0
- data/lib/chef/provider/package/freebsd.rb +123 -0
- data/lib/chef/provider/package/macports.rb +105 -0
- data/lib/chef/provider/package/pacman.rb +101 -0
- data/lib/chef/provider/package/portage.rb +135 -0
- data/lib/chef/provider/package/rpm.rb +101 -0
- data/lib/chef/provider/package/rubygems.rb +462 -0
- data/lib/chef/provider/package/solaris.rb +127 -0
- data/lib/chef/provider/package/yum-dump.py +128 -0
- data/lib/chef/provider/package/yum.rb +261 -0
- data/lib/chef/provider/package/zypper.rb +133 -0
- data/lib/chef/provider/remote_directory.rb +138 -0
- data/lib/chef/provider/remote_file.rb +119 -0
- data/lib/chef/provider/route.rb +195 -0
- data/lib/chef/provider/ruby_block.rb +33 -0
- data/lib/chef/provider/script.rb +55 -0
- data/lib/chef/provider/service.rb +128 -0
- data/lib/chef/provider/service/arch.rb +109 -0
- data/lib/chef/provider/service/debian.rb +130 -0
- data/lib/chef/provider/service/freebsd.rb +156 -0
- data/lib/chef/provider/service/gentoo.rb +54 -0
- data/lib/chef/provider/service/init.rb +71 -0
- data/lib/chef/provider/service/insserv.rb +52 -0
- data/lib/chef/provider/service/redhat.rb +60 -0
- data/lib/chef/provider/service/simple.rb +118 -0
- data/lib/chef/provider/service/solaris.rb +85 -0
- data/lib/chef/provider/service/upstart.rb +192 -0
- data/lib/chef/provider/service/windows.rb +146 -0
- data/lib/chef/provider/subversion.rb +194 -0
- data/lib/chef/provider/template.rb +105 -0
- data/lib/chef/provider/user.rb +187 -0
- data/lib/chef/provider/user/dscl.rb +280 -0
- data/lib/chef/provider/user/pw.rb +113 -0
- data/lib/chef/provider/user/useradd.rb +137 -0
- data/lib/chef/provider/user/windows.rb +124 -0
- data/lib/chef/providers.rb +93 -0
- data/lib/chef/recipe.rb +128 -0
- data/lib/chef/resource.rb +530 -0
- data/lib/chef/resource/apt_package.rb +34 -0
- data/lib/chef/resource/bash.rb +33 -0
- data/lib/chef/resource/breakpoint.rb +35 -0
- data/lib/chef/resource/cookbook_file.rb +45 -0
- data/lib/chef/resource/cron.rb +188 -0
- data/lib/chef/resource/csh.rb +33 -0
- data/lib/chef/resource/deploy.rb +371 -0
- data/lib/chef/resource/deploy_revision.rb +35 -0
- data/lib/chef/resource/directory.rb +76 -0
- data/lib/chef/resource/dpkg_package.rb +34 -0
- data/lib/chef/resource/easy_install_package.rb +57 -0
- data/lib/chef/resource/env.rb +58 -0
- data/lib/chef/resource/erl_call.rb +83 -0
- data/lib/chef/resource/execute.rb +127 -0
- data/lib/chef/resource/file.rb +99 -0
- data/lib/chef/resource/freebsd_package.rb +35 -0
- data/lib/chef/resource/gem_package.rb +53 -0
- data/lib/chef/resource/git.rb +37 -0
- data/lib/chef/resource/group.rb +70 -0
- data/lib/chef/resource/http_request.rb +61 -0
- data/lib/chef/resource/ifconfig.rb +134 -0
- data/lib/chef/resource/link.rb +78 -0
- data/lib/chef/resource/log.rb +62 -0
- data/lib/chef/resource/macports_package.rb +29 -0
- data/lib/chef/resource/mdadm.rb +82 -0
- data/lib/chef/resource/mount.rb +135 -0
- data/lib/chef/resource/ohai.rb +40 -0
- data/lib/chef/resource/package.rb +80 -0
- data/lib/chef/resource/pacman_package.rb +33 -0
- data/lib/chef/resource/perl.rb +33 -0
- data/lib/chef/resource/portage_package.rb +33 -0
- data/lib/chef/resource/python.rb +33 -0
- data/lib/chef/resource/remote_directory.rb +109 -0
- data/lib/chef/resource/remote_file.rb +83 -0
- data/lib/chef/resource/route.rb +135 -0
- data/lib/chef/resource/rpm_package.rb +34 -0
- data/lib/chef/resource/ruby.rb +33 -0
- data/lib/chef/resource/ruby_block.rb +40 -0
- data/lib/chef/resource/scm.rb +147 -0
- data/lib/chef/resource/script.rb +60 -0
- data/lib/chef/resource/service.rb +160 -0
- data/lib/chef/resource/solaris_package.rb +36 -0
- data/lib/chef/resource/subversion.rb +36 -0
- data/lib/chef/resource/template.rb +69 -0
- data/lib/chef/resource/timestamped_deploy.rb +31 -0
- data/lib/chef/resource/user.rb +130 -0
- data/lib/chef/resource/yum_package.rb +43 -0
- data/lib/chef/resource_collection.rb +217 -0
- data/lib/chef/resource_collection/stepable_iterator.rb +124 -0
- data/lib/chef/resource_definition.rb +67 -0
- data/lib/chef/resource_definition_list.rb +38 -0
- data/lib/chef/resources.rb +64 -0
- data/lib/chef/rest.rb +386 -0
- data/lib/chef/rest/auth_credentials.rb +71 -0
- data/lib/chef/rest/cookie_jar.rb +31 -0
- data/lib/chef/rest/rest_request.rb +188 -0
- data/lib/chef/role.rb +341 -0
- data/lib/chef/run_context.rb +126 -0
- data/lib/chef/run_list.rb +165 -0
- data/lib/chef/run_list/run_list_expansion.rb +193 -0
- data/lib/chef/run_list/run_list_item.rb +92 -0
- data/lib/chef/run_list/versioned_recipe_list.rb +68 -0
- data/lib/chef/run_status.rb +121 -0
- data/lib/chef/runner.rb +99 -0
- data/lib/chef/sandbox.rb +153 -0
- data/lib/chef/search/query.rb +65 -0
- data/lib/chef/shef.rb +326 -0
- data/lib/chef/shef/ext.rb +569 -0
- data/lib/chef/shef/model_wrapper.rb +120 -0
- data/lib/chef/shef/shef_rest.rb +28 -0
- data/lib/chef/shef/shef_session.rb +284 -0
- data/lib/chef/shell_out.rb +238 -0
- data/lib/chef/shell_out/unix.rb +223 -0
- data/lib/chef/shell_out/windows.rb +98 -0
- data/lib/chef/solr_query.rb +187 -0
- data/lib/chef/solr_query/lucene.treetop +150 -0
- data/lib/chef/solr_query/lucene_nodes.rb +285 -0
- data/lib/chef/solr_query/query_transform.rb +65 -0
- data/lib/chef/solr_query/solr_http_request.rb +118 -0
- data/lib/chef/streaming_cookbook_uploader.rb +201 -0
- data/lib/chef/tasks/chef_repo.rake +256 -0
- data/lib/chef/util/file_edit.rb +122 -0
- data/lib/chef/util/windows.rb +56 -0
- data/lib/chef/util/windows/net_group.rb +101 -0
- data/lib/chef/util/windows/net_use.rb +121 -0
- data/lib/chef/util/windows/net_user.rb +198 -0
- data/lib/chef/util/windows/volume.rb +59 -0
- data/lib/chef/version.rb +23 -0
- data/lib/chef/version_class.rb +70 -0
- data/lib/chef/version_constraint.rb +116 -0
- data/lib/chef/webui_user.rb +231 -0
- metadata +600 -0
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
require 'rest_client'
|
|
2
|
+
require 'chef/exceptions'
|
|
3
|
+
require 'chef/knife/cookbook_metadata'
|
|
4
|
+
require 'chef/checksum_cache'
|
|
5
|
+
require 'chef/sandbox'
|
|
6
|
+
require 'chef/cookbook_version'
|
|
7
|
+
require 'chef/cookbook/syntax_check'
|
|
8
|
+
require 'chef/cookbook/file_system_file_vendor'
|
|
9
|
+
|
|
10
|
+
class Chef
|
|
11
|
+
class CookbookUploader
|
|
12
|
+
|
|
13
|
+
attr_reader :cookbook
|
|
14
|
+
attr_reader :path
|
|
15
|
+
attr_reader :opts
|
|
16
|
+
attr_reader :rest
|
|
17
|
+
|
|
18
|
+
# Creates a new CookbookUploader.
|
|
19
|
+
# ===Arguments:
|
|
20
|
+
# * cookbook::: A Chef::CookbookVersion describing the cookbook to be uploaded
|
|
21
|
+
# * path::: A String or Array of Strings representing the base paths to the
|
|
22
|
+
# cookbook repositories.
|
|
23
|
+
# * opts::: (optional) An options Hash
|
|
24
|
+
# ===Options:
|
|
25
|
+
# * :force indicates that the uploader should set the force option when
|
|
26
|
+
# uploading the cookbook. This allows frozen CookbookVersion
|
|
27
|
+
# documents on the server to be overwritten (otherwise a 409 is
|
|
28
|
+
# returned by the server)
|
|
29
|
+
# * :rest A Chef::REST object that you have configured the way you like it.
|
|
30
|
+
# If you don't provide this, one will be created using the values
|
|
31
|
+
# in Chef::Config.
|
|
32
|
+
def initialize(cookbook, path, opts={})
|
|
33
|
+
@cookbook, @path, @opts = cookbook, path, opts
|
|
34
|
+
@rest = opts[:rest] || Chef::REST.new(Chef::Config[:chef_server_url])
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def upload_cookbook
|
|
38
|
+
Chef::Log.info("Saving #{cookbook.name}")
|
|
39
|
+
|
|
40
|
+
# Syntax Check
|
|
41
|
+
validate_cookbook
|
|
42
|
+
# Generate metadata.json from metadata.rb
|
|
43
|
+
build_metadata
|
|
44
|
+
|
|
45
|
+
# generate checksums of cookbook files and create a sandbox
|
|
46
|
+
checksum_files = cookbook.checksums
|
|
47
|
+
checksums = checksum_files.inject({}){|memo,elt| memo[elt.first]=nil ; memo}
|
|
48
|
+
new_sandbox = rest.post_rest("sandboxes", { :checksums => checksums })
|
|
49
|
+
|
|
50
|
+
Chef::Log.info("Uploading files")
|
|
51
|
+
# upload the new checksums and commit the sandbox
|
|
52
|
+
new_sandbox['checksums'].each do |checksum, info|
|
|
53
|
+
if info['needs_upload'] == true
|
|
54
|
+
Chef::Log.info("Uploading #{checksum_files[checksum]} (checksum hex = #{checksum}) to #{info['url']}")
|
|
55
|
+
|
|
56
|
+
# Checksum is the hexadecimal representation of the md5,
|
|
57
|
+
# but we need the base64 encoding for the content-md5
|
|
58
|
+
# header
|
|
59
|
+
checksum64 = Base64.encode64([checksum].pack("H*")).strip
|
|
60
|
+
timestamp = Time.now.utc.iso8601
|
|
61
|
+
file_contents = File.read(checksum_files[checksum])
|
|
62
|
+
# TODO - 5/28/2010, cw: make signing and sending the request streaming
|
|
63
|
+
sign_obj = Mixlib::Authentication::SignedHeaderAuth.signing_object(
|
|
64
|
+
:http_method => :put,
|
|
65
|
+
:path => URI.parse(info['url']).path,
|
|
66
|
+
:body => file_contents,
|
|
67
|
+
:timestamp => timestamp,
|
|
68
|
+
:user_id => rest.client_name
|
|
69
|
+
)
|
|
70
|
+
headers = { 'content-type' => 'application/x-binary', 'content-md5' => checksum64, :accept => 'application/json' }
|
|
71
|
+
headers.merge!(sign_obj.sign(OpenSSL::PKey::RSA.new(rest.signing_key)))
|
|
72
|
+
|
|
73
|
+
begin
|
|
74
|
+
RestClient::Resource.new(info['url'], :headers=>headers, :timeout=>1800, :open_timeout=>1800).put(file_contents)
|
|
75
|
+
rescue RestClient::Exception => e
|
|
76
|
+
Chef::Log.error("Upload failed: #{e.message}\n#{e.response.body}")
|
|
77
|
+
raise
|
|
78
|
+
end
|
|
79
|
+
else
|
|
80
|
+
Chef::Log.debug("#{checksum_files[checksum]} has not changed")
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
sandbox_url = new_sandbox['uri']
|
|
84
|
+
Chef::Log.debug("Committing sandbox")
|
|
85
|
+
# Retry if S3 is claims a checksum doesn't exist (the eventual
|
|
86
|
+
# in eventual consistency)
|
|
87
|
+
retries = 0
|
|
88
|
+
begin
|
|
89
|
+
rest.put_rest(sandbox_url, {:is_completed => true})
|
|
90
|
+
rescue Net::HTTPServerException => e
|
|
91
|
+
if e.message =~ /^400/ && (retries += 1) <= 5
|
|
92
|
+
sleep 2
|
|
93
|
+
retry
|
|
94
|
+
else
|
|
95
|
+
raise
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
# files are uploaded, so save the manifest
|
|
99
|
+
opts[:force] ? cookbook.force_save : cookbook.save
|
|
100
|
+
Chef::Log.info("Upload complete!")
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def build_metadata
|
|
104
|
+
Chef::Log.debug("Generating metadata")
|
|
105
|
+
# FIXME: This knife command should be factored out into a
|
|
106
|
+
# library for use here
|
|
107
|
+
kcm = Chef::Knife::CookbookMetadata.new
|
|
108
|
+
kcm.config[:cookbook_path] = path
|
|
109
|
+
kcm.name_args = [ cookbook.name.to_s ]
|
|
110
|
+
kcm.run
|
|
111
|
+
cookbook.reload_metadata!
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def validate_cookbook
|
|
115
|
+
syntax_checker = Chef::Cookbook::SyntaxCheck.for_cookbook(cookbook.name, @user_cookbook_path)
|
|
116
|
+
Chef::Log.info("Validating ruby files")
|
|
117
|
+
exit(1) unless syntax_checker.validate_ruby_files
|
|
118
|
+
Chef::Log.info("Validating templates")
|
|
119
|
+
exit(1) unless syntax_checker.validate_templates
|
|
120
|
+
Chef::Log.info("Syntax OK")
|
|
121
|
+
true
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
end
|
|
125
|
+
end
|
|
@@ -0,0 +1,979 @@
|
|
|
1
|
+
# Author:: Adam Jacob (<adam@opscode.com>)
|
|
2
|
+
# Author:: Nuo Yan (<nuo@opscode.com>)
|
|
3
|
+
# Author:: Christopher Walters (<cw@opscode.com>)
|
|
4
|
+
# Author:: Tim Hinderliter (<tim@opscode.com>)
|
|
5
|
+
# Author:: Seth Falcon (<seth@opscode.com>)
|
|
6
|
+
# Copyright:: Copyright 2008-2010 Opscode, Inc.
|
|
7
|
+
# License:: Apache License, Version 2.0
|
|
8
|
+
#
|
|
9
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
10
|
+
# you may not use this file except in compliance with the License.
|
|
11
|
+
# You may obtain a copy of the License at
|
|
12
|
+
#
|
|
13
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
14
|
+
#
|
|
15
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
16
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
17
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
18
|
+
# See the License for the specific language governing permissions and
|
|
19
|
+
# limitations under the License.
|
|
20
|
+
|
|
21
|
+
require 'chef/log'
|
|
22
|
+
require 'chef/client'
|
|
23
|
+
require 'chef/node'
|
|
24
|
+
require 'chef/resource_definition_list'
|
|
25
|
+
require 'chef/recipe'
|
|
26
|
+
require 'chef/cookbook/file_vendor'
|
|
27
|
+
require 'chef/checksum'
|
|
28
|
+
require 'chef/cookbook/metadata'
|
|
29
|
+
require 'chef/version_class'
|
|
30
|
+
|
|
31
|
+
class Chef
|
|
32
|
+
# == Chef::CookbookVersion
|
|
33
|
+
# CookbookVersion is a model object encapsulating the data about a Chef
|
|
34
|
+
# cookbook. Chef supports maintaining multiple versions of a cookbook on a
|
|
35
|
+
# single server; each version is represented by a distinct instance of this
|
|
36
|
+
# class.
|
|
37
|
+
#--
|
|
38
|
+
# TODO: timh/cw: 5-24-2010: mutators for files (e.g., recipe_filenames=,
|
|
39
|
+
# recipe_filenames.insert) should dirty the manifest so it gets regenerated.
|
|
40
|
+
class CookbookVersion
|
|
41
|
+
include Chef::IndexQueue::Indexable
|
|
42
|
+
include Comparable
|
|
43
|
+
|
|
44
|
+
COOKBOOK_SEGMENTS = [ :resources, :providers, :recipes, :definitions, :libraries, :attributes, :files, :templates, :root_files ]
|
|
45
|
+
|
|
46
|
+
DESIGN_DOCUMENT = {
|
|
47
|
+
"version" => 7,
|
|
48
|
+
"language" => "javascript",
|
|
49
|
+
"views" => {
|
|
50
|
+
"all" => {
|
|
51
|
+
"map" => <<-EOJS
|
|
52
|
+
function(doc) {
|
|
53
|
+
if (doc.chef_type == "cookbook_version") {
|
|
54
|
+
emit(doc.name, doc);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
EOJS
|
|
58
|
+
},
|
|
59
|
+
"all_id" => {
|
|
60
|
+
"map" => <<-EOJS
|
|
61
|
+
function(doc) {
|
|
62
|
+
if (doc.chef_type == "cookbook_version") {
|
|
63
|
+
emit(doc.name, doc.name);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
EOJS
|
|
67
|
+
},
|
|
68
|
+
"all_with_version" => {
|
|
69
|
+
"map" => <<-EOJS
|
|
70
|
+
function(doc) {
|
|
71
|
+
if (doc.chef_type == "cookbook_version") {
|
|
72
|
+
emit(doc.cookbook_name, doc.version);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
EOJS
|
|
76
|
+
},
|
|
77
|
+
"all_latest_version" => {
|
|
78
|
+
"map" => %q@
|
|
79
|
+
function(doc) {
|
|
80
|
+
if (doc.chef_type == "cookbook_version") {
|
|
81
|
+
emit(doc.cookbook_name, doc.version);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
@,
|
|
85
|
+
"reduce" => %q@
|
|
86
|
+
function(keys, values, rereduce) {
|
|
87
|
+
var result = null;
|
|
88
|
+
|
|
89
|
+
for (var idx in values) {
|
|
90
|
+
var value = values[idx];
|
|
91
|
+
|
|
92
|
+
if (idx == 0) {
|
|
93
|
+
result = value;
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
var valueParts = value.split('.').map(function(v) { return parseInt(v); });
|
|
98
|
+
var resultParts = result.split('.').map(function(v) { return parseInt(v); });
|
|
99
|
+
|
|
100
|
+
if (valueParts[0] != resultParts[0]) {
|
|
101
|
+
if (valueParts[0] > resultParts[0]) {
|
|
102
|
+
result = value;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
else if (valueParts[1] != resultParts[1]) {
|
|
106
|
+
if (valueParts[1] > resultParts[1]) {
|
|
107
|
+
result = value;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
else if (valueParts[2] != resultParts[2]) {
|
|
111
|
+
if (valueParts[2] > resultParts[2]) {
|
|
112
|
+
result = value;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return result;
|
|
117
|
+
}
|
|
118
|
+
@
|
|
119
|
+
},
|
|
120
|
+
"all_latest_version_by_id" => {
|
|
121
|
+
"map" => %q@
|
|
122
|
+
function(doc) {
|
|
123
|
+
if (doc.chef_type == "cookbook_version") {
|
|
124
|
+
emit(doc.cookbook_name, {version: doc.version, id:doc._id});
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
@,
|
|
128
|
+
"reduce" => %q@
|
|
129
|
+
function(keys, values, rereduce) {
|
|
130
|
+
var result = null;
|
|
131
|
+
|
|
132
|
+
for (var idx in values) {
|
|
133
|
+
var value = values[idx];
|
|
134
|
+
|
|
135
|
+
if (idx == 0) {
|
|
136
|
+
result = value;
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
var valueParts = value.version.split('.').map(function(v) { return parseInt(v); });
|
|
141
|
+
var resultParts = result.version.split('.').map(function(v) { return parseInt(v); });
|
|
142
|
+
|
|
143
|
+
if (valueParts[0] != resultParts[0]) {
|
|
144
|
+
if (valueParts[0] > resultParts[0]) {
|
|
145
|
+
result = value;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
else if (valueParts[1] != resultParts[1]) {
|
|
149
|
+
if (valueParts[1] > resultParts[1]) {
|
|
150
|
+
result = value;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
else if (valueParts[2] != resultParts[2]) {
|
|
154
|
+
if (valueParts[2] > resultParts[2]) {
|
|
155
|
+
result = value;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
return result;
|
|
160
|
+
}
|
|
161
|
+
@
|
|
162
|
+
},
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
attr_accessor :root_dir
|
|
167
|
+
attr_accessor :definition_filenames
|
|
168
|
+
attr_accessor :template_filenames
|
|
169
|
+
attr_accessor :file_filenames
|
|
170
|
+
attr_accessor :library_filenames
|
|
171
|
+
attr_accessor :resource_filenames
|
|
172
|
+
attr_accessor :provider_filenames
|
|
173
|
+
attr_accessor :root_filenames
|
|
174
|
+
attr_accessor :name
|
|
175
|
+
attr_accessor :metadata
|
|
176
|
+
attr_accessor :metadata_filenames
|
|
177
|
+
attr_accessor :status
|
|
178
|
+
attr_accessor :couchdb_rev
|
|
179
|
+
attr_accessor :couchdb
|
|
180
|
+
|
|
181
|
+
attr_reader :couchdb_id
|
|
182
|
+
|
|
183
|
+
# attribute_filenames also has a setter that has non-default
|
|
184
|
+
# functionality.
|
|
185
|
+
attr_reader :attribute_filenames
|
|
186
|
+
|
|
187
|
+
# recipe_filenames also has a setter that has non-default
|
|
188
|
+
# functionality.
|
|
189
|
+
attr_reader :recipe_filenames
|
|
190
|
+
|
|
191
|
+
attr_reader :recipe_filenames_by_name
|
|
192
|
+
attr_reader :attribute_filenames_by_short_filename
|
|
193
|
+
|
|
194
|
+
# This is the one and only method that knows how cookbook files'
|
|
195
|
+
# checksums are generated.
|
|
196
|
+
def self.checksum_cookbook_file(filepath)
|
|
197
|
+
Chef::ChecksumCache.generate_md5_checksum_for_file(filepath)
|
|
198
|
+
rescue Errno::ENOENT
|
|
199
|
+
Chef::Log.debug("File #{filepath} does not exist, so there is no checksum to generate")
|
|
200
|
+
nil
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
# Keep track of the filenames that we use in both eager cookbook
|
|
204
|
+
# downloading (during sync_cookbooks) and lazy (during the run
|
|
205
|
+
# itself, through FileVendor). After the run is over, clean up the
|
|
206
|
+
# cache.
|
|
207
|
+
def self.valid_cache_entries
|
|
208
|
+
@valid_cache_entries ||= {}
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
def self.reset_cache_validity
|
|
212
|
+
@valid_cache_entries = nil
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
def self.cache
|
|
216
|
+
Chef::FileCache
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
# Setup a notification to clear the valid_cache_entries when a Chef client
|
|
220
|
+
# run starts
|
|
221
|
+
Chef::Client.when_run_starts do |run_status|
|
|
222
|
+
reset_cache_validity
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
# Synchronizes all the cookbooks from the chef-server.
|
|
226
|
+
#
|
|
227
|
+
# === Returns
|
|
228
|
+
# true:: Always returns true
|
|
229
|
+
def self.sync_cookbooks(cookbook_hash)
|
|
230
|
+
Chef::Log.info("Loading cookbooks [#{cookbook_hash.keys.sort.join(', ')}]")
|
|
231
|
+
Chef::Log.debug("Cookbooks detail: #{cookbook_hash.inspect}")
|
|
232
|
+
|
|
233
|
+
clear_obsoleted_cookbooks(cookbook_hash)
|
|
234
|
+
|
|
235
|
+
# Synchronize each of the node's cookbooks, and add to the
|
|
236
|
+
# valid_cache_entries hash.
|
|
237
|
+
cookbook_hash.values.each do |cookbook|
|
|
238
|
+
sync_cookbook_file_cache(cookbook)
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
true
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
# Iterates over cached cookbooks' files, removing files belonging to
|
|
245
|
+
# cookbooks that don't appear in +cookbook_hash+
|
|
246
|
+
def self.clear_obsoleted_cookbooks(cookbook_hash)
|
|
247
|
+
# Remove all cookbooks no longer relevant to this node
|
|
248
|
+
cache.find(File.join(%w{cookbooks ** *})).each do |cache_file|
|
|
249
|
+
cache_file =~ /^cookbooks\/([^\/]+)\//
|
|
250
|
+
unless cookbook_hash.has_key?($1)
|
|
251
|
+
Chef::Log.info("Removing #{cache_file} from the cache; its cookbook is no longer needed on this client.")
|
|
252
|
+
cache.delete(cache_file)
|
|
253
|
+
end
|
|
254
|
+
end
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
# Update the file caches for a given cache segment. Takes a segment name
|
|
258
|
+
# and a hash that matches one of the cookbooks/_attribute_files style
|
|
259
|
+
# remote file listings.
|
|
260
|
+
#
|
|
261
|
+
# === Parameters
|
|
262
|
+
# cookbook<Chef::Cookbook>:: The cookbook to update
|
|
263
|
+
# valid_cache_entries<Hash>:: Out-param; Added to this hash are the files that
|
|
264
|
+
# were referred to by this cookbook
|
|
265
|
+
def self.sync_cookbook_file_cache(cookbook)
|
|
266
|
+
Chef::Log.debug("Synchronizing cookbook #{cookbook.name}")
|
|
267
|
+
|
|
268
|
+
# files and templates are lazily loaded, and will be done later.
|
|
269
|
+
eager_segments = COOKBOOK_SEGMENTS.dup
|
|
270
|
+
eager_segments.delete(:files)
|
|
271
|
+
eager_segments.delete(:templates)
|
|
272
|
+
|
|
273
|
+
eager_segments.each do |segment|
|
|
274
|
+
segment_filenames = Array.new
|
|
275
|
+
cookbook.manifest[segment].each do |manifest_record|
|
|
276
|
+
# segment = cookbook segment
|
|
277
|
+
# remote_list = list of file hashes
|
|
278
|
+
#
|
|
279
|
+
# We need the list of known good attribute files, so we can delete any that are
|
|
280
|
+
# just laying about.
|
|
281
|
+
|
|
282
|
+
cache_filename = File.join("cookbooks", cookbook.name, manifest_record['path'])
|
|
283
|
+
valid_cache_entries[cache_filename] = true
|
|
284
|
+
|
|
285
|
+
current_checksum = nil
|
|
286
|
+
if cache.has_key?(cache_filename)
|
|
287
|
+
current_checksum = checksum_cookbook_file(cache.load(cache_filename, false))
|
|
288
|
+
end
|
|
289
|
+
|
|
290
|
+
# If the checksums are different between on-disk (current) and on-server
|
|
291
|
+
# (remote, per manifest), do the update. This will also execute if there
|
|
292
|
+
# is no current checksum.
|
|
293
|
+
if current_checksum != manifest_record['checksum']
|
|
294
|
+
raw_file = chef_server_rest.get_rest(manifest_record[:url], true)
|
|
295
|
+
|
|
296
|
+
Chef::Log.info("Storing updated #{cache_filename} in the cache.")
|
|
297
|
+
cache.move_to(raw_file.path, cache_filename)
|
|
298
|
+
else
|
|
299
|
+
Chef::Log.debug("Not storing #{cache_filename}, as the cache is up to date.")
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
# make the segment filenames a full path.
|
|
303
|
+
full_path_cache_filename = cache.load(cache_filename, false)
|
|
304
|
+
segment_filenames << full_path_cache_filename
|
|
305
|
+
end
|
|
306
|
+
|
|
307
|
+
# replace segment filenames with a full-path one.
|
|
308
|
+
if segment.to_sym == :recipes
|
|
309
|
+
cookbook.recipe_filenames = segment_filenames
|
|
310
|
+
elsif segment.to_sym == :attributes
|
|
311
|
+
cookbook.attribute_filenames = segment_filenames
|
|
312
|
+
else
|
|
313
|
+
cookbook.segment_filenames(segment).replace(segment_filenames)
|
|
314
|
+
end
|
|
315
|
+
end
|
|
316
|
+
end
|
|
317
|
+
|
|
318
|
+
def self.cleanup_file_cache
|
|
319
|
+
unless Chef::Config[:solo]
|
|
320
|
+
# Delete each file in the cache that we didn't encounter in the
|
|
321
|
+
# manifest.
|
|
322
|
+
cache.find(File.join(%w{cookbooks ** *})).each do |cache_filename|
|
|
323
|
+
unless valid_cache_entries[cache_filename]
|
|
324
|
+
Chef::Log.info("Removing #{cache_filename} from the cache; it is no longer needed by chef-client.")
|
|
325
|
+
cache.delete(cache_filename)
|
|
326
|
+
end
|
|
327
|
+
end
|
|
328
|
+
end
|
|
329
|
+
end
|
|
330
|
+
|
|
331
|
+
# Register a notification to cleanup unused files from cookbooks
|
|
332
|
+
Chef::Client.when_run_completes_successfully do |run_status|
|
|
333
|
+
cleanup_file_cache
|
|
334
|
+
end
|
|
335
|
+
|
|
336
|
+
# Creates a new Chef::CookbookVersion object.
|
|
337
|
+
#
|
|
338
|
+
# === Returns
|
|
339
|
+
# object<Chef::CookbookVersion>:: Duh. :)
|
|
340
|
+
def initialize(name, couchdb=nil)
|
|
341
|
+
@name = name
|
|
342
|
+
@frozen = false
|
|
343
|
+
@attribute_filenames = Array.new
|
|
344
|
+
@definition_filenames = Array.new
|
|
345
|
+
@template_filenames = Array.new
|
|
346
|
+
@file_filenames = Array.new
|
|
347
|
+
@recipe_filenames = Array.new
|
|
348
|
+
@recipe_filenames_by_name = Hash.new
|
|
349
|
+
@library_filenames = Array.new
|
|
350
|
+
@resource_filenames = Array.new
|
|
351
|
+
@provider_filenames = Array.new
|
|
352
|
+
@metadata_filenames = Array.new
|
|
353
|
+
@root_dir = nil
|
|
354
|
+
@root_filenames = Array.new
|
|
355
|
+
@couchdb_id = nil
|
|
356
|
+
@couchdb = couchdb || Chef::CouchDB.new
|
|
357
|
+
@couchdb_rev = nil
|
|
358
|
+
@status = :ready
|
|
359
|
+
@manifest = nil
|
|
360
|
+
@file_vendor = nil
|
|
361
|
+
@metadata = Chef::Cookbook::Metadata.new
|
|
362
|
+
end
|
|
363
|
+
|
|
364
|
+
def version
|
|
365
|
+
metadata.version
|
|
366
|
+
end
|
|
367
|
+
|
|
368
|
+
# Indicates if this version is frozen or not. Freezing a coobkook version
|
|
369
|
+
# indicates that a new cookbook with the same name and version number
|
|
370
|
+
# shoule
|
|
371
|
+
def frozen_version?
|
|
372
|
+
@frozen
|
|
373
|
+
end
|
|
374
|
+
|
|
375
|
+
def freeze_version
|
|
376
|
+
@frozen = true
|
|
377
|
+
end
|
|
378
|
+
|
|
379
|
+
def version=(new_version)
|
|
380
|
+
manifest["version"] = new_version
|
|
381
|
+
metadata.version(new_version)
|
|
382
|
+
end
|
|
383
|
+
|
|
384
|
+
# A manifest is a Mash that maps segment names to arrays of manifest
|
|
385
|
+
# records (see #preferred_manifest_record for format of manifest records),
|
|
386
|
+
# as well as describing cookbook metadata. The manifest follows a form
|
|
387
|
+
# like the following:
|
|
388
|
+
#
|
|
389
|
+
# {
|
|
390
|
+
# :cookbook_name = "apache2",
|
|
391
|
+
# :version = "1.0",
|
|
392
|
+
# :name = "Apache 2"
|
|
393
|
+
# :metadata = ???TODO: timh/cw: 5-24-2010: describe this format,
|
|
394
|
+
#
|
|
395
|
+
# :files => [
|
|
396
|
+
# {
|
|
397
|
+
# :name => "afile.rb",
|
|
398
|
+
# :path => "files/ubuntu-9.10/afile.rb",
|
|
399
|
+
# :checksum => "2222",
|
|
400
|
+
# :specificity => "ubuntu-9.10"
|
|
401
|
+
# },
|
|
402
|
+
# ],
|
|
403
|
+
# :templates => [ manifest_record1, ... ],
|
|
404
|
+
# ...
|
|
405
|
+
# }
|
|
406
|
+
def manifest
|
|
407
|
+
unless @manifest
|
|
408
|
+
generate_manifest
|
|
409
|
+
end
|
|
410
|
+
@manifest
|
|
411
|
+
end
|
|
412
|
+
|
|
413
|
+
def manifest=(new_manifest)
|
|
414
|
+
@manifest = Mash.new new_manifest
|
|
415
|
+
@checksums = extract_checksums_from_manifest(@manifest)
|
|
416
|
+
@manifest_records_by_path = extract_manifest_records_by_path(@manifest)
|
|
417
|
+
|
|
418
|
+
COOKBOOK_SEGMENTS.each do |segment|
|
|
419
|
+
next unless @manifest.has_key?(segment)
|
|
420
|
+
filenames = @manifest[segment].map{|manifest_record| manifest_record['name']}
|
|
421
|
+
|
|
422
|
+
if segment == :recipes
|
|
423
|
+
self.recipe_filenames = filenames
|
|
424
|
+
elsif segment == :attributes
|
|
425
|
+
self.attribute_filenames = filenames
|
|
426
|
+
else
|
|
427
|
+
segment_filenames(segment).clear
|
|
428
|
+
filenames.each { |filename| segment_filenames(segment) << filename }
|
|
429
|
+
end
|
|
430
|
+
end
|
|
431
|
+
end
|
|
432
|
+
|
|
433
|
+
# Returns a hash of checksums to either nil or the on disk path (which is
|
|
434
|
+
# done by generate_manifest).
|
|
435
|
+
def checksums
|
|
436
|
+
unless @checksums
|
|
437
|
+
generate_manifest
|
|
438
|
+
end
|
|
439
|
+
@checksums
|
|
440
|
+
end
|
|
441
|
+
|
|
442
|
+
def full_name
|
|
443
|
+
"#{name}-#{version}"
|
|
444
|
+
end
|
|
445
|
+
|
|
446
|
+
def attribute_filenames=(*filenames)
|
|
447
|
+
@attribute_filenames = filenames.flatten
|
|
448
|
+
@attribute_filenames_by_short_filename = filenames_by_name(attribute_filenames)
|
|
449
|
+
attribute_filenames
|
|
450
|
+
end
|
|
451
|
+
|
|
452
|
+
## BACKCOMPAT/DEPRECATED - Remove these and fix breakage before release [DAN - 5/20/2010]##
|
|
453
|
+
alias :attribute_files :attribute_filenames
|
|
454
|
+
alias :attribute_files= :attribute_filenames=
|
|
455
|
+
|
|
456
|
+
# Return recipe names in the form of cookbook_name::recipe_name
|
|
457
|
+
def fully_qualified_recipe_names
|
|
458
|
+
results = Array.new
|
|
459
|
+
recipe_filenames_by_name.each_key do |rname|
|
|
460
|
+
results << "#{name}::#{rname}"
|
|
461
|
+
end
|
|
462
|
+
results
|
|
463
|
+
end
|
|
464
|
+
|
|
465
|
+
def recipe_filenames=(*filenames)
|
|
466
|
+
@recipe_filenames = filenames.flatten
|
|
467
|
+
@recipe_filenames_by_name = filenames_by_name(recipe_filenames)
|
|
468
|
+
recipe_filenames
|
|
469
|
+
end
|
|
470
|
+
|
|
471
|
+
## BACKCOMPAT/DEPRECATED - Remove these and fix breakage before release [DAN - 5/20/2010]##
|
|
472
|
+
alias :recipe_files :recipe_filenames
|
|
473
|
+
alias :recipe_files= :recipe_filenames=
|
|
474
|
+
|
|
475
|
+
# called from DSL
|
|
476
|
+
def load_recipe(recipe_name, run_context)
|
|
477
|
+
unless recipe_filenames_by_name.has_key?(recipe_name)
|
|
478
|
+
raise ArgumentError, "Cannot find a recipe matching #{recipe_name} in cookbook #{name}"
|
|
479
|
+
end
|
|
480
|
+
|
|
481
|
+
Chef::Log.debug("Found recipe #{recipe_name} in cookbook #{name}")
|
|
482
|
+
recipe = Chef::Recipe.new(name, recipe_name, run_context)
|
|
483
|
+
recipe_filename = recipe_filenames_by_name[recipe_name]
|
|
484
|
+
|
|
485
|
+
unless recipe_filename
|
|
486
|
+
raise Chef::Exceptions::RecipeNotFound, "could not find recipe #{recipe_name} for cookbook #{name}"
|
|
487
|
+
end
|
|
488
|
+
|
|
489
|
+
recipe.from_file(recipe_filename)
|
|
490
|
+
recipe
|
|
491
|
+
end
|
|
492
|
+
|
|
493
|
+
def segment_filenames(segment)
|
|
494
|
+
unless COOKBOOK_SEGMENTS.include?(segment)
|
|
495
|
+
raise ArgumentError, "invalid segment #{segment}: must be one of #{COOKBOOK_SEGMENTS.join(', ')}"
|
|
496
|
+
end
|
|
497
|
+
|
|
498
|
+
case segment.to_sym
|
|
499
|
+
when :resources
|
|
500
|
+
@resource_filenames
|
|
501
|
+
when :providers
|
|
502
|
+
@provider_filenames
|
|
503
|
+
when :recipes
|
|
504
|
+
@recipe_filenames
|
|
505
|
+
when :libraries
|
|
506
|
+
@library_filenames
|
|
507
|
+
when :definitions
|
|
508
|
+
@definition_filenames
|
|
509
|
+
when :attributes
|
|
510
|
+
@attribute_filenames
|
|
511
|
+
when :files
|
|
512
|
+
@file_filenames
|
|
513
|
+
when :templates
|
|
514
|
+
@template_filenames
|
|
515
|
+
when :root_files
|
|
516
|
+
@root_filenames
|
|
517
|
+
end
|
|
518
|
+
end
|
|
519
|
+
|
|
520
|
+
# Determine the most specific manifest record for the given
|
|
521
|
+
# segment/filename, given information in the node. Throws
|
|
522
|
+
# FileNotFound if there is no such segment and filename in the
|
|
523
|
+
# manifest.
|
|
524
|
+
#
|
|
525
|
+
# A manifest record is a Mash that follows the following form:
|
|
526
|
+
# {
|
|
527
|
+
# :name => "example.rb",
|
|
528
|
+
# :path => "files/default/example.rb",
|
|
529
|
+
# :specificity => "default",
|
|
530
|
+
# :checksum => "1234"
|
|
531
|
+
# }
|
|
532
|
+
def preferred_manifest_record(node, segment, filename)
|
|
533
|
+
preferences = preferences_for_path(node, segment, filename)
|
|
534
|
+
|
|
535
|
+
# ensure that we generate the manifest, which will also generate
|
|
536
|
+
# @manifest_records_by_path
|
|
537
|
+
manifest
|
|
538
|
+
|
|
539
|
+
# in order of prefernce, look for the filename in the manifest
|
|
540
|
+
found_pref = preferences.find {|preferred_filename| @manifest_records_by_path[preferred_filename] }
|
|
541
|
+
if found_pref
|
|
542
|
+
@manifest_records_by_path[found_pref]
|
|
543
|
+
else
|
|
544
|
+
raise Chef::Exceptions::FileNotFound, "cookbook #{name} does not contain file #{segment}/#{filename}"
|
|
545
|
+
end
|
|
546
|
+
end
|
|
547
|
+
|
|
548
|
+
def preferred_filename_on_disk_location(node, segment, filename, current_filepath=nil)
|
|
549
|
+
manifest_record = preferred_manifest_record(node, segment, filename)
|
|
550
|
+
if current_filepath && (manifest_record['checksum'] == self.class.checksum_cookbook_file(current_filepath))
|
|
551
|
+
nil
|
|
552
|
+
else
|
|
553
|
+
file_vendor.get_filename(manifest_record['path'])
|
|
554
|
+
end
|
|
555
|
+
end
|
|
556
|
+
|
|
557
|
+
def relative_filenames_in_preferred_directory(node, segment, dirname)
|
|
558
|
+
preferences = preferences_for_path(node, segment, dirname)
|
|
559
|
+
filenames_by_pref = Hash.new
|
|
560
|
+
preferences.each { |pref| filenames_by_pref[pref] = Array.new }
|
|
561
|
+
|
|
562
|
+
manifest[segment].each do |manifest_record|
|
|
563
|
+
manifest_record_path = manifest_record[:path]
|
|
564
|
+
|
|
565
|
+
# find the NON SPECIFIC filenames, but prefer them by filespecificity.
|
|
566
|
+
# For example, if we have a file:
|
|
567
|
+
# 'files/default/somedir/somefile.conf' we only keep
|
|
568
|
+
# 'somedir/somefile.conf'. If there is also
|
|
569
|
+
# 'files/$hostspecific/somedir/otherfiles' that matches the requested
|
|
570
|
+
# hostname specificity, that directory will win, as it is more specific.
|
|
571
|
+
#
|
|
572
|
+
# This is clearly ugly b/c the use case is for remote directory, where
|
|
573
|
+
# we're just going to make cookbook_files out of these and make the
|
|
574
|
+
# cookbook find them by filespecificity again. but it's the shortest
|
|
575
|
+
# path to "success" for now.
|
|
576
|
+
if manifest_record_path =~ /(#{Regexp.escape(segment.to_s)}\/[^\/]+\/#{Regexp.escape(dirname)})\/.+$/
|
|
577
|
+
specificity_dirname = $1
|
|
578
|
+
non_specific_path = manifest_record_path[/#{Regexp.escape(segment.to_s)}\/[^\/]+\/#{Regexp.escape(dirname)}\/(.+)$/, 1]
|
|
579
|
+
# Record the specificity_dirname only if it's in the list of
|
|
580
|
+
# valid preferences
|
|
581
|
+
if filenames_by_pref[specificity_dirname]
|
|
582
|
+
filenames_by_pref[specificity_dirname] << non_specific_path
|
|
583
|
+
end
|
|
584
|
+
end
|
|
585
|
+
end
|
|
586
|
+
|
|
587
|
+
best_pref = preferences.find { |pref| !filenames_by_pref[pref].empty? }
|
|
588
|
+
|
|
589
|
+
raise Chef::Exceptions::FileNotFound, "cookbook #{name} has no directory #{segment}/#{dirname}" unless best_pref
|
|
590
|
+
|
|
591
|
+
filenames_by_pref[best_pref]
|
|
592
|
+
|
|
593
|
+
end
|
|
594
|
+
|
|
595
|
+
# Determine the manifest records from the most specific directory
|
|
596
|
+
# for the given node. See #preferred_manifest_record for a
|
|
597
|
+
# description of entries of the returned Array.
|
|
598
|
+
def preferred_manifest_records_for_directory(node, segment, dirname)
|
|
599
|
+
preferences = preferences_for_path(node, segment, dirname)
|
|
600
|
+
records_by_pref = Hash.new
|
|
601
|
+
preferences.each { |pref| records_by_pref[pref] = Array.new }
|
|
602
|
+
|
|
603
|
+
manifest[segment].each do |manifest_record|
|
|
604
|
+
manifest_record_path = manifest_record[:path]
|
|
605
|
+
|
|
606
|
+
# extract the preference part from the path.
|
|
607
|
+
if manifest_record_path =~ /(#{Regexp.escape(segment.to_s)}\/[^\/]+\/#{Regexp.escape(dirname)})\/.+$/
|
|
608
|
+
# Note the specificy_dirname includes the segment and
|
|
609
|
+
# dirname argument as above, which is what
|
|
610
|
+
# preferences_for_path returns. It could be
|
|
611
|
+
# "files/ubuntu-9.10/dirname", for example.
|
|
612
|
+
specificity_dirname = $1
|
|
613
|
+
|
|
614
|
+
# Record the specificity_dirname only if it's in the list of
|
|
615
|
+
# valid preferences
|
|
616
|
+
if records_by_pref[specificity_dirname]
|
|
617
|
+
records_by_pref[specificity_dirname] << manifest_record
|
|
618
|
+
end
|
|
619
|
+
end
|
|
620
|
+
end
|
|
621
|
+
|
|
622
|
+
best_pref = preferences.find { |pref| !records_by_pref[pref].empty? }
|
|
623
|
+
|
|
624
|
+
raise Chef::Exceptions::FileNotFound, "cookbook #{name} has no directory #{segment}/#{dirname}" unless best_pref
|
|
625
|
+
|
|
626
|
+
records_by_pref[best_pref]
|
|
627
|
+
end
|
|
628
|
+
|
|
629
|
+
|
|
630
|
+
# Given a node, segment and path (filename or directory name),
|
|
631
|
+
# return the priority-ordered list of preference locations to
|
|
632
|
+
# look.
|
|
633
|
+
def preferences_for_path(node, segment, path)
|
|
634
|
+
# only files and templates can be platform-specific
|
|
635
|
+
if segment.to_sym == :files || segment.to_sym == :templates
|
|
636
|
+
begin
|
|
637
|
+
platform, version = Chef::Platform.find_platform_and_version(node)
|
|
638
|
+
rescue ArgumentError => e
|
|
639
|
+
# Skip platform/version if they were not found by find_platform_and_version
|
|
640
|
+
if e.message =~ /Cannot find a (?:platform|version)/
|
|
641
|
+
platform = "/unknown_platform/"
|
|
642
|
+
version = "/unknown_platform_version/"
|
|
643
|
+
else
|
|
644
|
+
raise
|
|
645
|
+
end
|
|
646
|
+
end
|
|
647
|
+
|
|
648
|
+
fqdn = node[:fqdn]
|
|
649
|
+
|
|
650
|
+
# Most specific to least specific places to find the path
|
|
651
|
+
[
|
|
652
|
+
File.join(segment.to_s, "host-#{fqdn}", path),
|
|
653
|
+
File.join(segment.to_s, "#{platform}-#{version}", path),
|
|
654
|
+
File.join(segment.to_s, platform.to_s, path),
|
|
655
|
+
File.join(segment.to_s, "default", path)
|
|
656
|
+
]
|
|
657
|
+
else
|
|
658
|
+
[File.join(segment, path)]
|
|
659
|
+
end
|
|
660
|
+
end
|
|
661
|
+
private :preferences_for_path
|
|
662
|
+
|
|
663
|
+
def to_hash
|
|
664
|
+
result = manifest.dup
|
|
665
|
+
result['frozen?'] = frozen_version?
|
|
666
|
+
result['chef_type'] = 'cookbook_version'
|
|
667
|
+
result["_rev"] = couchdb_rev if couchdb_rev
|
|
668
|
+
result.to_hash
|
|
669
|
+
end
|
|
670
|
+
|
|
671
|
+
def to_json(*a)
|
|
672
|
+
result = self.to_hash
|
|
673
|
+
result['json_class'] = self.class.name
|
|
674
|
+
result.to_json(*a)
|
|
675
|
+
end
|
|
676
|
+
|
|
677
|
+
def self.json_create(o)
|
|
678
|
+
cookbook_version = new(o["cookbook_name"])
|
|
679
|
+
if o.has_key?('_rev')
|
|
680
|
+
cookbook_version.couchdb_rev = o["_rev"] if o.has_key?("_rev")
|
|
681
|
+
o.delete("_rev")
|
|
682
|
+
end
|
|
683
|
+
if o.has_key?("_id")
|
|
684
|
+
cookbook_version.couchdb_id = o["_id"] if o.has_key?("_id")
|
|
685
|
+
cookbook_version.index_id = cookbook_version.couchdb_id
|
|
686
|
+
o.delete("_id")
|
|
687
|
+
end
|
|
688
|
+
# We want the Chef::Cookbook::Metadata object to always be inflated
|
|
689
|
+
cookbook_version.metadata = Chef::Cookbook::Metadata.from_hash(o["metadata"])
|
|
690
|
+
cookbook_version.manifest = o
|
|
691
|
+
|
|
692
|
+
# We don't need the following step when we decide to stop supporting deprecated operators in the metadata (e.g. <<, >>)
|
|
693
|
+
cookbook_version.manifest["metadata"] = JSON.parse(cookbook_version.metadata.to_json)
|
|
694
|
+
|
|
695
|
+
cookbook_version.freeze_version if o["frozen?"]
|
|
696
|
+
cookbook_version
|
|
697
|
+
end
|
|
698
|
+
|
|
699
|
+
def generate_manifest_with_urls(&url_generator)
|
|
700
|
+
rendered_manifest = manifest.dup
|
|
701
|
+
COOKBOOK_SEGMENTS.each do |segment|
|
|
702
|
+
if rendered_manifest.has_key?(segment)
|
|
703
|
+
rendered_manifest[segment].each do |manifest_record|
|
|
704
|
+
url_options = { :cookbook_name => name.to_s, :cookbook_version => version, :checksum => manifest_record["checksum"] }
|
|
705
|
+
manifest_record["url"] = url_generator.call(url_options)
|
|
706
|
+
end
|
|
707
|
+
end
|
|
708
|
+
end
|
|
709
|
+
rendered_manifest
|
|
710
|
+
end
|
|
711
|
+
|
|
712
|
+
def metadata_json_file
|
|
713
|
+
File.join(root_dir, "metadata.json")
|
|
714
|
+
end
|
|
715
|
+
|
|
716
|
+
def metadata_rb_file
|
|
717
|
+
File.join(root_dir, "metadata.rb")
|
|
718
|
+
end
|
|
719
|
+
|
|
720
|
+
def reload_metadata!
|
|
721
|
+
if File.exists?(metadata_json_file)
|
|
722
|
+
metadata.from_json(IO.read(metadata_json_file))
|
|
723
|
+
end
|
|
724
|
+
end
|
|
725
|
+
|
|
726
|
+
##
|
|
727
|
+
# REST API
|
|
728
|
+
##
|
|
729
|
+
def self.chef_server_rest
|
|
730
|
+
Chef::REST.new(Chef::Config[:chef_server_url])
|
|
731
|
+
end
|
|
732
|
+
|
|
733
|
+
def chef_server_rest
|
|
734
|
+
self.class.chef_server_rest
|
|
735
|
+
end
|
|
736
|
+
|
|
737
|
+
# Save this object to the server via the REST api. If there is an existing
|
|
738
|
+
# document on the server and it is marked frozen, a
|
|
739
|
+
# Net::HTTPServerException will be raised for 409 Conflict.
|
|
740
|
+
def save
|
|
741
|
+
chef_server_rest.put_rest("cookbooks/#{name}/#{version}", self)
|
|
742
|
+
self
|
|
743
|
+
end
|
|
744
|
+
alias :create :save
|
|
745
|
+
|
|
746
|
+
# Adds the `force=true` parameter to the upload. This allows the user to
|
|
747
|
+
# overwrite a frozen cookbook (normal #save raises a
|
|
748
|
+
# Net::HTTPServerException for 409 Conflict in this case).
|
|
749
|
+
def force_save
|
|
750
|
+
chef_server_rest.put_rest("cookbooks/#{name}/#{version}?force=true", self)
|
|
751
|
+
self
|
|
752
|
+
end
|
|
753
|
+
|
|
754
|
+
def destroy
|
|
755
|
+
chef_server_rest.delete_rest("cookbooks/#{name}/#{version}")
|
|
756
|
+
self
|
|
757
|
+
end
|
|
758
|
+
|
|
759
|
+
def self.load(name, version="_latest")
|
|
760
|
+
version = "_latest" if version == "latest"
|
|
761
|
+
chef_server_rest.get_rest("cookbooks/#{name}/#{version}")
|
|
762
|
+
end
|
|
763
|
+
|
|
764
|
+
def self.list
|
|
765
|
+
chef_server_rest.get_rest('cookbooks')
|
|
766
|
+
end
|
|
767
|
+
|
|
768
|
+
##
|
|
769
|
+
# Given a +cookbook_name+, get a list of all versions that exist on the
|
|
770
|
+
# server.
|
|
771
|
+
# ===Returns
|
|
772
|
+
# [String]:: Array of cookbook versions, which are strings like 'x.y.z'
|
|
773
|
+
# nil:: if the cookbook doesn't exist. an error will also be logged.
|
|
774
|
+
def self.available_versions(cookbook_name)
|
|
775
|
+
chef_server_rest.get_rest("cookbooks/#{cookbook_name}").values.flatten
|
|
776
|
+
rescue Net::HTTPServerException => e
|
|
777
|
+
if e.to_s =~ /^404/
|
|
778
|
+
Chef::Log.error("Cannot find a cookbook named #{cookbook_name}")
|
|
779
|
+
nil
|
|
780
|
+
else
|
|
781
|
+
raise
|
|
782
|
+
end
|
|
783
|
+
end
|
|
784
|
+
|
|
785
|
+
# Get the newest version of all cookbooks
|
|
786
|
+
def self.latest_cookbooks
|
|
787
|
+
chef_server_rest.get_rest('cookbooks/_latest')
|
|
788
|
+
end
|
|
789
|
+
|
|
790
|
+
##
|
|
791
|
+
# Couchdb
|
|
792
|
+
##
|
|
793
|
+
|
|
794
|
+
def self.cdb_by_name(cookbook_name, couchdb=nil)
|
|
795
|
+
cdb = (couchdb || Chef::CouchDB.new)
|
|
796
|
+
options = { :startkey => cookbook_name, :endkey => cookbook_name }
|
|
797
|
+
rs = cdb.get_view("cookbooks", "all_with_version", options)
|
|
798
|
+
rs["rows"].inject({}) { |memo, row| memo.has_key?(row["key"]) ? memo[row["key"]] << row["value"] : memo[row["key"]] = [ row["value"] ]; memo }
|
|
799
|
+
end
|
|
800
|
+
|
|
801
|
+
def self.create_design_document(couchdb=nil)
|
|
802
|
+
(couchdb || Chef::CouchDB.new).create_design_document("cookbooks", DESIGN_DOCUMENT)
|
|
803
|
+
end
|
|
804
|
+
|
|
805
|
+
def self.cdb_list_latest(inflate=false, couchdb=nil)
|
|
806
|
+
couchdb ||= Chef::CouchDB.new
|
|
807
|
+
if inflate
|
|
808
|
+
doc_ids = cdb_list_latest_ids.map {|i|i["id"]}
|
|
809
|
+
couchdb.bulk_get(doc_ids)
|
|
810
|
+
else
|
|
811
|
+
results = couchdb.get_view("cookbooks", "all_latest_version", :group=>true)["rows"]
|
|
812
|
+
results.inject({}) { |mapped, row| mapped[row["key"]] = row["value"]; mapped}
|
|
813
|
+
end
|
|
814
|
+
end
|
|
815
|
+
|
|
816
|
+
def self.cdb_list_latest_ids(inflate=false, couchdb=nil)
|
|
817
|
+
couchdb ||= Chef::CouchDB.new
|
|
818
|
+
results = couchdb.get_view("cookbooks", "all_latest_version_by_id", :group=>true)["rows"]
|
|
819
|
+
results.map { |name_and_id| name_and_id["value"]}
|
|
820
|
+
end
|
|
821
|
+
|
|
822
|
+
def self.cdb_list(inflate=false, couchdb=nil)
|
|
823
|
+
couchdb ||= Chef::CouchDB.new
|
|
824
|
+
if inflate
|
|
825
|
+
couchdb.list("cookbooks", true)["rows"].collect{|r| r["value"]}
|
|
826
|
+
else
|
|
827
|
+
# If you modify this, please make sure the desc sorted order on the versions doesn't get broken.
|
|
828
|
+
couchdb.get_view("cookbooks", "all_with_version")["rows"].inject({}) { |mapped, row| mapped[row["key"]]||=Array.new; mapped[row["key"]].push(Chef::Version.new(row["value"])); mapped[row["key"]].sort!.reverse!; mapped}
|
|
829
|
+
end
|
|
830
|
+
end
|
|
831
|
+
|
|
832
|
+
def self.cdb_load(name, version='latest', couchdb=nil)
|
|
833
|
+
cdb = couchdb || Chef::CouchDB.new
|
|
834
|
+
if version == "latest" || version == "_latest"
|
|
835
|
+
rs = cdb.get_view("cookbooks", "all_latest_version", :key => name, :descending => true, :group => true, :reduce => true)["rows"].first
|
|
836
|
+
cdb.load("cookbook_version", "#{rs["key"]}-#{rs["value"]}")
|
|
837
|
+
else
|
|
838
|
+
cdb.load("cookbook_version", "#{name}-#{version}")
|
|
839
|
+
end
|
|
840
|
+
end
|
|
841
|
+
|
|
842
|
+
def cdb_destroy
|
|
843
|
+
(couchdb || Chef::CouchDB.new).delete("cookbook_version", full_name, couchdb_rev)
|
|
844
|
+
end
|
|
845
|
+
|
|
846
|
+
# Runs on Chef Server (API); deletes the cookbook from couchdb and also destroys associated
|
|
847
|
+
# checksum documents
|
|
848
|
+
def purge
|
|
849
|
+
checksums.keys.each do |checksum|
|
|
850
|
+
begin
|
|
851
|
+
Chef::Checksum.cdb_load(checksum, couchdb).purge
|
|
852
|
+
rescue Chef::Exceptions::CouchDBNotFound
|
|
853
|
+
end
|
|
854
|
+
end
|
|
855
|
+
cdb_destroy
|
|
856
|
+
end
|
|
857
|
+
|
|
858
|
+
def cdb_save
|
|
859
|
+
@couchdb_rev = couchdb.store("cookbook_version", full_name, self)["rev"]
|
|
860
|
+
end
|
|
861
|
+
|
|
862
|
+
def couchdb_id=(value)
|
|
863
|
+
@couchdb_id = value
|
|
864
|
+
@index_id = value
|
|
865
|
+
end
|
|
866
|
+
|
|
867
|
+
def <=>(o)
|
|
868
|
+
raise Chef::Exceptions::CookbookVersionNameMismatch if self.name != o.name
|
|
869
|
+
# FIXME: can we change the interface to the Metadata class such
|
|
870
|
+
# that metadata.version returns a Chef::Version instance instead
|
|
871
|
+
# of a string?
|
|
872
|
+
Chef::Version.new(self.version) <=> Chef::Version.new(o.version)
|
|
873
|
+
end
|
|
874
|
+
|
|
875
|
+
private
|
|
876
|
+
|
|
877
|
+
# For each filename, produce a mapping of base filename (i.e. recipe name
|
|
878
|
+
# or attribute file) to on disk location
|
|
879
|
+
def filenames_by_name(filenames)
|
|
880
|
+
filenames.select{|filename| filename =~ /\.rb$/}.inject({}){|memo, filename| memo[File.basename(filename, '.rb')] = filename ; memo }
|
|
881
|
+
end
|
|
882
|
+
|
|
883
|
+
# See #manifest for a description of the manifest return value.
|
|
884
|
+
# See #preferred_manifest_record for a description an individual manifest record.
|
|
885
|
+
def generate_manifest
|
|
886
|
+
manifest = Mash.new({
|
|
887
|
+
:recipes => Array.new,
|
|
888
|
+
:definitions => Array.new,
|
|
889
|
+
:libraries => Array.new,
|
|
890
|
+
:attributes => Array.new,
|
|
891
|
+
:files => Array.new,
|
|
892
|
+
:templates => Array.new,
|
|
893
|
+
:resources => Array.new,
|
|
894
|
+
:providers => Array.new,
|
|
895
|
+
:root_files => Array.new
|
|
896
|
+
})
|
|
897
|
+
checksums_to_on_disk_paths = {}
|
|
898
|
+
|
|
899
|
+
COOKBOOK_SEGMENTS.each do |segment|
|
|
900
|
+
segment_filenames(segment).each do |segment_file|
|
|
901
|
+
next if File.directory?(segment_file)
|
|
902
|
+
|
|
903
|
+
file_name = nil
|
|
904
|
+
path = nil
|
|
905
|
+
specificity = "default"
|
|
906
|
+
|
|
907
|
+
if segment == :root_files
|
|
908
|
+
matcher = segment_file.match(".+/#{Regexp.escape(name.to_s)}/(.+)")
|
|
909
|
+
file_name = matcher[1]
|
|
910
|
+
path = file_name
|
|
911
|
+
elsif segment == :templates || segment == :files
|
|
912
|
+
matcher = segment_file.match("/#{Regexp.escape(name.to_s)}/(#{Regexp.escape(segment.to_s)}/(.+?)/(.+))")
|
|
913
|
+
unless matcher
|
|
914
|
+
Chef::Log.debug("Skipping file #{segment_file}, as it doesn't have a proper segment.")
|
|
915
|
+
next
|
|
916
|
+
end
|
|
917
|
+
path = matcher[1]
|
|
918
|
+
specificity = matcher[2]
|
|
919
|
+
file_name = matcher[3]
|
|
920
|
+
else
|
|
921
|
+
matcher = segment_file.match("/#{Regexp.escape(name.to_s)}/(#{Regexp.escape(segment.to_s)}/(.+))")
|
|
922
|
+
path = matcher[1]
|
|
923
|
+
file_name = matcher[2]
|
|
924
|
+
end
|
|
925
|
+
|
|
926
|
+
csum = self.class.checksum_cookbook_file(segment_file)
|
|
927
|
+
checksums_to_on_disk_paths[csum] = segment_file
|
|
928
|
+
rs = Mash.new({
|
|
929
|
+
:name => file_name,
|
|
930
|
+
:path => path,
|
|
931
|
+
:checksum => csum
|
|
932
|
+
})
|
|
933
|
+
rs[:specificity] = specificity
|
|
934
|
+
|
|
935
|
+
manifest[segment] << rs
|
|
936
|
+
end
|
|
937
|
+
end
|
|
938
|
+
|
|
939
|
+
manifest[:cookbook_name] = name.to_s
|
|
940
|
+
manifest[:metadata] = metadata
|
|
941
|
+
manifest[:version] = metadata.version
|
|
942
|
+
manifest[:name] = full_name
|
|
943
|
+
|
|
944
|
+
@checksums = checksums_to_on_disk_paths
|
|
945
|
+
@manifest = manifest
|
|
946
|
+
@manifest_records_by_path = extract_manifest_records_by_path(manifest)
|
|
947
|
+
end
|
|
948
|
+
|
|
949
|
+
def file_vendor
|
|
950
|
+
unless @file_vendor
|
|
951
|
+
@file_vendor = Chef::Cookbook::FileVendor.create_from_manifest(manifest)
|
|
952
|
+
end
|
|
953
|
+
@file_vendor
|
|
954
|
+
end
|
|
955
|
+
|
|
956
|
+
def extract_checksums_from_manifest(manifest)
|
|
957
|
+
checksums = {}
|
|
958
|
+
COOKBOOK_SEGMENTS.each do |segment|
|
|
959
|
+
next unless manifest.has_key?(segment)
|
|
960
|
+
manifest[segment].each do |manifest_record|
|
|
961
|
+
checksums[manifest_record[:checksum]] = nil
|
|
962
|
+
end
|
|
963
|
+
end
|
|
964
|
+
checksums
|
|
965
|
+
end
|
|
966
|
+
|
|
967
|
+
def extract_manifest_records_by_path(manifest)
|
|
968
|
+
manifest_records_by_path = {}
|
|
969
|
+
COOKBOOK_SEGMENTS.each do |segment|
|
|
970
|
+
next unless manifest.has_key?(segment)
|
|
971
|
+
manifest[segment].each do |manifest_record|
|
|
972
|
+
manifest_records_by_path[manifest_record[:path]] = manifest_record
|
|
973
|
+
end
|
|
974
|
+
end
|
|
975
|
+
manifest_records_by_path
|
|
976
|
+
end
|
|
977
|
+
|
|
978
|
+
end
|
|
979
|
+
end
|