summaryrefslogtreecommitdiff
path: root/lib/chef
diff options
context:
space:
mode:
authorsersut <serdar@opscode.com>2013-10-17 15:28:23 -0700
committersersut <serdar@opscode.com>2013-10-17 15:28:23 -0700
commit180e9c1ec6cc324c598b3575a6ba2a209df44a24 (patch)
tree09bfce4f8c4e8f29a7c6c740f7ed86cec11d5737 /lib/chef
parentc995e37339f37be82d7e5b1b7866bef64c1bd05a (diff)
parent05ba3e301794bd09173c5c3f13a62c2530d8b403 (diff)
downloadchef-180e9c1ec6cc324c598b3575a6ba2a209df44a24.tar.gz
Merge branch 'master' into 11-stable
Diffstat (limited to 'lib/chef')
-rw-r--r--lib/chef/api_client.rb25
-rw-r--r--lib/chef/application.rb75
-rw-r--r--lib/chef/application/agent.rb4
-rw-r--r--lib/chef/application/client.rb58
-rw-r--r--lib/chef/application/knife.rb10
-rw-r--r--lib/chef/application/solo.rb36
-rw-r--r--lib/chef/application/windows_service.rb34
-rw-r--r--lib/chef/application/windows_service_manager.rb8
-rw-r--r--lib/chef/checksum/storage.rb4
-rw-r--r--lib/chef/checksum/storage/filesystem.rb4
-rw-r--r--lib/chef/chef_fs/chef_fs_data_store.rb2
-rw-r--r--lib/chef/chef_fs/command_line.rb3
-rw-r--r--lib/chef/chef_fs/config.rb83
-rw-r--r--lib/chef/chef_fs/data_handler/client_data_handler.rb3
-rw-r--r--lib/chef/chef_fs/file_system.rb4
-rw-r--r--lib/chef/chef_fs/file_system/acl_entry.rb2
-rw-r--r--lib/chef/chef_fs/file_system/chef_repository_file_system_acls_dir.rb37
-rw-r--r--lib/chef/chef_fs/file_system/chef_repository_file_system_cookbook_dir.rb24
-rw-r--r--lib/chef/chef_fs/file_system/chef_repository_file_system_cookbook_entry.rb23
-rw-r--r--lib/chef/chef_fs/file_system/chef_repository_file_system_cookbooks_dir.rb39
-rw-r--r--lib/chef/chef_fs/file_system/chef_repository_file_system_entry.rb34
-rw-r--r--lib/chef/chef_fs/file_system/chef_repository_file_system_root_dir.rb17
-rw-r--r--lib/chef/chef_fs/file_system/chef_server_root_dir.rb14
-rw-r--r--lib/chef/chef_fs/file_system/cookbook_dir.rb5
-rw-r--r--lib/chef/chef_fs/file_system/cookbook_file.rb7
-rw-r--r--lib/chef/chef_fs/file_system/cookbooks_dir.rb27
-rw-r--r--lib/chef/chef_fs/file_system/data_bag_dir.rb2
-rw-r--r--lib/chef/chef_fs/file_system/data_bags_dir.rb5
-rw-r--r--lib/chef/chef_fs/file_system/file_system_entry.rb20
-rw-r--r--lib/chef/chef_fs/file_system/multiplexed_dir.rb3
-rw-r--r--lib/chef/chef_fs/file_system/nodes_dir.rb2
-rw-r--r--lib/chef/chef_fs/file_system/operation_failed_error.rb8
-rw-r--r--lib/chef/chef_fs/file_system/rest_list_dir.rb6
-rw-r--r--lib/chef/chef_fs/file_system/rest_list_entry.rb10
-rw-r--r--lib/chef/chef_fs/knife.rb61
-rw-r--r--lib/chef/chef_fs/path_utils.rb5
-rw-r--r--lib/chef/chef_fs/raw_request.rb79
-rw-r--r--lib/chef/client.rb12
-rw-r--r--lib/chef/config.rb393
-rw-r--r--lib/chef/config_fetcher.rb79
-rw-r--r--lib/chef/cookbook/file_vendor.rb10
-rw-r--r--lib/chef/cookbook/metadata.rb4
-rw-r--r--lib/chef/cookbook/syntax_check.rb22
-rw-r--r--lib/chef/cookbook_site_streaming_uploader.rb12
-rw-r--r--lib/chef/cookbook_uploader.rb18
-rw-r--r--lib/chef/cookbook_version.rb32
-rw-r--r--lib/chef/daemon.rb89
-rw-r--r--lib/chef/data_bag.rb5
-rw-r--r--lib/chef/dsl/include_recipe.rb4
-rw-r--r--lib/chef/event_dispatch/base.rb2
-rw-r--r--lib/chef/event_dispatch/dispatcher.rb2
-rw-r--r--lib/chef/file_access_control/windows.rb2
-rw-r--r--lib/chef/formatters/doc.rb10
-rw-r--r--lib/chef/formatters/error_inspectors/api_error_formatting.rb4
-rw-r--r--lib/chef/formatters/error_inspectors/compile_error_inspector.rb4
-rw-r--r--lib/chef/formatters/error_inspectors/cookbook_sync_error_inspector.rb4
-rw-r--r--lib/chef/formatters/error_inspectors/node_load_error_inspector.rb4
-rw-r--r--lib/chef/formatters/error_inspectors/resource_failure_inspector.rb4
-rw-r--r--lib/chef/handler/json_file.rb4
-rw-r--r--lib/chef/http.rb386
-rw-r--r--lib/chef/http/auth_credentials.rb (renamed from lib/chef/rest/auth_credentials.rb)2
-rw-r--r--lib/chef/http/authenticator.rb89
-rw-r--r--lib/chef/http/basic_client.rb114
-rw-r--r--lib/chef/http/cookie_jar.rb (renamed from lib/chef/rest/cookie_jar.rb)2
-rw-r--r--lib/chef/http/cookie_manager.rb56
-rw-r--r--lib/chef/http/decompressor.rb137
-rw-r--r--lib/chef/http/http_request.rb (renamed from lib/chef/rest/rest_request.rb)87
-rw-r--r--lib/chef/http/json_input.rb53
-rw-r--r--lib/chef/http/json_output.rb69
-rw-r--r--lib/chef/http/json_to_model_output.rb34
-rw-r--r--lib/chef/http/simple.rb16
-rw-r--r--lib/chef/http/ssl_policies.rb121
-rw-r--r--lib/chef/knife.rb68
-rw-r--r--lib/chef/knife/bootstrap.rb13
-rw-r--r--lib/chef/knife/bootstrap/chef-full.erb10
-rw-r--r--lib/chef/knife/client_create.rb2
-rw-r--r--lib/chef/knife/configure.rb2
-rw-r--r--lib/chef/knife/cookbook_create.rb14
-rw-r--r--lib/chef/knife/cookbook_download.rb4
-rw-r--r--lib/chef/knife/cookbook_metadata_from_file.rb4
-rw-r--r--lib/chef/knife/cookbook_show.rb6
-rw-r--r--lib/chef/knife/cookbook_site_install.rb4
-rw-r--r--lib/chef/knife/cookbook_site_list.rb4
-rw-r--r--lib/chef/knife/cookbook_site_search.rb6
-rw-r--r--lib/chef/knife/cookbook_site_show.rb10
-rw-r--r--lib/chef/knife/core/bootstrap_context.rb10
-rw-r--r--lib/chef/knife/core/node_presenter.rb2
-rw-r--r--lib/chef/knife/core/subcommand_loader.rb10
-rw-r--r--lib/chef/knife/core/ui.rb2
-rw-r--r--lib/chef/knife/data_bag_create.rb12
-rw-r--r--lib/chef/knife/data_bag_delete.rb6
-rw-r--r--lib/chef/knife/data_bag_edit.rb16
-rw-r--r--lib/chef/knife/data_bag_from_file.rb18
-rw-r--r--lib/chef/knife/data_bag_list.rb4
-rw-r--r--lib/chef/knife/data_bag_show.rb16
-rw-r--r--lib/chef/knife/delete.rb2
-rw-r--r--lib/chef/knife/deps.rb2
-rw-r--r--lib/chef/knife/diff.rb6
-rw-r--r--lib/chef/knife/download.rb6
-rw-r--r--lib/chef/knife/edit.rb2
-rw-r--r--lib/chef/knife/environment_from_file.rb4
-rw-r--r--lib/chef/knife/index_rebuild.rb4
-rw-r--r--lib/chef/knife/list.rb2
-rw-r--r--lib/chef/knife/raw.rb36
-rw-r--r--lib/chef/knife/show.rb2
-rw-r--r--lib/chef/knife/ssh.rb28
-rw-r--r--lib/chef/knife/status.rb2
-rw-r--r--lib/chef/knife/upload.rb2
-rw-r--r--lib/chef/knife/xargs.rb2
-rw-r--r--lib/chef/mixin/checksum.rb4
-rw-r--r--lib/chef/mixin/command.rb43
-rw-r--r--lib/chef/mixin/convert_to_class_name.rb16
-rw-r--r--lib/chef/mixin/create_path.rb18
-rw-r--r--lib/chef/mixin/deep_merge.rb4
-rw-r--r--lib/chef/mixin/from_file.rb12
-rw-r--r--lib/chef/mixin/language_include_recipe.rb4
-rw-r--r--lib/chef/mixin/params_validate.rb42
-rw-r--r--lib/chef/mixin/shell_out.rb9
-rw-r--r--lib/chef/mixin/template.rb29
-rw-r--r--lib/chef/mixin/why_run.rb32
-rw-r--r--lib/chef/mixin/windows_architecture_helper.rb10
-rw-r--r--lib/chef/mixin/xml_escape.rb20
-rw-r--r--lib/chef/monkey_patches/numeric.rb2
-rw-r--r--lib/chef/monkey_patches/regexp.rb8
-rw-r--r--lib/chef/monkey_patches/string.rb6
-rw-r--r--lib/chef/monkey_patches/tempfile.rb4
-rw-r--r--lib/chef/node.rb8
-rw-r--r--lib/chef/node/attribute.rb2
-rw-r--r--lib/chef/platform/provider_mapping.rb27
-rw-r--r--lib/chef/provider/batch.rb6
-rw-r--r--lib/chef/provider/cron.rb40
-rw-r--r--lib/chef/provider/cron/aix.rb48
-rw-r--r--lib/chef/provider/cron/solaris.rb46
-rw-r--r--lib/chef/provider/cron/unix.rb76
-rw-r--r--lib/chef/provider/deploy/timestamped.rb8
-rw-r--r--lib/chef/provider/erl_call.rb2
-rw-r--r--lib/chef/provider/execute.rb4
-rw-r--r--lib/chef/provider/git.rb1
-rw-r--r--lib/chef/provider/group.rb42
-rw-r--r--lib/chef/provider/group/dscl.rb18
-rw-r--r--lib/chef/provider/group/gpasswd.rb10
-rw-r--r--lib/chef/provider/group/groupadd.rb21
-rw-r--r--lib/chef/provider/group/pw.rb22
-rw-r--r--lib/chef/provider/group/suse.rb8
-rw-r--r--lib/chef/provider/group/usermod.rb16
-rw-r--r--lib/chef/provider/group/windows.rb18
-rw-r--r--lib/chef/provider/http_request.rb16
-rw-r--r--lib/chef/provider/ifconfig.rb94
-rw-r--r--lib/chef/provider/ifconfig/aix.rb99
-rw-r--r--lib/chef/provider/log.rb6
-rw-r--r--lib/chef/provider/mdadm.rb9
-rw-r--r--lib/chef/provider/mount.rb24
-rw-r--r--lib/chef/provider/mount/aix.rb179
-rw-r--r--lib/chef/provider/mount/mount.rb44
-rw-r--r--lib/chef/provider/package.rb42
-rw-r--r--lib/chef/provider/package/aix.rb146
-rw-r--r--lib/chef/provider/package/apt.rb47
-rw-r--r--lib/chef/provider/package/dpkg.rb18
-rw-r--r--lib/chef/provider/package/freebsd.rb4
-rw-r--r--lib/chef/provider/package/ips.rb6
-rw-r--r--lib/chef/provider/package/macports.rb2
-rw-r--r--lib/chef/provider/package/pacman.rb16
-rw-r--r--lib/chef/provider/package/rpm.rb28
-rw-r--r--lib/chef/provider/package/rubygems.rb2
-rw-r--r--lib/chef/provider/package/smartos.rb6
-rw-r--r--lib/chef/provider/package/solaris.rb22
-rw-r--r--lib/chef/provider/package/yum-dump.py8
-rw-r--r--lib/chef/provider/package/yum.rb6
-rw-r--r--lib/chef/provider/powershell_script.rb14
-rw-r--r--lib/chef/provider/remote_file/ftp.rb1
-rw-r--r--lib/chef/provider/remote_file/http.rb10
-rw-r--r--lib/chef/provider/remote_file/local_file.rb1
-rw-r--r--lib/chef/provider/resource_update.rb18
-rw-r--r--lib/chef/provider/ruby_block.rb6
-rw-r--r--lib/chef/provider/script.rb2
-rw-r--r--lib/chef/provider/service.rb4
-rw-r--r--lib/chef/provider/service/debian.rb50
-rw-r--r--lib/chef/provider/service/freebsd.rb18
-rw-r--r--lib/chef/provider/service/gentoo.rb8
-rw-r--r--lib/chef/provider/service/init.rb2
-rw-r--r--lib/chef/provider/service/insserv.rb4
-rw-r--r--lib/chef/provider/service/invokercd.rb2
-rw-r--r--lib/chef/provider/service/redhat.rb4
-rw-r--r--lib/chef/provider/service/simple.rb12
-rw-r--r--lib/chef/provider/service/solaris.rb2
-rw-r--r--lib/chef/provider/service/systemd.rb6
-rw-r--r--lib/chef/provider/service/upstart.rb30
-rw-r--r--lib/chef/provider/subversion.rb11
-rw-r--r--lib/chef/provider/user.rb22
-rw-r--r--lib/chef/provider/user/dscl.rb56
-rw-r--r--lib/chef/provider/user/pw.rb22
-rw-r--r--lib/chef/provider/user/useradd.rb2
-rw-r--r--lib/chef/provider/user/windows.rb14
-rw-r--r--lib/chef/provider/windows_script.rb14
-rw-r--r--lib/chef/providers.rb4
-rw-r--r--lib/chef/recipe.rb21
-rw-r--r--lib/chef/resource/apt_package.rb6
-rw-r--r--lib/chef/resource/bash.rb6
-rw-r--r--lib/chef/resource/batch.rb8
-rw-r--r--lib/chef/resource/bff_package.rb36
-rw-r--r--lib/chef/resource/breakpoint.rb6
-rw-r--r--lib/chef/resource/cron.rb10
-rw-r--r--lib/chef/resource/csh.rb6
-rw-r--r--lib/chef/resource/deploy.rb19
-rw-r--r--lib/chef/resource/deploy_revision.rb12
-rw-r--r--lib/chef/resource/directory.rb4
-rw-r--r--lib/chef/resource/dpkg_package.rb8
-rw-r--r--lib/chef/resource/easy_install_package.rb2
-rw-r--r--lib/chef/resource/erl_call.rb2
-rw-r--r--lib/chef/resource/freebsd_package.rb8
-rw-r--r--lib/chef/resource/group.rb21
-rw-r--r--lib/chef/resource/http_request.rb12
-rw-r--r--lib/chef/resource/ifconfig.rb8
-rw-r--r--lib/chef/resource/ips_package.rb4
-rw-r--r--lib/chef/resource/log.rb23
-rw-r--r--lib/chef/resource/macports_package.rb4
-rw-r--r--lib/chef/resource/mount.rb23
-rw-r--r--lib/chef/resource/ohai.rb6
-rw-r--r--lib/chef/resource/pacman_package.rb8
-rw-r--r--lib/chef/resource/perl.rb6
-rw-r--r--lib/chef/resource/portage_package.rb8
-rw-r--r--lib/chef/resource/powershell_script.rb6
-rw-r--r--lib/chef/resource/python.rb6
-rw-r--r--lib/chef/resource/route.rb8
-rw-r--r--lib/chef/resource/rpm_package.rb4
-rw-r--r--lib/chef/resource/ruby.rb6
-rw-r--r--lib/chef/resource/ruby_block.rb6
-rw-r--r--lib/chef/resource/scm.rb12
-rw-r--r--lib/chef/resource/script.rb10
-rw-r--r--lib/chef/resource/service.rb10
-rw-r--r--lib/chef/resource/smartos_package.rb14
-rw-r--r--lib/chef/resource/solaris_package.rb15
-rw-r--r--lib/chef/resource/subversion.rb6
-rw-r--r--lib/chef/resource/timestamped_deploy.rb8
-rw-r--r--lib/chef/resource/user.rb26
-rw-r--r--lib/chef/resource/windows_script.rb12
-rw-r--r--lib/chef/resource/yum_package.rb4
-rw-r--r--lib/chef/resource_collection.rb2
-rw-r--r--lib/chef/resource_collection/stepable_iterator.rb44
-rw-r--r--lib/chef/resource_definition.rb16
-rw-r--r--lib/chef/resource_definition_list.rb4
-rw-r--r--lib/chef/resource_reporter.rb10
-rw-r--r--lib/chef/resources.rb2
-rw-r--r--lib/chef/rest.rb404
-rw-r--r--lib/chef/role.rb30
-rw-r--r--lib/chef/run_context.rb14
-rw-r--r--lib/chef/run_context/cookbook_compiler.rb6
-rw-r--r--lib/chef/run_lock.rb93
-rw-r--r--lib/chef/server_api.rb41
-rw-r--r--lib/chef/shell.rb22
-rw-r--r--lib/chef/shell/shell_session.rb2
-rw-r--r--lib/chef/streaming_cookbook_uploader.rb56
-rw-r--r--lib/chef/tasks/chef_repo.rake34
-rw-r--r--lib/chef/util/backup.rb3
-rw-r--r--lib/chef/util/diff.rb109
-rw-r--r--lib/chef/util/windows.rb4
-rw-r--r--lib/chef/util/windows/net_group.rb4
-rw-r--r--lib/chef/util/windows/net_use.rb4
-rw-r--r--lib/chef/util/windows/net_user.rb6
-rw-r--r--lib/chef/util/windows/volume.rb6
-rw-r--r--lib/chef/version.rb6
-rw-r--r--lib/chef/win32/api/file.rb2
-rw-r--r--lib/chef/win32/api/synchronization.rb89
-rw-r--r--lib/chef/win32/handle.rb2
-rw-r--r--lib/chef/win32/mutex.rb94
-rw-r--r--lib/chef/win32/security/ace.rb2
-rw-r--r--lib/chef/win32/security/sid.rb2
-rw-r--r--lib/chef/win32/version.rb8
268 files changed, 4317 insertions, 2095 deletions
diff --git a/lib/chef/api_client.rb b/lib/chef/api_client.rb
index 32e1eee017..66cbd3f30e 100644
--- a/lib/chef/api_client.rb
+++ b/lib/chef/api_client.rb
@@ -36,6 +36,7 @@ class Chef
@public_key = nil
@private_key = nil
@admin = false
+ @validator = false
end
# Gets or sets the client name.
@@ -74,6 +75,19 @@ class Chef
)
end
+ # Gets or sets whether this client is a validator.
+ #
+ # @params [Boolean] whether or not the client is a validator. If
+ # `nil`, retrieves the already-set value.
+ # @return [Boolean] The current value
+ def validator(arg=nil)
+ set_or_return(
+ :validator,
+ arg,
+ :kind_of => [TrueClass, FalseClass]
+ )
+ end
+
# Gets or sets the private key.
#
# @params [Optional String] The string representation of the private key.
@@ -94,6 +108,7 @@ class Chef
result = {
"name" => @name,
"public_key" => @public_key,
+ "validator" => @validator,
"admin" => @admin,
'json_class' => self.class.name,
"chef_type" => "client"
@@ -115,6 +130,7 @@ class Chef
client.private_key(o["private_key"]) if o.key?("private_key")
client.public_key(o["public_key"])
client.admin(o["admin"])
+ client.validator(o["validator"])
client
end
@@ -160,11 +176,11 @@ class Chef
# Save this client via the REST API, returns a hash including the private key
def save
begin
- http_api.put("clients/#{name}", { :name => self.name, :admin => self.admin})
+ http_api.put("clients/#{name}", { :name => self.name, :admin => self.admin, :validator => self.validator})
rescue Net::HTTPServerException => e
# If that fails, go ahead and try and update it
if e.response.code == "404"
- http_api.post("clients", {:name => self.name, :admin => self.admin })
+ http_api.post("clients", {:name => self.name, :admin => self.admin, :validator => self.validator })
else
raise e
end
@@ -172,7 +188,7 @@ class Chef
end
def reregister
- reregistered_self = http_api.put("clients/#{name}", { :name => name, :admin => admin, :private_key => true })
+ reregistered_self = http_api.put("clients/#{name}", { :name => name, :admin => admin, :validator => validator, :private_key => true })
if reregistered_self.respond_to?(:[])
private_key(reregistered_self["private_key"])
else
@@ -192,7 +208,7 @@ class Chef
end
def inspect
- "Chef::ApiClient name:'#{name}' admin:'#{admin.inspect}' " +
+ "Chef::ApiClient name:'#{name}' admin:'#{admin.inspect}' validator:'#{validator}' " +
"public_key:'#{public_key}' private_key:'#{private_key}'"
end
@@ -202,4 +218,3 @@ class Chef
end
end
-
diff --git a/lib/chef/application.rb b/lib/chef/application.rb
index 6522ba6e64..c1fc3a78a4 100644
--- a/lib/chef/application.rb
+++ b/lib/chef/application.rb
@@ -66,31 +66,26 @@ class Chef::Application
run_application
end
- # Parse the configuration file
+ # Parse configuration (options and config file)
def configure_chef
parse_options
+ load_config_file
+ end
- begin
- case config[:config_file]
- when /^(http|https):\/\//
- Chef::REST.new("", nil, nil).fetch(config[:config_file]) { |f| apply_config(f.path) }
- else
- ::File::open(config[:config_file]) { |f| apply_config(f.path) }
- end
- rescue Errno::ENOENT => error
+ # Parse the config file
+ def load_config_file
+ config_fetcher = Chef::ConfigFetcher.new(config[:config_file], Chef::Config.config_file_jail)
+ if config[:config_file].nil?
+ Chef::Log.warn("No config file found or specified on command line, using command line options.")
+ elsif config_fetcher.config_missing?
Chef::Log.warn("*****************************************")
Chef::Log.warn("Did not find config file: #{config[:config_file]}, using command line options.")
Chef::Log.warn("*****************************************")
-
- Chef::Config.merge!(config)
- rescue SocketError => error
- Chef::Application.fatal!("Error getting config file #{config[:config_file]}", 2)
- rescue Chef::Exceptions::ConfigurationError => error
- Chef::Application.fatal!("Error processing config file #{config[:config_file]} with error #{error.message}", 2)
- rescue Exception => error
- Chef::Application.fatal!("Unknown error processing config file #{config[:config_file]} with error #{error.message}", 2)
+ else
+ config_content = config_fetcher.read_config
+ apply_config(config_content, config[:config_file])
end
-
+ Chef::Config.merge!(config)
end
# Initialize and configure the logger.
@@ -172,23 +167,59 @@ class Chef::Application
raise Chef::Exceptions::Application, "#{self.to_s}: you must override run_application"
end
+ def self.setup_server_connectivity
+ if Chef::Config.chef_zero.enabled
+ destroy_server_connectivity
+
+ require 'chef_zero/server'
+ require 'chef/chef_fs/chef_fs_data_store'
+ require 'chef/chef_fs/config'
+
+ chef_fs = Chef::ChefFS::Config.new.local_fs
+ chef_fs.write_pretty_json = true
+ server_options = {}
+ server_options[:data_store] = Chef::ChefFS::ChefFSDataStore.new(chef_fs)
+ server_options[:log_level] = Chef::Log.level
+ server_options[:port] = Chef::Config.chef_zero.port
+ Chef::Log.info("Starting chef-zero on port #{Chef::Config.chef_zero.port} with repository at #{server_options[:data_store].chef_fs.fs_description}")
+ @chef_zero_server = ChefZero::Server.new(server_options)
+ @chef_zero_server.start_background
+ Chef::Config.chef_server_url = @chef_zero_server.url
+ end
+ end
+
+ def self.destroy_server_connectivity
+ if @chef_zero_server
+ @chef_zero_server.stop
+ @chef_zero_server = nil
+ end
+ end
+
# Initializes Chef::Client instance and runs it
def run_chef_client
+ Chef::Application.setup_server_connectivity
+
@chef_client = Chef::Client.new(
- @chef_client_json,
+ @chef_client_json,
:override_runlist => config[:override_runlist]
)
@chef_client_json = nil
@chef_client.run
@chef_client = nil
+
+ Chef::Application.destroy_server_connectivity
end
private
- def apply_config(config_file_path)
- Chef::Config.from_file(config_file_path)
- Chef::Config.merge!(config)
+ def apply_config(config_content, config_file_path)
+ Chef::Config.from_string(config_content, config_file_path)
+ rescue Exception => error
+ Chef::Log.fatal("Configuration error #{error.class}: #{error.message}")
+ filtered_trace = error.backtrace.grep(/#{Regexp.escape(config_file_path)}/)
+ filtered_trace.each {|line| Chef::Log.fatal(" " + line )}
+ Chef::Application.fatal!("Aborting due to error in '#{config_file_path}'", 2)
end
class << self
diff --git a/lib/chef/application/agent.rb b/lib/chef/application/agent.rb
index 353d45252e..66b0c25cbf 100644
--- a/lib/chef/application/agent.rb
+++ b/lib/chef/application/agent.rb
@@ -6,9 +6,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
diff --git a/lib/chef/application/client.rb b/lib/chef/application/client.rb
index b08a795697..a04b4f1cf6 100644
--- a/lib/chef/application/client.rb
+++ b/lib/chef/application/client.rb
@@ -22,7 +22,7 @@ require 'chef/client'
require 'chef/config'
require 'chef/daemon'
require 'chef/log'
-require 'chef/rest'
+require 'chef/config_fetcher'
require 'chef/handler/error_report'
@@ -34,7 +34,6 @@ class Chef::Application::Client < Chef::Application
option :config_file,
:short => "-c CONFIG",
:long => "--config CONFIG",
- :default => Chef::Config.platform_specific_path("/etc/chef/client.rb"),
:description => "The configuration file to use"
option :formatter,
@@ -197,6 +196,20 @@ class Chef::Application::Client < Chef::Application
:description => "Enable reporting data collection for chef runs",
:boolean => true
+ option :local_mode,
+ :short => "-z",
+ :long => "--local-mode",
+ :description => "Point chef-client at local repository",
+ :boolean => true
+
+ option :chef_zero_port,
+ :long => "--chef-zero-port PORT",
+ :description => "Port to start chef-zero on"
+
+ option :config_file_jail,
+ :long => "--config-file-jail PATH",
+ :description => "Directory under which config files are allowed to be loaded (no client.rb or knife.rb outside this path will be loaded)."
+
if Chef::Platform.windows?
option :fatal_windows_admin_check,
:short => "-A",
@@ -219,6 +232,12 @@ class Chef::Application::Client < Chef::Application
Chef::Config[:chef_server_url] = config[:chef_server_url] if config.has_key? :chef_server_url
+ Chef::Config.local_mode = config[:local_mode] if config.has_key?(:local_mode)
+ if Chef::Config.local_mode && !Chef::Config.has_key?(:cookbook_path) && !Chef::Config.has_key?(:chef_repo_path)
+ Chef::Config.chef_repo_path = Chef::Config.find_chef_repo_path(Dir.pwd)
+ end
+ Chef::Config.chef_zero.port = config[:chef_zero_port] if config[:chef_zero_port]
+
if Chef::Config[:daemonize]
Chef::Config[:interval] ||= 1800
end
@@ -229,31 +248,22 @@ class Chef::Application::Client < Chef::Application
end
if Chef::Config[:json_attribs]
- begin
- json_io = case Chef::Config[:json_attribs]
- when /^(http|https):\/\//
- @rest = Chef::REST.new(Chef::Config[:json_attribs], nil, nil)
- @rest.get_rest(Chef::Config[:json_attribs], true).open
- else
- open(Chef::Config[:json_attribs])
- end
- rescue SocketError => error
- Chef::Application.fatal!("I cannot connect to #{Chef::Config[:json_attribs]}", 2)
- rescue Errno::ENOENT => error
- Chef::Application.fatal!("I cannot find #{Chef::Config[:json_attribs]}", 2)
- rescue Errno::EACCES => error
- Chef::Application.fatal!("Permissions are incorrect on #{Chef::Config[:json_attribs]}. Please chmod a+r #{Chef::Config[:json_attribs]}", 2)
- rescue Exception => error
- Chef::Application.fatal!("Got an unexpected error reading #{Chef::Config[:json_attribs]}: #{error.message}", 2)
- end
+ config_fetcher = Chef::ConfigFetcher.new(Chef::Config[:json_attribs])
+ @chef_client_json = config_fetcher.fetch_json
+ end
+ end
- begin
- @chef_client_json = Chef::JSONCompat.from_json(json_io.read)
- json_io.close unless json_io.closed?
- rescue JSON::ParserError => error
- Chef::Application.fatal!("Could not parse the provided JSON file (#{Chef::Config[:json_attribs]})!: " + error.message, 2)
+ def load_config_file
+ Chef::Config.config_file_jail = config[:config_file_jail] if config[:config_file_jail]
+ if !config.has_key?(:config_file)
+ if config[:local_mode]
+ require 'chef/knife'
+ config[:config_file] = Chef::Knife.locate_config_file
+ else
+ config[:config_file] = Chef::Config.platform_specific_path("/etc/chef/client.rb")
end
end
+ super
end
def configure_logging
diff --git a/lib/chef/application/knife.rb b/lib/chef/application/knife.rb
index 13612a4bf3..3a9cd4e870 100644
--- a/lib/chef/application/knife.rb
+++ b/lib/chef/application/knife.rb
@@ -106,6 +106,16 @@ class Chef::Application::Knife < Chef::Application
:description => "Which format to use for output",
:default => "summary"
+ option :local_mode,
+ :short => "-z",
+ :long => "--local-mode",
+ :description => "Point knife commands at local repository instead of server",
+ :boolean => true
+
+ option :chef_zero_port,
+ :long => "--chef-zero-port PORT",
+ :description => "Port to start chef-zero on"
+
option :version,
:short => "-v",
:long => "--version",
diff --git a/lib/chef/application/solo.rb b/lib/chef/application/solo.rb
index 5e3fe90607..ba563ce3a8 100644
--- a/lib/chef/application/solo.rb
+++ b/lib/chef/application/solo.rb
@@ -23,7 +23,7 @@ require 'chef/config'
require 'chef/daemon'
require 'chef/log'
require 'chef/rest'
-require 'open-uri'
+require 'chef/config_fetcher'
require 'fileutils'
class Chef::Application::Solo < Chef::Application
@@ -31,7 +31,7 @@ class Chef::Application::Solo < Chef::Application
option :config_file,
:short => "-c CONFIG",
:long => "--config CONFIG",
- :default => Chef::Config.platform_specfic_path('/etc/chef/solo.rb'),
+ :default => Chef::Config.platform_specific_path('/etc/chef/solo.rb'),
:description => "The configuration file to use"
option :formatter,
@@ -160,6 +160,11 @@ class Chef::Application::Solo < Chef::Application
:description => 'Enable whyrun mode',
:boolean => true
+ option :environment,
+ :short => '-E ENVIRONMENT',
+ :long => '--environment ENVIRONMENT',
+ :description => 'Set the Chef Environment on the node'
+
attr_reader :chef_solo_json
def initialize
@@ -176,36 +181,13 @@ class Chef::Application::Solo < Chef::Application
end
if Chef::Config[:json_attribs]
- begin
- json_io = case Chef::Config[:json_attribs]
- when /^(http|https):\/\//
- @rest = Chef::REST.new(Chef::Config[:json_attribs], nil, nil)
- @rest.get_rest(Chef::Config[:json_attribs], true).open
- else
- open(Chef::Config[:json_attribs])
- end
- rescue SocketError => error
- Chef::Application.fatal!("I cannot connect to #{Chef::Config[:json_attribs]}", 2)
- rescue Errno::ENOENT => error
- Chef::Application.fatal!("I cannot find #{Chef::Config[:json_attribs]}", 2)
- rescue Errno::EACCES => error
- Chef::Application.fatal!("Permissions are incorrect on #{Chef::Config[:json_attribs]}. Please chmod a+r #{Chef::Config[:json_attribs]}", 2)
- rescue Exception => error
- Chef::Application.fatal!("Got an unexpected error reading #{Chef::Config[:json_attribs]}: #{error.message}", 2)
- end
-
- begin
- @chef_client_json = Chef::JSONCompat.from_json(json_io.read)
- json_io.close unless json_io.closed?
- rescue JSON::ParserError => error
- Chef::Application.fatal!("Could not parse the provided JSON file (#{Chef::Config[:json_attribs]})!: " + error.message, 2)
- end
+ config_fetcher = Chef::ConfigFetcher.new(Chef::Config[:json_attribs])
+ @chef_solo_json = config_fetcher.fetch_json
end
if Chef::Config[:recipe_url]
cookbooks_path = Array(Chef::Config[:cookbook_path]).detect{|e| e =~ /\/cookbooks\/*$/ }
recipes_path = File.expand_path(File.join(cookbooks_path, '..'))
- target_file = File.join(recipes_path, 'recipes.tgz')
Chef::Log.debug "Creating path #{recipes_path} to extract recipes into"
FileUtils.mkdir_p recipes_path
diff --git a/lib/chef/application/windows_service.rb b/lib/chef/application/windows_service.rb
index 85a18c7a17..08403c7aa2 100644
--- a/lib/chef/application/windows_service.rb
+++ b/lib/chef/application/windows_service.rb
@@ -27,11 +27,13 @@ require 'chef/rest'
require 'mixlib/cli'
require 'socket'
require 'win32/daemon'
+require 'chef/mixin/shell_out'
class Chef
class Application
class WindowsService < ::Win32::Daemon
include Mixlib::CLI
+ include Chef::Mixin::ShellOut
option :config_file,
:short => "-c CONFIG",
@@ -160,17 +162,29 @@ class Chef
# Initializes Chef::Client instance and runs it
def run_chef_client
- @chef_client = Chef::Client.new(
- @chef_client_json,
- :override_runlist => config[:override_runlist]
- )
- @chef_client_json = nil
-
- @chef_client.run
- @chef_client = nil
+ # The chef client will be started in a new process. We have used shell_out to start the chef-client.
+ # The log_location and config_file of the parent process is passed to the new chef-client process.
+ # We need to add the --no-fork, as by default it is set to fork=true.
+ begin
+ Chef::Log.info "Starting chef-client in a new process"
+ # Pass config params to the new process
+ config_params = " --no-fork"
+ config_params += " -c #{Chef::Config[:config_file]}" unless Chef::Config[:config_file].nil?
+ config_params += " -L #{Chef::Config[:log_location]}" unless Chef::Config[:log_location] == STDOUT
+ # Starts a new process and waits till the process exits
+ result = shell_out("chef-client #{config_params}")
+ Chef::Log.debug "#{result.stdout}"
+ Chef::Log.debug "#{result.stderr}"
+ rescue Mixlib::ShellOut::ShellCommandFailed => e
+ Chef::Log.warn "Not able to start chef-client in new process (#{e})"
+ rescue => e
+ Chef::Log.error e
+ ensure
+ # Once process exits, we log the current process' pid
+ Chef::Log.info "Child process exited (pid: #{Process.pid})"
+ end
end
-
def apply_config(config_file_path)
Chef::Config.from_file(config_file_path)
Chef::Config.merge!(config)
@@ -241,7 +255,7 @@ class Chef
def configure_chef(startup_parameters)
# Bit of a hack ahead:
# It is possible to specify a service's binary_path_name with arguments, like "foo.exe -x argX".
- # It is also possible to specify startup parameters separately, either via the the Services manager
+ # It is also possible to specify startup parameters separately, either via the Services manager
# or by using the registry (I think).
# In order to accommodate all possible sources of parameterization, we first parse any command line
diff --git a/lib/chef/application/windows_service_manager.rb b/lib/chef/application/windows_service_manager.rb
index 13bd2c5cd6..493f0dfc62 100644
--- a/lib/chef/application/windows_service_manager.rb
+++ b/lib/chef/application/windows_service_manager.rb
@@ -61,6 +61,14 @@ class Chef
:show_options => true,
:exit => 0
+ option :version,
+ :short => "-v",
+ :long => "--version",
+ :description => "Show chef version",
+ :boolean => true,
+ :proc => lambda {|v| puts "Chef: #{::Chef::VERSION}"},
+ :exit => 0
+
def initialize(service_options)
# having to call super in initialize is the most annoying
# anti-pattern :(
diff --git a/lib/chef/checksum/storage.rb b/lib/chef/checksum/storage.rb
index 90aef57081..4a1b3d38df 100644
--- a/lib/chef/checksum/storage.rb
+++ b/lib/chef/checksum/storage.rb
@@ -6,9 +6,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
diff --git a/lib/chef/checksum/storage/filesystem.rb b/lib/chef/checksum/storage/filesystem.rb
index 7500a5ad85..94257f518b 100644
--- a/lib/chef/checksum/storage/filesystem.rb
+++ b/lib/chef/checksum/storage/filesystem.rb
@@ -6,9 +6,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
diff --git a/lib/chef/chef_fs/chef_fs_data_store.rb b/lib/chef/chef_fs/chef_fs_data_store.rb
index c1c5a81e04..1fedc98380 100644
--- a/lib/chef/chef_fs/chef_fs_data_store.rb
+++ b/lib/chef/chef_fs/chef_fs_data_store.rb
@@ -135,7 +135,7 @@ class Chef
if path[0] == 'cookbooks' && path.length >= 3
entry.delete(true)
else
- entry.delete
+ entry.delete(false)
end
end
end
diff --git a/lib/chef/chef_fs/command_line.rb b/lib/chef/chef_fs/command_line.rb
index dd5e62b755..d0183a5a2a 100644
--- a/lib/chef/chef_fs/command_line.rb
+++ b/lib/chef/chef_fs/command_line.rb
@@ -19,6 +19,7 @@
require 'chef/chef_fs/file_system'
require 'chef/chef_fs/file_system/operation_failed_error'
require 'chef/chef_fs/file_system/operation_not_allowed_error'
+require 'chef/util/diff'
class Chef
module ChefFS
@@ -268,7 +269,7 @@ class Chef
old_tempfile.write(old_value)
old_tempfile.close
- result = `diff -u #{old_tempfile.path} #{new_tempfile.path}`
+ result = Chef::Util::Diff.new.udiff(old_tempfile.path, new_tempfile.path)
result = result.gsub(/^--- #{old_tempfile.path}/, "--- #{old_path}")
result = result.gsub(/^\+\+\+ #{new_tempfile.path}/, "+++ #{new_path}")
result
diff --git a/lib/chef/chef_fs/config.rb b/lib/chef/chef_fs/config.rb
index ab4cea89f2..e08b976961 100644
--- a/lib/chef/chef_fs/config.rb
+++ b/lib/chef/chef_fs/config.rb
@@ -25,13 +25,24 @@ class Chef
# Helpers to take Chef::Config and create chef_fs and local_fs from it
#
class Config
- def initialize(chef_config = Chef::Config, cwd = Dir.pwd)
+ def initialize(chef_config = Chef::Config, cwd = Dir.pwd, options = {})
@chef_config = chef_config
@cwd = cwd
- configure_repo_paths
+ @cookbook_version = options[:cookbook_version]
+
+ # Default to getting *everything* from the server.
+ if !@chef_config[:repo_mode]
+ if @chef_config[:chef_server_url] =~ /\/+organizations\/.+/
+ @chef_config[:repo_mode] = 'hosted_everything'
+ else
+ @chef_config[:repo_mode] = 'everything'
+ end
+ end
end
- PATH_VARIABLES = %w(acl_path client_path cookbook_path container_path data_bag_path environment_path group_path node_path role_path user_path)
+ attr_reader :chef_config
+ attr_reader :cwd
+ attr_reader :cookbook_version
def chef_fs
@chef_fs ||= create_chef_fs
@@ -39,7 +50,7 @@ class Chef
def create_chef_fs
require 'chef/chef_fs/file_system/chef_server_root_dir'
- Chef::ChefFS::FileSystem::ChefServerRootDir.new("remote", @chef_config)
+ Chef::ChefFS::FileSystem::ChefServerRootDir.new("remote", @chef_config, :cookbook_version => @cookbook_version)
end
def local_fs
@@ -73,16 +84,14 @@ class Chef
# If the path does not reach into ANY specified directory, nil is returned.
def server_path(file_path)
pwd = File.expand_path(Dir.pwd)
- absolute_path = Chef::ChefFS::PathUtils.realest_path(File.expand_path(file_path, pwd))
+ absolute_pwd = Chef::ChefFS::PathUtils.realest_path(File.expand_path(file_path, pwd))
# Check all object paths (cookbooks_dir, data_bags_dir, etc.)
object_paths.each_pair do |name, paths|
paths.each do |path|
realest_path = Chef::ChefFS::PathUtils.realest_path(path)
- if absolute_path[0,realest_path.length] == realest_path &&
- (absolute_path.length == realest_path.length ||
- absolute_path[realest_path.length,1] =~ /#{PathUtils.regexp_path_separator}/)
- relative_path = Chef::ChefFS::PathUtils::relative_to(absolute_path, realest_path)
+ if PathUtils.descendant_of?(absolute_pwd, realest_path)
+ relative_path = Chef::ChefFS::PathUtils::relative_to(absolute_pwd, realest_path)
return relative_path == '.' ? "/#{name}" : "/#{name}/#{relative_path}"
end
end
@@ -91,7 +100,7 @@ class Chef
# Check chef_repo_path
Array(@chef_config[:chef_repo_path]).flatten.each do |chef_repo_path|
realest_chef_repo_path = Chef::ChefFS::PathUtils.realest_path(chef_repo_path)
- if absolute_path == realest_chef_repo_path
+ if absolute_pwd == realest_chef_repo_path
return '/'
end
end
@@ -125,19 +134,10 @@ class Chef
server_path
end
- def require_chef_repo_path
- if !@chef_config[:chef_repo_path]
- Chef::Log.error("Must specify either chef_repo_path or cookbook_path in Chef config file")
- exit(1)
- end
- end
-
private
def object_paths
@object_paths ||= begin
- require_chef_repo_path
-
result = {}
case @chef_config[:repo_mode]
when 'static'
@@ -155,51 +155,6 @@ class Chef
result
end
end
-
- def configure_repo_paths
- # Smooth out some (for now) inappropriate defaults set by Chef
- if @chef_config[:cookbook_path] == [ @chef_config.platform_specific_path("/var/chef/cookbooks"),
- @chef_config.platform_specific_path("/var/chef/site-cookbooks") ]
- @chef_config[:cookbook_path] = nil
- end
- if @chef_config[:data_bag_path] == @chef_config.platform_specific_path('/var/chef/data_bags')
- @chef_config[:data_bag_path] = nil
- end
- if @chef_config[:node_path] == '/var/chef/node'
- @chef_config[:node_path] = nil
- end
- if @chef_config[:role_path] == @chef_config.platform_specific_path('/var/chef/roles')
- @chef_config[:role_path] = nil
- end
-
- # Infer chef_repo_path from cookbook_path if not speciifed
- if !@chef_config[:chef_repo_path]
- if @chef_config[:cookbook_path]
- @chef_config[:chef_repo_path] = Array(@chef_config[:cookbook_path]).flatten.map { |path| File.expand_path('..', path) }
- end
- end
-
- # Default to getting *everything* from the server.
- if !@chef_config[:repo_mode]
- if @chef_config[:chef_server_url] =~ /\/+organizations\/.+/
- @chef_config[:repo_mode] = 'hosted_everything'
- else
- @chef_config[:repo_mode] = 'everything'
- end
- end
-
- # Infer any *_path variables that are not specified
- if @chef_config[:chef_repo_path]
- PATH_VARIABLES.each do |variable_name|
- chef_repo_paths = Array(@chef_config[:chef_repo_path]).flatten
- variable = variable_name.to_sym
- if !@chef_config[variable]
- # cookbook_path -> cookbooks
- @chef_config[variable] = chef_repo_paths.map { |path| File.join(path, "#{variable_name[0..-6]}s") }
- end
- end
- end
- end
end
end
end
diff --git a/lib/chef/chef_fs/data_handler/client_data_handler.rb b/lib/chef/chef_fs/data_handler/client_data_handler.rb
index 2db3fa897f..4b6b8f5c79 100644
--- a/lib/chef/chef_fs/data_handler/client_data_handler.rb
+++ b/lib/chef/chef_fs/data_handler/client_data_handler.rb
@@ -9,12 +9,11 @@ class Chef
defaults = {
'name' => remove_dot_json(entry.name),
'clientname' => remove_dot_json(entry.name),
- 'orgname' => entry.org,
'admin' => false,
'validator' => false,
'chef_type' => 'client'
}
- if entry.org
+ if entry.respond_to?(:org) && entry.org
defaults['orgname'] = entry.org
end
result = normalize_hash(client, defaults)
diff --git a/lib/chef/chef_fs/file_system.rb b/lib/chef/chef_fs/file_system.rb
index a6e14e548c..f2478c4680 100644
--- a/lib/chef/chef_fs/file_system.rb
+++ b/lib/chef/chef_fs/file_system.rb
@@ -289,7 +289,7 @@ class Chef
ui.output "Deleted extra entry #{dest_path} (purge is on)" if ui
end
else
- Chef::Log.info("Not deleting extra entry #{dest_path} (purge is off)") if ui
+ ui.output ("Not deleting extra entry #{dest_path} (purge is off)") if ui
end
end
@@ -407,7 +407,7 @@ class Chef
parent = entry.parent
if parent && !parent.exists?
parent_path = format_path.call(parent) if ui
- parent_parent = get_or_create_parent(entry.parent, options, ui, format_path)
+ parent_parent = get_or_create_parent(parent, options, ui, format_path)
if options[:dry_run]
ui.output "Would create #{parent_path}" if ui
else
diff --git a/lib/chef/chef_fs/file_system/acl_entry.rb b/lib/chef/chef_fs/file_system/acl_entry.rb
index 0be9076038..8edc02d5c5 100644
--- a/lib/chef/chef_fs/file_system/acl_entry.rb
+++ b/lib/chef/chef_fs/file_system/acl_entry.rb
@@ -40,7 +40,7 @@ class Chef
acls = data_handler.normalize(JSON.parse(file_contents, :create_additions => false), self)
PERMISSIONS.each do |permission|
begin
- rest.put_rest("#{api_path}/#{permission}", { permission => acls[permission] })
+ rest.put("#{api_path}/#{permission}", { permission => acls[permission] })
rescue Timeout::Error => e
raise Chef::ChefFS::FileSystem::OperationFailedError.new(:write, self, e), "Timeout writing: #{e}"
rescue Net::HTTPServerException => e
diff --git a/lib/chef/chef_fs/file_system/chef_repository_file_system_acls_dir.rb b/lib/chef/chef_fs/file_system/chef_repository_file_system_acls_dir.rb
new file mode 100644
index 0000000000..7d2a930633
--- /dev/null
+++ b/lib/chef/chef_fs/file_system/chef_repository_file_system_acls_dir.rb
@@ -0,0 +1,37 @@
+#
+# Author:: John Keiser (<jkeiser@opscode.com>)
+# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require 'chef/chef_fs/file_system/chef_repository_file_system_entry'
+require 'chef/chef_fs/file_system/acls_dir'
+require 'chef/chef_fs/data_handler/acl_data_handler'
+
+class Chef
+ module ChefFS
+ module FileSystem
+ class ChefRepositoryFileSystemAclsDir < ChefRepositoryFileSystemEntry
+ def initialize(name, parent, path = nil)
+ super(name, parent, path, Chef::ChefFS::DataHandler::AclDataHandler.new)
+ end
+
+ def can_have_child?(name, is_dir)
+ is_dir ? Chef::ChefFS::FileSystem::AclsDir::ENTITY_TYPES.include?(name) : name == 'organization.json'
+ end
+ end
+ end
+ end
+end \ No newline at end of file
diff --git a/lib/chef/chef_fs/file_system/chef_repository_file_system_cookbook_dir.rb b/lib/chef/chef_fs/file_system/chef_repository_file_system_cookbook_dir.rb
index e3d8e47cf2..5203637012 100644
--- a/lib/chef/chef_fs/file_system/chef_repository_file_system_cookbook_dir.rb
+++ b/lib/chef/chef_fs/file_system/chef_repository_file_system_cookbook_dir.rb
@@ -18,6 +18,7 @@
require 'chef/chef_fs/file_system/chef_repository_file_system_cookbook_entry'
require 'chef/chef_fs/file_system/cookbook_dir'
+require 'chef/chef_fs/file_system/not_found_error'
require 'chef/cookbook/chefignore'
require 'chef/cookbook/cookbook_version_loader'
@@ -51,13 +52,14 @@ class Chef
end
def children
- Dir.entries(file_path).sort.
- select { |child_name| can_have_child?(child_name, File.directory?(File.join(file_path, child_name))) }.
- map do |child_name|
- segment_info = CookbookDir::COOKBOOK_SEGMENT_INFO[child_name.to_sym] || {}
- ChefRepositoryFileSystemCookbookEntry.new(child_name, self, nil, segment_info[:ruby_only], segment_info[:recursive])
- end.
- select { |entry| !(entry.dir? && entry.children.size == 0) }
+ begin
+ Dir.entries(file_path).sort.
+ select { |child_name| can_have_child?(child_name, File.directory?(File.join(file_path, child_name))) }.
+ map { |child_name| make_child(child_name) }.
+ select { |entry| !(entry.dir? && entry.children.size == 0) }
+ rescue Errno::ENOENT
+ raise Chef::ChefFS::FileSystem::NotFoundError.new(self, $!)
+ end
end
def can_have_child?(name, is_dir)
@@ -65,7 +67,6 @@ class Chef
# Only the given directories will be uploaded.
return CookbookDir::COOKBOOK_SEGMENT_INFO.keys.include?(name.to_sym) && name != 'root_files'
end
-
super(name, is_dir)
end
@@ -79,6 +80,13 @@ class Chef
def canonical_cookbook_name(entry_name)
self.class.canonical_cookbook_name(entry_name)
end
+
+ protected
+
+ def make_child(child_name)
+ segment_info = CookbookDir::COOKBOOK_SEGMENT_INFO[child_name.to_sym] || {}
+ ChefRepositoryFileSystemCookbookEntry.new(child_name, self, nil, segment_info[:ruby_only], segment_info[:recursive])
+ end
end
end
end
diff --git a/lib/chef/chef_fs/file_system/chef_repository_file_system_cookbook_entry.rb b/lib/chef/chef_fs/file_system/chef_repository_file_system_cookbook_entry.rb
index d2fe3ed5f6..6541b07065 100644
--- a/lib/chef/chef_fs/file_system/chef_repository_file_system_cookbook_entry.rb
+++ b/lib/chef/chef_fs/file_system/chef_repository_file_system_cookbook_entry.rb
@@ -18,6 +18,7 @@
require 'chef/chef_fs/file_system/chef_repository_file_system_entry'
require 'chef/chef_fs/file_system/chef_repository_file_system_cookbooks_dir'
+require 'chef/chef_fs/file_system/not_found_error'
class Chef
module ChefFS
@@ -33,10 +34,14 @@ class Chef
attr_reader :recursive
def children
- Dir.entries(file_path).sort.
- select { |child_name| can_have_child?(child_name, File.directory?(File.join(file_path, child_name))) }.
- map { |child_name| ChefRepositoryFileSystemCookbookEntry.new(child_name, self, nil, ruby_only, recursive) }.
- select { |entry| !(entry.dir? && entry.children.size == 0) }
+ begin
+ Dir.entries(file_path).sort.
+ select { |child_name| can_have_child?(child_name, File.directory?(File.join(file_path, child_name))) }.
+ map { |child_name| make_child(child_name) }.
+ select { |entry| !(entry.dir? && entry.children.size == 0) }
+ rescue Errno::ENOENT
+ raise Chef::ChefFS::FileSystem::NotFoundError.new(self, $!)
+ end
end
def can_have_child?(name, is_dir)
@@ -65,6 +70,16 @@ class Chef
true
end
+
+ def write_pretty_json
+ false
+ end
+
+ protected
+
+ def make_child(child_name)
+ ChefRepositoryFileSystemCookbookEntry.new(child_name, self, nil, ruby_only, recursive)
+ end
end
end
end
diff --git a/lib/chef/chef_fs/file_system/chef_repository_file_system_cookbooks_dir.rb b/lib/chef/chef_fs/file_system/chef_repository_file_system_cookbooks_dir.rb
index ba4ea0bd1f..6e16f18f24 100644
--- a/lib/chef/chef_fs/file_system/chef_repository_file_system_cookbooks_dir.rb
+++ b/lib/chef/chef_fs/file_system/chef_repository_file_system_cookbooks_dir.rb
@@ -26,29 +26,44 @@ class Chef
class ChefRepositoryFileSystemCookbooksDir < ChefRepositoryFileSystemEntry
def initialize(name, parent, file_path)
super(name, parent, file_path)
- @chefignore = Chef::Cookbook::Chefignore.new(self.file_path)
+ begin
+ @chefignore = Chef::Cookbook::Chefignore.new(self.file_path)
+ rescue Errno::EISDIR
+ rescue Errno::EACCES
+ # Work around a bug in Chefignore when chefignore is a directory
+ end
end
attr_reader :chefignore
def children
- Dir.entries(file_path).sort.
- select { |child_name| can_have_child?(child_name, File.directory?(File.join(file_path, child_name))) }.
- map { |child_name| ChefRepositoryFileSystemCookbookDir.new(child_name, self) }.
- select do |entry|
- # empty cookbooks and cookbook directories are ignored
- if entry.children.size == 0
- Chef::Log.warn("Cookbook '#{entry.name}' is empty or entirely chefignored at #{entry.path_for_printing}")
- false
- else
- true
+ begin
+ Dir.entries(file_path).sort.
+ select { |child_name| can_have_child?(child_name, File.directory?(File.join(file_path, child_name))) }.
+ map { |child_name| make_child(child_name) }.
+ select do |entry|
+ # empty cookbooks and cookbook directories are ignored
+ if entry.children.size == 0
+ Chef::Log.warn("Cookbook '#{entry.name}' is empty or entirely chefignored at #{entry.path_for_printing}")
+ false
+ else
+ true
+ end
end
- end
+ rescue Errno::ENOENT
+ raise Chef::ChefFS::FileSystem::NotFoundError.new(self, $!)
+ end
end
def can_have_child?(name, is_dir)
is_dir && !name.start_with?('.')
end
+
+ protected
+
+ def make_child(child_name)
+ ChefRepositoryFileSystemCookbookDir.new(child_name, self)
+ end
end
end
end
diff --git a/lib/chef/chef_fs/file_system/chef_repository_file_system_entry.rb b/lib/chef/chef_fs/file_system/chef_repository_file_system_entry.rb
index fa4fda4eb6..3d3f58201e 100644
--- a/lib/chef/chef_fs/file_system/chef_repository_file_system_entry.rb
+++ b/lib/chef/chef_fs/file_system/chef_repository_file_system_entry.rb
@@ -18,6 +18,7 @@
#
require 'chef/chef_fs/file_system/file_system_entry'
+require 'chef/chef_fs/file_system/not_found_error'
class Chef
module ChefFS
@@ -30,6 +31,10 @@ class Chef
@data_handler = data_handler
end
+ def write_pretty_json
+ root.write_pretty_json
+ end
+
def data_handler
@data_handler || parent.data_handler
end
@@ -47,13 +52,36 @@ class Chef
!is_dir && name[-5..-1] == '.json'
end
+ def write(file_contents)
+ if file_contents && write_pretty_json && name[-5..-1] == '.json'
+ file_contents = minimize(file_contents, self)
+ end
+ super(file_contents)
+ end
+
+ def minimize(file_contents, entry)
+ object = JSONCompat.from_json(file_contents, :create_additions => false)
+ object = data_handler.normalize(object, entry)
+ object = data_handler.minimize(object, entry)
+ JSONCompat.to_json_pretty(object)
+ end
+
def children
# Except cookbooks and data bag dirs, all things must be json files
- Dir.entries(file_path).sort.
- select { |child_name| can_have_child?(child_name, File.directory?(File.join(file_path, child_name))) }.
- map { |child_name| ChefRepositoryFileSystemEntry.new(child_name, self) }
+ begin
+ Dir.entries(file_path).sort.
+ select { |child_name| can_have_child?(child_name, File.directory?(File.join(file_path, child_name))) }.
+ map { |child_name| make_child(child_name) }
+ rescue Errno::ENOENT
+ raise Chef::ChefFS::FileSystem::NotFoundError.new(self, $!)
+ end
end
+ protected
+
+ def make_child(child_name)
+ ChefRepositoryFileSystemEntry.new(child_name, self)
+ end
end
end
end
diff --git a/lib/chef/chef_fs/file_system/chef_repository_file_system_root_dir.rb b/lib/chef/chef_fs/file_system/chef_repository_file_system_root_dir.rb
index 3523d85a4e..d615e0f415 100644
--- a/lib/chef/chef_fs/file_system/chef_repository_file_system_root_dir.rb
+++ b/lib/chef/chef_fs/file_system/chef_repository_file_system_root_dir.rb
@@ -18,6 +18,7 @@
require 'chef/chef_fs/file_system/base_fs_dir'
require 'chef/chef_fs/file_system/chef_repository_file_system_entry'
+require 'chef/chef_fs/file_system/chef_repository_file_system_acls_dir'
require 'chef/chef_fs/file_system/chef_repository_file_system_cookbooks_dir'
require 'chef/chef_fs/file_system/chef_repository_file_system_data_bags_dir'
require 'chef/chef_fs/file_system/multiplexed_dir'
@@ -28,7 +29,6 @@ require 'chef/chef_fs/data_handler/role_data_handler'
require 'chef/chef_fs/data_handler/user_data_handler'
require 'chef/chef_fs/data_handler/group_data_handler'
require 'chef/chef_fs/data_handler/container_data_handler'
-require 'chef/chef_fs/data_handler/acl_data_handler'
class Chef
module ChefFS
@@ -39,6 +39,8 @@ class Chef
@child_paths = child_paths
end
+ attr_accessor :write_pretty_json
+
attr_reader :child_paths
def children
@@ -51,9 +53,14 @@ class Chef
def create_child(name, file_contents = nil)
child_paths[name].each do |path|
- Dir.mkdir(path)
+ begin
+ Dir.mkdir(path)
+ rescue Errno::EEXIST
+ end
end
- make_child_entry(name)
+ child = make_child_entry(name)
+ @children = nil
+ child
end
def json_class
@@ -90,6 +97,8 @@ class Chef
dirs = paths.map { |path| ChefRepositoryFileSystemCookbooksDir.new(name, self, path) }
elsif name == 'data_bags'
dirs = paths.map { |path| ChefRepositoryFileSystemDataBagsDir.new(name, self, path) }
+ elsif name == 'acls'
+ dirs = paths.map { |path| ChefRepositoryFileSystemAclsDir.new(name, self, path) }
else
data_handler = case name
when 'clients'
@@ -106,8 +115,6 @@ class Chef
Chef::ChefFS::DataHandler::GroupDataHandler.new
when 'containers'
Chef::ChefFS::DataHandler::ContainerDataHandler.new
- when 'acls'
- Chef::ChefFS::DataHandler::AclDataHandler.new
else
raise "Unknown top level path #{name}"
end
diff --git a/lib/chef/chef_fs/file_system/chef_server_root_dir.rb b/lib/chef/chef_fs/file_system/chef_server_root_dir.rb
index 5eb72657c5..0083ee4cfa 100644
--- a/lib/chef/chef_fs/file_system/chef_server_root_dir.rb
+++ b/lib/chef/chef_fs/file_system/chef_server_root_dir.rb
@@ -16,6 +16,7 @@
# limitations under the License.
#
+require 'chef/server_api'
require 'chef/chef_fs/file_system/acls_dir'
require 'chef/chef_fs/file_system/base_fs_dir'
require 'chef/chef_fs/file_system/rest_list_dir'
@@ -23,7 +24,6 @@ require 'chef/chef_fs/file_system/cookbooks_dir'
require 'chef/chef_fs/file_system/data_bags_dir'
require 'chef/chef_fs/file_system/nodes_dir'
require 'chef/chef_fs/file_system/environments_dir'
-require 'chef/rest'
require 'chef/chef_fs/data_handler/client_data_handler'
require 'chef/chef_fs/data_handler/role_data_handler'
require 'chef/chef_fs/data_handler/user_data_handler'
@@ -34,7 +34,7 @@ class Chef
module ChefFS
module FileSystem
class ChefServerRootDir < BaseFSDir
- def initialize(root_name, chef_config)
+ def initialize(root_name, chef_config, options = {})
super("", nil)
@chef_server_url = chef_config[:chef_server_url]
@chef_username = chef_config[:node_name]
@@ -42,6 +42,7 @@ class Chef
@environment = chef_config[:environment]
@repo_mode = chef_config[:repo_mode]
@root_name = root_name
+ @cookbook_version = options[:cookbook_version] # Used in knife diff and download for server cookbook version
end
attr_reader :chef_server_url
@@ -49,12 +50,21 @@ class Chef
attr_reader :chef_private_key
attr_reader :environment
attr_reader :repo_mode
+ attr_reader :cookbook_version
def fs_description
"Chef server at #{chef_server_url} (user #{chef_username}), repo_mode = #{repo_mode}"
end
def rest
+ Chef::ServerAPI.new(chef_server_url, :client_name => chef_username, :signing_key_filename => chef_private_key, :raw_output => true)
+ end
+
+ def get_json(path)
+ Chef::ServerAPI.new(chef_server_url, :client_name => chef_username, :signing_key_filename => chef_private_key).get(path)
+ end
+
+ def chef_rest
Chef::REST.new(chef_server_url, chef_username, chef_private_key)
end
diff --git a/lib/chef/chef_fs/file_system/cookbook_dir.rb b/lib/chef/chef_fs/file_system/cookbook_dir.rb
index cae29a1690..d7411e1c74 100644
--- a/lib/chef/chef_fs/file_system/cookbook_dir.rb
+++ b/lib/chef/chef_fs/file_system/cookbook_dir.rb
@@ -41,6 +41,7 @@ class Chef
end
else
@cookbook_name = name
+ @version = root.cookbook_version # nil unless --cookbook-version specified in download/diff
end
end
@@ -125,7 +126,7 @@ class Chef
def delete(recurse)
if recurse
begin
- rest.delete_rest(api_path)
+ rest.delete(api_path)
rescue Timeout::Error => e
raise Chef::ChefFS::FileSystem::OperationFailedError.new(:delete, self, e), "Timeout deleting: #{e}"
rescue Net::HTTPServerException
@@ -190,7 +191,7 @@ class Chef
old_retry_count = Chef::Config[:http_retry_count]
begin
Chef::Config[:http_retry_count] = 0
- @chef_object ||= Chef::CookbookVersion.json_create(Chef::ChefFS::RawRequest.raw_json(rest, api_path))
+ @chef_object ||= Chef::CookbookVersion.json_create(root.get_json(api_path))
ensure
Chef::Config[:http_retry_count] = old_retry_count
end
diff --git a/lib/chef/chef_fs/file_system/cookbook_file.rb b/lib/chef/chef_fs/file_system/cookbook_file.rb
index e05c4aa614..7868322590 100644
--- a/lib/chef/chef_fs/file_system/cookbook_file.rb
+++ b/lib/chef/chef_fs/file_system/cookbook_file.rb
@@ -17,6 +17,7 @@
#
require 'chef/chef_fs/file_system/base_fs_object'
+require 'chef/http/simple'
require 'digest/md5'
class Chef
@@ -35,16 +36,12 @@ class Chef
end
def read
- old_sign_on_redirect = rest.sign_on_redirect
- rest.sign_on_redirect = false
begin
- tmpfile = rest.get_rest(file[:url], true)
+ tmpfile = rest.streaming_request(file[:url])
rescue Timeout::Error => e
raise Chef::ChefFS::FileSystem::OperationFailedError.new(:read, self, e), "Timeout reading #{file[:url]}: #{e}"
rescue Net::HTTPServerException => e
raise Chef::ChefFS::FileSystem::OperationFailedError.new(:read, self, e), "#{e.message} retrieving #{file[:url]}"
- ensure
- rest.sign_on_redirect = old_sign_on_redirect
end
begin
diff --git a/lib/chef/chef_fs/file_system/cookbooks_dir.rb b/lib/chef/chef_fs/file_system/cookbooks_dir.rb
index c6af933290..a58bfdd1f2 100644
--- a/lib/chef/chef_fs/file_system/cookbooks_dir.rb
+++ b/lib/chef/chef_fs/file_system/cookbooks_dir.rb
@@ -18,10 +18,10 @@
require 'chef/chef_fs/file_system/rest_list_dir'
require 'chef/chef_fs/file_system/cookbook_dir'
-require 'chef/chef_fs/raw_request'
require 'chef/chef_fs/file_system/operation_failed_error'
require 'chef/chef_fs/file_system/cookbook_frozen_error'
require 'chef/chef_fs/file_system/chef_repository_file_system_cookbook_dir'
+require 'chef/mixin/file_class'
require 'tmpdir'
@@ -29,6 +29,9 @@ class Chef
module ChefFS
module FileSystem
class CookbooksDir < RestListDir
+
+ include Chef::Mixin::FileClass
+
def initialize(parent)
super("cookbooks", parent)
end
@@ -50,19 +53,20 @@ class Chef
@children ||= begin
if Chef::Config[:versioned_cookbooks]
result = []
- Chef::ChefFS::RawRequest.raw_json(rest, "#{api_path}/?num_versions=all").each_pair do |cookbook_name, cookbooks|
+ root.get_json("#{api_path}/?num_versions=all").each_pair do |cookbook_name, cookbooks|
cookbooks['versions'].each do |cookbook_version|
result << CookbookDir.new("#{cookbook_name}-#{cookbook_version['version']}", self, :exists => true)
end
end
else
- result = Chef::ChefFS::RawRequest.raw_json(rest, api_path).keys.map { |cookbook_name| CookbookDir.new(cookbook_name, self, :exists => true) }
+ result = root.get_json(api_path).keys.map { |cookbook_name| CookbookDir.new(cookbook_name, self, :exists => true) }
end
result.sort_by(&:name)
end
end
def create_child_from(other, options = {})
+ @children = nil
upload_cookbook_from(other, options)
end
@@ -92,7 +96,7 @@ class Chef
proxy_cookbook_path = "#{temp_cookbooks_path}/#{cookbook_name}"
# Make a symlink
- File.symlink other.file_path, proxy_cookbook_path
+ file_class.symlink other.file_path, proxy_cookbook_path
# Instantiate a proxy loader using the temporary symlink
proxy_loader = Chef::Cookbook::CookbookVersionLoader.new(proxy_cookbook_path, other.parent.chefignore)
@@ -102,18 +106,29 @@ class Chef
cookbook_to_upload.freeze_version if options[:freeze]
# Instantiate a new uploader based on the proxy loader
- uploader = Chef::CookbookUploader.new(cookbook_to_upload, proxy_cookbook_path, :force => options[:force], :rest => rest)
+ uploader = Chef::CookbookUploader.new(cookbook_to_upload, proxy_cookbook_path, :force => options[:force], :rest => root.chef_rest)
with_actual_cookbooks_dir(temp_cookbooks_path) do
upload_cookbook!(uploader)
end
+
+ #
+ # When the temporary directory is being deleted on
+ # windows, the contents of the symlink under that
+ # directory is also deleted. So explicitly remove
+ # the symlink without removing the original contents if we
+ # are running on windows
+ #
+ if Chef::Platform.windows?
+ Dir.rmdir proxy_cookbook_path
+ end
end
end
def upload_unversioned_cookbook(other, options)
cookbook_to_upload = other.chef_object
cookbook_to_upload.freeze_version if options[:freeze]
- uploader = Chef::CookbookUploader.new(cookbook_to_upload, other.parent.file_path, :force => options[:force], :rest => rest)
+ uploader = Chef::CookbookUploader.new(cookbook_to_upload, other.parent.file_path, :force => options[:force], :rest => root.chef_rest)
with_actual_cookbooks_dir(other.parent.file_path) do
upload_cookbook!(uploader)
diff --git a/lib/chef/chef_fs/file_system/data_bag_dir.rb b/lib/chef/chef_fs/file_system/data_bag_dir.rb
index 3814b94fac..212f76fdb9 100644
--- a/lib/chef/chef_fs/file_system/data_bag_dir.rb
+++ b/lib/chef/chef_fs/file_system/data_bag_dir.rb
@@ -52,7 +52,7 @@ class Chef
raise MustDeleteRecursivelyError.new(self), "#{path_for_printing} must be deleted recursively"
end
begin
- rest.delete_rest(api_path)
+ rest.delete(api_path)
rescue Timeout::Error => e
raise Chef::ChefFS::FileSystem::OperationFailedError.new(:delete, self, e), "Timeout deleting: #{e}"
rescue Net::HTTPServerException => e
diff --git a/lib/chef/chef_fs/file_system/data_bags_dir.rb b/lib/chef/chef_fs/file_system/data_bags_dir.rb
index 46c3c21cf6..6d0685d3b7 100644
--- a/lib/chef/chef_fs/file_system/data_bags_dir.rb
+++ b/lib/chef/chef_fs/file_system/data_bags_dir.rb
@@ -34,7 +34,7 @@ class Chef
def children
begin
- @children ||= Chef::ChefFS::RawRequest.raw_json(rest, api_path).keys.sort.map do |entry|
+ @children ||= root.get_json(api_path).keys.sort.map do |entry|
DataBagDir.new(entry, self, true)
end
rescue Timeout::Error => e
@@ -54,7 +54,7 @@ class Chef
def create_child(name, file_contents)
begin
- rest.post_rest(api_path, { 'name' => name })
+ rest.post(api_path, { 'name' => name })
rescue Timeout::Error => e
raise Chef::ChefFS::FileSystem::OperationFailedError.new(:create_child, self, e), "Timeout creating child '#{name}': #{e}"
rescue Net::HTTPServerException => e
@@ -64,6 +64,7 @@ class Chef
raise Chef::ChefFS::FileSystem::OperationFailedError.new(:create_child, self, e), "HTTP error creating child '#{name}': #{e}"
end
end
+ @children = nil
DataBagDir.new(name, self, true)
end
end
diff --git a/lib/chef/chef_fs/file_system/file_system_entry.rb b/lib/chef/chef_fs/file_system/file_system_entry.rb
index 82c52deae8..46d4eb5538 100644
--- a/lib/chef/chef_fs/file_system/file_system_entry.rb
+++ b/lib/chef/chef_fs/file_system/file_system_entry.rb
@@ -40,20 +40,24 @@ class Chef
def children
begin
- @children ||= Dir.entries(file_path).sort.select { |entry| entry != '.' && entry != '..' }.map { |entry| FileSystemEntry.new(entry, self) }
+ Dir.entries(file_path).sort.select { |entry| entry != '.' && entry != '..' }.map { |entry| make_child(entry) }
rescue Errno::ENOENT
raise Chef::ChefFS::FileSystem::NotFoundError.new(self, $!)
end
end
def create_child(child_name, file_contents=nil)
- result = FileSystemEntry.new(child_name, self)
+ child = make_child(child_name)
if file_contents
- result.write(file_contents)
+ child.write(file_contents)
else
- Dir.mkdir(result.file_path)
+ begin
+ Dir.mkdir(child.file_path)
+ rescue Errno::EEXIST
+ end
end
- result
+ @children = nil
+ child
end
def dir?
@@ -84,6 +88,12 @@ class Chef
file.write(content)
end
end
+
+ protected
+
+ def make_child(child_name)
+ FileSystemEntry.new(child_name, self)
+ end
end
end
end
diff --git a/lib/chef/chef_fs/file_system/multiplexed_dir.rb b/lib/chef/chef_fs/file_system/multiplexed_dir.rb
index a7a901e304..06d4af705d 100644
--- a/lib/chef/chef_fs/file_system/multiplexed_dir.rb
+++ b/lib/chef/chef_fs/file_system/multiplexed_dir.rb
@@ -17,7 +17,7 @@ class Chef
end
def children
- @children ||= begin
+ begin
result = []
seen = {}
# If multiple things have the same name, the first one wins.
@@ -40,6 +40,7 @@ class Chef
end
def create_child(name, file_contents = nil)
+ @children = nil
write_dir.create_child(name, file_contents)
end
end
diff --git a/lib/chef/chef_fs/file_system/nodes_dir.rb b/lib/chef/chef_fs/file_system/nodes_dir.rb
index 82683e81ac..c3c48377cd 100644
--- a/lib/chef/chef_fs/file_system/nodes_dir.rb
+++ b/lib/chef/chef_fs/file_system/nodes_dir.rb
@@ -32,7 +32,7 @@ class Chef
# Identical to RestListDir.children, except supports environments
def children
begin
- @children ||= Chef::ChefFS::RawRequest.raw_json(rest, env_api_path).keys.sort.map do |key|
+ @children ||= root.get_json(env_api_path).keys.sort.map do |key|
_make_child_entry("#{key}.json", true)
end
rescue Timeout::Error => e
diff --git a/lib/chef/chef_fs/file_system/operation_failed_error.rb b/lib/chef/chef_fs/file_system/operation_failed_error.rb
index 1af2d2dcff..28d170d628 100644
--- a/lib/chef/chef_fs/file_system/operation_failed_error.rb
+++ b/lib/chef/chef_fs/file_system/operation_failed_error.rb
@@ -27,6 +27,14 @@ class Chef
@operation = operation
end
+ def message
+ if cause && cause.is_a?(Net::HTTPExceptions) && cause.response.code == "400"
+ "#{super} cause: #{cause.response.body}"
+ else
+ super
+ end
+ end
+
attr_reader :operation
end
end
diff --git a/lib/chef/chef_fs/file_system/rest_list_dir.rb b/lib/chef/chef_fs/file_system/rest_list_dir.rb
index 594fec8ab6..b7ee51d284 100644
--- a/lib/chef/chef_fs/file_system/rest_list_dir.rb
+++ b/lib/chef/chef_fs/file_system/rest_list_dir.rb
@@ -45,7 +45,7 @@ class Chef
def children
begin
- @children ||= Chef::ChefFS::RawRequest.raw_json(rest, api_path).keys.sort.map do |key|
+ @children ||= root.get_json(api_path).keys.sort.map do |key|
_make_child_entry("#{key}.json", true)
end
rescue Timeout::Error => e
@@ -76,7 +76,7 @@ class Chef
end
begin
- rest.post_rest(api_path, object)
+ rest.post(api_path, object)
rescue Timeout::Error => e
raise Chef::ChefFS::FileSystem::OperationFailedError.new(:create_child, self, e), "Timeout creating '#{name}': #{e}"
rescue Net::HTTPServerException => e
@@ -89,6 +89,8 @@ class Chef
end
end
+ @children = nil
+
result
end
diff --git a/lib/chef/chef_fs/file_system/rest_list_entry.rb b/lib/chef/chef_fs/file_system/rest_list_entry.rb
index 6e6ad12438..0d5557de1d 100644
--- a/lib/chef/chef_fs/file_system/rest_list_entry.rb
+++ b/lib/chef/chef_fs/file_system/rest_list_entry.rb
@@ -19,7 +19,6 @@
require 'chef/chef_fs/file_system/base_fs_object'
require 'chef/chef_fs/file_system/not_found_error'
require 'chef/chef_fs/file_system/operation_failed_error'
-require 'chef/chef_fs/raw_request'
require 'chef/role'
require 'chef/node'
@@ -68,7 +67,7 @@ class Chef
def delete(recurse)
begin
- rest.delete_rest(api_path)
+ rest.delete(api_path)
rescue Timeout::Error => e
raise Chef::ChefFS::FileSystem::OperationFailedError.new(:delete, self, e), "Timeout deleting: #{e}"
rescue Net::HTTPServerException => e
@@ -86,7 +85,8 @@ class Chef
def _read_hash
begin
- json = Chef::ChefFS::RawRequest.raw_request(rest, api_path)
+ # Minimize the value (get rid of defaults) so the results don't look terrible
+ minimize_value(root.get_json(api_path))
rescue Timeout::Error => e
raise Chef::ChefFS::FileSystem::OperationFailedError.new(:read, self, e), "Timeout reading: #{e}"
rescue Net::HTTPServerException => e
@@ -96,8 +96,6 @@ class Chef
raise Chef::ChefFS::FileSystem::OperationFailedError.new(:read, self, e), "HTTP error reading: #{e}"
end
end
- # Minimize the value (get rid of defaults) so the results don't look terrible
- minimize_value(JSON.parse(json, :create_additions => false))
end
def chef_object
@@ -160,7 +158,7 @@ class Chef
end
begin
- rest.put_rest(api_path, object)
+ rest.put(api_path, object)
rescue Timeout::Error => e
raise Chef::ChefFS::FileSystem::OperationFailedError.new(:write, self, e), "Timeout writing: #{e}"
rescue Net::HTTPServerException => e
diff --git a/lib/chef/chef_fs/knife.rb b/lib/chef/chef_fs/knife.rb
index 5900c29f61..652c728550 100644
--- a/lib/chef/chef_fs/knife.rb
+++ b/lib/chef/chef_fs/knife.rb
@@ -35,37 +35,40 @@ class Chef
def self.inherited(c)
super
+
# Ensure we always get to do our includes, whether subclass calls deps or not
c.deps do
end
- option :repo_mode,
- :long => '--repo-mode MODE',
- :description => "Specifies the local repository layout. Values: static, everything, hosted_everything. Default: everything/hosted_everything"
+ c.options.merge!(options)
+ end
- option :chef_repo_path,
- :long => '--chef-repo-path PATH',
- :description => 'Overrides the location of chef repo. Default is specified by chef_repo_path in the config'
+ option :repo_mode,
+ :long => '--repo-mode MODE',
+ :description => "Specifies the local repository layout. Values: static, everything, hosted_everything. Default: everything/hosted_everything"
- option :concurrency,
- :long => '--concurrency THREADS',
- :description => 'Maximum number of simultaneous requests to send (default: 10)'
- end
+ option :chef_repo_path,
+ :long => '--chef-repo-path PATH',
+ :description => 'Overrides the location of chef repo. Default is specified by chef_repo_path in the config'
+
+ option :concurrency,
+ :long => '--concurrency THREADS',
+ :description => 'Maximum number of simultaneous requests to send (default: 10)'
def configure_chef
super
Chef::Config[:repo_mode] = config[:repo_mode] if config[:repo_mode]
Chef::Config[:concurrency] = config[:concurrency].to_i if config[:concurrency]
- # --chef-repo-path overrides all other paths
+ # --chef-repo-path forcibly overrides all other paths
if config[:chef_repo_path]
Chef::Config[:chef_repo_path] = config[:chef_repo_path]
- Chef::ChefFS::Config::PATH_VARIABLES.each do |variable_name|
- Chef::Config[variable_name.to_sym] = chef_repo_paths.map { |path| File.join(path, "#{variable_name[0..-6]}s") }
+ %w(acl client cookbook container data_bag environment group node role user).each do |variable_name|
+ Chef::Config.delete("#{variable_name}_path".to_sym)
end
end
- @chef_fs_config = Chef::ChefFS::Config.new(Chef::Config)
+ @chef_fs_config = Chef::ChefFS::Config.new(Chef::Config, Dir.pwd, config)
Chef::ChefFS::Parallelizer.threads = (Chef::Config[:concurrency] || 10) - 1
end
@@ -91,17 +94,18 @@ class Chef
end
def pattern_args_from(args)
+ args.map { |arg| pattern_arg_from(arg) }
+ end
+
+ def pattern_arg_from(arg)
# TODO support absolute file paths and not just patterns? Too much?
# Could be super useful in a world with multiple repo paths
- args.map do |arg|
- if !@chef_fs_config.base_path && !Chef::ChefFS::PathUtils.is_absolute?(arg)
- # Check if chef repo path is specified to give a better error message
- @chef_fs_config.require_chef_repo_path
- ui.error("Attempt to use relative path '#{arg}' when current directory is outside the repository path")
- exit(1)
- end
- Chef::ChefFS::FilePattern.relative_to(@chef_fs_config.base_path, arg)
+ if !@chef_fs_config.base_path && !Chef::ChefFS::PathUtils.is_absolute?(arg)
+ # Check if chef repo path is specified to give a better error message
+ ui.error("Attempt to use relative path '#{arg}' when current directory is outside the repository path")
+ exit(1)
end
+ Chef::ChefFS::FilePattern.relative_to(@chef_fs_config.base_path, arg)
end
def format_path(entry)
@@ -111,6 +115,19 @@ class Chef
def parallelize(inputs, options = {}, &block)
Chef::ChefFS::Parallelizer.parallelize(inputs, options, &block)
end
+
+ def discover_repo_dir(dir)
+ %w(.chef cookbooks data_bags environments roles).each do |subdir|
+ return dir if File.directory?(File.join(dir, subdir))
+ end
+ # If this isn't it, check the parent
+ parent = File.dirname(dir)
+ if parent && parent != dir
+ discover_repo_dir(parent)
+ else
+ nil
+ end
+ end
end
end
end
diff --git a/lib/chef/chef_fs/path_utils.rb b/lib/chef/chef_fs/path_utils.rb
index 805b092b3a..9ef75ce2e5 100644
--- a/lib/chef/chef_fs/path_utils.rb
+++ b/lib/chef/chef_fs/path_utils.rb
@@ -82,6 +82,11 @@ class Chef
end
end
+ def self.descendant_of?(path, ancestor)
+ path[0,ancestor.length] == ancestor &&
+ (ancestor.length == path.length || path[ancestor.length,1] =~ /#{PathUtils.regexp_path_separator}/)
+ end
+
def self.is_absolute?(path)
path =~ /^#{regexp_path_separator}/
end
diff --git a/lib/chef/chef_fs/raw_request.rb b/lib/chef/chef_fs/raw_request.rb
deleted file mode 100644
index 43907282f6..0000000000
--- a/lib/chef/chef_fs/raw_request.rb
+++ /dev/null
@@ -1,79 +0,0 @@
-class Chef
- module ChefFS
- module RawRequest
- def self.raw_json(chef_rest, api_path)
- JSON.parse(raw_request(chef_rest, api_path), :create_additions => false)
- end
-
- def self.raw_request(chef_rest, api_path)
- api_request(chef_rest, :GET, chef_rest.create_url(api_path), {}, false)
- end
-
- def self.api_request(chef_rest, method, url, headers={}, data=false)
- json_body = data
- # json_body = data ? Chef::JSONCompat.to_json(data) : nil
- # Force encoding to binary to fix SSL related EOFErrors
- # cf. http://tickets.opscode.com/browse/CHEF-2363
- # http://redmine.ruby-lang.org/issues/5233
- # json_body.force_encoding(Encoding::BINARY) if json_body.respond_to?(:force_encoding)
- headers = build_headers(chef_rest, method, url, headers, json_body)
-
- chef_rest.retriable_rest_request(method, url, json_body, headers) do |rest_request|
- response = rest_request.call {|r| r.read_body}
-
- response_body = chef_rest.decompress_body(response)
-
- if response.kind_of?(Net::HTTPSuccess)
- response_body
- elsif redirect_location = redirected_to(response)
- if [:GET, :HEAD].include?(method)
- chef_rest.follow_redirect do
- api_request(chef_rest, method, chef_rest.create_url(redirect_location))
- end
- else
- raise Exceptions::InvalidRedirect, "#{method} request was redirected from #{url} to #{redirect_location}. Only GET and HEAD support redirects."
- end
- else
- # have to decompress the body before making an exception for it. But the body could be nil.
- response.body.replace(chef_rest.decompress_body(response)) if response.body.respond_to?(:replace)
-
- if response['content-type'] =~ /json/
- exception = response_body
- msg = "HTTP Request Returned #{response.code} #{response.message}: "
- msg << (exception["error"].respond_to?(:join) ? exception["error"].join(", ") : exception["error"].to_s)
- Chef::Log.info(msg)
- end
- response.error!
- end
- end
- end
-
- private
-
- # Copied so that it does not automatically inflate an object
- # This is also used by knife raw_essentials
-
- ACCEPT_ENCODING = "Accept-Encoding".freeze
- ENCODING_GZIP_DEFLATE = "gzip;q=1.0,deflate;q=0.6,identity;q=0.3".freeze
-
- def self.redirected_to(response)
- return nil unless response.kind_of?(Net::HTTPRedirection)
- # Net::HTTPNotModified is undesired subclass of Net::HTTPRedirection so test for this
- return nil if response.kind_of?(Net::HTTPNotModified)
- response['location']
- end
-
- def self.build_headers(chef_rest, method, url, headers={}, json_body=false, raw=false)
- # headers = @default_headers.merge(headers)
- #headers['Accept'] = "application/json" unless raw
- headers['Accept'] = "application/json" unless raw
- headers["Content-Type"] = 'application/json' if json_body
- headers['Content-Length'] = json_body.bytesize.to_s if json_body
- headers[Chef::REST::RESTRequest::ACCEPT_ENCODING] = Chef::REST::RESTRequest::ENCODING_GZIP_DEFLATE
- headers.merge!(chef_rest.authentication_headers(method, url, json_body)) if chef_rest.sign_requests?
- headers.merge!(Chef::Config[:custom_http_headers]) if Chef::Config[:custom_http_headers]
- headers
- end
- end
- end
-end
diff --git a/lib/chef/client.rb b/lib/chef/client.rb
index ceb0873079..04d6799988 100644
--- a/lib/chef/client.rb
+++ b/lib/chef/client.rb
@@ -198,6 +198,7 @@ class Chef
Chef::Log.debug "Forked instance now converging"
do_run
rescue Exception
+ Chef::Log.error $!
exit 1
else
exit 0
@@ -206,7 +207,7 @@ class Chef
Chef::Log.debug "Fork successful. Waiting for new chef pid: #{pid}"
result = Process.waitpid2(pid)
handle_child_exit(result)
- Chef::Log.debug "Forked child successfully reaped (pid: #{pid})"
+ Chef::Log.debug "Forked instance successfully reaped (pid: #{pid})"
true
else
do_run
@@ -367,7 +368,10 @@ class Chef
# === Returns
# rest<Chef::REST>:: returns Chef::REST connection object
def register(client_name=node_name, config=Chef::Config)
- if File.exists?(config[:client_key])
+ if !config[:client_key]
+ @events.skipping_registration(client_name, config)
+ Chef::Log.debug("Client key is unspecified - skipping registration")
+ elsif File.exists?(config[:client_key])
@events.skipping_registration(client_name, config)
Chef::Log.debug("Client key #{config[:client_key]} is present - skipping registration")
else
@@ -467,13 +471,15 @@ class Chef
# === Returns
# true:: Always returns true.
def do_run
- runlock = RunLock.new(Chef::Config)
+ runlock = RunLock.new(Chef::Config.lockfile)
runlock.acquire
# don't add code that may fail before entering this section to be sure to release lock
begin
+ runlock.save_pid
run_context = nil
@events.run_start(Chef::VERSION)
Chef::Log.info("*** Chef #{Chef::VERSION} ***")
+ Chef::Log.info "Chef-client pid: #{Process.pid}"
enforce_path_sanity
run_ohai
@events.ohai_completed(node)
diff --git a/lib/chef/config.rb b/lib/chef/config.rb
index e3211d232e..feb7e4ea94 100644
--- a/lib/chef/config.rb
+++ b/lib/chef/config.rb
@@ -29,6 +29,13 @@ class Chef
extend Mixlib::Config
+ # Evaluates the given string as config.
+ #
+ # +filename+ is used for context in stacktraces, but doesn't need to be the name of an actual file.
+ def self.from_string(string, filename)
+ self.instance_eval(string, filename, 1)
+ end
+
# Manages the chef secret session key
# === Returns
# <newkey>:: A new or retrieved session key
@@ -50,8 +57,32 @@ class Chef
configuration.inspect
end
+ def self.on_windows?
+ RUBY_PLATFORM =~ /mswin|mingw|windows/
+ end
+
+ BACKSLASH = '\\'.freeze
+
+ def self.platform_path_separator
+ if on_windows?
+ File::ALT_SEPARATOR || BACKSLASH
+ else
+ File::SEPARATOR
+ end
+ end
+
+ def self.path_join(*args)
+ args = args.flatten
+ args.inject do |joined_path, component|
+ unless joined_path[-1,1] == platform_path_separator
+ joined_path += platform_path_separator
+ end
+ joined_path += component
+ end
+ end
+
def self.platform_specific_path(path)
- if RUBY_PLATFORM =~ /mswin|mingw|windows/
+ if on_windows?
# turns /etc/chef/client.rb into C:/chef/client.rb
system_drive = ENV['SYSTEMDRIVE'] ? ENV['SYSTEMDRIVE'] : ""
path = File.join(system_drive, path.split('/')[2..-1])
@@ -65,32 +96,35 @@ class Chef
formatters << [name, file_path]
end
- def self.formatters
- @formatters ||= []
+ # Config file to load (client.rb, knife.rb, etc. defaults set differently in knife, chef-client, etc.)
+ configurable(:config_file)
+
+ default(:config_dir) do
+ if local_mode
+ path_join(user_home, ".chef#{platform_path_separator}")
+ else
+ config_file && ::File.dirname(config_file)
+ end
end
+ # No config file (client.rb / knife.rb / etc.) will be loaded outside this path.
+ # Major use case is tests, where we don't want to load the user's config files.
+ configurable(:config_file_jail)
+
+ default :formatters, []
+
# Override the config dispatch to set the value of multiple server options simultaneously
#
# === Parameters
# url<String>:: String to be set for all of the chef-server-api URL's
#
- config_attr_writer :chef_server_url do |url|
- url = url.strip
- configure do |c|
- c[:chef_server_url] = url
- end
- url
- end
+ configurable(:chef_server_url).writes_value { |url| url.strip }
# When you are using ActiveSupport, they monkey-patch 'daemonize' into Kernel.
# So while this is basically identical to what method_missing would do, we pull
# it up here and get a real method written so that things get dispatched
# properly.
- config_attr_writer :daemonize do |v|
- configure do |c|
- c[:daemonize] = v
- end
- end
+ configurable(:daemonize).writes_value { |v| v }
# Override the config dispatch to set the value of log_location configuration option
#
@@ -108,50 +142,148 @@ class Chef
rescue Errno::ENOENT
raise Chef::Exceptions::ConfigurationError, "Failed to open or create log file at #{location.to_str}"
end
- f
+ f
+ end
+ end
+
+ # The root where all local chef object data is stored. cookbooks, data bags,
+ # environments are all assumed to be in separate directories under this.
+ # chef-solo uses these directories for input data. knife commands
+ # that upload or download files (such as knife upload, knife role from file,
+ # etc.) work.
+ default :chef_repo_path do
+ if self.configuration[:cookbook_path]
+ if self.configuration[:cookbook_path].kind_of?(String)
+ File.expand_path('..', self.configuration[:cookbook_path])
+ else
+ self.configuration[:cookbook_path].map do |path|
+ File.expand_path('..', path)
+ end
+ end
+ else
+ platform_specific_path("/var/chef")
+ end
+ end
+
+ def self.find_chef_repo_path(cwd)
+ # In local mode, we auto-discover the repo root by looking for a path with "cookbooks" under it.
+ # This allows us to run config-free.
+ path = cwd
+ until File.directory?(path_join(path, "cookbooks"))
+ new_path = File.expand_path('..', path)
+ if new_path == path
+ Chef::Log.warn("No cookbooks directory found at or above current directory. Assuming #{Dir.pwd}.")
+ return Dir.pwd
+ end
+ path = new_path
+ end
+ Chef::Log.info("Auto-discovered chef repository at #{path}")
+ path
+ end
+
+ def self.derive_path_from_chef_repo_path(child_path)
+ if chef_repo_path.kind_of?(String)
+ path_join(chef_repo_path, child_path)
+ else
+ chef_repo_path.map { |path| path_join(path, child_path)}
end
end
+ # Location of acls on disk. String or array of strings.
+ # Defaults to <chef_repo_path>/acls.
+ # Only applies to Enterprise Chef commands.
+ default(:acl_path) { derive_path_from_chef_repo_path('acls') }
+
+ # Location of clients on disk. String or array of strings.
+ # Defaults to <chef_repo_path>/acls.
+ default(:client_path) { derive_path_from_chef_repo_path('clients') }
+
+ # Location of cookbooks on disk. String or array of strings.
+ # Defaults to <chef_repo_path>/cookbooks. If chef_repo_path
+ # is not specified, this is set to [/var/chef/cookbooks, /var/chef/site-cookbooks]).
+ default(:cookbook_path) do
+ if self.configuration[:chef_repo_path]
+ derive_path_from_chef_repo_path('cookbooks')
+ else
+ Array(derive_path_from_chef_repo_path('cookbooks')).flatten +
+ Array(derive_path_from_chef_repo_path('site-cookbooks')).flatten
+ end
+ end
+
+ # Location of containers on disk. String or array of strings.
+ # Defaults to <chef_repo_path>/containers.
+ # Only applies to Enterprise Chef commands.
+ default(:container_path) { derive_path_from_chef_repo_path('containers') }
+
+ # Location of data bags on disk. String or array of strings.
+ # Defaults to <chef_repo_path>/data_bags.
+ default(:data_bag_path) { derive_path_from_chef_repo_path('data_bags') }
+
+ # Location of environments on disk. String or array of strings.
+ # Defaults to <chef_repo_path>/environments.
+ default(:environment_path) { derive_path_from_chef_repo_path('environments') }
+
+ # Location of groups on disk. String or array of strings.
+ # Defaults to <chef_repo_path>/groups.
+ # Only applies to Enterprise Chef commands.
+ default(:group_path) { derive_path_from_chef_repo_path('groups') }
+
+ # Location of nodes on disk. String or array of strings.
+ # Defaults to <chef_repo_path>/nodes.
+ default(:node_path) { derive_path_from_chef_repo_path('nodes') }
+
+ # Location of roles on disk. String or array of strings.
+ # Defaults to <chef_repo_path>/roles.
+ default(:role_path) { derive_path_from_chef_repo_path('roles') }
+
+ # Location of users on disk. String or array of strings.
+ # Defaults to <chef_repo_path>/users.
+ # Does not apply to Enterprise Chef commands.
+ default(:user_path) { derive_path_from_chef_repo_path('users') }
+
# Turn on "path sanity" by default. See also: http://wiki.opscode.com/display/chef/User+Environment+PATH+Sanity
- enforce_path_sanity(true)
+ default :enforce_path_sanity, true
# Formatted Chef Client output is a beta feature, disabled by default:
- formatter "null"
+ default :formatter, "null"
# The number of times the client should retry when registering with the server
- client_registration_retries 5
-
- # Where the cookbooks are located. Meaning is somewhat context dependent between
- # knife, chef-client, and chef-solo.
- cookbook_path [ platform_specific_path("/var/chef/cookbooks"),
- platform_specific_path("/var/chef/site-cookbooks") ]
+ default :client_registration_retries, 5
# An array of paths to search for knife exec scripts if they aren't in the current directory
- script_path []
+ default :script_path, []
+
+ # The root of all caches (checksums, cache and backup). If local mode is on,
+ # this is under the user's home directory.
+ default(:cache_path) do
+ if local_mode
+ "#{config_dir}local-mode-cache"
+ else
+ platform_specific_path("/var/chef")
+ end
+ end
# Where cookbook files are stored on the server (by content checksum)
- checksum_path "/var/chef/checksums"
+ default(:checksum_path) { path_join(cache_path, "checksums") }
# Where chef's cache files should be stored
- file_cache_path platform_specific_path("/var/chef/cache")
+ default(:file_cache_path) { path_join(cache_path, "cache") }
- # By default, chef-client (or solo) creates a lockfile in
- # `file_cache_path`/chef-client-running.pid
- # If `lockfile` is explicitly set, this path will be used instead.
+ # Where backups of chef-managed files should go
+ default(:file_backup_path) { path_join(cache_path, "backup") }
+
+ # The chef-client (or solo) lockfile.
#
# If your `file_cache_path` resides on a NFS (or non-flock()-supporting
# fs), it's recommended to set this to something like
# '/tmp/chef-client-running.pid'
- lockfile nil
-
- # Where backups of chef-managed files should go
- file_backup_path platform_specific_path("/var/chef/backup")
+ default(:lockfile) { path_join(file_cache_path, "chef-client-running.pid") }
## Daemonization Settings ##
# What user should Chef run as?
- user nil
- group nil
- umask 0022
+ default :user, nil
+ default :group, nil
+ default :umask, 0022
# Valid log_levels are:
# * :debug
@@ -164,57 +296,76 @@ class Chef
# in a console), the log level is set to :warn, and output formatters are
# used as the primary mode of output. When a tty is not available, the
# logger is the primary mode of output, and the log level is set to :info
- log_level :auto
+ default :log_level, :auto
# Using `force_formatter` causes chef to default to formatter output when STDOUT is not a tty
- force_formatter false
+ default :force_formatter, false
# Using `force_logger` causes chef to default to logger output when STDOUT is a tty
- force_logger false
-
- http_retry_count 5
- http_retry_delay 5
- interval nil
- json_attribs nil
- log_location STDOUT
+ default :force_logger, false
+
+ default :http_retry_count, 5
+ default :http_retry_delay, 5
+ default :interval, nil
+ default :once, nil
+ default :json_attribs, nil
+ default :log_location, STDOUT
# toggle info level log items that can create a lot of output
- verbose_logging true
- node_name nil
- diff_disabled false
- diff_filesize_threshold 10000000
- diff_output_threshold 1000000
-
- pid_file nil
-
- chef_server_url "https://localhost:443"
-
- rest_timeout 300
- yum_timeout 900
- solo false
- splay nil
- why_run false
- color false
- client_fork true
- enable_reporting true
- enable_reporting_url_fatals false
+ default :verbose_logging, true
+ default :node_name, nil
+ default :diff_disabled, false
+ default :diff_filesize_threshold, 10000000
+ default :diff_output_threshold, 1000000
+ default :local_mode, false
+
+ default :pid_file, nil
+
+ config_context :chef_zero do
+ config_strict_mode true
+ default(:enabled) { Chef::Config.local_mode }
+ default :port, 8889
+ end
+ default :chef_server_url, "https://localhost:443"
+
+ default :rest_timeout, 300
+ default :yum_timeout, 900
+ default :solo, false
+ default :splay, nil
+ default :why_run, false
+ default :color, false
+ default :client_fork, true
+ default :enable_reporting, true
+ default :enable_reporting_url_fatals, false
# Set these to enable SSL authentication / mutual-authentication
# with the server
- ssl_client_cert nil
- ssl_client_key nil
- ssl_verify_mode :verify_none
- ssl_ca_path nil
- ssl_ca_file nil
- # Where should chef-solo look for role files?
- role_path platform_specific_path("/var/chef/roles")
+ # Client side SSL cert/key for mutual auth
+ default :ssl_client_cert, nil
+ default :ssl_client_key, nil
+
+ # Whether or not to verify the SSL cert for all HTTPS requests. If set to
+ # :verify_peer, all HTTPS requests will be validated regardless of other
+ # SSL verification settings.
+ default :ssl_verify_mode, :verify_none
- data_bag_path platform_specific_path("/var/chef/data_bags")
+ # Whether or not to verify the SSL cert for HTTPS requests to the Chef
+ # server API. If set to `true`, the server's cert will be validated
+ # regardless of the :ssl_verify_mode setting.
+ default :verify_api_cert, false
- environment_path platform_specific_path("/var/chef/environments")
+ # Path to the default CA bundle files.
+ default :ssl_ca_path, nil
+ default :ssl_ca_file, nil
+
+ # A directory that contains additional SSL certificates to trust. Any
+ # certificates in this directory will be added to whatever CA bundle ruby
+ # is using. Use this to add self-signed certs for your Chef Server or local
+ # HTTP file servers.
+ default(:trusted_certs_dir) { config_dir && path_join(config_dir, "trusted_certs") }
# Where should chef-solo download recipes from?
- recipe_url nil
+ default :recipe_url, nil
# Sets the version of the signed header authentication protocol to use (see
# the 'mixlib-authorization' project for more detail). Currently, versions
@@ -230,7 +381,7 @@ class Chef
#
# In the future, this configuration option may be replaced with an
# automatic negotiation scheme.
- authentication_protocol_version "1.0"
+ default :authentication_protocol_version, "1.0"
# This key will be used to sign requests to the Chef server. This location
# must be writable by Chef during initial setup when generating a client
@@ -238,17 +389,21 @@ class Chef
#
# The chef-server will look up the public key for the client using the
# `node_name` of the client.
- client_key platform_specific_path("/etc/chef/client.pem")
+ #
+ # If chef-zero is enabled, this defaults to nil (no authentication).
+ default(:client_key) { chef_zero.enabled ? nil : platform_specific_path("/etc/chef/client.pem") }
# This secret is used to decrypt encrypted data bag items.
- encrypted_data_bag_secret platform_specific_path("/etc/chef/encrypted_data_bag_secret")
-
- # We have to check for the existence of the default file before setting it
- # since +Chef::Config[:encrypted_data_bag_secret]+ is read by older
- # bootstrap templates to determine if the local secret should be uploaded to
- # node being bootstrapped. This should be removed in Chef 12.
- unless File.exist?(platform_specific_path("/etc/chef/encrypted_data_bag_secret"))
- encrypted_data_bag_secret(nil)
+ default(:encrypted_data_bag_secret) do
+ # We have to check for the existence of the default file before setting it
+ # since +Chef::Config[:encrypted_data_bag_secret]+ is read by older
+ # bootstrap templates to determine if the local secret should be uploaded to
+ # node being bootstrapped. This should be removed in Chef 12.
+ if File.exist?(platform_specific_path("/etc/chef/encrypted_data_bag_secret"))
+ platform_specific_path("/etc/chef/encrypted_data_bag_secret")
+ else
+ nil
+ end
end
# As of Chef 11.0, version "1" is the default encrypted data bag item
@@ -256,7 +411,7 @@ class Chef
# To maintain compatibility, versions other than 1 must be opt-in.
#
# Set this to `2` if you have chef-client 11.6.0+ in your infrastructure:
- data_bag_encrypt_version 1
+ default :data_bag_encrypt_version, 1
# When reading data bag items, any supported version is accepted. However,
# if all encrypted data bags have been generated with the version 2 format,
@@ -264,7 +419,7 @@ class Chef
# security. For example, the version 2 format is identical to version 1
# except for the addition of an HMAC, so an attacker with MITM capability
# could downgrade an encrypted data bag to version 1 as part of an attack.
- data_bag_decrypt_minimum_version 0
+ default :data_bag_decrypt_minimum_version, 0
# If there is no file in the location given by `client_key`, chef-client
# will temporarily use the "validator" identity to generate one. If the
@@ -272,43 +427,53 @@ class Chef
# chef-client will not be able to authenticate to the server.
#
# The `validation_key` is never used if the `client_key` exists.
- validation_key platform_specific_path("/etc/chef/validation.pem")
- validation_client_name "chef-validator"
+ #
+ # If chef-zero is enabled, this defaults to nil (no authentication).
+ default(:validation_key) { chef_zero.enabled ? nil : platform_specific_path("/etc/chef/validation.pem") }
+ default :validation_client_name, "chef-validator"
# Zypper package provider gpg checks. Set to true to enable package
# gpg signature checking. This will be default in the
# future. Setting to false disables the warnings.
# Leaving this set to nil or false is a security hazard!
- zypper_check_gpg nil
+ default :zypper_check_gpg, nil
# Report Handlers
- report_handlers []
+ default :report_handlers, []
# Exception Handlers
- exception_handlers []
+ default :exception_handlers, []
# Start handlers
- start_handlers []
+ default :start_handlers, []
# Syntax Check Cache. Knife keeps track of files that is has already syntax
# checked by storing files in this directory. `syntax_check_cache_path` is
# the new (and preferred) configuration setting. If not set, knife will
- # fall back to using cache_options[:path].
- #
- # Because many users will have knife configs with cache_options (generated
- # by `knife configure`), the default for now is to *not* set
- # syntax_check_cache_path, and thus fallback to cache_options[:path]. We
- # leave that value to the same default as was previously set.
- syntax_check_cache_path nil
+ # fall back to using cache_options[:path], which is deprecated but exists in
+ # many client configs generated by pre-Chef-11 bootstrappers.
+ default(:syntax_check_cache_path) { cache_options[:path] }
# Deprecated:
- cache_options({ :path => platform_specific_path("/var/chef/cache/checksums") })
+ default(:cache_options) { { :path => path_join(file_cache_path, "checksums") } }
# Set to false to silence Chef 11 deprecation warnings:
- chef11_deprecation_warnings true
-
- # Arbitrary knife configuration data
- knife Hash.new
+ default :chef11_deprecation_warnings, true
+
+ # knife configuration data
+ config_context :knife do
+ default :ssh_port, nil
+ default :ssh_user, nil
+ default :ssh_attribute, nil
+ default :ssh_gateway, nil
+ default :bootstrap_version, nil
+ default :bootstrap_proxy, nil
+ default :identity_file, nil
+ default :host_key_verify, nil
+ default :forward_agent, nil
+ default :sort_status_reverse, nil
+ default :hints, {}
+ end
# Those lists of regular expressions define what chef considers a
# valid user and group name
@@ -316,31 +481,31 @@ class Chef
# From http://technet.microsoft.com/en-us/library/cc776019(WS.10).aspx
principal_valid_regex_part = '[^"\/\\\\\[\]\:;|=,+*?<>]+'
- user_valid_regex [ /^(#{principal_valid_regex_part}\\)?#{principal_valid_regex_part}$/ ]
- group_valid_regex [ /^(#{principal_valid_regex_part}\\)?#{principal_valid_regex_part}$/ ]
+ default :user_valid_regex, [ /^(#{principal_valid_regex_part}\\)?#{principal_valid_regex_part}$/ ]
+ default :group_valid_regex, [ /^(#{principal_valid_regex_part}\\)?#{principal_valid_regex_part}$/ ]
- fatal_windows_admin_check false
+ default :fatal_windows_admin_check, false
else
- user_valid_regex [ /^([-a-zA-Z0-9_.]+[\\@]?[-a-zA-Z0-9_.]+)$/, /^\d+$/ ]
- group_valid_regex [ /^([-a-zA-Z0-9_.\\@^ ]+)$/, /^\d+$/ ]
+ default :user_valid_regex, [ /^([-a-zA-Z0-9_.]+[\\@]?[-a-zA-Z0-9_.]+)$/, /^\d+$/ ]
+ default :group_valid_regex, [ /^([-a-zA-Z0-9_.\\@^ ]+)$/, /^\d+$/ ]
end
# returns a platform specific path to the user home dir
windows_home_path = ENV['SYSTEMDRIVE'] + ENV['HOMEPATH'] if ENV['SYSTEMDRIVE'] && ENV['HOMEPATH']
- user_home(ENV['HOME'] || windows_home_path || ENV['USERPROFILE'])
+ default :user_home, (ENV['HOME'] || windows_home_path || ENV['USERPROFILE'])
# Enable file permission fixup for selinux. Fixup will be done
# only if selinux is enabled in the system.
- enable_selinux_file_permission_fixup true
+ default :enable_selinux_file_permission_fixup, true
# Use atomic updates (i.e. move operation) while updating contents
# of the files resources. When set to false copy operation is
# used to update files.
- file_atomic_update true
+ default :file_atomic_update, true
# If false file staging is will be done via tempfiles that are
# created under ENV['TMP'] otherwise tempfiles will be created in
# the directory that files are going to reside.
- file_staging_uses_destdir false
+ default :file_staging_uses_destdir, false
end
end
diff --git a/lib/chef/config_fetcher.rb b/lib/chef/config_fetcher.rb
new file mode 100644
index 0000000000..80a313590b
--- /dev/null
+++ b/lib/chef/config_fetcher.rb
@@ -0,0 +1,79 @@
+require 'chef/application'
+require 'chef/chef_fs/path_utils'
+require 'chef/http/simple'
+require 'chef/json_compat'
+
+class Chef
+ class ConfigFetcher
+
+ attr_reader :config_location
+ attr_reader :config_file_jail
+
+ def initialize(config_location, config_file_jail)
+ @config_location = config_location
+ @config_file_jail = config_file_jail
+ end
+
+ def fetch_json
+ config_data = read_config
+ begin
+ Chef::JSONCompat.from_json(config_data)
+ rescue JSON::ParserError => error
+ Chef::Application.fatal!("Could not parse the provided JSON file (#{config_location}): " + error.message, 2)
+ end
+ end
+
+ def read_config
+ if remote_config?
+ fetch_remote_config
+ else
+ read_local_config
+ end
+ end
+
+ def fetch_remote_config
+ http.get("")
+ rescue SocketError, SystemCallError, Net::HTTPServerException => error
+ Chef::Application.fatal!("Cannot fetch config '#{config_location}': '#{error.class}: #{error.message}", 2)
+ end
+
+ def read_local_config
+ ::File.read(config_location)
+ rescue Errno::ENOENT => error
+ Chef::Application.fatal!("Cannot load configuration from #{config_location}", 2)
+ rescue Errno::EACCES => error
+ Chef::Application.fatal!("Permissions are incorrect on #{config_location}. Please chmod a+r #{config_location}", 2)
+ end
+
+ def config_missing?
+ return false if remote_config?
+
+ # Check if the config file exists, and check if it is underneath the config file jail
+ begin
+ real_config_file = Pathname.new(config_location).realpath.to_s
+ rescue Errno::ENOENT
+ return true
+ end
+
+ # If realpath succeeded, the file exists
+ return false if !config_file_jail
+
+ begin
+ real_jail = Pathname.new(config_file_jail).realpath.to_s
+ rescue Errno::ENOENT
+ Chef::Log.warn("Config file jail #{config_file_jail} does not exist: will not load any config file.")
+ return true
+ end
+
+ !Chef::ChefFS::PathUtils.descendant_of?(real_config_file, real_jail)
+ end
+
+ def http
+ Chef::HTTP::Simple.new(config_location)
+ end
+
+ def remote_config?
+ !!(config_location =~ %r{^(http|https)://})
+ end
+ end
+end
diff --git a/lib/chef/cookbook/file_vendor.rb b/lib/chef/cookbook/file_vendor.rb
index 38eab185ca..406f23ca25 100644
--- a/lib/chef/cookbook/file_vendor.rb
+++ b/lib/chef/cookbook/file_vendor.rb
@@ -7,9 +7,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -27,14 +27,14 @@ class Chef
def self.on_create(&block)
@instance_creator = block
end
-
+
# Factory method that creates the appropriate kind of
# Cookbook::FileVendor to serve the contents of the manifest
def self.create_from_manifest(manifest)
raise "Must call Chef::Cookbook::FileVendor.on_create before calling create_from_manifest factory" unless defined?(@instance_creator)
@instance_creator.call(manifest)
end
-
+
# Gets the on-disk location for the given cookbook file.
#
# Subclasses are responsible for determining exactly how the
@@ -42,7 +42,7 @@ class Chef
def get_filename(filename)
raise NotImplemented, "Subclasses must implement this method"
end
-
+
end
end
end
diff --git a/lib/chef/cookbook/metadata.rb b/lib/chef/cookbook/metadata.rb
index 18368bd99f..b9b32c8224 100644
--- a/lib/chef/cookbook/metadata.rb
+++ b/lib/chef/cookbook/metadata.rb
@@ -110,8 +110,8 @@ class Chef
@version = Version.new "0.0.0"
if cookbook
@recipes = cookbook.fully_qualified_recipe_names.inject({}) do |r, e|
- e = self.name if e =~ /::default$/
- r[e] = ""
+ e = self.name.to_s if e =~ /::default$/
+ r[e] ||= ""
self.provides e
r
end
diff --git a/lib/chef/cookbook/syntax_check.rb b/lib/chef/cookbook/syntax_check.rb
index 0e757074e3..59888e2ba3 100644
--- a/lib/chef/cookbook/syntax_check.rb
+++ b/lib/chef/cookbook/syntax_check.rb
@@ -6,9 +6,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -39,19 +39,9 @@ class Chef
attr_reader :cache_path
# Create a new PersistentSet. Values in the set are persisted by
- # creating a file in the +cache_path+ directory. If not given, the
- # value of Chef::Config[:syntax_check_cache_path] is used; if that
- # value is not configured, the value of
- # Chef::Config[:cache_options][:path] is used.
- #--
- # history: prior to Chef 11, the cache implementation was based on
- # moneta and configured via cache_options[:path]. Knife configs
- # generated with Chef 11 will have `syntax_check_cache_path`, but older
- # configs will have `cache_options[:path]`. `cache_options` is marked
- # deprecated in chef/config.rb but doesn't currently trigger a warning.
- # See also: CHEF-3715
- def initialize(cache_path=nil)
- @cache_path = cache_path || Chef::Config[:syntax_check_cache_path] || Chef::Config[:cache_options][:path]
+ # creating a file in the +cache_path+ directory.
+ def initialize(cache_path=Chef::Config[:syntax_check_cache_path])
+ @cache_path = cache_path
@cache_path_created = false
end
@@ -137,7 +127,7 @@ class Chef
end
def untested_template_files
- template_files.reject do |file|
+ template_files.reject do |file|
if validated?(file)
Chef::Log.debug("Template #{file} is unchanged, skipping syntax check")
true
diff --git a/lib/chef/cookbook_site_streaming_uploader.rb b/lib/chef/cookbook_site_streaming_uploader.rb
index abb5499042..92193fee33 100644
--- a/lib/chef/cookbook_site_streaming_uploader.rb
+++ b/lib/chef/cookbook_site_streaming_uploader.rb
@@ -208,8 +208,11 @@ class Chef
@parts.inject(0) {|size, part| size + part.size}
end
- def read(how_much)
- return nil if @part_no >= @parts.size
+ def read(how_much, dst_buf = nil)
+ if @part_no >= @parts.size
+ dst_buf.replace('') if dst_buf
+ return dst_buf
+ end
how_much_current_part = @parts[@part_no].size - @part_offset
@@ -228,15 +231,16 @@ class Chef
@part_no += 1
@part_offset = 0
next_part = read(how_much_next_part)
- current_part + if next_part
+ result = current_part + if next_part
next_part
else
''
end
else
@part_offset += how_much_current_part
- current_part
+ result = current_part
end
+ dst_buf ? dst_buf.replace(result || '') : result
end
end
diff --git a/lib/chef/cookbook_uploader.rb b/lib/chef/cookbook_uploader.rb
index 9ba5b2bd8b..3ead26e56d 100644
--- a/lib/chef/cookbook_uploader.rb
+++ b/lib/chef/cookbook_uploader.rb
@@ -137,15 +137,17 @@ class Chef
timestamp = Time.now.utc.iso8601
file_contents = File.open(file, "rb") {|f| f.read}
# TODO - 5/28/2010, cw: make signing and sending the request streaming
- sign_obj = Mixlib::Authentication::SignedHeaderAuth.signing_object(
- :http_method => :put,
- :path => URI.parse(url).path,
- :body => file_contents,
- :timestamp => timestamp,
- :user_id => rest.client_name
- )
headers = { 'content-type' => 'application/x-binary', 'content-md5' => checksum64, :accept => 'application/json' }
- headers.merge!(sign_obj.sign(OpenSSL::PKey::RSA.new(rest.signing_key)))
+ if rest.signing_key
+ sign_obj = Mixlib::Authentication::SignedHeaderAuth.signing_object(
+ :http_method => :put,
+ :path => URI.parse(url).path,
+ :body => file_contents,
+ :timestamp => timestamp,
+ :user_id => rest.client_name
+ )
+ headers.merge!(sign_obj.sign(OpenSSL::PKey::RSA.new(rest.signing_key)))
+ end
begin
RestClient::Resource.new(url, :headers=>headers, :timeout=>1800, :open_timeout=>1800).put(file_contents)
diff --git a/lib/chef/cookbook_version.rb b/lib/chef/cookbook_version.rb
index 4e8b2a048e..5bd0ca064c 100644
--- a/lib/chef/cookbook_version.rb
+++ b/lib/chef/cookbook_version.rb
@@ -265,6 +265,18 @@ class Chef
end
end
+ # Query whether a template file +template_filename+ is available. File
+ # specificity for the given +node+ is obeyed in the lookup.
+ def has_template_for_node?(node, template_filename)
+ !!find_preferred_manifest_record(node, :templates, template_filename)
+ end
+
+ # Query whether a cookbook_file file +cookbook_filename+ is available. File
+ # specificity for the given +node+ is obeyed in the lookup.
+ def has_cookbook_file_for_node?(node, cookbook_filename)
+ !!find_preferred_manifest_record(node, :files, cookbook_filename)
+ end
+
# Determine the most specific manifest record for the given
# segment/filename, given information in the node. Throws
# FileNotFound if there is no such segment and filename in the
@@ -278,14 +290,7 @@ class Chef
# :checksum => "1234"
# }
def preferred_manifest_record(node, segment, filename)
- preferences = preferences_for_path(node, segment, filename)
-
- # ensure that we generate the manifest, which will also generate
- # @manifest_records_by_path
- manifest
-
- # in order of prefernce, look for the filename in the manifest
- found_pref = preferences.find {|preferred_filename| @manifest_records_by_path[preferred_filename] }
+ found_pref = find_preferred_manifest_record(node, segment, filename)
if found_pref
@manifest_records_by_path[found_pref]
else
@@ -567,6 +572,17 @@ class Chef
private
+ def find_preferred_manifest_record(node, segment, filename)
+ preferences = preferences_for_path(node, segment, filename)
+
+ # ensure that we generate the manifest, which will also generate
+ # @manifest_records_by_path
+ manifest
+
+ # in order of prefernce, look for the filename in the manifest
+ preferences.find {|preferred_filename| @manifest_records_by_path[preferred_filename] }
+ end
+
# For each filename, produce a mapping of base filename (i.e. recipe name
# or attribute file) to on disk location
def filenames_by_name(filenames)
diff --git a/lib/chef/daemon.rb b/lib/chef/daemon.rb
index 9a3d5a884a..e5abca29d8 100644
--- a/lib/chef/daemon.rb
+++ b/lib/chef/daemon.rb
@@ -6,9 +6,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -18,12 +18,14 @@
# I love you Merb (lib/merb-core/server.rb)
require 'chef/config'
+require 'chef/run_lock'
require 'etc'
class Chef
class Daemon
class << self
attr_accessor :name
+ attr_accessor :runlock
# Daemonize the current process, managing pidfiles and process uid/gid
#
@@ -32,9 +34,9 @@ class Chef
#
def daemonize(name)
@name = name
- pid = pid_from_file
- unless running?
- remove_pid_file()
+ @runlock = RunLock.new(pid_file)
+ if runlock.test
+ # We've acquired the daemon lock. Now daemonize.
Chef::Log.info("Daemonizing..")
begin
exit if fork
@@ -45,53 +47,15 @@ class Chef
$stdin.reopen("/dev/null")
$stdout.reopen("/dev/null", "a")
$stderr.reopen($stdout)
- save_pid_file
- at_exit { remove_pid_file }
+ runlock.save_pid
rescue NotImplementedError => e
Chef::Application.fatal!("There is no fork: #{e.message}")
end
else
- Chef::Application.fatal!("Chef is already running pid #{pid}")
- end
- end
-
- # Check if Chef is running based on the pid_file
- # ==== Returns
- # Boolean::
- # True if Chef is running
- # False if Chef is not running
- #
- def running?
- if pid_from_file.nil?
- false
- else
- Process.kill(0, pid_from_file)
- true
- end
- rescue Errno::ESRCH, Errno::ENOENT
- false
- rescue Errno::EACCES => e
- Chef::Application.fatal!("You don't have access to the PID file at #{pid_file}: #{e.message}")
- end
-
- # Check if this process if forked from a Chef daemon
- # ==== Returns
- # Boolean::
- # True if this process is forked
- # False if this process is not forked
- #
- def forked?
- if running? and Process.ppid == pid_from_file.to_i
- # chef daemon is running and this process is a child of it
- true
- elsif not running? and Process.ppid == 1
- # an orphaned fork, its parent becomes init, launchd, etc. after chef daemon dies
- true
- else
- false
+ Chef::Application.fatal!("Chef is already running pid #{pid_from_file}")
end
end
-
+
# Gets the pid file for @name
# ==== Returns
# String::
@@ -99,7 +63,7 @@ class Chef
def pid_file
Chef::Config[:pid_file] or "/tmp/#{@name}.pid"
end
-
+
# Suck the pid out of pid_file
# ==== Returns
# Integer::
@@ -112,31 +76,6 @@ class Chef
rescue Errno::ENOENT, Errno::EACCES
nil
end
-
- # Store the PID on the filesystem
- # This uses the Chef::Config[:pid_file] option, or "/tmp/name.pid" otherwise
- #
- def save_pid_file
- file = pid_file
- begin
- FileUtils.mkdir_p(File.dirname(file))
- rescue Errno::EACCES => e
- Chef::Application.fatal!("Failed store pid in #{File.dirname(file)}, permission denied: #{e.message}")
- end
-
- begin
- File.open(file, "w") { |f| f.write(Process.pid.to_s) }
- rescue Errno::EACCES => e
- Chef::Application.fatal!("Couldn't write to pidfile #{file}, permission denied: #{e.message}")
- end
- end
-
- # Delete the PID from the filesystem
- def remove_pid_file
- if not forked? then
- FileUtils.rm(pid_file) if File.exists?(pid_file)
- end
- end
# Change process user/group to those specified in Chef::Config
#
@@ -151,7 +90,7 @@ class Chef
_change_privilege(Chef::Config[:user])
end
end
-
+
# Change privileges of the process to be the specified user and group
#
# ==== Parameters
@@ -170,14 +109,14 @@ class Chef
Chef::Application.fatal!("Failed to get UID for user #{user}, does it exist? #{e.message}")
return false
end
-
+
begin
target_gid = Etc.getgrnam(group).gid
rescue ArgumentError => e
Chef::Application.fatal!("Failed to get GID for group #{group}, does it exist? #{e.message}")
return false
end
-
+
if (uid != target_uid) or (gid != target_gid)
Process.initgroups(user, target_gid)
Process::GID.change_privilege(target_gid)
diff --git a/lib/chef/data_bag.rb b/lib/chef/data_bag.rb
index dcc01ec743..5994e6f8d1 100644
--- a/lib/chef/data_bag.rb
+++ b/lib/chef/data_bag.rb
@@ -129,11 +129,10 @@ class Chef
if Chef::Config[:why_run]
Chef::Log.warn("In whyrun mode, so NOT performing data bag save.")
else
- chef_server_rest.put_rest("data/#{@name}", self)
+ create
end
rescue Net::HTTPServerException => e
- raise e unless e.response.code == "404"
- chef_server_rest.post_rest("data", self)
+ raise e unless e.response.code == "409"
end
self
end
diff --git a/lib/chef/dsl/include_recipe.rb b/lib/chef/dsl/include_recipe.rb
index b4d076da10..fc95e38c75 100644
--- a/lib/chef/dsl/include_recipe.rb
+++ b/lib/chef/dsl/include_recipe.rb
@@ -6,9 +6,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
diff --git a/lib/chef/event_dispatch/base.rb b/lib/chef/event_dispatch/base.rb
index 494d3cee79..82beefeec9 100644
--- a/lib/chef/event_dispatch/base.rb
+++ b/lib/chef/event_dispatch/base.rb
@@ -295,7 +295,7 @@ class Chef
# Called when a provider makes an assumption after a failed assertion
# in whyrun mode, in order to allow execution to continue
- def whyrun_assumption(action, resource, message)
+ def whyrun_assumption(action, resource, message)
end
## TODO: deprecation warning. this way we can queue them up and present
diff --git a/lib/chef/event_dispatch/dispatcher.rb b/lib/chef/event_dispatch/dispatcher.rb
index 82da69a60c..c172a406d8 100644
--- a/lib/chef/event_dispatch/dispatcher.rb
+++ b/lib/chef/event_dispatch/dispatcher.rb
@@ -23,7 +23,7 @@ class Chef
# define the forwarding in one go:
#
- # Define a method that will be forwarded to all
+ # Define a method that will be forwarded to all
def self.def_forwarding_method(method_name)
class_eval(<<-END_OF_METHOD, __FILE__, __LINE__)
def #{method_name}(*args)
diff --git a/lib/chef/file_access_control/windows.rb b/lib/chef/file_access_control/windows.rb
index 35a16337ab..32ac2996bd 100644
--- a/lib/chef/file_access_control/windows.rb
+++ b/lib/chef/file_access_control/windows.rb
@@ -220,7 +220,7 @@ class Chef
flags = 0
#
- # Configure child inheritence only if the the resource is some
+ # Configure child inheritence only if the resource is some
# type of a directory.
#
if resource.is_a? Chef::Resource::Directory
diff --git a/lib/chef/formatters/doc.rb b/lib/chef/formatters/doc.rb
index 300311819f..e403ed9f5b 100644
--- a/lib/chef/formatters/doc.rb
+++ b/lib/chef/formatters/doc.rb
@@ -188,13 +188,13 @@ class Chef
def resource_update_applied(resource, action, update)
prefix = Chef::Config[:why_run] ? "Would " : ""
Array(update).each do |line|
- next if line.nil?
+ next if line.nil?
output_record line
if line.kind_of? String
@output.color "\n - #{prefix}#{line}", :green
- elsif line.kind_of? Array
- # Expanded output - delta
- # @todo should we have a resource_update_delta callback?
+ elsif line.kind_of? Array
+ # Expanded output - delta
+ # @todo should we have a resource_update_delta callback?
line.each do |detail|
@output.color "\n #{detail}", :white
end
@@ -216,7 +216,7 @@ class Chef
# Called when a provider makes an assumption after a failed assertion
# in whyrun mode, in order to allow execution to continue
- def whyrun_assumption(action, resource, message)
+ def whyrun_assumption(action, resource, message)
return unless message
[ message ].flatten.each do |line|
@output.color("\n * #{line}", :yellow)
diff --git a/lib/chef/formatters/error_inspectors/api_error_formatting.rb b/lib/chef/formatters/error_inspectors/api_error_formatting.rb
index bb5379ed3f..cb64955961 100644
--- a/lib/chef/formatters/error_inspectors/api_error_formatting.rb
+++ b/lib/chef/formatters/error_inspectors/api_error_formatting.rb
@@ -6,9 +6,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
diff --git a/lib/chef/formatters/error_inspectors/compile_error_inspector.rb b/lib/chef/formatters/error_inspectors/compile_error_inspector.rb
index 1fa8a70b52..93328adbe3 100644
--- a/lib/chef/formatters/error_inspectors/compile_error_inspector.rb
+++ b/lib/chef/formatters/error_inspectors/compile_error_inspector.rb
@@ -6,9 +6,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
diff --git a/lib/chef/formatters/error_inspectors/cookbook_sync_error_inspector.rb b/lib/chef/formatters/error_inspectors/cookbook_sync_error_inspector.rb
index 054984a50e..56a55a296b 100644
--- a/lib/chef/formatters/error_inspectors/cookbook_sync_error_inspector.rb
+++ b/lib/chef/formatters/error_inspectors/cookbook_sync_error_inspector.rb
@@ -6,9 +6,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
diff --git a/lib/chef/formatters/error_inspectors/node_load_error_inspector.rb b/lib/chef/formatters/error_inspectors/node_load_error_inspector.rb
index 7168ac0edb..e257ee30c0 100644
--- a/lib/chef/formatters/error_inspectors/node_load_error_inspector.rb
+++ b/lib/chef/formatters/error_inspectors/node_load_error_inspector.rb
@@ -6,9 +6,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
diff --git a/lib/chef/formatters/error_inspectors/resource_failure_inspector.rb b/lib/chef/formatters/error_inspectors/resource_failure_inspector.rb
index 9ad56bb70b..6f1f71b8f9 100644
--- a/lib/chef/formatters/error_inspectors/resource_failure_inspector.rb
+++ b/lib/chef/formatters/error_inspectors/resource_failure_inspector.rb
@@ -7,9 +7,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
diff --git a/lib/chef/handler/json_file.rb b/lib/chef/handler/json_file.rb
index 977c5a2c92..3473db1838 100644
--- a/lib/chef/handler/json_file.rb
+++ b/lib/chef/handler/json_file.rb
@@ -41,11 +41,11 @@ class Chef
build_report_dir
savetime = Time.now.strftime("%Y%m%d%H%M%S")
File.open(File.join(config[:path], "chef-run-report-#{savetime}.json"), "w") do |file|
-
+
#ensure start time and end time are output in the json properly in the event activesupport happens to be on the system
run_data = data
run_data[:start_time] = run_data[:start_time].to_s
- run_data[:end_time] = run_data[:end_time].to_s
+ run_data[:end_time] = run_data[:end_time].to_s
file.puts Chef::JSONCompat.to_json_pretty(run_data)
end
diff --git a/lib/chef/http.rb b/lib/chef/http.rb
new file mode 100644
index 0000000000..2b2466843e
--- /dev/null
+++ b/lib/chef/http.rb
@@ -0,0 +1,386 @@
+#--
+# Author:: Adam Jacob (<adam@opscode.com>)
+# Author:: Thom May (<thom@clearairturbulence.org>)
+# Author:: Nuo Yan (<nuo@opscode.com>)
+# Author:: Christopher Brown (<cb@opscode.com>)
+# Author:: Christopher Walters (<cw@opscode.com>)
+# Author:: Daniel DeLeo (<dan@opscode.com>)
+# Copyright:: Copyright (c) 2009, 2010, 2013 Opscode, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require 'net/https'
+require 'uri'
+require 'chef/http/basic_client'
+require 'chef/monkey_patches/string'
+require 'chef/monkey_patches/net_http'
+require 'chef/config'
+require 'chef/exceptions'
+
+class Chef
+
+ # == Chef::HTTP
+ # Basic HTTP client, with support for adding features via middleware
+ class HTTP
+
+ # Class for applying middleware behaviors to streaming
+ # responses. Collects stream handlers (if any) from each
+ # middleware. When #handle_chunk is called, the chunk gets
+ # passed to all handlers in turn for processing.
+ class StreamHandler
+ def initialize(middlewares, response)
+ middlewares = middlewares.flatten
+ @stream_handlers = []
+ middlewares.each do |middleware|
+ stream_handler = middleware.stream_response_handler(response)
+ @stream_handlers << stream_handler unless stream_handler.nil?
+ end
+ end
+
+ def handle_chunk(next_chunk)
+ @stream_handlers.inject(next_chunk) do |chunk, handler|
+ handler.handle_chunk(chunk)
+ end
+ end
+
+ end
+
+
+ def self.middlewares
+ @middlewares ||= []
+ end
+
+ def self.use(middleware_class)
+ middlewares << middleware_class
+ end
+
+ attr_reader :url
+ attr_reader :sign_on_redirect
+ attr_reader :redirect_limit
+
+ attr_reader :middlewares
+
+ # Create a HTTP client object. The supplied +url+ is used as the base for
+ # all subsequent requests. For example, when initialized with a base url
+ # http://localhost:4000, a call to +get+ with 'nodes' will make an
+ # HTTP GET request to http://localhost:4000/nodes
+ def initialize(url, options={})
+ @url = url
+ @default_headers = options[:headers] || {}
+ @sign_on_redirect = true
+ @redirects_followed = 0
+ @redirect_limit = 10
+
+ @middlewares = []
+ self.class.middlewares.each do |middleware_class|
+ @middlewares << middleware_class.new(options)
+ end
+ end
+
+ # Send an HTTP HEAD request to the path
+ #
+ # === Parameters
+ # path:: path part of the request URL
+ def head(path, headers={})
+ request(:HEAD, path, headers)
+ end
+
+ # Send an HTTP GET request to the path
+ #
+ # === Parameters
+ # path:: The path to GET
+ def get(path, headers={})
+ request(:GET, path, headers)
+ end
+
+ # Send an HTTP PUT request to the path
+ #
+ # === Parameters
+ # path:: path part of the request URL
+ def put(path, json, headers={})
+ request(:PUT, path, headers, json)
+ end
+
+ # Send an HTTP POST request to the path
+ #
+ # === Parameters
+ # path:: path part of the request URL
+ def post(path, json, headers={})
+ request(:POST, path, headers, json)
+ end
+
+ # Send an HTTP DELETE request to the path
+ #
+ # === Parameters
+ # path:: path part of the request URL
+ def delete(path, headers={})
+ request(:DELETE, path, headers)
+ end
+
+ # Makes an HTTP request to +path+ with the given +method+, +headers+, and
+ # +data+ (if applicable).
+ def request(method, path, headers={}, data=false)
+ url = create_url(path)
+ method, url, headers, data = apply_request_middleware(method, url, headers, data)
+
+ response, rest_request, return_value = send_http_request(method, url, headers, data)
+ response, rest_request, return_value = apply_response_middleware(response, rest_request, return_value)
+ response.error! unless success_response?(response)
+ return_value
+ rescue Exception => exception
+ log_failed_request(response, return_value) unless response.nil?
+
+ if exception.respond_to?(:chef_rest_request=)
+ exception.chef_rest_request = rest_request
+ end
+ raise
+ end
+
+ # Makes a streaming download request, streaming the response body to a
+ # tempfile. If a block is given, the tempfile is passed to the block and
+ # the tempfile will automatically be unlinked after the block is executed.
+ #
+ # If no block is given, the tempfile is returned, which means it's up to
+ # you to unlink the tempfile when you're done with it.
+ def streaming_request(path, headers={}, &block)
+ url = create_url(path)
+ response, rest_request, return_value = nil, nil, nil
+ tempfile = nil
+
+ method = :GET
+ method, url, headers, data = apply_request_middleware(method, url, headers, data)
+
+ response, rest_request, return_value = send_http_request(method, url, headers, data) do |http_response|
+ if http_response.kind_of?(Net::HTTPSuccess)
+ tempfile = stream_to_tempfile(url, http_response)
+ if block_given?
+ begin
+ yield tempfile
+ ensure
+ tempfile && tempfile.close!
+ end
+ end
+ end
+ end
+ unless response.kind_of?(Net::HTTPSuccess) or response.kind_of?(Net::HTTPRedirection)
+ response.error!
+ end
+ tempfile
+ rescue Exception => e
+ log_failed_request(response, return_value) unless response.nil?
+ if e.respond_to?(:chef_rest_request=)
+ e.chef_rest_request = rest_request
+ end
+ raise
+ end
+
+ def http_client(base_url=nil)
+ base_url ||= url
+ BasicClient.new(base_url)
+ end
+
+ protected
+
+ def create_url(path)
+ return path if path.is_a?(URI)
+ if path =~ /^(http|https):\/\//
+ URI.parse(path)
+ elsif path.nil? or path.empty?
+ URI.parse(@url)
+ else
+ URI.parse("#{@url}/#{path}")
+ end
+ end
+
+ def apply_request_middleware(method, url, headers, data)
+ middlewares.inject([method, url, headers, data]) do |req_data, middleware|
+ middleware.handle_request(*req_data)
+ end
+ end
+
+ def apply_response_middleware(response, rest_request, return_value)
+ middlewares.reverse.inject([response, rest_request, return_value]) do |res_data, middleware|
+ middleware.handle_response(*res_data)
+ end
+ end
+
+ def log_failed_request(response, return_value)
+ return_value ||= {}
+ error_message = "HTTP Request Returned #{response.code} #{response.message}: "
+ error_message << (return_value["error"].respond_to?(:join) ? return_value["error"].join(", ") : return_value["error"].to_s)
+ Chef::Log.info(error_message)
+ end
+
+ def success_response?(response)
+ response.kind_of?(Net::HTTPSuccess) || response.kind_of?(Net::HTTPRedirection)
+ end
+
+ # Runs a synchronous HTTP request, with no middleware applied (use #request
+ # to have the middleware applied). The entire response will be loaded into memory.
+ def send_http_request(method, url, headers, body, &response_handler)
+ headers = build_headers(method, url, headers, body)
+
+ retrying_http_errors(url) do
+ client = http_client(url)
+ return_value = nil
+ if block_given?
+ request, response = client.request(method, url, body, headers, &response_handler)
+ else
+ request, response = client.request(method, url, body, headers) {|r| r.read_body }
+ return_value = response.read_body
+ end
+ @last_response = response
+
+ Chef::Log.debug("---- HTTP Status and Header Data: ----")
+ Chef::Log.debug("HTTP #{response.http_version} #{response.code} #{response.msg}")
+
+ response.each do |header, value|
+ Chef::Log.debug("#{header}: #{value}")
+ end
+ Chef::Log.debug("---- End HTTP Status/Header Data ----")
+
+ if response.kind_of?(Net::HTTPSuccess)
+ [response, request, return_value]
+ elsif response.kind_of?(Net::HTTPNotModified) # Must be tested before Net::HTTPRedirection because it's subclass.
+ [response, request, false]
+ elsif redirect_location = redirected_to(response)
+ if [:GET, :HEAD].include?(method)
+ follow_redirect do
+ send_http_request(method, create_url(redirect_location), headers, body, &response_handler)
+ end
+ else
+ raise Exceptions::InvalidRedirect, "#{method} request was redirected from #{url} to #{redirect_location}. Only GET and HEAD support redirects."
+ end
+ else
+ [response, request, nil]
+ end
+ end
+ end
+
+
+ # Wraps an HTTP request with retry logic.
+ # === Arguments
+ # url:: URL of the request, used for error messages
+ def retrying_http_errors(url)
+ http_attempts = 0
+ begin
+ http_attempts += 1
+
+ yield
+
+ rescue SocketError, Errno::ETIMEDOUT => e
+ e.message.replace "Error connecting to #{url} - #{e.message}"
+ raise e
+ rescue Errno::ECONNREFUSED
+ if http_retry_count - http_attempts + 1 > 0
+ Chef::Log.error("Connection refused connecting to #{url}, retry #{http_attempts}/#{http_retry_count}")
+ sleep(http_retry_delay)
+ retry
+ end
+ raise Errno::ECONNREFUSED, "Connection refused connecting to #{url}, giving up"
+ rescue Timeout::Error
+ if http_retry_count - http_attempts + 1 > 0
+ Chef::Log.error("Timeout connecting to #{url}, retry #{http_attempts}/#{http_retry_count}")
+ sleep(http_retry_delay)
+ retry
+ end
+ raise Timeout::Error, "Timeout connecting to #{url}, giving up"
+ rescue Net::HTTPFatalError => e
+ if http_retry_count - http_attempts + 1 > 0
+ sleep_time = 1 + (2 ** http_attempts) + rand(2 ** http_attempts)
+ Chef::Log.error("Server returned error for #{url}, retrying #{http_attempts}/#{http_retry_count} in #{sleep_time}s")
+ sleep(sleep_time)
+ retry
+ end
+ raise
+ end
+ end
+
+ def http_retry_delay
+ config[:http_retry_delay]
+ end
+
+ def http_retry_count
+ config[:http_retry_count]
+ end
+
+ def config
+ Chef::Config
+ end
+
+ def follow_redirect
+ raise Chef::Exceptions::RedirectLimitExceeded if @redirects_followed >= redirect_limit
+ @redirects_followed += 1
+ Chef::Log.debug("Following redirect #{@redirects_followed}/#{redirect_limit}")
+
+ yield
+ ensure
+ @redirects_followed = 0
+ end
+
+ private
+
+ def redirected_to(response)
+ return nil unless response.kind_of?(Net::HTTPRedirection)
+ # Net::HTTPNotModified is undesired subclass of Net::HTTPRedirection so test for this
+ return nil if response.kind_of?(Net::HTTPNotModified)
+ response['location']
+ end
+
+ def build_headers(method, url, headers={}, json_body=false)
+ headers = @default_headers.merge(headers)
+ headers['Content-Length'] = json_body.bytesize.to_s if json_body
+ headers.merge!(Chef::Config[:custom_http_headers]) if Chef::Config[:custom_http_headers]
+ headers
+ end
+
+ def stream_to_tempfile(url, response)
+ tf = Tempfile.open("chef-rest")
+ if Chef::Platform.windows?
+ tf.binmode # required for binary files on Windows platforms
+ end
+ Chef::Log.debug("Streaming download from #{url.to_s} to tempfile #{tf.path}")
+ # Stolen from http://www.ruby-forum.com/topic/166423
+ # Kudos to _why!
+
+ stream_handler = StreamHandler.new(middlewares, response)
+
+ response.read_body do |chunk|
+ tf.write(stream_handler.handle_chunk(chunk))
+ end
+ tf.close
+ tf
+ rescue Exception
+ tf.close!
+ raise
+ end
+
+
+ public
+
+ ############################################################################
+ # DEPRECATED
+ ############################################################################
+
+ # This is only kept around to provide access to cache control data in
+ # lib/chef/provider/remote_file/http.rb
+ # Find a better API.
+ def last_response
+ @last_response
+ end
+
+ end
+end
+
diff --git a/lib/chef/rest/auth_credentials.rb b/lib/chef/http/auth_credentials.rb
index 00711c960d..bd73524b1f 100644
--- a/lib/chef/rest/auth_credentials.rb
+++ b/lib/chef/http/auth_credentials.rb
@@ -24,7 +24,7 @@ require 'chef/log'
require 'mixlib/authentication/signedheaderauth'
class Chef
- class REST
+ class HTTP
class AuthCredentials
attr_reader :client_name, :key
diff --git a/lib/chef/http/authenticator.rb b/lib/chef/http/authenticator.rb
new file mode 100644
index 0000000000..489675ad66
--- /dev/null
+++ b/lib/chef/http/authenticator.rb
@@ -0,0 +1,89 @@
+#--
+# Author:: Daniel DeLeo (<dan@opscode.com>)
+# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require 'chef/http/auth_credentials'
+require 'chef/exceptions'
+require 'openssl'
+
+class Chef
+ class HTTP
+ class Authenticator
+
+ attr_reader :signing_key_filename
+ attr_reader :raw_key
+ attr_reader :attr_names
+ attr_reader :auth_credentials
+
+ attr_accessor :sign_request
+
+ def initialize(opts={})
+ @raw_key = nil
+ @sign_request = true
+ @signing_key_filename = opts[:signing_key_filename]
+ @key = load_signing_key(opts[:signing_key_filename], opts[:raw_key])
+ @auth_credentials = AuthCredentials.new(opts[:client_name], @key)
+ end
+
+ def handle_request(method, url, headers={}, data=false)
+ headers.merge!(authentication_headers(method, url, data)) if sign_requests?
+ [method, url, headers, data]
+ end
+
+ def handle_response(http_response, rest_request, return_value)
+ [http_response, rest_request, return_value]
+ end
+
+ def stream_response_handler(response)
+ nil
+ end
+
+ def sign_requests?
+ auth_credentials.sign_requests? && @sign_request
+ end
+
+ def client_name
+ @auth_credentials.client_name
+ end
+
+ def load_signing_key(key_file, raw_key = nil)
+ if (!!key_file)
+ @raw_key = IO.read(key_file).strip
+ elsif (!!raw_key)
+ @raw_key = raw_key.strip
+ else
+ return nil
+ end
+ @key = OpenSSL::PKey::RSA.new(@raw_key)
+ rescue SystemCallError, IOError => e
+ Chef::Log.warn "Failed to read the private key #{key_file}: #{e.inspect}"
+ raise Chef::Exceptions::PrivateKeyMissing, "I cannot read #{key_file}, which you told me to use to sign requests!"
+ rescue OpenSSL::PKey::RSAError
+ msg = "The file #{key_file} or :raw_key option does not contain a correctly formatted private key.\n"
+ msg << "The key file should begin with '-----BEGIN RSA PRIVATE KEY-----' and end with '-----END RSA PRIVATE KEY-----'"
+ raise Chef::Exceptions::InvalidPrivateKey, msg
+ end
+
+ def authentication_headers(method, url, json_body=nil)
+ request_params = {:http_method => method, :path => url.path, :body => json_body, :host => "#{url.host}:#{url.port}"}
+ request_params[:body] ||= ""
+ auth_credentials.signature_headers(request_params)
+ end
+
+ end
+ end
+end
diff --git a/lib/chef/http/basic_client.rb b/lib/chef/http/basic_client.rb
new file mode 100644
index 0000000000..5ee0fbf88d
--- /dev/null
+++ b/lib/chef/http/basic_client.rb
@@ -0,0 +1,114 @@
+#--
+# Author:: Adam Jacob (<adam@opscode.com>)
+# Author:: Thom May (<thom@clearairturbulence.org>)
+# Author:: Nuo Yan (<nuo@opscode.com>)
+# Author:: Christopher Brown (<cb@opscode.com>)
+# Author:: Christopher Walters (<cw@opscode.com>)
+# Author:: Daniel DeLeo (<dan@opscode.com>)
+# Copyright:: Copyright (c) 2009, 2010 Opscode, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+require 'uri'
+require 'net/http'
+require 'chef/http/ssl_policies'
+require 'chef/http/http_request'
+
+class Chef
+ class HTTP
+ class BasicClient
+
+ HTTPS = "https".freeze
+
+ attr_reader :url
+ attr_reader :http_client
+ attr_reader :ssl_policy
+
+ # Instantiate a BasicClient.
+ # === Arguments:
+ # url:: An URI for the remote server.
+ # === Options:
+ # ssl_policy:: The SSL Policy to use, defaults to DefaultSSLPolicy
+ def initialize(url, opts={})
+ @url = url
+ @ssl_policy = opts[:ssl_policy] || DefaultSSLPolicy
+ @http_client = build_http_client
+ end
+
+ def host
+ @url.host
+ end
+
+ def port
+ @url.port
+ end
+
+ def request(method, url, req_body, base_headers={})
+ http_request = HTTPRequest.new(method, url, req_body, base_headers).http_request
+ Chef::Log.debug("Initiating #{method} to #{url}")
+ http_client.request(http_request) do |response|
+ yield response if block_given?
+ # http_client.request may not have the return signature we want, so
+ # force the issue:
+ return [http_request, response]
+ end
+ rescue OpenSSL::SSL::SSLError => e
+ Chef::Log.error("SSL Validation failure connecting to host: #{host} - #{e.message}")
+ raise
+ end
+
+ #adapted from buildr/lib/buildr/core/transports.rb
+ def proxy_uri
+ proxy = Chef::Config["#{url.scheme}_proxy"]
+ proxy = URI.parse(proxy) if String === proxy
+ excludes = Chef::Config[:no_proxy].to_s.split(/\s*,\s*/).compact
+ excludes = excludes.map { |exclude| exclude =~ /:\d+$/ ? exclude : "#{exclude}:*" }
+ return proxy unless excludes.any? { |exclude| File.fnmatch(exclude, "#{host}:#{port}") }
+ end
+
+ def build_http_client
+ http_client = http_client_builder.new(host, port)
+
+ if url.scheme == HTTPS
+ configure_ssl(http_client)
+ end
+
+ http_client.read_timeout = config[:rest_timeout]
+ http_client
+ end
+
+ def config
+ Chef::Config
+ end
+
+ def http_client_builder
+ http_proxy = proxy_uri
+ if http_proxy.nil?
+ Net::HTTP
+ else
+ Chef::Log.debug("Using #{http_proxy.host}:#{http_proxy.port} for proxy")
+ user = Chef::Config["#{url.scheme}_proxy_user"]
+ pass = Chef::Config["#{url.scheme}_proxy_pass"]
+ Net::HTTP.Proxy(http_proxy.host, http_proxy.port, user, pass)
+ end
+ end
+
+ def configure_ssl(http_client)
+ http_client.use_ssl = true
+ ssl_policy.apply_to(http_client)
+ end
+
+ end
+ end
+end
diff --git a/lib/chef/rest/cookie_jar.rb b/lib/chef/http/cookie_jar.rb
index e3137708a2..418fb1d352 100644
--- a/lib/chef/rest/cookie_jar.rb
+++ b/lib/chef/http/cookie_jar.rb
@@ -23,7 +23,7 @@
require 'singleton'
class Chef
- class REST
+ class HTTP
class CookieJar < Hash
include Singleton
end
diff --git a/lib/chef/http/cookie_manager.rb b/lib/chef/http/cookie_manager.rb
new file mode 100644
index 0000000000..f6dcf9aa32
--- /dev/null
+++ b/lib/chef/http/cookie_manager.rb
@@ -0,0 +1,56 @@
+#--
+# Author:: Daniel DeLeo (<dan@opscode.com>)
+# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require 'chef/http/cookie_jar'
+
+class Chef
+ class HTTP
+
+ # An HTTP middleware to manage storing/sending cookies in HTTP requests.
+ # Most HTTP communication in Chef does not need cookies, it was originally
+ # implemented to support OpenID, but it's not known who might be relying on
+ # it, so it's included with Chef::REST
+ class CookieManager
+
+ def initialize(options={})
+ @cookies = CookieJar.instance
+ end
+
+ def handle_request(method, url, headers={}, data=false)
+ @host, @port = url.host, url.port
+ if @cookies.has_key?("#{@host}:#{@port}")
+ headers['Cookie'] = @cookies["#{@host}:#{@port}"]
+ end
+ [method, url, headers, data]
+ end
+
+ def handle_response(http_response, rest_request, return_value)
+ if http_response['set-cookie']
+ @cookies["#{@host}:#{@port}"] = http_response['set-cookie']
+ end
+ [http_response, rest_request, return_value]
+ end
+
+ def stream_response_handler(response)
+ nil
+ end
+
+
+ end
+ end
+end
diff --git a/lib/chef/http/decompressor.rb b/lib/chef/http/decompressor.rb
new file mode 100644
index 0000000000..6010ffa698
--- /dev/null
+++ b/lib/chef/http/decompressor.rb
@@ -0,0 +1,137 @@
+#--
+# Author:: Daniel DeLeo (<dan@opscode.com>)
+# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require 'zlib'
+require 'chef/http/http_request'
+
+class Chef
+ class HTTP
+
+ # Middleware-esque class for handling compression in HTTP responses.
+ class Decompressor
+ class NoopInflater
+ def inflate(chunk)
+ chunk
+ end
+ alias :handle_chunk :inflate
+ end
+
+ class GzipInflater < Zlib::Inflate
+ def initialize
+ super(Zlib::MAX_WBITS + 16)
+ end
+ alias :handle_chunk :inflate
+ end
+
+ class DeflateInflater < Zlib::Inflate
+ def initialize
+ super
+ end
+ alias :handle_chunk :inflate
+ end
+
+ CONTENT_ENCODING = "content-encoding".freeze
+ GZIP = "gzip".freeze
+ DEFLATE = "deflate".freeze
+ IDENTITY = "identity".freeze
+
+ def initialize(opts={})
+ @disable_gzip = false
+ handle_options(opts)
+ end
+
+ def handle_request(method, url, headers={}, data=false)
+ headers[HTTPRequest::ACCEPT_ENCODING] = HTTPRequest::ENCODING_GZIP_DEFLATE unless gzip_disabled?
+ [method, url, headers, data]
+ end
+
+ def handle_response(http_response, rest_request, return_value)
+ # temporary hack, skip processing if return_value is false
+ # needed to keep conditional get stuff working correctly.
+ return [http_response, rest_request, return_value] if return_value == false
+ response_body = decompress_body(http_response)
+ http_response.body.replace(response_body) if http_response.body.respond_to?(:replace)
+ [http_response, rest_request, return_value]
+ end
+
+ def decompress_body(response)
+ if gzip_disabled? || response.body.nil?
+ response.body
+ else
+ case response[CONTENT_ENCODING]
+ when GZIP
+ Chef::Log.debug "decompressing gzip response"
+ Zlib::Inflate.new(Zlib::MAX_WBITS + 16).inflate(response.body)
+ when DEFLATE
+ Chef::Log.debug "decompressing deflate response"
+ Zlib::Inflate.inflate(response.body)
+ else
+ response.body
+ end
+ end
+ end
+
+ # This isn't used when this class is used as middleware; it returns an
+ # object you can use to unzip/inflate a streaming response.
+ def stream_response_handler(response)
+ if gzip_disabled?
+ NoopInflater.new
+ else
+ case response[CONTENT_ENCODING]
+ when GZIP
+ Chef::Log.debug "decompressing gzip stream"
+ GzipInflater.new
+ when DEFLATE
+ Chef::Log.debug "decompressing inflate stream"
+ DeflateInflater.new
+ else
+ NoopInflater.new
+ end
+ end
+ end
+
+
+ # gzip is disabled using the disable_gzip => true option in the
+ # constructor. When gzip is disabled, no 'Accept-Encoding' header will be
+ # set, and the response will not be decompressed, no matter what the
+ # Content-Encoding header of the response is. The intended use case for
+ # this is to work around situations where you request +file.tar.gz+, but
+ # the server responds with a content type of tar and a content encoding of
+ # gzip, tricking the client into decompressing the response so you end up
+ # with a tar archive (no gzip) named file.tar.gz
+ def gzip_disabled?
+ @disable_gzip
+ end
+
+ private
+
+ def handle_options(opts)
+ opts.each do |name, value|
+ case name.to_s
+ when 'disable_gzip'
+ @disable_gzip = value
+ end
+ end
+ end
+
+
+ end
+ end
+end
+
+
diff --git a/lib/chef/rest/rest_request.rb b/lib/chef/http/http_request.rb
index ff9738de99..ec837f13f2 100644
--- a/lib/chef/rest/rest_request.rb
+++ b/lib/chef/http/http_request.rb
@@ -22,7 +22,6 @@
#
require 'uri'
require 'net/http'
-require 'chef/rest/cookie_jar'
# To load faster, we only want ohai's version string.
# However, in ohai before 0.6.0, the version is defined
@@ -36,8 +35,8 @@ end
require 'chef/version'
class Chef
- class REST
- class RESTRequest
+ class HTTP
+ class HTTPRequest
engine = defined?(RUBY_ENGINE) ? RUBY_ENGINE : "ruby"
@@ -72,8 +71,6 @@ class Chef
def initialize(method, url, req_body, base_headers={})
@method, @url = method, url
@request_body = nil
- @cookies = CookieJar.instance
- configure_http_client
build_headers(base_headers)
configure_http_request(req_body)
end
@@ -94,10 +91,10 @@ class Chef
@url.path.empty? ? SLASH : @url.path
end
+ # DEPRECATED. Call request on an HTTP client object instead.
def call
hide_net_http_bug do
http_client.request(http_request) do |response|
- store_cookie(response)
yield response if block_given?
response
end
@@ -108,6 +105,11 @@ class Chef
Chef::Config
end
+ # DEPRECATED. Call request on an HTTP client object instead.
+ def http_client
+ @http_client ||= BasicClient.new(url).http_client
+ end
+
private
def hide_net_http_bug
@@ -125,77 +127,12 @@ class Chef
end
end
- def store_cookie(response)
- if response['set-cookie']
- @cookies["#{host}:#{port}"] = response['set-cookie']
- end
- end
-
def build_headers(headers)
@headers = headers.dup
- # TODO: need to set accept somewhere else
- # headers.merge!('Accept' => "application/json") unless raw
+ # No response compression unless we asked for it explicitly:
+ @headers[HTTPRequest::ACCEPT_ENCODING] ||= "identity"
@headers['X-Chef-Version'] = ::Chef::VERSION
- @headers[ACCEPT_ENCODING] = ENCODING_GZIP_DEFLATE
-
- if @cookies.has_key?("#{host}:#{port}")
- @headers['Cookie'] = @cookies["#{host}:#{port}"]
- end
- end
-
- #adapted from buildr/lib/buildr/core/transports.rb
- def proxy_uri
- proxy = Chef::Config["#{url.scheme}_proxy"]
- proxy = URI.parse(proxy) if String === proxy
- excludes = Chef::Config[:no_proxy].to_s.split(/\s*,\s*/).compact
- excludes = excludes.map { |exclude| exclude =~ /:\d+$/ ? exclude : "#{exclude}:*" }
- return proxy unless excludes.any? { |exclude| File.fnmatch(exclude, "#{host}:#{port}") }
- end
-
- def configure_http_client
- http_proxy = proxy_uri
- if http_proxy.nil?
- @http_client = Net::HTTP.new(host, port)
- else
- Chef::Log.debug("Using #{http_proxy.host}:#{http_proxy.port} for proxy")
- user = Chef::Config["#{url.scheme}_proxy_user"]
- pass = Chef::Config["#{url.scheme}_proxy_pass"]
- @http_client = Net::HTTP.Proxy(http_proxy.host, http_proxy.port, user, pass).new(host, port)
- end
- if url.scheme == HTTPS
- @http_client.use_ssl = true
- if config[:ssl_verify_mode] == :verify_none
- @http_client.verify_mode = OpenSSL::SSL::VERIFY_NONE
- elsif config[:ssl_verify_mode] == :verify_peer
- @http_client.verify_mode = OpenSSL::SSL::VERIFY_PEER
- end
- if config[:ssl_ca_path]
- unless ::File.exist?(config[:ssl_ca_path])
- raise Chef::Exceptions::ConfigurationError, "The configured ssl_ca_path #{config[:ssl_ca_path]} does not exist"
- end
- @http_client.ca_path = config[:ssl_ca_path]
- elsif config[:ssl_ca_file]
- unless ::File.exist?(config[:ssl_ca_file])
- raise Chef::Exceptions::ConfigurationError, "The configured ssl_ca_file #{config[:ssl_ca_file]} does not exist"
- end
- @http_client.ca_file = config[:ssl_ca_file]
- end
- if (config[:ssl_client_cert] || config[:ssl_client_key])
- unless (config[:ssl_client_cert] && config[:ssl_client_key])
- raise Chef::Exceptions::ConfigurationError, "You must configure ssl_client_cert and ssl_client_key together"
- end
- unless ::File.exists?(config[:ssl_client_cert])
- raise Chef::Exceptions::ConfigurationError, "The configured ssl_client_cert #{config[:ssl_client_cert]} does not exist"
- end
- unless ::File.exists?(config[:ssl_client_key])
- raise Chef::Exceptions::ConfigurationError, "The configured ssl_client_key #{config[:ssl_client_key]} does not exist"
- end
- @http_client.cert = OpenSSL::X509::Certificate.new(::File.read(config[:ssl_client_cert]))
- @http_client.key = OpenSSL::PKey::RSA.new(::File.read(config[:ssl_client_key]))
- end
- end
-
- @http_client.read_timeout = config[:rest_timeout]
+ @headers
end
@@ -225,6 +162,8 @@ class Chef
password = URI.unescape(url.password) if url.password
@http_request.basic_auth(user, password)
end
+
+ # Overwrite default UA
@http_request[USER_AGENT] = self.class.user_agent
end
diff --git a/lib/chef/http/json_input.rb b/lib/chef/http/json_input.rb
new file mode 100644
index 0000000000..741c48f5f6
--- /dev/null
+++ b/lib/chef/http/json_input.rb
@@ -0,0 +1,53 @@
+#--
+# Author:: Daniel DeLeo (<dan@opscode.com>)
+# Author:: John Keiser (<jkeiser@opscode.com>)
+# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require 'chef/json_compat'
+
+class Chef
+ class HTTP
+
+ # Middleware that takes json input and turns it into raw text
+ class JSONInput
+
+ def initialize(opts={})
+ end
+
+ def handle_request(method, url, headers={}, data=false)
+ if data
+ headers["Content-Type"] = 'application/json'
+ data = Chef::JSONCompat.to_json(data)
+ # Force encoding to binary to fix SSL related EOFErrors
+ # cf. http://tickets.opscode.com/browse/CHEF-2363
+ # http://redmine.ruby-lang.org/issues/5233
+ data.force_encoding(Encoding::BINARY) if data.respond_to?(:force_encoding)
+ end
+ [method, url, headers, data]
+ end
+
+ def handle_response(http_response, rest_request, return_value)
+ [http_response, rest_request, return_value]
+ end
+
+ def stream_response_handler(response)
+ nil
+ end
+
+ end
+ end
+end
diff --git a/lib/chef/http/json_output.rb b/lib/chef/http/json_output.rb
new file mode 100644
index 0000000000..48407d933f
--- /dev/null
+++ b/lib/chef/http/json_output.rb
@@ -0,0 +1,69 @@
+#--
+# Author:: Daniel DeLeo (<dan@opscode.com>)
+# Author:: John Keiser (<jkeiser@opscode.com>)
+# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require 'chef/json_compat'
+require 'chef/log'
+
+class Chef
+ class HTTP
+
+ # Middleware that takes an HTTP response, parses it as JSON if possible.
+ class JSONOutput
+
+ def initialize(opts={})
+ @raw_output = opts[:raw_output]
+ @inflate_json_class = opts[:inflate_json_class]
+ end
+
+ def handle_request(method, url, headers={}, data=false)
+ # Ideally this should always set Accept to application/json, but
+ # Chef::REST is sometimes used to make non-JSON requests, so it sets
+ # Accept to the desired value before middlewares get called.
+ headers['Accept'] ||= 'application/json'
+ [method, url, headers, data]
+ end
+
+ def handle_response(http_response, rest_request, return_value)
+ # temporary hack, skip processing if return_value is false
+ # needed to keep conditional get stuff working correctly.
+ return [http_response, rest_request, return_value] if return_value == false
+ if http_response['content-type'] =~ /json/
+ if @raw_output
+ return_value = http_response.body.to_s
+ else
+ if @inflate_json_class
+ return_value = Chef::JSONCompat.from_json(http_response.body.chomp)
+ else
+ return_value = Chef::JSONCompat.from_json(http_response.body.chomp, :create_additions => false)
+ end
+ end
+ [http_response, rest_request, return_value]
+ else
+ Chef::Log.warn("Expected JSON response, but got content-type '#{http_response['content-type']}'")
+ return [http_response, rest_request, http_response.body.to_s]
+ end
+ end
+
+ def stream_response_handler(response)
+ nil
+ end
+
+ end
+ end
+end
diff --git a/lib/chef/http/json_to_model_output.rb b/lib/chef/http/json_to_model_output.rb
new file mode 100644
index 0000000000..9bc90a52ae
--- /dev/null
+++ b/lib/chef/http/json_to_model_output.rb
@@ -0,0 +1,34 @@
+#--
+# Author:: Daniel DeLeo (<dan@opscode.com>)
+# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require 'chef/http/json_output'
+
+class Chef
+ class HTTP
+
+ # A Middleware-ish thing that takes an HTTP response, parses it as JSON if
+ # possible, and converts it into an appropriate model object if it contains
+ # a `json_class` key.
+ class JSONToModelOutput < JSONOutput
+ def initialize(opts={})
+ opts[:inflate_json_class] = true if !opts.has_key?(:inflate_json_class)
+ super
+ end
+ end
+ end
+end
diff --git a/lib/chef/http/simple.rb b/lib/chef/http/simple.rb
new file mode 100644
index 0000000000..0ecb28846c
--- /dev/null
+++ b/lib/chef/http/simple.rb
@@ -0,0 +1,16 @@
+require 'chef/http'
+require 'chef/http/authenticator'
+require 'chef/http/decompressor'
+
+
+class Chef
+ class HTTP
+
+ class Simple < HTTP
+
+ use Decompressor
+ use CookieManager
+
+ end
+ end
+end
diff --git a/lib/chef/http/ssl_policies.rb b/lib/chef/http/ssl_policies.rb
new file mode 100644
index 0000000000..17b46a6762
--- /dev/null
+++ b/lib/chef/http/ssl_policies.rb
@@ -0,0 +1,121 @@
+#--
+# Author:: Adam Jacob (<adam@opscode.com>)
+# Author:: Thom May (<thom@clearairturbulence.org>)
+# Author:: Nuo Yan (<nuo@opscode.com>)
+# Author:: Christopher Brown (<cb@opscode.com>)
+# Author:: Christopher Walters (<cw@opscode.com>)
+# Author:: Daniel DeLeo (<dan@opscode.com>)
+# Copyright:: Copyright (c) 2009, 2010, 2013 Opscode, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require 'openssl'
+
+class Chef
+ class HTTP
+
+ # == Chef::HTTP::DefaultSSLPolicy
+ # Configures SSL behavior on an HTTP object via visitor pattern.
+ class DefaultSSLPolicy
+
+ def self.apply_to(http_client)
+ new(http_client).apply
+ http_client
+ end
+
+ attr_reader :http_client
+
+ def initialize(http_client)
+ @http_client = http_client
+ end
+
+ def apply
+ set_verify_mode
+ set_ca_store
+ set_custom_certs
+ set_client_credentials
+ end
+
+ def set_verify_mode
+ if config[:ssl_verify_mode] == :verify_none
+ http_client.verify_mode = OpenSSL::SSL::VERIFY_NONE
+ elsif config[:ssl_verify_mode] == :verify_peer
+ http_client.verify_mode = OpenSSL::SSL::VERIFY_PEER
+ end
+ end
+
+ def set_ca_store
+ if config[:ssl_ca_path]
+ unless ::File.exist?(config[:ssl_ca_path])
+ raise Chef::Exceptions::ConfigurationError, "The configured ssl_ca_path #{config[:ssl_ca_path]} does not exist"
+ end
+ http_client.ca_path = config[:ssl_ca_path]
+ elsif config[:ssl_ca_file]
+ unless ::File.exist?(config[:ssl_ca_file])
+ raise Chef::Exceptions::ConfigurationError, "The configured ssl_ca_file #{config[:ssl_ca_file]} does not exist"
+ end
+ http_client.ca_file = config[:ssl_ca_file]
+ end
+ end
+
+ def set_custom_certs
+ unless http_client.cert_store
+ http_client.cert_store = OpenSSL::X509::Store.new
+ http_client.cert_store.set_default_paths
+ end
+ if config.trusted_certs_dir
+ certs = Dir.glob(File.join(config.trusted_certs_dir, "*.{crt,pem}"))
+ certs.each do |cert_file|
+ cert = OpenSSL::X509::Certificate.new(File.read(cert_file))
+ http_client.cert_store.add_cert(cert)
+ end
+ end
+ end
+
+ def set_client_credentials
+ if (config[:ssl_client_cert] || config[:ssl_client_key])
+ unless (config[:ssl_client_cert] && config[:ssl_client_key])
+ raise Chef::Exceptions::ConfigurationError, "You must configure ssl_client_cert and ssl_client_key together"
+ end
+ unless ::File.exists?(config[:ssl_client_cert])
+ raise Chef::Exceptions::ConfigurationError, "The configured ssl_client_cert #{config[:ssl_client_cert]} does not exist"
+ end
+ unless ::File.exists?(config[:ssl_client_key])
+ raise Chef::Exceptions::ConfigurationError, "The configured ssl_client_key #{config[:ssl_client_key]} does not exist"
+ end
+ http_client.cert = OpenSSL::X509::Certificate.new(::File.read(config[:ssl_client_cert]))
+ http_client.key = OpenSSL::PKey::RSA.new(::File.read(config[:ssl_client_key]))
+ end
+ end
+
+ def config
+ Chef::Config
+ end
+
+ end
+
+ class APISSLPolicy < DefaultSSLPolicy
+
+ def set_verify_mode
+ if config[:ssl_verify_mode] == :verify_peer or config[:verify_api_cert]
+ http_client.verify_mode = OpenSSL::SSL::VERIFY_PEER
+ elsif config[:ssl_verify_mode] == :verify_none
+ http_client.verify_mode = OpenSSL::SSL::VERIFY_NONE
+ end
+ end
+ end
+
+ end
+end
diff --git a/lib/chef/knife.rb b/lib/chef/knife.rb
index 9c48925216..341402242e 100644
--- a/lib/chef/knife.rb
+++ b/lib/chef/knife.rb
@@ -20,6 +20,7 @@
require 'forwardable'
require 'chef/version'
require 'mixlib/cli'
+require 'chef/config_fetcher'
require 'chef/mixin/convert_to_class_name'
require 'chef/mixin/path_sanity'
require 'chef/knife/core/subcommand_loader'
@@ -314,7 +315,11 @@ class Chef
config_file_settings
end
- def locate_config_file
+ def self.config_fetcher(candidate_config)
+ Chef::ConfigFetcher.new(candidate_config, Chef::Config.config_file_jail)
+ end
+
+ def self.locate_config_file
candidate_configs = []
# Look for $KNIFE_HOME/knife.rb (allow multiple knives config on same machine)
@@ -326,8 +331,8 @@ class Chef
candidate_configs << File.join(Dir.pwd, 'knife.rb')
end
# Look for $UPWARD/.chef/knife.rb
- if self.class.chef_config_dir
- candidate_configs << File.join(self.class.chef_config_dir, 'knife.rb')
+ if chef_config_dir
+ candidate_configs << File.join(chef_config_dir, 'knife.rb')
end
# Look for $HOME/.chef/knife.rb
if ENV['HOME']
@@ -335,12 +340,12 @@ class Chef
end
candidate_configs.each do | candidate_config |
- candidate_config = File.expand_path(candidate_config)
- if File.exist?(candidate_config)
- config[:config_file] = candidate_config
- break
+ fetcher = config_fetcher(candidate_config)
+ if !fetcher.config_missing?
+ return candidate_config
end
end
+ return nil
end
# Apply Config in this order:
@@ -379,6 +384,12 @@ class Chef
Chef::Config[:chef_server_url] = config[:chef_server_url] if config[:chef_server_url]
Chef::Config[:environment] = config[:environment] if config[:environment]
+ Chef::Config.local_mode = config[:local_mode] if config.has_key?(:local_mode)
+ if Chef::Config.local_mode && !Chef::Config.has_key?(:cookbook_path) && !Chef::Config.has_key?(:chef_repo_path)
+ Chef::Config.chef_repo_path = Chef::Config.find_chef_repo_path(Dir.pwd)
+ end
+ Chef::Config.chef_zero.port = config[:chef_zero_port] if config[:chef_zero_port]
+
# Expand a relative path from the config directory. Config from command
# line should already be expanded, and absolute paths will be unchanged.
if Chef::Config[:client_key] && config[:config_file]
@@ -397,14 +408,20 @@ class Chef
end
def configure_chef
- unless config[:config_file]
- locate_config_file
+ if !config[:config_file]
+ located_config_file = self.class.locate_config_file
+ config[:config_file] = located_config_file if located_config_file
end
- # Don't try to load a knife.rb if it doesn't exist.
+ # Don't try to load a knife.rb if it wasn't specified.
if config[:config_file]
+ fetcher = Chef::ConfigFetcher.new(config[:config_file], Chef::Config.config_file_jail)
+ if fetcher.config_missing?
+ ui.error("Specified config file #{config[:config_file]} does not exist#{Chef::Config.config_file_jail ? " or is not under config file jail #{Chef::Config.config_file_jail}" : ""}!")
+ exit 1
+ end
Chef::Log.debug("Using configuration from #{config[:config_file]}")
- read_config_file(config[:config_file])
+ read_config(fetcher.read_config, config[:config_file])
else
# ...but do log a message if no config was found.
Chef::Config[:color] = config[:color]
@@ -415,24 +432,24 @@ class Chef
apply_computed_config
end
- def read_config_file(file)
- Chef::Config.from_file(file)
+ def read_config(config_content, config_file_path)
+ Chef::Config.from_string(config_content, config_file_path)
rescue SyntaxError => e
- ui.error "You have invalid ruby syntax in your config file #{file}"
+ ui.error "You have invalid ruby syntax in your config file #{config_file_path}"
ui.info(ui.color(e.message, :red))
- if file_line = e.message[/#{Regexp.escape(file)}:[\d]+/]
+ if file_line = e.message[/#{Regexp.escape(config_file_path)}:[\d]+/]
line = file_line[/:([\d]+)$/, 1].to_i
- highlight_config_error(file, line)
+ highlight_config_error(config_file_path, line)
end
exit 1
rescue Exception => e
- ui.error "You have an error in your config file #{file}"
+ ui.error "You have an error in your config file #{config_file_path}"
ui.info "#{e.class.name}: #{e.message}"
- filtered_trace = e.backtrace.grep(/#{Regexp.escape(file)}/)
+ filtered_trace = e.backtrace.grep(/#{Regexp.escape(config_file_path)}/)
filtered_trace.each {|line| ui.msg(" " + ui.color(line, :red))}
if !filtered_trace.empty?
- line_nr = filtered_trace.first[/#{Regexp.escape(file)}:([\d]+)/, 1]
- highlight_config_error(file, line_nr.to_i)
+ line_nr = filtered_trace.first[/#{Regexp.escape(config_file_path)}:([\d]+)/, 1]
+ highlight_config_error(config_file_path, line_nr.to_i)
end
exit 1
@@ -458,14 +475,19 @@ class Chef
stdout.puts("USAGE: " + self.opt_parser.to_s)
end
- def run_with_pretty_exceptions
+ def run_with_pretty_exceptions(raise_exception = false)
unless self.respond_to?(:run)
ui.error "You need to add a #run method to your knife command before you can use it"
end
enforce_path_sanity
- run
+ Chef::Application.setup_server_connectivity
+ begin
+ run
+ ensure
+ Chef::Application.destroy_server_connectivity
+ end
rescue Exception => e
- raise if Chef::Config[:verbosity] == 2
+ raise if raise_exception || Chef::Config[:verbosity] == 2
humanize_exception(e)
exit 100
end
diff --git a/lib/chef/knife/bootstrap.rb b/lib/chef/knife/bootstrap.rb
index 942a5681b8..e88bbc1f19 100644
--- a/lib/chef/knife/bootstrap.rb
+++ b/lib/chef/knife/bootstrap.rb
@@ -89,6 +89,11 @@ class Chef
:description => "The proxy server for the node being bootstrapped",
:proc => Proc.new { |p| Chef::Config[:knife][:bootstrap_proxy] = p }
+ option :bootstrap_no_proxy,
+ :long => "--bootstrap-no-proxy [NO_PROXY_URL|NO_PROXY_IP]",
+ :description => "Do not proxy locations for the node being bootstrapped",
+ :proc => Proc.new { |np| Chef::Config[:knife][:bootstrap_no_proxy] = np }
+
option :distro,
:short => "-d DISTRO",
:long => "--distro DISTRO",
@@ -141,11 +146,13 @@ class Chef
option :secret,
:short => "-s SECRET",
:long => "--secret ",
- :description => "The secret key to use to encrypt data bag item values"
+ :description => "The secret key to use to encrypt data bag item values",
+ :proc => Proc.new { |s| Chef::Config[:knife][:secret] = s }
option :secret_file,
:long => "--secret-file SECRET_FILE",
- :description => "A file containing the secret key to use to encrypt data bag item values"
+ :description => "A file containing the secret key to use to encrypt data bag item values",
+ :proc => Proc.new { |sf| Chef::Config[:knife][:secret_file] = sf }
def find_template(template=nil)
# Are we bootstrapping using an already shipped template?
@@ -244,7 +251,7 @@ class Chef
command = render_template(read_template)
if config[:use_sudo]
- command = config[:use_sudo_password] ? "echo #{config[:ssh_password]} | sudo -S #{command}" : "sudo #{command}"
+ command = config[:use_sudo_password] ? "echo '#{config[:ssh_password]}' | sudo -S #{command}" : "sudo #{command}"
end
command
diff --git a/lib/chef/knife/bootstrap/chef-full.erb b/lib/chef/knife/bootstrap/chef-full.erb
index 974b522653..549ffaea8c 100644
--- a/lib/chef/knife/bootstrap/chef-full.erb
+++ b/lib/chef/knife/bootstrap/chef-full.erb
@@ -1,5 +1,13 @@
bash -c '
-<%= "export http_proxy=\"#{knife_config[:bootstrap_proxy]}\"" if knife_config[:bootstrap_proxy] -%>
+<%= "export https_proxy=\"#{knife_config[:bootstrap_proxy]}\"" if knife_config[:bootstrap_proxy] -%>
+
+distro=`uname -s`
+
+if [ "X$distro" == "XSunOS" ]; then
+ if [ -e "/usr/sfw/bin" ]; then
+ export PATH=/usr/sfw/bin:$PATH
+ fi
+fi
exists() {
if command -v $1 &>/dev/null
diff --git a/lib/chef/knife/client_create.rb b/lib/chef/knife/client_create.rb
index 5b5078b574..285254aef0 100644
--- a/lib/chef/knife/client_create.rb
+++ b/lib/chef/knife/client_create.rb
@@ -61,7 +61,7 @@ class Chef
# We only get a private_key on client creation, not on client update.
if client['private_key']
ui.info("Created #{output}")
-
+
if config[:file]
File.open(config[:file], "w") do |f|
f.print(client['private_key'])
diff --git a/lib/chef/knife/configure.rb b/lib/chef/knife/configure.rb
index 8e725952b4..3ad4fac970 100644
--- a/lib/chef/knife/configure.rb
+++ b/lib/chef/knife/configure.rb
@@ -57,7 +57,7 @@ class Chef
option :validation_key,
:long => "--validation-key PATH",
- :description => "The location of the location of the validation key (usually a file named validation.pem)"
+ :description => "The location of the validation key (usually a file named validation.pem)"
def configure_chef
# We are just faking out the system so that you can do this without a key specified
diff --git a/lib/chef/knife/cookbook_create.rb b/lib/chef/knife/cookbook_create.rb
index 4e6b8d0c1f..01bd8293f3 100644
--- a/lib/chef/knife/cookbook_create.rb
+++ b/lib/chef/knife/cookbook_create.rb
@@ -214,7 +214,7 @@ EOH
TODO: Enter the cookbook description here.
e.g.
-This cookbook makes your favorite breakfast sandwhich.
+This cookbook makes your favorite breakfast sandwich.
== Requirements
TODO: List your cookbook requirements. Be sure to include any requirements this cookbook has on platforms, libraries, other cookbooks, packages, operating systems, etc.
@@ -224,7 +224,7 @@ e.g.
- +toaster+ - #{cookbook_name} needs toaster to brown your bagel.
== Attributes
-TODO: List you cookbook attributes here.
+TODO: List your cookbook attributes here.
e.g.
==== #{cookbook_name}::default
@@ -263,7 +263,7 @@ TODO: (optional) If this is a public cookbook, detail the process for contributi
e.g.
1. Fork the repository on Github
2. Create a named feature branch (like `add_component_x`)
-3. Write you change
+3. Write your change
4. Write tests for your change (if applicable)
5. Run the tests, ensuring they all pass
6. Submit a Pull Request using Github
@@ -278,7 +278,7 @@ EOH
TODO: Enter the cookbook description here.
e.g.
-This cookbook makes your favorite breakfast sandwhich.
+This cookbook makes your favorite breakfast sandwich.
Requirements
------------
@@ -333,7 +333,7 @@ TODO: (optional) If this is a public cookbook, detail the process for contributi
e.g.
1. Fork the repository on Github
2. Create a named feature branch (like `add_component_x`)
-3. Write you change
+3. Write your change
4. Write tests for your change (if applicable)
5. Run the tests, ensuring they all pass
6. Submit a Pull Request using Github
@@ -349,7 +349,7 @@ EOH
TODO: Enter the cookbook description here.
e.g.
- This cookbook makes your favorite breakfast sandwhich.
+ This cookbook makes your favorite breakfast sandwich.
Requirements
TODO: List your cookbook requirements. Be sure to include any requirements this cookbook has on platforms, libraries, other cookbooks, packages, operating systems, etc.
@@ -386,7 +386,7 @@ Contributing
e.g.
1. Fork the repository on Github
2. Create a named feature branch (like `add_component_x`)
- 3. Write you change
+ 3. Write your change
4. Write tests for your change (if applicable)
5. Run the tests, ensuring they all pass
6. Submit a Pull Request using Github
diff --git a/lib/chef/knife/cookbook_download.rb b/lib/chef/knife/cookbook_download.rb
index 6132c9dca0..cb8eeb8edf 100644
--- a/lib/chef/knife/cookbook_download.rb
+++ b/lib/chef/knife/cookbook_download.rb
@@ -7,9 +7,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
diff --git a/lib/chef/knife/cookbook_metadata_from_file.rb b/lib/chef/knife/cookbook_metadata_from_file.rb
index eb1afa8b11..8e26251d6e 100644
--- a/lib/chef/knife/cookbook_metadata_from_file.rb
+++ b/lib/chef/knife/cookbook_metadata_from_file.rb
@@ -9,9 +9,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
diff --git a/lib/chef/knife/cookbook_show.rb b/lib/chef/knife/cookbook_show.rb
index 3545d20817..7c9cbebdb1 100644
--- a/lib/chef/knife/cookbook_show.rb
+++ b/lib/chef/knife/cookbook_show.rb
@@ -6,9 +6,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -50,7 +50,7 @@ class Chef
:long => "--with-uri",
:description => "Show corresponding URIs"
- def run
+ def run
case @name_args.length
when 4 # We are showing a specific file
node = Hash.new
diff --git a/lib/chef/knife/cookbook_site_install.rb b/lib/chef/knife/cookbook_site_install.rb
index d7a3bfd62c..913d171b3c 100644
--- a/lib/chef/knife/cookbook_site_install.rb
+++ b/lib/chef/knife/cookbook_site_install.rb
@@ -151,11 +151,11 @@ class Chef
ui.info("Removing pre-existing version.")
FileUtils.rmtree(cookbook_path) if File.directory?(cookbook_path)
end
-
+
def convert_path(upstream_file)
if ENV['MSYSTEM'] == 'MINGW32'
return upstream_file.sub(/^([[:alpha:]]):/, '/\1')
- else
+ else
return Shellwords.escape upstream_file
end
end
diff --git a/lib/chef/knife/cookbook_site_list.rb b/lib/chef/knife/cookbook_site_list.rb
index 96c4ef0eed..fe83b71388 100644
--- a/lib/chef/knife/cookbook_site_list.rb
+++ b/lib/chef/knife/cookbook_site_list.rb
@@ -6,9 +6,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
diff --git a/lib/chef/knife/cookbook_site_search.rb b/lib/chef/knife/cookbook_site_search.rb
index 5df7d67327..b636276cba 100644
--- a/lib/chef/knife/cookbook_site_search.rb
+++ b/lib/chef/knife/cookbook_site_search.rb
@@ -5,9 +5,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -36,7 +36,7 @@ class Chef
end
new_start = start + cr["items"].length
if new_start < cr["total"]
- search_cookbook(query, items, new_start, cookbook_collection)
+ search_cookbook(query, items, new_start, cookbook_collection)
else
cookbook_collection
end
diff --git a/lib/chef/knife/cookbook_site_show.rb b/lib/chef/knife/cookbook_site_show.rb
index a02dd61fc8..d15098e915 100644
--- a/lib/chef/knife/cookbook_site_show.rb
+++ b/lib/chef/knife/cookbook_site_show.rb
@@ -5,9 +5,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -27,10 +27,10 @@ class Chef
def run
output(format_for_display(get_cookbook_data))
end
-
+
def get_cookbook_data
case @name_args.length
- when 1
+ when 1
noauth_rest.get_rest("http://cookbooks.opscode.com/api/v1/cookbooks/#{@name_args[0]}")
when 2
noauth_rest.get_rest("http://cookbooks.opscode.com/api/v1/cookbooks/#{@name_args[0]}/versions/#{name_args[1].gsub('.', '_')}")
@@ -45,7 +45,7 @@ class Chef
end
new_start = start + cr["items"].length
if new_start < cr["total"]
- get_cookbook_list(items, new_start, cookbook_collection)
+ get_cookbook_list(items, new_start, cookbook_collection)
else
cookbook_collection
end
diff --git a/lib/chef/knife/core/bootstrap_context.rb b/lib/chef/knife/core/bootstrap_context.rb
index 248d7c7a64..e1ad606c80 100644
--- a/lib/chef/knife/core/bootstrap_context.rb
+++ b/lib/chef/knife/core/bootstrap_context.rb
@@ -51,9 +51,9 @@ class Chef
end
def encrypted_data_bag_secret
- @config[:secret] || begin
- if @config[:secret_file] && File.exist?(@config[:secret_file])
- IO.read(File.expand_path(@config[:secret_file]))
+ knife_config[:secret] || begin
+ if knife_config[:secret_file] && File.exist?(knife_config[:secret_file])
+ IO.read(File.expand_path(knife_config[:secret_file]))
elsif @chef_config[:encrypted_data_bag_secret] && File.exist?(@chef_config[:encrypted_data_bag_secret])
IO.read(File.expand_path(@chef_config[:encrypted_data_bag_secret]))
end
@@ -78,6 +78,10 @@ CONFIG
client_rb << %Q{https_proxy "#{knife_config[:bootstrap_proxy]}"\n}
end
+ if knife_config[:bootstrap_no_proxy]
+ client_rb << %Q{no_proxy "#{knife_config[:bootstrap_no_proxy]}"\n}
+ end
+
if encrypted_data_bag_secret
client_rb << %Q{encrypted_data_bag_secret "/etc/chef/encrypted_data_bag_secret"\n}
end
diff --git a/lib/chef/knife/core/node_presenter.rb b/lib/chef/knife/core/node_presenter.rb
index a35baf2264..d1aab592ef 100644
--- a/lib/chef/knife/core/node_presenter.rb
+++ b/lib/chef/knife/core/node_presenter.rb
@@ -86,7 +86,7 @@ class Chef
# Converts a Chef::Node object to a string suitable for output to a
# terminal. If config[:medium_output] or config[:long_output] are set
# the volume of output is adjusted accordingly. Uses colors if enabled
- # in the the ui object.
+ # in the ui object.
def summarize(data)
if data.kind_of?(Chef::Node)
node = data
diff --git a/lib/chef/knife/core/subcommand_loader.rb b/lib/chef/knife/core/subcommand_loader.rb
index 2475717441..91c0590121 100644
--- a/lib/chef/knife/core/subcommand_loader.rb
+++ b/lib/chef/knife/core/subcommand_loader.rb
@@ -6,9 +6,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -112,7 +112,7 @@ class Chef
check_spec_for_glob(spec, glob)
end
end.flatten
-
+
files.concat gem_files
files.uniq! if check_load_path
@@ -133,9 +133,9 @@ class Chef
else
spec.require_paths.first
end
-
+
glob = File.join("#{spec.full_gem_path}/#{dirs}", glob)
-
+
Dir[glob].map { |f| f.untaint }
end
end
diff --git a/lib/chef/knife/core/ui.rb b/lib/chef/knife/core/ui.rb
index f18d30a039..d0bdaa7ac0 100644
--- a/lib/chef/knife/core/ui.rb
+++ b/lib/chef/knife/core/ui.rb
@@ -167,7 +167,7 @@ class Chef
if (!config[:disable_editing])
filename = "knife-edit-"
0.upto(20) { filename += rand(9).to_s }
- filename << ".js"
+ filename << ".json"
filename = File.join(Dir.tmpdir, filename)
tf = File.open(filename, "w")
tf.sync = true
diff --git a/lib/chef/knife/data_bag_create.rb b/lib/chef/knife/data_bag_create.rb
index e644ab78d3..55c1c71798 100644
--- a/lib/chef/knife/data_bag_create.rb
+++ b/lib/chef/knife/data_bag_create.rb
@@ -32,13 +32,15 @@ class Chef
category "data bag"
option :secret,
- :short => "-s SECRET",
- :long => "--secret ",
- :description => "The secret key to use to encrypt data bag item values"
+ :short => "-s SECRET",
+ :long => "--secret ",
+ :description => "The secret key to use to encrypt data bag item values",
+ :proc => Proc.new { |s| Chef::Config[:knife][:secret] = s }
option :secret_file,
- :long => "--secret-file SECRET_FILE",
- :description => "A file containing the secret key to use to encrypt data bag item values"
+ :long => "--secret-file SECRET_FILE",
+ :description => "A file containing the secret key to use to encrypt data bag item values",
+ :proc => Proc.new { |sf| Chef::Config[:knife][:secret_file] = sf }
def read_secret
if config[:secret]
diff --git a/lib/chef/knife/data_bag_delete.rb b/lib/chef/knife/data_bag_delete.rb
index f8e52018a6..575e9d604d 100644
--- a/lib/chef/knife/data_bag_delete.rb
+++ b/lib/chef/knife/data_bag_delete.rb
@@ -6,9 +6,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -29,7 +29,7 @@ class Chef
banner "knife data bag delete BAG [ITEM] (options)"
category "data bag"
- def run
+ def run
if @name_args.length == 2
delete_object(Chef::DataBagItem, @name_args[1], "data_bag_item") do
rest.delete_rest("data/#{@name_args[0]}/#{@name_args[1]}")
diff --git a/lib/chef/knife/data_bag_edit.rb b/lib/chef/knife/data_bag_edit.rb
index 234c77177d..b3f53af919 100644
--- a/lib/chef/knife/data_bag_edit.rb
+++ b/lib/chef/knife/data_bag_edit.rb
@@ -7,9 +7,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -32,13 +32,15 @@ class Chef
category "data bag"
option :secret,
- :short => "-s SECRET",
- :long => "--secret ",
- :description => "The secret key to use to encrypt data bag item values"
+ :short => "-s SECRET",
+ :long => "--secret ",
+ :description => "The secret key to use to encrypt data bag item values",
+ :proc => Proc.new { |s| Chef::Config[:knife][:secret] = s }
option :secret_file,
- :long => "--secret-file SECRET_FILE",
- :description => "A file containing the secret key to use to encrypt data bag item values"
+ :long => "--secret-file SECRET_FILE",
+ :description => "A file containing the secret key to use to encrypt data bag item values",
+ :proc => Proc.new { |sf| Chef::Config[:knife][:secret_file] = sf }
def read_secret
if config[:secret]
diff --git a/lib/chef/knife/data_bag_from_file.rb b/lib/chef/knife/data_bag_from_file.rb
index 275cbeac52..4c90fe6c6c 100644
--- a/lib/chef/knife/data_bag_from_file.rb
+++ b/lib/chef/knife/data_bag_from_file.rb
@@ -35,18 +35,20 @@ class Chef
category "data bag"
option :secret,
- :short => "-s SECRET",
- :long => "--secret ",
- :description => "The secret key to use to encrypt data bag item values"
+ :short => "-s SECRET",
+ :long => "--secret ",
+ :description => "The secret key to use to encrypt data bag item values",
+ :proc => Proc.new { |s| Chef::Config[:knife][:secret] = s }
option :secret_file,
- :long => "--secret-file SECRET_FILE",
- :description => "A file containing the secret key to use to encrypt data bag item values"
+ :long => "--secret-file SECRET_FILE",
+ :description => "A file containing the secret key to use to encrypt data bag item values",
+ :proc => Proc.new { |sf| Chef::Config[:knife][:secret_file] = sf }
option :all,
- :short => "-a",
- :long => "--all",
- :description => "Upload all data bags or all items for specified data bags"
+ :short => "-a",
+ :long => "--all",
+ :description => "Upload all data bags or all items for specified data bags"
def read_secret
if config[:secret]
diff --git a/lib/chef/knife/data_bag_list.rb b/lib/chef/knife/data_bag_list.rb
index 31dcf984f6..5e556b60bc 100644
--- a/lib/chef/knife/data_bag_list.rb
+++ b/lib/chef/knife/data_bag_list.rb
@@ -6,9 +6,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
diff --git a/lib/chef/knife/data_bag_show.rb b/lib/chef/knife/data_bag_show.rb
index 81b1425f78..519859ca2d 100644
--- a/lib/chef/knife/data_bag_show.rb
+++ b/lib/chef/knife/data_bag_show.rb
@@ -7,9 +7,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -32,13 +32,15 @@ class Chef
category "data bag"
option :secret,
- :short => "-s SECRET",
- :long => "--secret ",
- :description => "The secret key to use to decrypt data bag item values"
+ :short => "-s SECRET",
+ :long => "--secret ",
+ :description => "The secret key to use to decrypt data bag item values",
+ :proc => Proc.new { |s| Chef::Config[:knife][:secret] = s }
option :secret_file,
- :long => "--secret-file SECRET_FILE",
- :description => "A file containing the secret key to use to decrypt data bag item values"
+ :long => "--secret-file SECRET_FILE",
+ :description => "A file containing the secret key to use to decrypt data bag item values",
+ :proc => Proc.new { |sf| Chef::Config[:knife][:secret_file] = sf }
def read_secret
if config[:secret]
diff --git a/lib/chef/knife/delete.rb b/lib/chef/knife/delete.rb
index fb26b9ea35..0030c45026 100644
--- a/lib/chef/knife/delete.rb
+++ b/lib/chef/knife/delete.rb
@@ -5,6 +5,8 @@ class Chef
class Delete < Chef::ChefFS::Knife
banner "knife delete [PATTERN1 ... PATTERNn]"
+ category "path-based"
+
deps do
require 'chef/chef_fs/file_system'
end
diff --git a/lib/chef/knife/deps.rb b/lib/chef/knife/deps.rb
index c4b3678ff8..b2a39a0725 100644
--- a/lib/chef/knife/deps.rb
+++ b/lib/chef/knife/deps.rb
@@ -5,6 +5,8 @@ class Chef
class Deps < Chef::ChefFS::Knife
banner "knife deps PATTERN1 [PATTERNn]"
+ category "path-based"
+
deps do
require 'chef/chef_fs/file_system'
require 'chef/run_list'
diff --git a/lib/chef/knife/diff.rb b/lib/chef/knife/diff.rb
index 5a3a80544d..e5eda5228c 100644
--- a/lib/chef/knife/diff.rb
+++ b/lib/chef/knife/diff.rb
@@ -5,6 +5,8 @@ class Chef
class Diff < Chef::ChefFS::Knife
banner "knife diff PATTERNS"
+ category "path-based"
+
deps do
require 'chef/chef_fs/command_line'
end
@@ -30,6 +32,10 @@ class Chef
:description => "Select only files that are Added (A), Deleted (D), Modified (M), or have their type (i.e. regular file, directory) changed (T). Any combination of the filter characters (including none) can be used. When * (All-or-none) is added to the combination, all paths are selected if
there is any file that matches other criteria in the comparison; if there is no file that matches other criteria, nothing is selected."
+ option :cookbook_version,
+ :long => '--cookbook-version VERSION',
+ :description => 'Version of cookbook to download (if there are multiple versions and cookbook_versions is false)'
+
def run
if config[:name_only]
output_mode = :name_only
diff --git a/lib/chef/knife/download.rb b/lib/chef/knife/download.rb
index e8f26a74aa..5a432afd47 100644
--- a/lib/chef/knife/download.rb
+++ b/lib/chef/knife/download.rb
@@ -5,6 +5,8 @@ class Chef
class Download < Chef::ChefFS::Knife
banner "knife download PATTERNS"
+ category "path-based"
+
deps do
require 'chef/chef_fs/command_line'
end
@@ -40,6 +42,10 @@ class Chef
:default => true,
:description => 'Turn off to avoid uploading existing files; only new (and possibly deleted) files with --no-diff'
+ option :cookbook_version,
+ :long => '--cookbook-version VERSION',
+ :description => 'Version of cookbook to download (if there are multiple versions and cookbook_versions is false)'
+
def run
if name_args.length == 0
show_usage
diff --git a/lib/chef/knife/edit.rb b/lib/chef/knife/edit.rb
index ea068cb250..830da84a12 100644
--- a/lib/chef/knife/edit.rb
+++ b/lib/chef/knife/edit.rb
@@ -5,6 +5,8 @@ class Chef
class Edit < Chef::ChefFS::Knife
banner "knife edit [PATTERN1 ... PATTERNn]"
+ category "path-based"
+
deps do
require 'chef/chef_fs/file_system'
require 'chef/chef_fs/file_system/not_found_error'
diff --git a/lib/chef/knife/environment_from_file.rb b/lib/chef/knife/environment_from_file.rb
index af72f84622..3812024c9c 100644
--- a/lib/chef/knife/environment_from_file.rb
+++ b/lib/chef/knife/environment_from_file.rb
@@ -62,7 +62,7 @@ class Chef
ui.info("Updated Environment #{updated.name}")
end
-
+
def run
if config[:all] == true
load_all_environments
@@ -72,7 +72,7 @@ class Chef
ui.fatal("You must specify a file to load")
exit 1
end
-
+
@name_args.each do |arg|
load_environment(arg)
end
diff --git a/lib/chef/knife/index_rebuild.rb b/lib/chef/knife/index_rebuild.rb
index 3e97c7751b..4b9fcdd159 100644
--- a/lib/chef/knife/index_rebuild.rb
+++ b/lib/chef/knife/index_rebuild.rb
@@ -40,7 +40,7 @@ class Chef
nag
output rest.post_rest("/search/reindex", {})
end
-
+
end
def grab_api_info
@@ -55,7 +55,7 @@ class Chef
r = exception.response
parse_api_info(r)
end
-
+
# Only Chef 11+ servers will have version information in their
# headers, and only those servers will lack an API endpoint for
# index rebuilding.
diff --git a/lib/chef/knife/list.rb b/lib/chef/knife/list.rb
index 83d5c5a8c4..4338e195bd 100644
--- a/lib/chef/knife/list.rb
+++ b/lib/chef/knife/list.rb
@@ -5,6 +5,8 @@ class Chef
class List < Chef::ChefFS::Knife
banner "knife list [-dfR1p] [PATTERN1 ... PATTERNn]"
+ category "path-based"
+
deps do
require 'chef/chef_fs/file_system'
require 'highline'
diff --git a/lib/chef/knife/raw.rb b/lib/chef/knife/raw.rb
index ee22d1ade5..2756de1a5a 100644
--- a/lib/chef/knife/raw.rb
+++ b/lib/chef/knife/raw.rb
@@ -6,10 +6,13 @@ class Chef
banner "knife raw REQUEST_PATH"
deps do
- require 'json'
- require 'chef/rest'
+ require 'chef/json_compat'
require 'chef/config'
- require 'chef/chef_fs/raw_request'
+ require 'chef/http'
+ require 'chef/http/authenticator'
+ require 'chef/http/cookie_manager'
+ require 'chef/http/decompressor'
+ require 'chef/http/json_output'
end
option :method,
@@ -29,6 +32,18 @@ class Chef
:short => '-i FILE',
:description => "Name of file to use for PUT or POST"
+ class RawInputServerAPI < Chef::HTTP
+ def initialize(options = {})
+ options[:client_name] ||= Chef::Config[:node_name]
+ options[:signing_key_filename] ||= Chef::Config[:client_key]
+ super(Chef::Config[:chef_server_url], options)
+ end
+ use Chef::HTTP::JSONOutput
+ use Chef::HTTP::CookieManager
+ use Chef::HTTP::Decompressor
+ use Chef::HTTP::Authenticator
+ end
+
def run
if name_args.length == 0
show_usage
@@ -45,9 +60,20 @@ class Chef
if config[:input]
data = IO.read(config[:input])
end
- chef_rest = Chef::REST.new(Chef::Config[:chef_server_url])
begin
- output Chef::ChefFS::RawRequest.api_request(chef_rest, config[:method].to_sym, chef_rest.create_url(name_args[0]), {}, data)
+ method = config[:method].to_sym
+
+ if config[:pretty]
+ chef_rest = RawInputServerAPI.new
+ result = chef_rest.request(method, name_args[0], {'Content-Type' => 'application/json'}, data)
+ unless result.is_a?(String)
+ result = Chef::JSONCompat.to_json_pretty(result)
+ end
+ else
+ chef_rest = RawInputServerAPI.new(:raw_output => true)
+ result = chef_rest.request(method, name_args[0], {'Content-Type' => 'application/json'}, data)
+ end
+ output result
rescue Timeout::Error => e
ui.error "Server timeout"
exit 1
diff --git a/lib/chef/knife/show.rb b/lib/chef/knife/show.rb
index b5e8aa9882..acf1996e96 100644
--- a/lib/chef/knife/show.rb
+++ b/lib/chef/knife/show.rb
@@ -5,6 +5,8 @@ class Chef
class Show < Chef::ChefFS::Knife
banner "knife show [PATTERN1 ... PATTERNn]"
+ category "path-based"
+
deps do
require 'chef/chef_fs/file_system'
require 'chef/chef_fs/file_system/not_found_error'
diff --git a/lib/chef/knife/ssh.rb b/lib/chef/knife/ssh.rb
index 8cc05bd433..e1090fcca0 100644
--- a/lib/chef/knife/ssh.rb
+++ b/lib/chef/knife/ssh.rb
@@ -147,7 +147,7 @@ class Chef
@action_nodes = q.search(:node, @name_args[0])[0]
@action_nodes.each do |item|
# we should skip the loop to next iteration if the item returned by the search is nil
- next if item.nil?
+ next if item.nil?
# if a command line attribute was not passed, and we have a cloud public_hostname, use that.
# see #configure_attribute for the source of config[:attribute] and config[:override_attribute]
if !config[:override_attribute] && item[:cloud] and item[:cloud][:public_hostname]
@@ -211,15 +211,28 @@ class Chef
end
def print_data(host, data)
- if data =~ /\n/
- data.split(/\n/).each { |d| print_data(host, d) }
+ @buffers ||= {}
+ if leftover = @buffers[host]
+ @buffers[host] = nil
+ print_data(host, leftover + data)
else
- padding = @longest - host.length
- str = ui.color(host, :cyan) + (" " * (padding + 1)) + data
- ui.msg(str)
+ if newline_index = data.index("\n")
+ line = data.slice!(0...newline_index)
+ data.slice!(0)
+ print_line(host, line)
+ print_data(host, data)
+ else
+ @buffers[host] = data
+ end
end
end
+ def print_line(host, data)
+ padding = @longest - host.length
+ str = ui.color(host, :cyan) + (" " * (padding + 1)) + data
+ ui.msg(str)
+ end
+
def ssh_command(command, subsession=nil)
exit_status = 0
subsession ||= session
@@ -232,6 +245,7 @@ class Chef
ch.on_data do |ichannel, data|
print_data(ichannel[:host], data)
if data =~ /^knife sudo password: /
+ print_data(ichannel[:host], "\n")
ichannel.send_data("#{get_password}\n")
end
end
@@ -383,7 +397,7 @@ class Chef
# Thus we can differentiate between a config file value and a command line override at this point by checking config[:attribute]
# We can tell here if fqdn was passed from the command line, rather than being the default, by checking config[:attribute]
# However, after here, we cannot tell these things, so we must preserve config[:attribute]
- config[:override_attribute] = config[:attribute] || Chef::Config[:knife][:ssh_attribute]
+ config[:override_attribute] = config[:attribute] || Chef::Config[:knife][:ssh_attribute]
config[:attribute] = (Chef::Config[:knife][:ssh_attribute] ||
config[:attribute] ||
"fqdn").strip
diff --git a/lib/chef/knife/status.rb b/lib/chef/knife/status.rb
index ceb394ce3a..5906a4a624 100644
--- a/lib/chef/knife/status.rb
+++ b/lib/chef/knife/status.rb
@@ -72,7 +72,7 @@ class Chef
hours, minutes, seconds = time_difference_in_hms(node["ohai_time"])
hours_text = "#{hours} hour#{hours == 1 ? ' ' : 's'}"
minutes_text = "#{minutes} minute#{minutes == 1 ? ' ' : 's'}"
- run_list = ", #{node.run_list}." if config[:run_list]
+ run_list = "#{node.run_list}" if config[:run_list]
if hours > 24
color = :red
text = hours_text
diff --git a/lib/chef/knife/upload.rb b/lib/chef/knife/upload.rb
index f72b6ea616..8abd22b4dd 100644
--- a/lib/chef/knife/upload.rb
+++ b/lib/chef/knife/upload.rb
@@ -5,6 +5,8 @@ class Chef
class Upload < Chef::ChefFS::Knife
banner "knife upload PATTERNS"
+ category "path-based"
+
deps do
require 'chef/chef_fs/command_line'
end
diff --git a/lib/chef/knife/xargs.rb b/lib/chef/knife/xargs.rb
index be6db9d64f..dd8e848058 100644
--- a/lib/chef/knife/xargs.rb
+++ b/lib/chef/knife/xargs.rb
@@ -5,6 +5,8 @@ class Chef
class Xargs < Chef::ChefFS::Knife
banner "knife xargs [COMMAND]"
+ category "path-based"
+
deps do
require 'chef/chef_fs/file_system'
require 'chef/chef_fs/file_system/not_found_error'
diff --git a/lib/chef/mixin/checksum.rb b/lib/chef/mixin/checksum.rb
index 8217296915..1d9c99ec7e 100644
--- a/lib/chef/mixin/checksum.rb
+++ b/lib/chef/mixin/checksum.rb
@@ -6,9 +6,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
diff --git a/lib/chef/mixin/command.rb b/lib/chef/mixin/command.rb
index 55c028ff5f..2cc25e149e 100644
--- a/lib/chef/mixin/command.rb
+++ b/lib/chef/mixin/command.rb
@@ -6,9 +6,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -41,23 +41,32 @@ class Chef
# === Parameters
# args<Hash>: A number of required and optional arguments
- # command<String>, <Array>: A complete command with options to execute or a command and options as an Array
+ # command<String>, <Array>: A complete command with options to execute or a command and options as an Array
# creates<String>: The absolute path to a file that prevents the command from running if it exists
# cwd<String>: Working directory to execute command in, defaults to Dir.tmpdir
# timeout<String>: How many seconds to wait for the command to execute before timing out
# returns<String>: The single exit value command is expected to return, otherwise causes an exception
# ignore_failure<Boolean>: Whether to raise an exception on failure, or just return the status
# output_on_failure<Boolean>: Return output in raised exception regardless of Log.level
- #
+ #
# user<String>: The UID or user name of the user to execute the command as
# group<String>: The GID or group name of the group to execute the command as
# environment<Hash>: Pairs of environment variable names and their values to set before execution
#
# === Returns
# Returns the exit status of args[:command]
- def run_command(args={})
+ def run_command(args={})
+ status, stdout, stderr = run_command_and_return_stdout_stderr(args)
+
+ status
+ end
+
+ # works same as above, except that it returns stdout and stderr
+ # requirement => platforms like solaris 9,10 has wierd issues where
+ # even in command failure the exit code is zero, so we need to lookup stderr.
+ def run_command_and_return_stdout_stderr(args={})
command_output = ""
-
+
args[:ignore_failure] ||= false
args[:output_on_failure] ||= false
@@ -68,28 +77,28 @@ class Chef
return false
end
end
-
+
status, stdout, stderr = output_of_command(args[:command], args)
command_output << "STDOUT: #{stdout}"
command_output << "STDERR: #{stderr}"
handle_command_failures(status, command_output, args)
-
- status
+
+ return status, stdout, stderr
end
-
+
def output_of_command(command, args)
Chef::Log.debug("Executing #{command}")
stderr_string, stdout_string, status = "", "", nil
-
+
exec_processing_block = lambda do |pid, stdin, stdout, stderr|
stdout_string, stderr_string = stdout.string.chomp, stderr.string.chomp
end
-
+
args[:cwd] ||= Dir.tmpdir
unless ::File.directory?(args[:cwd])
raise Chef::Exceptions::Exec, "#{args[:cwd]} does not exist or is not a directory"
end
-
+
Dir.chdir(args[:cwd]) do
if args[:timeout]
begin
@@ -103,17 +112,17 @@ class Chef
else
status = popen4(command, args, &exec_processing_block)
end
-
+
Chef::Log.debug("---- Begin output of #{command} ----")
Chef::Log.debug("STDOUT: #{stdout_string}")
Chef::Log.debug("STDERR: #{stderr_string}")
Chef::Log.debug("---- End output of #{command} ----")
Chef::Log.debug("Ran #{command} returned #{status.exitstatus}")
end
-
+
return status, stdout_string, stderr_string
end
-
+
def handle_command_failures(status, command_output, opts={})
unless opts[:ignore_failure]
opts[:returns] ||= 0
@@ -129,7 +138,7 @@ class Chef
end
end
end
-
+
# Call #run_command but set LC_ALL to the system's current environment so it doesn't get changed to C.
#
# === Parameters
diff --git a/lib/chef/mixin/convert_to_class_name.rb b/lib/chef/mixin/convert_to_class_name.rb
index 7b4ec7ad3f..ece16990a1 100644
--- a/lib/chef/mixin/convert_to_class_name.rb
+++ b/lib/chef/mixin/convert_to_class_name.rb
@@ -7,9 +7,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -27,20 +27,20 @@ class Chef
str.gsub!(/[^A-Za-z0-9_]/,'_')
rname = nil
regexp = %r{^(.+?)(_(.+))?$}
-
+
mn = str.match(regexp)
if mn
rname = mn[1].capitalize
while mn && mn[3]
- mn = mn[3].match(regexp)
+ mn = mn[3].match(regexp)
rname << mn[1].capitalize if mn
end
end
rname
end
-
+
def convert_to_snake_case(str, namespace=nil)
str = str.dup
str.sub!(/^#{namespace}(\:\:)?/, '') if namespace
@@ -49,17 +49,17 @@ class Chef
str.sub!(/^\_/, "")
str
end
-
+
def snake_case_basename(str)
with_namespace = convert_to_snake_case(str)
with_namespace.split("::").last.sub(/^_/, '')
end
-
+
def filename_to_qualified_string(base, filename)
file_base = File.basename(filename, ".rb")
base.to_s + (file_base == 'default' ? '' : "_#{file_base}")
end
-
+
end
end
end
diff --git a/lib/chef/mixin/create_path.rb b/lib/chef/mixin/create_path.rb
index 9b5dba14f2..9d1248e907 100644
--- a/lib/chef/mixin/create_path.rb
+++ b/lib/chef/mixin/create_path.rb
@@ -6,9 +6,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -18,21 +18,21 @@
class Chef
module Mixin
module CreatePath
-
+
# Creates a given path, including all directories that lead up to it.
# Like mkdir_p, but without the leaking.
#
# === Parameters
- # file_path<String, Array>:: A string that represents the path to create,
+ # file_path<String, Array>:: A string that represents the path to create,
# or an Array with the path-parts.
#
# === Returns
# The created file_path.
def create_path(file_path)
unless file_path.kind_of?(String) || file_path.kind_of?(Array)
- raise ArgumentError, "file_path must be a string or an array!"
+ raise ArgumentError, "file_path must be a string or an array!"
end
-
+
if file_path.kind_of?(String)
file_path = File.expand_path(file_path).split(File::SEPARATOR)
file_path.shift if file_path[0] == ''
@@ -41,17 +41,17 @@ class Chef
file_path[0] = "#{File::SEPARATOR}#{file_path[0]}"
end
end
-
+
file_path.each_index do |i|
create_path = File.join(file_path[0, i + 1])
unless File.directory?(create_path)
Chef::Log.debug("Creating directory #{create_path}")
Dir.mkdir(create_path)
- end
+ end
end
File.expand_path(File.join(file_path))
end
-
+
end
end
end
diff --git a/lib/chef/mixin/deep_merge.rb b/lib/chef/mixin/deep_merge.rb
index 1f2125be01..9fa86948b6 100644
--- a/lib/chef/mixin/deep_merge.rb
+++ b/lib/chef/mixin/deep_merge.rb
@@ -8,9 +8,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
diff --git a/lib/chef/mixin/from_file.rb b/lib/chef/mixin/from_file.rb
index 609fe1de55..0d1ddca4fa 100644
--- a/lib/chef/mixin/from_file.rb
+++ b/lib/chef/mixin/from_file.rb
@@ -7,9 +7,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -20,9 +20,9 @@
class Chef
module Mixin
module FromFile
-
- # Loads a given ruby file, and runs instance_eval against it in the context of the current
- # object.
+
+ # Loads a given ruby file, and runs instance_eval against it in the context of the current
+ # object.
#
# Raises an IOError if the file cannot be found, or is not readable.
def from_file(filename)
@@ -33,7 +33,7 @@ class Chef
end
end
- # Loads a given ruby file, and runs class_eval against it in the context of the current
+ # Loads a given ruby file, and runs class_eval against it in the context of the current
# object.
#
# Raises an IOError if the file cannot be found, or is not readable.
diff --git a/lib/chef/mixin/language_include_recipe.rb b/lib/chef/mixin/language_include_recipe.rb
index b534b6628f..d85e5c682d 100644
--- a/lib/chef/mixin/language_include_recipe.rb
+++ b/lib/chef/mixin/language_include_recipe.rb
@@ -6,9 +6,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
diff --git a/lib/chef/mixin/params_validate.rb b/lib/chef/mixin/params_validate.rb
index a9822df134..a9799f749c 100644
--- a/lib/chef/mixin/params_validate.rb
+++ b/lib/chef/mixin/params_validate.rb
@@ -6,9 +6,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -20,7 +20,7 @@ class Chef
end
module Mixin
module ParamsValidate
-
+
# Takes a hash of options, along with a map to validate them. Returns the original
# options hash, plus any changes that might have been made (through things like setting
# default values in the validation map)
@@ -28,19 +28,19 @@ class Chef
# For example:
#
# validate({ :one => "neat" }, { :one => { :kind_of => String }})
- #
+ #
# Would raise an exception if the value of :one above is not a kind_of? string. Valid
# map options are:
#
# :default:: Sets the default value for this parameter.
- # :callbacks:: Takes a hash of Procs, which should return true if the argument is valid.
+ # :callbacks:: Takes a hash of Procs, which should return true if the argument is valid.
# The key will be inserted into the error message if the Proc does not return true:
# "Option #{key}'s value #{value} #{message}!"
- # :kind_of:: Ensure that the value is a kind_of?(Whatever). If passed an array, it will ensure
+ # :kind_of:: Ensure that the value is a kind_of?(Whatever). If passed an array, it will ensure
# that the value is one of those types.
# :respond_to:: Ensure that the value has a given method. Takes one method name or an array of
# method names.
- # :required:: Raise an exception if this parameter is missing. Valid values are true or false,
+ # :required:: Raise an exception if this parameter is missing. Valid values are true or false,
# by default, options are not required.
# :regex:: Match the value of the paramater against a regular expression.
# :equal_to:: Match the value of the paramater with ==. An array means it can be equal to any
@@ -48,12 +48,12 @@ class Chef
def validate(opts, map)
#--
# validate works by taking the keys in the validation map, assuming it's a hash, and
- # looking for _pv_:symbol as methods. Assuming it find them, it calls the right
- # one.
+ # looking for _pv_:symbol as methods. Assuming it find them, it calls the right
+ # one.
#++
raise ArgumentError, "Options must be a hash" unless opts.kind_of?(Hash)
- raise ArgumentError, "Validation Map must be a hash" unless map.kind_of?(Hash)
-
+ raise ArgumentError, "Validation Map must be a hash" unless map.kind_of?(Hash)
+
map.each do |key, validation|
unless key.kind_of?(Symbol) || key.kind_of?(String)
raise ArgumentError, "Validation map keys must be symbols or strings!"
@@ -76,7 +76,7 @@ class Chef
end
opts
end
-
+
def lazy(&block)
DelayedEvaluator.new(&block)
end
@@ -99,9 +99,9 @@ class Chef
self.instance_variable_set(iv_symbol, val)
end
end
-
+
private
-
+
# Return the value of a parameter, or nil if it doesn't exist.
def _pv_opts_lookup(opts, key)
if opts.has_key?(key.to_s)
@@ -112,7 +112,7 @@ class Chef
nil
end
end
-
+
# Raise an exception if the parameter is not found.
def _pv_required(opts, key, is_required=true)
if is_required
@@ -124,7 +124,7 @@ class Chef
end
end
end
-
+
def _pv_equal_to(opts, key, to_be)
value = _pv_opts_lookup(opts, key)
unless value.nil?
@@ -137,7 +137,7 @@ class Chef
end
end
end
-
+
# Raise an exception if the parameter is not a kind_of?(to_be)
def _pv_kind_of(opts, key, to_be)
value = _pv_opts_lookup(opts, key)
@@ -151,7 +151,7 @@ class Chef
end
end
end
-
+
# Raise an exception if the parameter does not respond to a given set of methods.
def _pv_respond_to(opts, key, method_name_list)
value = _pv_opts_lookup(opts, key)
@@ -181,7 +181,7 @@ class Chef
end
end
end
-
+
# Assign a default value to a parameter.
def _pv_default(opts, key, default_value)
value = _pv_opts_lookup(opts, key)
@@ -189,7 +189,7 @@ class Chef
opts[key] = default_value
end
end
-
+
# Check a parameter against a regular expression.
def _pv_regex(opts, key, regex)
value = _pv_opts_lookup(opts, key)
@@ -207,7 +207,7 @@ class Chef
end
end
end
-
+
# Check a parameter against a hash of proc's.
def _pv_callbacks(opts, key, callbacks)
raise ArgumentError, "Callback list must be a hash!" unless callbacks.kind_of?(Hash)
diff --git a/lib/chef/mixin/shell_out.rb b/lib/chef/mixin/shell_out.rb
index 4eaa509f8b..f0c2ba2000 100644
--- a/lib/chef/mixin/shell_out.rb
+++ b/lib/chef/mixin/shell_out.rb
@@ -15,13 +15,22 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+# chef/shell_out has been deprecated in favor of mixlib/shellout
+# chef/shell_out is still required here to ensure backward compatibility
require 'chef/shell_out'
+
+require 'mixlib/shellout'
require 'chef/config'
class Chef
module Mixin
module ShellOut
+ # shell_out! runs a command on the system and will raise an error if the command fails, which is what you want
+ # for debugging, shell_out and shell_out! both will display command output to the tty when the log level is debug
+ # Generally speaking, 'extend Chef::Mixin::ShellOut' in your recipes and include 'Chef::Mixin::ShellOut' in your LWRPs
+ # You can also call Mixlib::Shellout.new directly, but you lose all of the above functionality
+
def shell_out(*command_args)
cmd = Mixlib::ShellOut.new(*run_command_compatible_options(command_args))
if STDOUT.tty? && !Chef::Config[:daemon] && Chef::Log.debug?
diff --git a/lib/chef/mixin/template.rb b/lib/chef/mixin/template.rb
index 9208ce057e..ae23336581 100644
--- a/lib/chef/mixin/template.rb
+++ b/lib/chef/mixin/template.rb
@@ -121,17 +121,6 @@ class Chef
###
def _render_template(template, context)
- # CHEF-2991
- # Erubis always emits unix line endings during template
- # rendering. This results in automatic conversion of windows
- # line endings to linux line endings if the original template
- # contains windows line endings. In order to fix this we
- # determine the line ending style of the template before
- # rendering and convert the line endings of the output if needed
- # If template contains any windows line endings we emit
- # the template result with windows line endings.
- windows_line_endings = template.include? "\r\n"
-
begin
eruby = Erubis::Eruby.new(template)
output = eruby.evaluate(context)
@@ -139,11 +128,19 @@ class Chef
raise TemplateError.new(e, template, context)
end
- if windows_line_endings
- # Convert line endings from "\n" -> "\r\n". Also converts
- # "\r\n" -> "\r\n".
- # This makes the regex match on all of "\r\n", so we don't
- # accidentally convert "\r\n" -> "\r\r\n".
+ # CHEF-4399
+ # Erubis always emits unix line endings during template
+ # rendering. Chef used to convert line endings to the
+ # original line endings in the template. However this
+ # created problems in cases when cookbook developer is
+ # coding the cookbook on windows but using it on non-windows
+ # platforms.
+ # The safest solution is to make sure that native to the
+ # platform we are running on is used in order to minimize
+ # potential issues for the applications that will consume
+ # this template.
+
+ if Chef::Platform.windows?
output = output.gsub(/\r?\n/,"\r\n")
end
diff --git a/lib/chef/mixin/why_run.rb b/lib/chef/mixin/why_run.rb
index 788e2fe2bc..d650e3332f 100644
--- a/lib/chef/mixin/why_run.rb
+++ b/lib/chef/mixin/why_run.rb
@@ -178,8 +178,8 @@ class Chef
# when the requirement is not met and Chef is executing in why run
# mode
#
- # If no failure_message is provided (above), then execution
- # will be allowed to continue in both whyrun an dnon-whyrun
+ # If no failure_message is provided (above), then execution
+ # will be allowed to continue in both whyrun and non-whyrun
# mode
#
# With a service resource that requires /etc/init.d/service-name to exist:
@@ -196,16 +196,16 @@ class Chef
@resource_modifier = resource_modifier
end
- # Prevents associated actions from being invoked in whyrun mode.
- # This will also stop further processing of assertions for a given action.
- #
- # An example from the template provider: if the source template doesn't exist
- # we can't parse it in the action_create block of template - something that we do
- # even in whyrun mode. Because the soruce template may have been created in an earlier
+ # Prevents associated actions from being invoked in whyrun mode.
+ # This will also stop further processing of assertions for a given action.
+ #
+ # An example from the template provider: if the source template doesn't exist
+ # we can't parse it in the action_create block of template - something that we do
+ # even in whyrun mode. Because the source template may have been created in an earlier
# step, we still want to keep going in whyrun mode.
- #
+ #
# assert(:create, :create_if_missing) do |a|
- # a.assertion { File::exists?(@new_resource.source) }
+ # a.assertion { File::exists?(@new_resource.source) }
# a.whyrun "Template source file does not exist, assuming it would have been created."
# a.block_action!
# end
@@ -214,7 +214,7 @@ class Chef
@block_action = true
end
- def block_action?
+ def block_action?
@block_action
end
@@ -258,7 +258,7 @@ class Chef
# Check to see if a given action is blocked by a failed assertion
#
# Takes the action name to be verified.
- def action_blocked?(action)
+ def action_blocked?(action)
@blocked_actions.include?(action)
end
@@ -296,9 +296,9 @@ class Chef
# "You don't have sufficient privileges to delete #{@new_resource.path}")
# end
#
- # A Template provider that will prevent action execution but continue the run in
+ # A Template provider that will prevent action execution but continue the run in
# whyrun mode if the template source is not available.
- # assert(:create, :create_if_missing) do |a|
+ # assert(:create, :create_if_missing) do |a|
# a.assertion { File::exist?(@new_resource.source) }
# a.failure_message Chef::Exceptions::TemplateError, "Template #{@new_resource.source} could not be found exist."
# a.whyrun "Template source #{@new_resource.source} does not exist. Assuming it would have been created."
@@ -318,9 +318,9 @@ class Chef
# Run the assertion and assumption logic.
def run(action)
- @assertions[action.to_sym].each do |a|
+ @assertions[action.to_sym].each do |a|
a.run(action, events, @resource)
- if a.assertion_failed? and a.block_action?
+ if a.assertion_failed? and a.block_action?
@blocked_actions << action
return
end
diff --git a/lib/chef/mixin/windows_architecture_helper.rb b/lib/chef/mixin/windows_architecture_helper.rb
index 38c08e236d..c13278693f 100644
--- a/lib/chef/mixin/windows_architecture_helper.rb
+++ b/lib/chef/mixin/windows_architecture_helper.rb
@@ -6,9 +6,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -17,7 +17,7 @@
#
-require 'chef/exceptions'
+require 'chef/exceptions'
require 'win32/api' if Chef::Platform.windows?
class Chef
@@ -32,7 +32,7 @@ class Chef
is_i386_windows_process? &&
node_windows_architecture(node) == :x86_64 &&
desired_architecture == :x86_64
- end
+ end
def node_supports_windows_architecture?(node, desired_architecture)
assert_valid_windows_architecture!(desired_architecture)
@@ -85,7 +85,7 @@ class Chef
end
end
end
-
+
end
end
end
diff --git a/lib/chef/mixin/xml_escape.rb b/lib/chef/mixin/xml_escape.rb
index dac2f0c6af..ceb45df3e6 100644
--- a/lib/chef/mixin/xml_escape.rb
+++ b/lib/chef/mixin/xml_escape.rb
@@ -7,9 +7,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -18,26 +18,26 @@
#--
# Portions of this code are adapted from Sam Ruby's xchar.rb
-# http://intertwingly.net/stories/2005/09/28/xchar.rb
+# http://intertwingly.net/stories/2005/09/28/xchar.rb
#
# Such code appears here under Sam's original MIT license, while portions of
# this file are covered by the above Apache License. For a completely MIT
# licensed version, please see Sam's original.
#
# Thanks, Sam!
-#
-# Copyright (c) 2005, Sam Ruby
-#
+#
+# Copyright (c) 2005, Sam Ruby
+#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
-#
+#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
-#
+#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@@ -99,7 +99,7 @@ class Chef
}
# http://www.w3.org/TR/REC-xml/#charsets
- VALID = [[0x9, 0xA, 0xD], (0x20..0xD7FF),
+ VALID = [[0x9, 0xA, 0xD], (0x20..0xD7FF),
(0xE000..0xFFFD), (0x10000..0x10FFFF)]
def xml_escape(unescaped_str)
@@ -118,7 +118,7 @@ class Chef
char = PREDEFINED[char] || (char<128 ? char.chr : "&##{char};")
end
end
-
+
module FastXS
extend self
diff --git a/lib/chef/monkey_patches/numeric.rb b/lib/chef/monkey_patches/numeric.rb
index 1f5ff14209..f4612fdbf3 100644
--- a/lib/chef/monkey_patches/numeric.rb
+++ b/lib/chef/monkey_patches/numeric.rb
@@ -8,7 +8,7 @@ end
# String elements referenced with [] <= 1.8.6 return a Fixnum. Cheat to allow
# for the simpler "test"[2].ord construct
-class Numeric
+class Numeric
def ord
return self
end
diff --git a/lib/chef/monkey_patches/regexp.rb b/lib/chef/monkey_patches/regexp.rb
index 9304209edf..8a7ee77cb5 100644
--- a/lib/chef/monkey_patches/regexp.rb
+++ b/lib/chef/monkey_patches/regexp.rb
@@ -1,5 +1,5 @@
# Copyright (c) 2009 Marc-Andre Lafortune
-#
+#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
@@ -7,10 +7,10 @@
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
-#
+#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
-#
+#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
@@ -31,4 +31,4 @@ class Regexp
end
end
end
-end \ No newline at end of file
+end
diff --git a/lib/chef/monkey_patches/string.rb b/lib/chef/monkey_patches/string.rb
index c77c5c8816..f91e27ddc5 100644
--- a/lib/chef/monkey_patches/string.rb
+++ b/lib/chef/monkey_patches/string.rb
@@ -6,9 +6,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -39,7 +39,7 @@ class String
end
end
-# <= 1.8.6 needs some ord!
+# <= 1.8.6 needs some ord!
class String
unless method_defined?(:ord)
def ord
diff --git a/lib/chef/monkey_patches/tempfile.rb b/lib/chef/monkey_patches/tempfile.rb
index 3135fb1a00..b9179f182b 100644
--- a/lib/chef/monkey_patches/tempfile.rb
+++ b/lib/chef/monkey_patches/tempfile.rb
@@ -6,9 +6,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
diff --git a/lib/chef/node.rb b/lib/chef/node.rb
index 6bd2226ac8..007bd3c560 100644
--- a/lib/chef/node.rb
+++ b/lib/chef/node.rb
@@ -290,6 +290,14 @@ class Chef
normal[:tags]
end
+ def tag(*tags)
+ tags.each do |tag|
+ self.normal[:tags].push(tag.to_s) unless self[:tags].include? tag.to_s
+ end
+
+ self[:tags]
+ end
+
# Extracts the run list from +attrs+ and applies it. Returns the remaining attributes
def consume_run_list(attrs)
attrs = attrs ? attrs.dup : {}
diff --git a/lib/chef/node/attribute.rb b/lib/chef/node/attribute.rb
index a417406721..66569cf0e1 100644
--- a/lib/chef/node/attribute.rb
+++ b/lib/chef/node/attribute.rb
@@ -243,7 +243,7 @@ class Chef
end
# Clears merged_attributes, which will cause it to be recomputed on the
- # next access.
+ # next access.
def reset_cache
@merged_attributes = nil
@combined_default = nil
diff --git a/lib/chef/platform/provider_mapping.rb b/lib/chef/platform/provider_mapping.rb
index 1a282624c8..a252bdc100 100644
--- a/lib/chef/platform/provider_mapping.rb
+++ b/lib/chef/platform/provider_mapping.rb
@@ -173,6 +173,17 @@ class Chef
:ifconfig => Chef::Provider::Ifconfig::Redhat
}
},
+ :opensuse => {
+ :default => {
+ :service => Chef::Provider::Service::Redhat,
+ :cron => Chef::Provider::Cron,
+ :package => Chef::Provider::Package::Zypper,
+ :group => Chef::Provider::Group::Suse
+ },
+ ">= 12.3" => {
+ :group => Chef::Provider::Group::Usermod
+ }
+ },
:suse => {
:default => {
:service => Chef::Provider::Service::Redhat,
@@ -180,6 +191,16 @@ class Chef
:package => Chef::Provider::Package::Zypper,
:group => Chef::Provider::Group::Suse
},
+ ###############################################
+ # TODO: Remove this after ohai update is released.
+ # Only OpenSuSE 12.3+ should use the Usermod group provider:
+ # Ohai before OHAI-339 is applied reports both OpenSuSE and SuSE
+ # Enterprise as "suse", Ohai after OHAI-339 will report OpenSuSE as
+ # "opensuse".
+ #
+ # In order to support OpenSuSE both before and after the Ohai
+ # change, I'm leaving this here. It needs to get removed before
+ # SuSE enterprise 12.3 ships.
">= 12.3" => {
:group => Chef::Provider::Group::Usermod
}
@@ -320,7 +341,11 @@ class Chef
},
:aix => {
:default => {
- :group => Chef::Provider::Group::Aix
+ :group => Chef::Provider::Group::Aix,
+ :mount => Chef::Provider::Mount::Aix,
+ :ifconfig => Chef::Provider::Ifconfig::Aix,
+ :cron => Chef::Provider::Cron::Aix,
+ :package => Chef::Provider::Package::Aix
}
},
:default => {
diff --git a/lib/chef/provider/batch.rb b/lib/chef/provider/batch.rb
index e4b35b64f3..354a640e59 100644
--- a/lib/chef/provider/batch.rb
+++ b/lib/chef/provider/batch.rb
@@ -6,9 +6,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -29,7 +29,7 @@ class Chef
def flags
@new_resource.flags.nil? ? '/c' : new_resource.flags + ' /c'
end
-
+
end
end
end
diff --git a/lib/chef/provider/cron.rb b/lib/chef/provider/cron.rb
index a7218fea5a..f6f062a410 100644
--- a/lib/chef/provider/cron.rb
+++ b/lib/chef/provider/cron.rb
@@ -40,11 +40,12 @@ class Chef
def whyrun_supported?
true
end
-
+
def load_current_resource
crontab_lines = []
@current_resource = Chef::Resource::Cron.new(@new_resource.name)
@current_resource.user(@new_resource.user)
+ @cron_exists = false
if crontab = read_crontab
cron_found = false
crontab.each_line do |line|
@@ -81,7 +82,7 @@ class Chef
@current_resource
end
-
+
def cron_different?
CRON_ATTRIBUTES.any? do |cron_var|
!@new_resource.send(cron_var).nil? && @new_resource.send(cron_var) != @current_resource.send(cron_var)
@@ -93,14 +94,7 @@ class Chef
newcron = String.new
cron_found = false
- newcron << "# Chef Name: #{new_resource.name}\n"
- [ :mailto, :path, :shell, :home ].each do |v|
- newcron << "#{v.to_s.upcase}=#{@new_resource.send(v)}\n" if @new_resource.send(v)
- end
- @new_resource.environment.each do |name, value|
- newcron << "#{name}=#{value}\n"
- end
- newcron << "#{@new_resource.minute} #{@new_resource.hour} #{@new_resource.day} #{@new_resource.month} #{@new_resource.weekday} #{@new_resource.command}\n"
+ newcron = get_crontab_entry
if @cron_exists
unless cron_different?
@@ -171,7 +165,7 @@ class Chef
end
crontab << line
end
- description = cron_found ? "remove #{@new_resource.name} from crontab" :
+ description = cron_found ? "remove #{@new_resource.name} from crontab" :
"save unmodified crontab"
converge_by(description) do
write_crontab crontab
@@ -202,13 +196,33 @@ class Chef
end
def write_crontab(crontab)
+ write_exception = false
status = popen4("crontab -u #{@new_resource.user} -", :waitlast => true) do |pid, stdin, stdout, stderr|
- stdin.write crontab
+ begin
+ stdin.write crontab
+ rescue Errno::EPIPE => e
+ # popen4 could yield while child has already died.
+ write_exception = true
+ Chef::Log.debug("#{e.message}")
+ end
end
- if status.exitstatus > 0
+ if status.exitstatus > 0 || write_exception
raise Chef::Exceptions::Cron, "Error updating state of #{@new_resource.name}, exit: #{status.exitstatus}"
end
end
+
+ def get_crontab_entry
+ newcron = ""
+ newcron << "# Chef Name: #{new_resource.name}\n"
+ [ :mailto, :path, :shell, :home ].each do |v|
+ newcron << "#{v.to_s.upcase}=#{@new_resource.send(v)}\n" if @new_resource.send(v)
+ end
+ @new_resource.environment.each do |name, value|
+ newcron << "#{name}=#{value}\n"
+ end
+ newcron << "#{@new_resource.minute} #{@new_resource.hour} #{@new_resource.day} #{@new_resource.month} #{@new_resource.weekday} #{@new_resource.command}\n"
+ newcron
+ end
end
end
end
diff --git a/lib/chef/provider/cron/aix.rb b/lib/chef/provider/cron/aix.rb
new file mode 100644
index 0000000000..473700bf2f
--- /dev/null
+++ b/lib/chef/provider/cron/aix.rb
@@ -0,0 +1,48 @@
+#
+# Author:: Kaustubh Deorukhkar (<kaustubh@clogeny.com>)
+# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "chef/provider/cron/unix"
+
+class Chef
+ class Provider
+ class Cron
+ class Aix < Chef::Provider::Cron::Unix
+
+ private
+
+ # For AIX we ignore env vars/[ :mailto, :path, :shell, :home ]
+ def get_crontab_entry
+ if env_vars_are_set?
+ raise Chef::Exceptions::Cron, "Aix cron entry does not support environment variables. Please set them in script and use script in cron."
+ end
+
+ newcron = ""
+ newcron << "# Chef Name: #{new_resource.name}\n"
+ newcron << "#{@new_resource.minute} #{@new_resource.hour} #{@new_resource.day} #{@new_resource.month} #{@new_resource.weekday}"
+
+ newcron << " #{@new_resource.command}\n"
+ newcron
+ end
+
+ def env_vars_are_set?
+ @new_resource.environment.length > 0 || !@new_resource.mailto.nil? || !@new_resource.path.nil? || !@new_resource.shell.nil? || !@new_resource.home.nil?
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/provider/cron/solaris.rb b/lib/chef/provider/cron/solaris.rb
index e0811ba0ac..20fa7abcce 100644
--- a/lib/chef/provider/cron/solaris.rb
+++ b/lib/chef/provider/cron/solaris.rb
@@ -1,15 +1,13 @@
#
-# Author:: Bryan McLellan (btm@loftninjas.org)
-# Author:: Toomas Pelberg (toomasp@gmx.net)
-# Copyright:: Copyright (c) 2009 Bryan McLellan
-# Copyright:: Copyright (c) 2010 Toomas Pelberg
+# Author:: Kaustubh Deorukhkar (<kaustubh@clogeny.com>)
+# Copyright:: Copyright (c) 2013 Opscode, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
-# http://www.apache.org/licenses/LICENSE-2.0
+# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
@@ -18,39 +16,7 @@
# limitations under the License.
#
-require 'chef/log'
-require 'chef/provider'
+require "chef/provider/cron/unix"
-class Chef
- class Provider
- class Cron
- class Solaris < Chef::Provider::Cron
-
- private
-
- def read_crontab
- crontab = nil
- status = popen4("crontab -l #{@new_resource.user}") do |pid, stdin, stdout, stderr|
- crontab = stdout.read
- end
- if status.exitstatus > 1
- raise Chef::Exceptions::Cron, "Error determining state of #{@new_resource.name}, exit: #{status.exitstatus}"
- end
- crontab
- end
-
- def write_crontab(crontab)
- tempcron = Tempfile.new("chef-cron")
- tempcron << crontab
- tempcron.flush
- tempcron.chmod(0644)
- status = run_command(:command => "/usr/bin/crontab #{tempcron.path}",:user => @new_resource.user)
- tempcron.close!
- if status.exitstatus > 0
- raise Chef::Exceptions::Cron, "Error updating state of #{@new_resource.name}, exit: #{status.exitstatus}"
- end
- end
- end
- end
- end
-end
+# Just to create an alias so 'Chef::Provider::Cron::Solaris' is exposed and accessible to existing consumers of class.
+Chef::Provider::Cron::Solaris = Chef::Provider::Cron::Unix
diff --git a/lib/chef/provider/cron/unix.rb b/lib/chef/provider/cron/unix.rb
new file mode 100644
index 0000000000..5cb1bcda41
--- /dev/null
+++ b/lib/chef/provider/cron/unix.rb
@@ -0,0 +1,76 @@
+#
+# Author:: Bryan McLellan (btm@loftninjas.org)
+# Author:: Toomas Pelberg (toomasp@gmx.net)
+# Copyright:: Copyright (c) 2009 Bryan McLellan
+# Copyright:: Copyright (c) 2010 Toomas Pelberg
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require 'chef/log'
+require 'chef/provider'
+
+class Chef
+ class Provider
+ class Cron
+ class Unix < Chef::Provider::Cron
+
+ private
+
+ def read_crontab
+ crontab = nil
+ status = popen4("crontab -l #{@new_resource.user}") do |pid, stdin, stdout, stderr|
+ crontab = stdout.read
+ end
+ if status.exitstatus > 1
+ raise Chef::Exceptions::Cron, "Error determining state of #{@new_resource.name}, exit: #{status.exitstatus}"
+ end
+ crontab
+ end
+
+ def write_crontab(crontab)
+ tempcron = Tempfile.new("chef-cron")
+ tempcron << crontab
+ tempcron.flush
+ tempcron.chmod(0644)
+ exit_status = 0
+ error_message = ""
+ begin
+ status, stdout, stderr = run_command_and_return_stdout_stderr(:command => "/usr/bin/crontab #{tempcron.path}",:user => @new_resource.user)
+ exit_status = status.exitstatus
+ # solaris9, 10 on some failures for example invalid 'mins' in crontab fails with exit code of zero :(
+ if stderr && stderr.include?("errors detected in input, no crontab file generated")
+ error_message = stderr
+ exit_status = 1
+ end
+ rescue Chef::Exceptions::Exec => e
+ Chef::Log.debug(e.message)
+ exit_status = 1
+ error_message = e.message
+ rescue ArgumentError => e
+ # usually raised on invalid user.
+ Chef::Log.debug(e.message)
+ exit_status = 1
+ error_message = e.message
+ end
+ tempcron.close!
+ if exit_status > 0
+ raise Chef::Exceptions::Cron, "Error updating state of #{@new_resource.name}, exit: #{exit_status}, message: #{error_message}"
+ end
+ end
+
+ end
+ end
+ end
+end
diff --git a/lib/chef/provider/deploy/timestamped.rb b/lib/chef/provider/deploy/timestamped.rb
index 9c2d55b490..ce921161e0 100644
--- a/lib/chef/provider/deploy/timestamped.rb
+++ b/lib/chef/provider/deploy/timestamped.rb
@@ -6,9 +6,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -20,9 +20,9 @@ class Chef
class Provider
class Deploy
class Timestamped < Chef::Provider::Deploy
-
+
protected
-
+
def release_slug
Time.now.utc.strftime("%Y%m%d%H%M%S")
end
diff --git a/lib/chef/provider/erl_call.rb b/lib/chef/provider/erl_call.rb
index 1ee1da500c..cdd494a243 100644
--- a/lib/chef/provider/erl_call.rb
+++ b/lib/chef/provider/erl_call.rb
@@ -32,7 +32,7 @@ class Chef
def whyrun_supported?
true
end
-
+
def load_current_resource
true
end
diff --git a/lib/chef/provider/execute.rb b/lib/chef/provider/execute.rb
index 8d2a7d997d..2907688e88 100644
--- a/lib/chef/provider/execute.rb
+++ b/lib/chef/provider/execute.rb
@@ -29,7 +29,7 @@ class Chef
def load_current_resource
true
end
-
+
def whyrun_supported?
true
end
@@ -56,7 +56,7 @@ class Chef
if STDOUT.tty? && !Chef::Config[:daemon] && Chef::Log.info?
opts[:live_stream] = STDOUT
end
- converge_by("execute #{@new_resource.command}") do
+ converge_by("execute #{@new_resource.command}") do
result = shell_out!(@new_resource.command, opts)
Chef::Log.info("#{@new_resource} ran successfully")
end
diff --git a/lib/chef/provider/git.rb b/lib/chef/provider/git.rb
index 7cda1a873a..b22004eda0 100644
--- a/lib/chef/provider/git.rb
+++ b/lib/chef/provider/git.rb
@@ -273,6 +273,7 @@ class Chef
run_opts[:group] = @new_resource.group if @new_resource.group
run_opts[:environment] = {"GIT_SSH" => @new_resource.ssh_wrapper} if @new_resource.ssh_wrapper
run_opts[:log_tag] = @new_resource.to_s
+ run_opts[:timeout] = @new_resource.timeout if @new_resource.timeout
run_opts
end
diff --git a/lib/chef/provider/group.rb b/lib/chef/provider/group.rb
index c941ed72bd..eacb033492 100644
--- a/lib/chef/provider/group.rb
+++ b/lib/chef/provider/group.rb
@@ -6,9 +6,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -35,11 +35,11 @@ class Chef
super
@group_exists = true
end
-
+
def load_current_resource
@current_resource = Chef::Resource::Group.new(@new_resource.name)
@current_resource.group_name(@new_resource.group_name)
-
+
group_info = nil
begin
group_info = Etc.getgrnam(@new_resource.group_name)
@@ -47,26 +47,26 @@ class Chef
@group_exists = false
Chef::Log.debug("#{@new_resource} group does not exist")
end
-
+
if group_info
@new_resource.gid(group_info.gid) unless @new_resource.gid
@current_resource.gid(group_info.gid)
@current_resource.members(group_info.mem)
end
-
+
@current_resource
end
def define_resource_requirements
- requirements.assert(:modify) do |a|
- a.assertion { @group_exists }
+ requirements.assert(:modify) do |a|
+ a.assertion { @group_exists }
a.failure_message(Chef::Exceptions::Group, "Cannot modify #{@new_resource} - group does not exist!")
a.whyrun("Group #{@new_resource} does not exist. Unless it would have been created earlier in this run, this attempt to modify it would fail.")
end
end
-
- # Check to see if a group needs any changes. Populate
- # @change_desc with a description of why a change must occur
+
+ # Check to see if a group needs any changes. Populate
+ # @change_desc with a description of why a change must occur
#
# ==== Returns
# <true>:: If a change is required
@@ -77,7 +77,7 @@ class Chef
@change_desc = "change gid #{@current_resource.gid} to #{@new_resource.gid}"
return true
end
-
+
if(@new_resource.append)
missing_members = []
@new_resource.members.each do |member|
@@ -96,24 +96,24 @@ class Chef
end
return false
end
-
+
def action_create
case @group_exists
when false
- converge_by("create #{@new_resource}") do
+ converge_by("create #{@new_resource}") do
create_group
Chef::Log.info("#{@new_resource} created")
end
- else
+ else
if compare_group
- converge_by(["alter group #{@new_resource}", @change_desc ]) do
+ converge_by(["alter group #{@new_resource}", @change_desc ]) do
manage_group
Chef::Log.info("#{@new_resource} altered")
end
end
end
end
-
+
def action_remove
if @group_exists
converge_by("remove group #{@new_resource}") do
@@ -122,16 +122,16 @@ class Chef
end
end
end
-
+
def action_manage
if @group_exists && compare_group
converge_by(["manage group #{@new_resource}", @change_desc]) do
- manage_group
+ manage_group
Chef::Log.info("#{@new_resource} managed")
end
end
end
-
+
def action_modify
if compare_group
converge_by(["modify group #{@new_resource}", @change_desc]) do
@@ -140,7 +140,7 @@ class Chef
end
end
end
-
+
def create_group
raise NotImplementedError, "subclasses of Chef::Provider::Group should define #create_group"
end
diff --git a/lib/chef/provider/group/dscl.rb b/lib/chef/provider/group/dscl.rb
index a8ba32641c..d0b2a4d499 100644
--- a/lib/chef/provider/group/dscl.rb
+++ b/lib/chef/provider/group/dscl.rb
@@ -6,9 +6,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -38,7 +38,7 @@ class Chef
raise(Chef::Exceptions::Group,"dscl error: #{result.inspect}") if result[2] =~ /No such key: /
return result[2]
end
-
+
# This is handled in providers/group.rb by Etc.getgrnam()
# def group_exists?(group)
# groups = safe_dscl("list /Groups")
@@ -86,8 +86,8 @@ class Chef
def define_resource_requirements
super
- requirements.assert(:all_actions) do |a|
- a.assertion { ::File.exists?("/usr/bin/dscl") }
+ requirements.assert(:all_actions) do |a|
+ a.assertion { ::File.exists?("/usr/bin/dscl") }
a.failure_message Chef::Exceptions::Group, "Could not find binary /usr/bin/dscl for #{@new_resource.name}"
# No whyrun alternative: this component should be available in the base install of any given system that uses it
end
@@ -96,13 +96,13 @@ class Chef
def load_current_resource
super
end
-
+
def create_group
dscl_create_group
set_gid
set_members
end
-
+
def manage_group
if @new_resource.group_name && (@current_resource.group_name != @new_resource.group_name)
dscl_create_group
@@ -114,12 +114,12 @@ class Chef
set_members
end
end
-
+
def dscl_create_group
safe_dscl("create /Groups/#{@new_resource.group_name}")
safe_dscl("create /Groups/#{@new_resource.group_name} Password '*'")
end
-
+
def remove_group
safe_dscl("delete /Groups/#{@new_resource.group_name}")
end
diff --git a/lib/chef/provider/group/gpasswd.rb b/lib/chef/provider/group/gpasswd.rb
index 7fb27a7777..2638b82383 100644
--- a/lib/chef/provider/group/gpasswd.rb
+++ b/lib/chef/provider/group/gpasswd.rb
@@ -6,9 +6,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -32,9 +32,9 @@ class Chef
def define_resource_requirements
super
- requirements.assert(:all_actions) do |a|
- a.assertion { ::File.exists?("/usr/bin/gpasswd") }
- a.failure_message Chef::Exceptions::Group, "Could not find binary /usr/bin/gpasswd for #{@new_resource}"
+ requirements.assert(:all_actions) do |a|
+ a.assertion { ::File.exists?("/usr/bin/gpasswd") }
+ a.failure_message Chef::Exceptions::Group, "Could not find binary /usr/bin/gpasswd for #{@new_resource}"
# No whyrun alternative: this component should be available in the base install of any given system that uses it
end
end
diff --git a/lib/chef/provider/group/groupadd.rb b/lib/chef/provider/group/groupadd.rb
index 544fee4304..45ae308612 100644
--- a/lib/chef/provider/group/groupadd.rb
+++ b/lib/chef/provider/group/groupadd.rb
@@ -6,9 +6,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -20,7 +20,7 @@ class Chef
class Provider
class Group
class Groupadd < Chef::Provider::Group
-
+
def required_binaries
[ "/usr/sbin/groupadd",
"/usr/sbin/groupmod",
@@ -34,9 +34,9 @@ class Chef
def define_resource_requirements
super
required_binaries.each do |required_binary|
- requirements.assert(:all_actions) do |a|
- a.assertion { ::File.exists?(required_binary) }
- a.failure_message Chef::Exceptions::Group, "Could not find binary #{required_binary} for #{@new_resource}"
+ requirements.assert(:all_actions) do |a|
+ a.assertion { ::File.exists?(required_binary) }
+ a.failure_message Chef::Exceptions::Group, "Could not find binary #{required_binary} for #{@new_resource}"
# No whyrun alternative: this component should be available in the base install of any given system that uses it
end
end
@@ -48,9 +48,9 @@ class Chef
command << set_options
command << groupadd_options
run_command(:command => command)
- modify_group_members
+ modify_group_members
end
-
+
# Manage the group when it already exists
def manage_group
command = "groupmod"
@@ -58,12 +58,12 @@ class Chef
run_command(:command => command)
modify_group_members
end
-
+
# Remove the group
def remove_group
run_command(:command => "groupdel #{@new_resource.group_name}")
end
-
+
def modify_group_members
raise Chef::Exceptions::Group, "you must override modify_group_members in #{self.to_s}"
end
@@ -87,6 +87,7 @@ class Chef
def groupadd_options
opts = ''
opts << " -r" if @new_resource.system
+ opts << " -o" if @new_resource.non_unique
opts
end
diff --git a/lib/chef/provider/group/pw.rb b/lib/chef/provider/group/pw.rb
index 3bf67a515a..66da8281be 100644
--- a/lib/chef/provider/group/pw.rb
+++ b/lib/chef/provider/group/pw.rb
@@ -6,9 +6,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -20,21 +20,21 @@ class Chef
class Provider
class Group
class Pw < Chef::Provider::Group
-
+
def load_current_resource
super
end
-
+
def define_resource_requirements
super
- requirements.assert(:all_actions) do |a|
- a.assertion { ::File.exists?("/usr/sbin/pw") }
+ requirements.assert(:all_actions) do |a|
+ a.assertion { ::File.exists?("/usr/sbin/pw") }
a.failure_message Chef::Exceptions::Group, "Could not find binary /usr/sbin/pw for #{@new_resource}"
# No whyrun alternative: this component should be available in the base install of any given system that uses it
end
end
-
+
# Create the group
def create_group
command = "pw groupadd"
@@ -42,7 +42,7 @@ class Chef
command << set_members_option
run_command(:command => command)
end
-
+
# Manage the group when it already exists
def manage_group
command = "pw groupmod"
@@ -50,12 +50,12 @@ class Chef
command << set_members_option
run_command(:command => command)
end
-
+
# Remove the group
def remove_group
run_command(:command => "pw groupdel #{@new_resource.group_name}")
end
-
+
# Little bit of magic as per Adam's useradd provider to pull and assign the command line flags
#
# ==== Returns
@@ -86,7 +86,7 @@ class Chef
end
opt
end
-
+
end
end
end
diff --git a/lib/chef/provider/group/suse.rb b/lib/chef/provider/group/suse.rb
index 0b66c1f912..4c343bddf9 100644
--- a/lib/chef/provider/group/suse.rb
+++ b/lib/chef/provider/group/suse.rb
@@ -6,9 +6,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -32,8 +32,8 @@ class Chef
def define_resource_requirements
super
- requirements.assert(:all_actions) do |a|
- a.assertion { ::File.exists?("/usr/sbin/groupmod") }
+ requirements.assert(:all_actions) do |a|
+ a.assertion { ::File.exists?("/usr/sbin/groupmod") }
a.failure_message Chef::Exceptions::Group, "Could not find binary /usr/sbin/groupmod for #{@new_resource.name}"
# No whyrun alternative: this component should be available in the base install of any given system that uses it
end
diff --git a/lib/chef/provider/group/usermod.rb b/lib/chef/provider/group/usermod.rb
index 0d44d3940f..5788ac8fad 100644
--- a/lib/chef/provider/group/usermod.rb
+++ b/lib/chef/provider/group/usermod.rb
@@ -6,9 +6,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -22,7 +22,7 @@ class Chef
class Provider
class Group
class Usermod < Chef::Provider::Group::Groupadd
-
+
def load_current_resource
super
end
@@ -30,24 +30,24 @@ class Chef
def define_resource_requirements
super
- requirements.assert(:all_actions) do |a|
- a.assertion { ::File.exists?("/usr/sbin/usermod") }
+ requirements.assert(:all_actions) do |a|
+ a.assertion { ::File.exists?("/usr/sbin/usermod") }
a.failure_message Chef::Exceptions::Group, "Could not find binary /usr/sbin/usermod for #{@new_resource}"
# No whyrun alternative: this component should be available in the base install of any given system that uses it
end
requirements.assert(:modify, :create) do |a|
- a.assertion { @new_resource.members.empty? || @new_resource.append }
+ a.assertion { @new_resource.members.empty? || @new_resource.append }
a.failure_message Chef::Exceptions::Group, "setting group members directly is not supported by #{self.to_s}, must set append true in group"
# No whyrun alternative - this action is simply not supported.
end
end
-
+
def modify_group_members
case node[:platform]
when "openbsd", "netbsd", "aix", "solaris2", "smartos"
append_flags = "-G"
- when "solaris", "suse"
+ when "solaris", "suse", "opensuse"
append_flags = "-a -G"
end
diff --git a/lib/chef/provider/group/windows.rb b/lib/chef/provider/group/windows.rb
index 88280408cd..da12366329 100644
--- a/lib/chef/provider/group/windows.rb
+++ b/lib/chef/provider/group/windows.rb
@@ -6,9 +6,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -25,16 +25,16 @@ class Chef
class Provider
class Group
class Windows < Chef::Provider::Group
-
+
def initialize(new_resource,run_context)
super
- @net_group = Chef::Util::Windows::NetGroup.new(@new_resource.name)
+ @net_group = Chef::Util::Windows::NetGroup.new(@new_resource.group_name)
end
def load_current_resource
@current_resource = Chef::Resource::Group.new(@new_resource.name)
@current_resource.group_name(@new_resource.group_name)
-
+
members = nil
begin
members = @net_group.local_get_members
@@ -49,12 +49,12 @@ class Chef
@current_resource
end
-
+
def create_group
@net_group.local_add
manage_group
end
-
+
def manage_group
if @new_resource.append
begin
@@ -68,11 +68,11 @@ class Chef
@net_group.local_set_members(@new_resource.members)
end
end
-
+
def remove_group
@net_group.local_delete
end
-
+
end
end
end
diff --git a/lib/chef/provider/http_request.rb b/lib/chef/provider/http_request.rb
index a5bc3b5e04..1e0aa8b4a0 100644
--- a/lib/chef/provider/http_request.rb
+++ b/lib/chef/provider/http_request.rb
@@ -17,26 +17,27 @@
#
require 'tempfile'
+require 'chef/http/simple'
class Chef
class Provider
class HttpRequest < Chef::Provider
- attr_accessor :rest
+ attr_accessor :http
def whyrun_supported?
true
end
def load_current_resource
- @rest = Chef::REST.new(@new_resource.url, nil, nil)
+ @http = Chef::HTTP::Simple.new(@new_resource.url)
end
# Send a HEAD request to @new_resource.url, with ?message=@new_resource.message
def action_head
message = check_message(@new_resource.message)
# returns true from Chef::REST if returns 2XX (Net::HTTPSuccess)
- modified = @rest.head(
+ modified = @http.head(
"#{@new_resource.url}?message=#{message}",
@new_resource.headers
)
@@ -53,9 +54,8 @@ class Chef
converge_by("#{@new_resource} GET to #{@new_resource.url}") do
message = check_message(@new_resource.message)
- body = @rest.get(
+ body = @http.get(
"#{@new_resource.url}?message=#{message}",
- false,
@new_resource.headers
)
Chef::Log.info("#{@new_resource} GET to #{@new_resource.url} successful")
@@ -67,7 +67,7 @@ class Chef
def action_put
converge_by("#{@new_resource} PUT to #{@new_resource.url}") do
message = check_message(@new_resource.message)
- body = @rest.put(
+ body = @http.put(
"#{@new_resource.url}",
message,
@new_resource.headers
@@ -81,7 +81,7 @@ class Chef
def action_post
converge_by("#{@new_resource} POST to #{@new_resource.url}") do
message = check_message(@new_resource.message)
- body = @rest.post(
+ body = @http.post(
"#{@new_resource.url}",
message,
@new_resource.headers
@@ -94,7 +94,7 @@ class Chef
# Send a DELETE request to @new_resource.url
def action_delete
converge_by("#{@new_resource} DELETE to #{@new_resource.url}") do
- body = @rest.delete(
+ body = @http.delete(
"#{@new_resource.url}",
@new_resource.headers
)
diff --git a/lib/chef/provider/ifconfig.rb b/lib/chef/provider/ifconfig.rb
index 0aacc9e616..31f88e5406 100644
--- a/lib/chef/provider/ifconfig.rb
+++ b/lib/chef/provider/ifconfig.rb
@@ -26,11 +26,11 @@ require 'erb'
#
# int = {Hash with your network settings...}
#
-# ifconfig int['ip'] do
-# ignore_failure true
-# device int['dev']
-# mask int['mask']
-# gateway int['gateway']
+# ifconfig int['ip'] do
+# ignore_failure true
+# device int['dev']
+# mask int['mask']
+# gateway int['gateway']
# mtu int['mtu']
# end
@@ -76,7 +76,7 @@ class Chef
@interface = @interfaces.fetch(@new_resource.device)
@current_resource.target(@new_resource.target)
- @current_resource.device(@int_name)
+ @current_resource.device(@new_resource.device)
@current_resource.inet_addr(@interface["inet_addr"])
@current_resource.hwaddr(@interface["hwaddr"])
@current_resource.bcast(@interface["bcast"])
@@ -89,12 +89,12 @@ class Chef
@current_resource
end
- def define_resource_requirements
- requirements.assert(:all_actions) do |a|
+ def define_resource_requirements
+ requirements.assert(:all_actions) do |a|
a.assertion { @status.exitstatus == 0 }
a.failure_message Chef::Exceptions::Ifconfig, "ifconfig failed - #{@status.inspect}!"
# no whyrun - if the base ifconfig used in load_current_resource fails
- # there's no reasonable action that could have been taken in the course of
+ # there's no reasonable action that could have been taken in the course of
# a chef run to fix it.
end
end
@@ -102,40 +102,32 @@ class Chef
def action_add
# check to see if load_current_resource found interface in ifconfig
unless @current_resource.inet_addr
- unless @new_resource.device == "lo"
- command = "ifconfig #{@new_resource.device} #{@new_resource.name}"
- command << " netmask #{@new_resource.mask}" if @new_resource.mask
- command << " metric #{@new_resource.metric}" if @new_resource.metric
- command << " mtu #{@new_resource.mtu}" if @new_resource.mtu
- end
- converge_by ("run #{command} to add #{@new_resource}") do
- run_command(
- :command => command
- )
- Chef::Log.info("#{@new_resource} added")
+ unless @new_resource.device == loopback_device
+ command = add_command
+ converge_by ("run #{command} to add #{@new_resource}") do
+ run_command(
+ :command => command
+ )
+ Chef::Log.info("#{@new_resource} added")
+ # Write out the config files
+ generate_config
+ end
end
end
-
- # Write out the config files
- generate_config
end
def action_enable
# check to see if load_current_resource found ifconfig
# enables, but does not manage config files
unless @current_resource.inet_addr
- unless @new_resource.device == "lo"
- command = "ifconfig #{@new_resource.device} #{@new_resource.name}"
- command << " netmask #{@new_resource.mask}" if @new_resource.mask
- command << " metric #{@new_resource.metric}" if @new_resource.metric
- command << " mtu #{@new_resource.mtu}" if @new_resource.mtu
- end
-
- converge_by ("run #{command} to enable #{@new_resource}") do
- run_command(
- :command => command
- )
- Chef::Log.info("#{@new_resource} enabled")
+ unless @new_resource.device == loopback_device
+ command = enable_command
+ converge_by ("run #{command} to enable #{@new_resource}") do
+ run_command(
+ :command => command
+ )
+ Chef::Log.info("#{@new_resource} enabled")
+ end
end
end
end
@@ -143,7 +135,7 @@ class Chef
def action_delete
# check to see if load_current_resource found the interface
if @current_resource.device
- command = "ifconfig #{@new_resource.device} down"
+ command = delete_command
converge_by ("run #{command} to delete #{@new_resource}") do
run_command(
:command => command
@@ -160,7 +152,7 @@ class Chef
# check to see if load_current_resource found the interface
# disables, but leaves config files in place.
if @current_resource.device
- command = "ifconfig #{@new_resource.device} down"
+ command = disable_command
converge_by ("run #{command} to disable #{@new_resource}") do
run_command(
:command => command
@@ -199,6 +191,34 @@ class Chef
Chef::Log.info("#{@new_resource} deleted configuration file")
end
+ private
+ def add_command
+ command = "ifconfig #{@new_resource.device} #{@new_resource.name}"
+ command << " netmask #{@new_resource.mask}" if @new_resource.mask
+ command << " metric #{@new_resource.metric}" if @new_resource.metric
+ command << " mtu #{@new_resource.mtu}" if @new_resource.mtu
+ command
+ end
+
+ def enable_command
+ command = "ifconfig #{@new_resource.device} #{@new_resource.name}"
+ command << " netmask #{@new_resource.mask}" if @new_resource.mask
+ command << " metric #{@new_resource.metric}" if @new_resource.metric
+ command << " mtu #{@new_resource.mtu}" if @new_resource.mtu
+ command
+ end
+
+ def disable_command
+ "ifconfig #{@new_resource.device} down"
+ end
+
+ def delete_command
+ "ifconfig #{@new_resource.device} down"
+ end
+
+ def loopback_device
+ 'lo'
+ end
end
end
end
diff --git a/lib/chef/provider/ifconfig/aix.rb b/lib/chef/provider/ifconfig/aix.rb
new file mode 100644
index 0000000000..460b1ba7f2
--- /dev/null
+++ b/lib/chef/provider/ifconfig/aix.rb
@@ -0,0 +1,99 @@
+#
+# Author:: Kaustubh Deorukhkar (kaustubh@clogeny.com)
+# Copyright:: Copyright (c) 2013 Opscode, Inc
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require 'chef/provider/ifconfig'
+
+class Chef
+ class Provider
+ class Ifconfig
+ class Aix < Chef::Provider::Ifconfig
+
+ def load_current_resource
+ @current_resource = Chef::Resource::Ifconfig.new(@new_resource.name)
+
+ @interface_exists = false
+ found_interface = false
+ interface = {}
+
+ @status = popen4("ifconfig -a") do |pid, stdin, stdout, stderr|
+ stdout.each do |line|
+
+ if !found_interface
+ if line =~ /^(\S+):\sflags=(\S+)/
+ # We have interface name, if this is the interface for @current_resource, load info else skip till next interface is found.
+ if $1 == @new_resource.device
+ # Found interface
+ found_interface = true
+ @interface_exists = true
+ @current_resource.target(@new_resource.target)
+ @current_resource.device($1)
+ interface[:flags] = $2
+ @current_resource.metric($1) if line =~ /metric\s(\S+)/
+ end
+ end
+ else
+ # parse interface related information, stop when next interface is found.
+ if line =~ /^(\S+):\sflags=(\S+)/
+ # we are done parsing interface info and hit another one, so stop.
+ found_interface = false
+ break
+ else
+ if found_interface
+ # read up interface info
+ @current_resource.inet_addr($1) if line =~ /inet\s(\S+)\s/
+ @current_resource.bcast($1) if line =~ /broadcast\s(\S+)/
+ @current_resource.mask(hex_to_dec_netmask($1)) if line =~ /netmask\s(\S+)\s/
+ end
+ end
+ end
+ end
+ end
+
+ @current_resource
+ end
+
+ private
+ def add_command
+ # ifconfig changes are temporary, chdev persist across reboots.
+ raise Chef::Exceptions::Ifconfig, "interface metric attribute cannot be set for :add action" if @new_resource.metric
+ command = "chdev -l #{@new_resource.device} -a netaddr=#{@new_resource.name}"
+ command << " -a netmask=#{@new_resource.mask}" if @new_resource.mask
+ command << " -a mtu=#{@new_resource.mtu}" if @new_resource.mtu
+ command
+ end
+
+ def delete_command
+ # ifconfig changes are temporary, chdev persist across reboots.
+ "chdev -l #{@new_resource.device} -a state=down"
+ end
+
+ def loopback_device
+ "lo0"
+ end
+
+ def hex_to_dec_netmask(netmask)
+ # example '0xffff0000' -> '255.255.0.0'
+ dec = netmask[2..3].to_i(16).to_s(10)
+ [4,6,8].each { |n| dec = dec + "." + netmask[n..n+1].to_i(16).to_s(10) }
+ dec
+ end
+
+ end
+ end
+ end
+end
diff --git a/lib/chef/provider/log.rb b/lib/chef/provider/log.rb
index 927ee72fcc..1c970cc888 100644
--- a/lib/chef/provider/log.rb
+++ b/lib/chef/provider/log.rb
@@ -6,9 +6,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -32,7 +32,7 @@ class Chef
def load_current_resource
true
end
-
+
# Write the log to Chef's log
#
# === Return
diff --git a/lib/chef/provider/mdadm.rb b/lib/chef/provider/mdadm.rb
index d93ff69c13..51c9b8d3c6 100644
--- a/lib/chef/provider/mdadm.rb
+++ b/lib/chef/provider/mdadm.rb
@@ -47,8 +47,9 @@ class Chef
def action_create
unless @current_resource.exists
- converge_by("create RAID device #{new_resource.raid_device}") do
- command = "yes | mdadm --create #{@new_resource.raid_device} --chunk=#{@new_resource.chunk} --level #{@new_resource.level}"
+ converge_by("create RAID device #{new_resource.raid_device}") do
+ command = "yes | mdadm --create #{@new_resource.raid_device} --level #{@new_resource.level}"
+ command << " --chunk=#{@new_resource.chunk}" unless @new_resource.level == 1
command << " --metadata=#{@new_resource.metadata}"
command << " --bitmap=#{@new_resource.bitmap}" if @new_resource.bitmap
command << " --raid-devices #{@new_resource.devices.length} #{@new_resource.devices.join(" ")}"
@@ -63,7 +64,7 @@ class Chef
def action_assemble
unless @current_resource.exists
- converge_by("assemble RAID device #{new_resource.raid_device}") do
+ converge_by("assemble RAID device #{new_resource.raid_device}") do
command = "yes | mdadm --assemble #{@new_resource.raid_device} #{@new_resource.devices.join(" ")}"
Chef::Log.debug("#{@new_resource} mdadm command: #{command}")
shell_out!(command)
@@ -76,7 +77,7 @@ class Chef
def action_stop
if @current_resource.exists
- converge_by("stop RAID device #{new_resource.raid_device}") do
+ converge_by("stop RAID device #{new_resource.raid_device}") do
command = "yes | mdadm --stop #{@new_resource.raid_device}"
Chef::Log.debug("#{@new_resource} mdadm command: #{command}")
shell_out!(command)
diff --git a/lib/chef/provider/mount.rb b/lib/chef/provider/mount.rb
index 6b9dd91ac8..5f58baa396 100644
--- a/lib/chef/provider/mount.rb
+++ b/lib/chef/provider/mount.rb
@@ -6,9 +6,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -37,7 +37,7 @@ class Chef
def action_mount
unless @current_resource.mounted
- converge_by("mount #{@current_resource.device} to #{@current_resource.mount_point}") do
+ converge_by("mount #{@current_resource.device} to #{@current_resource.mount_point}") do
status = mount_fs()
if status
Chef::Log.info("#{@new_resource} mounted")
@@ -50,7 +50,7 @@ class Chef
def action_umount
if @current_resource.mounted
- converge_by("unmount #{@current_resource.device}") do
+ converge_by("unmount #{@current_resource.device}") do
status = umount_fs()
if status
Chef::Log.info("#{@new_resource} unmounted")
@@ -66,7 +66,7 @@ class Chef
raise Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support :remount"
else
if @current_resource.mounted
- converge_by("remount #{@current_resource.device}") do
+ converge_by("remount #{@current_resource.device}") do
status = remount_fs()
if status
Chef::Log.info("#{@new_resource} remounted")
@@ -80,7 +80,7 @@ class Chef
def action_enable
unless @current_resource.enabled && mount_options_unchanged?
- converge_by("remount #{@current_resource.device}") do
+ converge_by("remount #{@current_resource.device}") do
status = enable_fs
if status
Chef::Log.info("#{@new_resource} enabled")
@@ -93,7 +93,7 @@ class Chef
def action_disable
if @current_resource.enabled
- converge_by("remount #{@current_resource.device}") do
+ converge_by("remount #{@current_resource.device}") do
status = disable_fs
if status
Chef::Log.info("#{@new_resource} disabled")
@@ -115,14 +115,14 @@ class Chef
def remount_fs
raise Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support :remount"
end
-
+
def enable_fs
- raise Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support :enable"
+ raise Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support :enable"
end
-
+
def disable_fs
- raise Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support :disable"
- end
+ raise Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support :disable"
+ end
end
end
end
diff --git a/lib/chef/provider/mount/aix.rb b/lib/chef/provider/mount/aix.rb
new file mode 100644
index 0000000000..0d7e11a1b8
--- /dev/null
+++ b/lib/chef/provider/mount/aix.rb
@@ -0,0 +1,179 @@
+#
+# Author::
+# Copyright:: Copyright (c) 2009 Opscode, Inc
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require 'chef/provider/mount'
+
+class Chef
+ class Provider
+ class Mount
+ class Aix < Chef::Provider::Mount::Mount
+
+ # Override for aix specific handling
+ def initialize(new_resource, run_context)
+ super
+ # options and fstype are set to "defaults" and "auto" respectively in the Mount Resource class. These options are not valid for AIX, override them.
+ if @new_resource.options[0] == "defaults"
+ @new_resource.options.clear
+ end
+ if @new_resource.fstype == "auto"
+ @new_resource.fstype = nil
+ end
+ end
+
+ def enabled?
+ # Check to see if there is an entry in /etc/filesystems. Last entry for a volume wins. Using command "lsfs" to fetch entries.
+ enabled = false
+
+ # lsfs o/p = #MountPoint:Device:Vfs:Nodename:Type:Size:Options:AutoMount:Acct
+ # search only for current mount point
+ shell_out("lsfs -c #{@new_resource.mount_point}").stdout.each_line do | line |
+ case line
+ when /^#\s/
+ next
+ when /^#{Regexp.escape(@new_resource.mount_point)}:#{device_fstab_regex}:(\S+):(\[\S+\])?:(\S+)?:(\S+):(\S+):(\S+):(\S+)/
+ # mount point entry with ipv6 address for nodename (ipv6 address use ':')
+ enabled = true
+ @current_resource.fstype($1)
+ @current_resource.options($5)
+ Chef::Log.debug("Found mount #{device_fstab} to #{@new_resource.mount_point} in /etc/filesystems")
+ next
+ when /^#{Regexp.escape(@new_resource.mount_point)}:#{device_fstab_regex}::(\S+):(\S+)?:(\S+)?:(\S+):(\S+):(\S+):(\S+)/
+ # mount point entry with hostname or ipv4 address
+ enabled = true
+ @current_resource.fstype($1)
+ @current_resource.options($5)
+ Chef::Log.debug("Found mount #{device_fstab} to #{@new_resource.mount_point} in /etc/filesystems")
+ next
+ when /^#{Regexp.escape(@new_resource.mount_point)}/
+ enabled=false
+ Chef::Log.debug("Found conflicting mount point #{@new_resource.mount_point} in /etc/filesystems")
+ end
+ end
+ @current_resource.enabled(enabled)
+ end
+
+ def mounted?
+ mounted = false
+ shell_out!("mount").stdout.each_line do |line|
+ if network_device?
+ device_details = device_fstab.split(":")
+ search_device = device_details[1]
+ else
+ search_device = device_fstab_regex
+ end
+ case line
+ when /#{search_device}\s+#{Regexp.escape(@new_resource.mount_point)}/
+ mounted = true
+ Chef::Log.debug("Special device #{device_logstring} mounted as #{@new_resource.mount_point}")
+ when /^[\/\w]+\s+#{Regexp.escape(@new_resource.mount_point)}\s+/
+ mounted = false
+ Chef::Log.debug("Found conflicting mount point #{@new_resource.mount_point} in /etc/fstab")
+ end
+ end
+ @current_resource.mounted(mounted)
+ end
+
+ def mount_fs
+ unless @current_resource.mounted
+ mountable?
+ command = "mount -v #{@new_resource.fstype}"
+
+ if !(@new_resource.options.nil? || @new_resource.options.empty?)
+ command << " -o #{@new_resource.options.join(',')}"
+ end
+
+ command << case @new_resource.device_type
+ when :device
+ " #{device_real}"
+ when :label
+ " -L #{@new_resource.device}"
+ when :uuid
+ " -U #{@new_resource.device}"
+ end
+ command << " #{@new_resource.mount_point}"
+ shell_out!(command)
+ Chef::Log.debug("#{@new_resource} is mounted at #{@new_resource.mount_point}")
+ else
+ Chef::Log.debug("#{@new_resource} is already mounted at #{@new_resource.mount_point}")
+ end
+ end
+
+ def remount_command
+ if !(@new_resource.options.nil? || @new_resource.options.empty?)
+ return "mount -o remount,#{@new_resource.options.join(',')} #{@new_resource.device} #{@new_resource.mount_point}"
+ else
+ return "mount -o remount #{@new_resource.device} #{@new_resource.mount_point}"
+ end
+ end
+
+ def enable_fs
+ if @current_resource.enabled && mount_options_unchanged?
+ Chef::Log.debug("#{@new_resource} is already enabled - nothing to do")
+ return nil
+ end
+
+ if @current_resource.enabled
+ # The current options don't match what we have, so
+ # disable, then enable.
+ disable_fs
+ end
+ ::File.open("/etc/filesystems", "a") do |fstab|
+ fstab.puts("#{@new_resource.mount_point}:")
+ if network_device?
+ device_details = device_fstab.split(":")
+ fstab.puts("\tdev\t\t= #{device_details[1]}")
+ fstab.puts("\tnodename\t\t= #{device_details[0]}")
+ else
+ fstab.puts("\tdev\t\t= #{device_fstab}")
+ end
+ fstab.puts("\tvfs\t\t= #{@new_resource.fstype}")
+ fstab.puts("\tmount\t\t= false")
+ fstab.puts "\toptions\t\t= #{@new_resource.options.join(',')}" unless @new_resource.options.nil? || @new_resource.options.empty?
+ Chef::Log.debug("#{@new_resource} is enabled at #{@new_resource.mount_point}")
+ end
+ end
+
+ def disable_fs
+ contents = []
+ if @current_resource.enabled
+ found_device = false
+ ::File.open("/etc/filesystems", "r").each_line do |line|
+ case line
+ when /^\/.+:\s*$/
+ if line =~ /#{Regexp.escape(@new_resource.mount_point)}+:/
+ found_device = true
+ else
+ found_device = false
+ end
+ end
+ if !found_device
+ contents << line
+ end
+ end
+ ::File.open("/etc/filesystems", "w") do |fstab|
+ contents.each { |line| fstab.puts line}
+ end
+ else
+ Chef::Log.debug("#{@new_resource} is not enabled - nothing to do")
+ end
+ end
+
+ end
+ end
+ end
+end
diff --git a/lib/chef/provider/mount/mount.rb b/lib/chef/provider/mount/mount.rb
index ec54831017..25dfd42725 100644
--- a/lib/chef/provider/mount/mount.rb
+++ b/lib/chef/provider/mount/mount.rb
@@ -39,7 +39,7 @@ class Chef
mounted?
enabled?
end
-
+
def mountable?
# only check for existence of non-remote devices
if (device_should_exist? && !::File.exists?(device_real) )
@@ -49,7 +49,7 @@ class Chef
end
return true
end
-
+
def enabled?
# Check to see if there is a entry in /etc/fstab. Last entry for a volume wins.
enabled = false
@@ -72,17 +72,27 @@ class Chef
end
@current_resource.enabled(enabled)
end
-
+
def mounted?
mounted = false
+
+ # "mount" outputs the mount points as real paths. Convert
+ # the mount_point of the resource to a real path in case it
+ # contains symlinks in its parents dirs.
+ real_mount_point = if ::File.exists? @new_resource.mount_point
+ ::File.realpath(@new_resource.mount_point)
+ else
+ @new_resource.mount_point
+ end
+
shell_out!("mount").stdout.each_line do |line|
case line
- when /^#{device_mount_regex}\s+on\s+#{Regexp.escape(@new_resource.mount_point)}/
+ when /^#{device_mount_regex}\s+on\s+#{Regexp.escape(real_mount_point)}/
mounted = true
- Chef::Log.debug("Special device #{device_logstring} mounted as #{@new_resource.mount_point}")
- when /^([\/\w])+\son\s#{Regexp.escape(@new_resource.mount_point)}\s+/
+ Chef::Log.debug("Special device #{device_logstring} mounted as #{real_mount_point}")
+ when /^([\/\w])+\son\s#{Regexp.escape(real_mount_point)}\s+/
mounted = false
- Chef::Log.debug("Special device #{$~[1]} mounted as #{@new_resource.mount_point}")
+ Chef::Log.debug("Special device #{$~[1]} mounted as #{real_mount_point}")
end
end
@current_resource.mounted(mounted)
@@ -118,9 +128,13 @@ class Chef
end
end
+ def remount_command
+ return "mount -o remount #{@new_resource.mount_point}"
+ end
+
def remount_fs
if @current_resource.mounted and @new_resource.supports[:remount]
- shell_out!("mount -o remount #{@new_resource.mount_point}")
+ shell_out!(remount_command)
@new_resource.updated_by_last_action(true)
Chef::Log.debug("#{@new_resource} is remounted at #{@new_resource.mount_point}")
elsif @current_resource.mounted
@@ -137,7 +151,7 @@ class Chef
Chef::Log.debug("#{@new_resource} is already enabled - nothing to do")
return nil
end
-
+
if @current_resource.enabled
# The current options don't match what we have, so
# disable, then enable.
@@ -152,7 +166,7 @@ class Chef
def disable_fs
if @current_resource.enabled
contents = []
-
+
found = false
::File.readlines("/etc/fstab").reverse_each do |line|
if !found && line =~ /^#{device_fstab_regex}\s+#{Regexp.escape(@new_resource.mount_point)}/
@@ -163,7 +177,7 @@ class Chef
contents << line
end
end
-
+
::File.open("/etc/fstab", "w") do |fstab|
contents.reverse_each { |line| fstab.puts line}
end
@@ -177,7 +191,7 @@ class Chef
end
def device_should_exist?
- ( @new_resource.device != "none" ) &&
+ ( @new_resource.device != "none" ) &&
( not network_device? ) &&
( not %w[ tmpfs fuse ].include? @new_resource.fstype )
end
@@ -196,7 +210,7 @@ class Chef
end
def device_real
- if @real_device == nil
+ if @real_device == nil
if @new_resource.device_type == :device
@real_device = @new_resource.device
else
@@ -243,14 +257,14 @@ class Chef
device_fstab
end
end
-
+
def mount_options_unchanged?
@current_resource.fstype == @new_resource.fstype and
@current_resource.options == @new_resource.options and
@current_resource.dump == @new_resource.dump and
@current_resource.pass == @new_resource.pass
end
-
+
end
end
end
diff --git a/lib/chef/provider/package.rb b/lib/chef/provider/package.rb
index a28a6f93fb..c7692a9746 100644
--- a/lib/chef/provider/package.rb
+++ b/lib/chef/provider/package.rb
@@ -50,7 +50,7 @@ class Chef
requirements.assert(:upgrade) do |a|
# Can't upgrade what we don't have
- a.assertion { !(@current_resource.version.nil? && candidate_version.nil?) }
+ a.assertion { !(@current_resource.version.nil? && candidate_version.nil?) }
a.failure_message(Chef::Exceptions::Package, "No candidate version available for #{@new_resource.package_name}")
a.whyrun("Assuming a repository that offers #{@new_resource.package_name} would have been configured")
end
@@ -71,9 +71,9 @@ class Chef
# We need to make sure we handle the preseed file
if @new_resource.response_file
if preseed_file = get_preseed_file(@new_resource.package_name, install_version)
- converge_by("preseed package #{@new_resource.package_name}") do
+ converge_by("preseed package #{@new_resource.package_name}") do
preseed_package(preseed_file)
- end
+ end
end
end
description = install_version ? "version #{install_version} of" : ""
@@ -92,7 +92,7 @@ class Chef
@new_resource.version(candidate_version)
orig_version = @current_resource.version || "uninstalled"
converge_by("upgrade package #{@new_resource.package_name} from #{orig_version} to #{candidate_version}") do
- status = upgrade_package(@new_resource.package_name, candidate_version)
+ upgrade_package(@new_resource.package_name, candidate_version)
Chef::Log.info("#{@new_resource} upgraded from #{orig_version} to #{candidate_version}")
end
end
@@ -146,7 +146,7 @@ class Chef
if preseed_file = get_preseed_file(@new_resource.package_name, @current_resource.version)
converge_by("reconfigure package #{@new_resource.package_name}") do
preseed_package(preseed_file)
- status = reconfig_package(@new_resource.package_name, @current_resource.version)
+ reconfig_package(@new_resource.package_name, @current_resource.version)
Chef::Log.info("#{@new_resource} reconfigured")
end
else
@@ -198,21 +198,21 @@ class Chef
Chef::Log.debug("#{@new_resource} fetching preseed file to #{cache_seed_to}")
- begin
+
+ if template_available?(@new_resource.response_file)
+ Chef::Log.debug("#{@new_resource} fetching preseed file via Template")
remote_file = Chef::Resource::Template.new(cache_seed_to, run_context)
- remote_file.cookbook_name = @new_resource.cookbook_name
- remote_file.source(@new_resource.response_file)
- remote_file.backup(false)
- provider = Chef::Platform.provider_for_resource(remote_file, :create)
- provider.template_location
- rescue
- Chef::Log.debug("#{@new_resource} fetching preseed file via Template resource failed, fallback to CookbookFile resource")
+ elsif cookbook_file_available?(@new_resource.response_file)
+ Chef::Log.debug("#{@new_resource} fetching preseed file via cookbook_file")
remote_file = Chef::Resource::CookbookFile.new(cache_seed_to, run_context)
- remote_file.cookbook_name = @new_resource.cookbook_name
- remote_file.source(@new_resource.response_file)
- remote_file.backup(false)
+ else
+ message = "No template or cookbook file found for response file #{@new_resource.response_file}"
+ raise Chef::Exceptions::FileNotFound, message
end
+ remote_file.cookbook_name = @new_resource.cookbook_name
+ remote_file.source(@new_resource.response_file)
+ remote_file.backup(false)
remote_file
end
@@ -224,6 +224,16 @@ class Chef
@new_resource.version == @current_resource.version
end
+ private
+
+ def template_available?(path)
+ run_context.has_template_in_cookbook?(@new_resource.cookbook_name, path)
+ end
+
+ def cookbook_file_available?(path)
+ run_context.has_cookbook_file_in_cookbook?(@new_resource.cookbook_name, path)
+ end
+
end
end
end
diff --git a/lib/chef/provider/package/aix.rb b/lib/chef/provider/package/aix.rb
new file mode 100644
index 0000000000..4df0ea7a33
--- /dev/null
+++ b/lib/chef/provider/package/aix.rb
@@ -0,0 +1,146 @@
+#
+# Author:: Deepali Jagtap
+# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+#
+require 'chef/provider/package'
+require 'chef/mixin/command'
+require 'chef/resource/package'
+require 'chef/mixin/get_source_from_package'
+
+class Chef
+ class Provider
+ class Package
+ class Aix < Chef::Provider::Package
+
+ include Chef::Mixin::GetSourceFromPackage
+
+ def define_resource_requirements
+ super
+ requirements.assert(:install) do |a|
+ a.assertion { @new_resource.source }
+ a.failure_message Chef::Exceptions::Package, "Source for package #{@new_resource.name} required for action install"
+ end
+ requirements.assert(:all_actions) do |a|
+ a.assertion { !@new_resource.source || @package_source_found }
+ a.failure_message Chef::Exceptions::Package, "Package #{@new_resource.name} not found: #{@new_resource.source}"
+ a.whyrun "would assume #{@new_resource.source} would be have previously been made available"
+ end
+ end
+
+ def load_current_resource
+ @current_resource = Chef::Resource::Package.new(@new_resource.name)
+ @current_resource.package_name(@new_resource.package_name)
+ @new_resource.version(nil)
+
+ if @new_resource.source
+ @package_source_found = ::File.exists?(@new_resource.source)
+ if @package_source_found
+ Chef::Log.debug("#{@new_resource} checking pkg status")
+ status = popen4("installp -L -d #{@new_resource.source}") do |pid, stdin, stdout, stderr|
+ package_found = false
+ stdout.each do |line|
+ case line
+ when /#{@new_resource.package_name}:/
+ package_found = true
+ fields = line.split(":")
+ @new_resource.version(fields[2])
+ end
+ end
+ end
+ end
+ end
+
+ Chef::Log.debug("#{@new_resource} checking install state")
+ status = popen4("lslpp -lcq #{@current_resource.package_name}") do |pid, stdin, stdout, stderr|
+ stdout.each do |line|
+ case line
+ when /#{@current_resource.package_name}/
+ fields = line.split(":")
+ Chef::Log.debug("#{@new_resource} version #{fields[2]} is already installed")
+ @current_resource.version(fields[2])
+ end
+ end
+ end
+
+ unless status.exitstatus == 0 || status.exitstatus == 1
+ raise Chef::Exceptions::Package, "lslpp failed - #{status.inspect}!"
+ end
+
+ @current_resource
+ end
+
+ def candidate_version
+ return @candidate_version if @candidate_version
+ status = popen4("installp -L -d #{@new_resource.source}") do |pid, stdin, stdout, stderr|
+ stdout.each_line do |line|
+ case line
+ when /\w:{Regexp.escape(@new_resource.package_name)}:(.*)/
+ fields = line.split(":")
+ @candidate_version = fields[2]
+ @new_resource.version(fields[2])
+ Chef::Log.debug("#{@new_resource} setting install candidate version to #{@candidate_version}")
+ end
+ end
+ end
+ unless status.exitstatus == 0
+ raise Chef::Exceptions::Package, "installp -L -d #{@new_resource.source} - #{status.inspect}!"
+ end
+ @candidate_version
+ end
+
+ #
+ # The install/update action needs to be tested with various kinds of packages
+ # on AIX viz. packages with or without licensing file dependencies, packages
+ # with dependencies on other packages which will help to test additional
+ # options of installp.
+ # So far, the code has been tested only with standalone packages.
+ #
+ def install_package(name, version)
+ Chef::Log.debug("#{@new_resource} package install options: #{@new_resource.options}")
+ if @new_resource.options.nil?
+ run_command_with_systems_locale(
+ :command => "installp -aYF -d #{@new_resource.source} #{@new_resource.package_name}"
+ )
+ Chef::Log.debug("#{@new_resource} installed version #{@new_resource.version} from: #{@new_resource.source}")
+ else
+ run_command_with_systems_locale(
+ :command => "installp -aYF #{expand_options(@new_resource.options)} -d #{@new_resource.source} #{@new_resource.package_name}"
+ )
+ Chef::Log.debug("#{@new_resource} installed version #{@new_resource.version} from: #{@new_resource.source}")
+ end
+ end
+
+ alias_method :upgrade_package, :install_package
+
+ def remove_package(name, version)
+ if @new_resource.options.nil?
+ run_command_with_systems_locale(
+ :command => "installp -u #{name}"
+ )
+ Chef::Log.debug("#{@new_resource} removed version #{@new_resource.version}")
+ else
+ run_command_with_systems_locale(
+ :command => "installp -u #{expand_options(@new_resource.options)} #{name}"
+ )
+ Chef::Log.debug("#{@new_resource} removed version #{@new_resource.version}")
+ end
+ end
+
+ end
+ end
+ end
+end
diff --git a/lib/chef/provider/package/apt.rb b/lib/chef/provider/package/apt.rb
index e8939b494e..dc7b3f2086 100644
--- a/lib/chef/provider/package/apt.rb
+++ b/lib/chef/provider/package/apt.rb
@@ -65,7 +65,8 @@ class Chef
@is_virtual_package = true
showpkg = shell_out!("apt-cache showpkg #{package}").stdout
providers = Hash.new
- showpkg.rpartition(/Reverse Provides:? #{$/}/)[2].each_line do |line|
+ # Returns all lines after 'Reverse Provides:'
+ showpkg.rpartition(/Reverse Provides:\s*#{$/}/)[2].each_line do |line|
provider, version = line.split
providers[provider] = version
end
@@ -90,12 +91,7 @@ class Chef
def install_package(name, version)
package_name = "#{name}=#{version}"
package_name = name if @is_virtual_package
- run_command_with_systems_locale(
- :command => "apt-get -q -y#{expand_options(default_release_options)}#{expand_options(@new_resource.options)} install #{package_name}",
- :environment => {
- "DEBIAN_FRONTEND" => "noninteractive"
- }
- )
+ run_noninteractive("apt-get -q -y#{expand_options(default_release_options)}#{expand_options(@new_resource.options)} install #{package_name}")
end
def upgrade_package(name, version)
@@ -104,41 +100,30 @@ class Chef
def remove_package(name, version)
package_name = "#{name}"
- run_command_with_systems_locale(
- :command => "apt-get -q -y#{expand_options(@new_resource.options)} remove #{package_name}",
- :environment => {
- "DEBIAN_FRONTEND" => "noninteractive"
- }
- )
+ run_noninteractive("apt-get -q -y#{expand_options(@new_resource.options)} remove #{package_name}")
end
def purge_package(name, version)
- run_command_with_systems_locale(
- :command => "apt-get -q -y#{expand_options(@new_resource.options)} purge #{@new_resource.package_name}",
- :environment => {
- "DEBIAN_FRONTEND" => "noninteractive"
- }
- )
+ run_noninteractive("apt-get -q -y#{expand_options(@new_resource.options)} purge #{@new_resource.package_name}")
end
def preseed_package(preseed_file)
Chef::Log.info("#{@new_resource} pre-seeding package installation instructions")
- run_command_with_systems_locale(
- :command => "debconf-set-selections #{preseed_file}",
- :environment => {
- "DEBIAN_FRONTEND" => "noninteractive"
- }
- )
+ run_noninteractive("debconf-set-selections #{preseed_file}")
end
def reconfig_package(name, version)
Chef::Log.info("#{@new_resource} reconfiguring")
- run_command_with_systems_locale(
- :command => "dpkg-reconfigure #{name}",
- :environment => {
- "DEBIAN_FRONTEND" => "noninteractive"
- }
- )
+ run_noninteractive("dpkg-reconfigure #{name}")
+ end
+
+ private
+
+ # Runs command via shell_out with magic environment to disable
+ # interactive prompts. Command is run with default localization rather
+ # than forcing locale to "C", so command output may not be stable.
+ def run_noninteractive(command)
+ shell_out!(command, :env => { "DEBIAN_FRONTEND" => "noninteractive", "LC_ALL" => nil })
end
end
diff --git a/lib/chef/provider/package/dpkg.rb b/lib/chef/provider/package/dpkg.rb
index 795a7b308b..8ec1ad5878 100644
--- a/lib/chef/provider/package/dpkg.rb
+++ b/lib/chef/provider/package/dpkg.rb
@@ -6,9 +6,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -32,14 +32,14 @@ class Chef
include Chef::Mixin::GetSourceFromPackage
def define_resource_requirements
super
- requirements.assert(:install) do |a|
+ requirements.assert(:install) do |a|
a.assertion{ not @new_resource.source.nil? }
a.failure_message Chef::Exceptions::Package, "Source for package #{@new_resource.name} required for action install"
end
# TODO this was originally written for any action in which .source is provided
# but would it make more sense to only look at source if the action is :install?
- requirements.assert(:all_actions) do |a|
+ requirements.assert(:all_actions) do |a|
a.assertion { @source_exists }
a.failure_message Chef::Exceptions::Package, "Package #{@new_resource.name} not found: #{@new_resource.source}"
a.whyrun "Assuming it would have been previously downloaded."
@@ -53,7 +53,7 @@ class Chef
@new_resource.version(nil)
if @new_resource.source
- @source_exists = ::File.exists?(@new_resource.source)
+ @source_exists = ::File.exists?(@new_resource.source)
if @source_exists
# Get information from the package if supplied
Chef::Log.debug("#{@new_resource} checking dpkg status")
@@ -71,7 +71,7 @@ class Chef
end
end
-
+
# Check to see if it is installed
package_installed = nil
Chef::Log.debug("#{@new_resource} checking install state")
@@ -92,10 +92,10 @@ class Chef
unless status.exitstatus == 0 || status.exitstatus == 1
raise Chef::Exceptions::Package, "dpkg failed - #{status.inspect}!"
end
-
+
@current_resource
end
-
+
def install_package(name, version)
run_command_with_systems_locale(
:command => "dpkg -i#{expand_options(@new_resource.options)} #{@new_resource.source}",
@@ -113,7 +113,7 @@ class Chef
}
)
end
-
+
def purge_package(name, version)
run_command_with_systems_locale(
:command => "dpkg -P#{expand_options(@new_resource.options)} #{@new_resource.package_name}",
diff --git a/lib/chef/provider/package/freebsd.rb b/lib/chef/provider/package/freebsd.rb
index afdd0d812e..f9cb5eb422 100644
--- a/lib/chef/provider/package/freebsd.rb
+++ b/lib/chef/provider/package/freebsd.rb
@@ -37,7 +37,7 @@ class Chef
def current_installed_version
pkg_info = shell_out!("pkg_info -E \"#{package_name}*\"", :env => nil, :returns => [0,1])
- pkg_info.stdout[/^#{package_name}-(.+)/, 1]
+ pkg_info.stdout[/^#{Regexp.escape(package_name)}-(.+)/, 1]
end
def port_path
@@ -52,7 +52,7 @@ class Chef
# Otherwise look up the path to the ports directory using 'whereis'
else
whereis = shell_out!("whereis -s #{@new_resource.package_name}", :env => nil)
- unless path = whereis.stdout[/^#{@new_resource.package_name}:\s+(.+)$/, 1]
+ unless path = whereis.stdout[/^#{Regexp.escape(@new_resource.package_name)}:\s+(.+)$/, 1]
raise Chef::Exceptions::Package, "Could not find port with the name #{@new_resource.package_name}"
end
path
diff --git a/lib/chef/provider/package/ips.rb b/lib/chef/provider/package/ips.rb
index 5beb46a20a..2c6d98d81a 100644
--- a/lib/chef/provider/package/ips.rb
+++ b/lib/chef/provider/package/ips.rb
@@ -33,12 +33,12 @@ class Chef
def define_resource_requirements
super
-
+
requirements.assert(:all_actions) do |a|
a.assertion { ! @candidate_version.nil? }
a.failure_message Chef::Exceptions::Package, "Package #{@new_resource.package_name} not found"
a.whyrun "Assuming package #{@new_resource.package_name} would have been made available."
- end
+ end
end
def load_current_resource
@@ -52,7 +52,7 @@ class Chef
Chef::Log.debug("Checking package status for #{package}")
installed = false
depends = false
-
+
shell_out!("pkg info -r #{package}").stdout.each_line do |line|
case line
when /^\s+State: Installed/
diff --git a/lib/chef/provider/package/macports.rb b/lib/chef/provider/package/macports.rb
index fd33788944..6ef303ee4f 100644
--- a/lib/chef/provider/package/macports.rb
+++ b/lib/chef/provider/package/macports.rb
@@ -44,7 +44,7 @@ class Chef
def install_package(name, version)
unless @current_resource.version == version
command = "port#{expand_options(@new_resource.options)} install #{name}"
- command << " @#{version}" if version and !version.empty?
+ command << " @#{version}" if version and !version.empty?
run_command_with_systems_locale(
:command => command
)
diff --git a/lib/chef/provider/package/pacman.rb b/lib/chef/provider/package/pacman.rb
index f81486ae84..2e8bb7850b 100644
--- a/lib/chef/provider/package/pacman.rb
+++ b/lib/chef/provider/package/pacman.rb
@@ -6,9 +6,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -24,7 +24,7 @@ class Chef
class Provider
class Package
class Pacman < Chef::Provider::Package
-
+
def load_current_resource
@current_resource = Chef::Resource::Package.new(@new_resource.name)
@current_resource.package_name(@new_resource.package_name)
@@ -84,27 +84,27 @@ class Chef
@candidate_version
end
-
+
def install_package(name, version)
run_command_with_systems_locale(
:command => "pacman --sync --noconfirm --noprogressbar#{expand_options(@new_resource.options)} #{name}"
)
end
-
+
def upgrade_package(name, version)
install_package(name, version)
end
-
+
def remove_package(name, version)
run_command_with_systems_locale(
:command => "pacman --remove --noconfirm --noprogressbar#{expand_options(@new_resource.options)} #{name}"
)
end
-
+
def purge_package(name, version)
remove_package(name, version)
end
-
+
end
end
end
diff --git a/lib/chef/provider/package/rpm.rb b/lib/chef/provider/package/rpm.rb
index 033ce8efb9..616a78a2f5 100644
--- a/lib/chef/provider/package/rpm.rb
+++ b/lib/chef/provider/package/rpm.rb
@@ -6,9 +6,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -30,18 +30,18 @@ class Chef
def define_resource_requirements
super
- requirements.assert(:all_actions) do |a|
+ requirements.assert(:all_actions) do |a|
a.assertion { @package_source_exists }
a.failure_message Chef::Exceptions::Package, "Package #{@new_resource.name} not found: #{@new_resource.source}"
a.whyrun "Assuming package #{@new_resource.name} would have been made available."
end
- requirements.assert(:all_actions) do |a|
- a.assertion { !@rpm_status.nil? && (@rpm_status.exitstatus == 0 || @rpm_status.exitstatus == 1) }
+ requirements.assert(:all_actions) do |a|
+ a.assertion { !@rpm_status.nil? && (@rpm_status.exitstatus == 0 || @rpm_status.exitstatus == 1) }
a.failure_message Chef::Exceptions::Package, "Unable to determine current version due to RPM failure. Detail: #{@rpm_status.inspect}"
a.whyrun "Assuming current version would have been determined for package#{@new_resource.name}."
end
end
-
+
def load_current_resource
@package_source_provided = true
@package_source_exists = true
@@ -49,13 +49,13 @@ class Chef
@current_resource = Chef::Resource::Package.new(@new_resource.name)
@current_resource.package_name(@new_resource.package_name)
@new_resource.version(nil)
-
+
if @new_resource.source
unless ::File.exists?(@new_resource.source)
@package_source_exists = false
return
end
-
+
Chef::Log.debug("#{@new_resource} checking rpm status")
status = popen4("rpm -qp --queryformat '%{NAME} %{VERSION}-%{RELEASE}\n' #{@new_resource.source}") do |pid, stdin, stdout, stderr|
stdout.each do |line|
@@ -72,7 +72,7 @@ class Chef
return
end
end
-
+
Chef::Log.debug("#{@new_resource} checking install state")
@rpm_status = popen4("rpm -q --queryformat '%{NAME} %{VERSION}-%{RELEASE}\n' #{@current_resource.package_name}") do |pid, stdin, stdout, stderr|
stdout.each do |line|
@@ -83,11 +83,11 @@ class Chef
end
end
end
-
-
+
+
@current_resource
end
-
+
def install_package(name, version)
unless @current_resource.version
run_command_with_systems_locale(
@@ -99,9 +99,9 @@ class Chef
)
end
end
-
+
alias_method :upgrade_package, :install_package
-
+
def remove_package(name, version)
if version
run_command_with_systems_locale(
diff --git a/lib/chef/provider/package/rubygems.rb b/lib/chef/provider/package/rubygems.rb
index 28d332420b..b423c199a0 100644
--- a/lib/chef/provider/package/rubygems.rb
+++ b/lib/chef/provider/package/rubygems.rb
@@ -72,7 +72,7 @@ class Chef
raise NotImplementedError
end
- ##
+ ##
# A rubygems specification object containing the list of gemspecs for all
# available gems in the gem installation.
# Implemented by subclasses
diff --git a/lib/chef/provider/package/smartos.rb b/lib/chef/provider/package/smartos.rb
index b17f6f2564..28d56ddc2c 100644
--- a/lib/chef/provider/package/smartos.rb
+++ b/lib/chef/provider/package/smartos.rb
@@ -64,14 +64,14 @@ class Chef
pkg = shell_out!("/opt/local/bin/pkgin se #{new_resource.package_name}", :env => nil, :returns => [0,1])
pkg.stdout.each_line do |line|
case line
- when /^#{name}/
+ when /^#{new_resource.package_name}/
name, version = line.split[0].split(/-([^-]+)$/)
end
end
@candidate_version = version
version
end
-
+
def install_package(name, version)
Chef::Log.debug("#{@new_resource} installing package #{name} version #{version}")
package = "#{name}-#{version}"
@@ -84,7 +84,7 @@ class Chef
end
def remove_package(name, version)
- Chef::Log.debug("#{@new_resource} removing package #{name} version #{version}")
+ Chef::Log.debug("#{@new_resource} removing package #{name} version #{version}")
package = "#{name}"
out = shell_out!("/opt/local/bin/pkgin -y remove #{package}", :env => nil)
end
diff --git a/lib/chef/provider/package/solaris.rb b/lib/chef/provider/package/solaris.rb
index f502a0dc96..0f45b61e18 100644
--- a/lib/chef/provider/package/solaris.rb
+++ b/lib/chef/provider/package/solaris.rb
@@ -33,12 +33,12 @@ class Chef
# end
def define_resource_requirements
super
- requirements.assert(:install) do |a|
+ requirements.assert(:install) do |a|
a.assertion { @new_resource.source }
a.failure_message Chef::Exceptions::Package, "Source for package #{@new_resource.name} required for action install"
end
- requirements.assert(:all_actions) do |a|
- a.assertion { !@new_resource.source || @package_source_found }
+ requirements.assert(:all_actions) do |a|
+ a.assertion { !@new_resource.source || @package_source_found }
a.failure_message Chef::Exceptions::Package, "Package #{@new_resource.name} not found: #{@new_resource.source}"
a.whyrun "would assume #{@new_resource.source} would be have previously been made available"
end
@@ -51,7 +51,7 @@ class Chef
if @new_resource.source
@package_source_found = ::File.exists?(@new_resource.source)
- if @package_source_found
+ if @package_source_found
Chef::Log.debug("#{@new_resource} checking pkg status")
status = popen4("pkginfo -l -d #{@new_resource.source} #{@new_resource.package_name}") do |pid, stdin, stdout, stderr|
stdout.each do |line|
@@ -107,13 +107,23 @@ class Chef
def install_package(name, version)
Chef::Log.debug("#{@new_resource} package install options: #{@new_resource.options}")
if @new_resource.options.nil?
+ if ::File.directory?(@new_resource.source) # CHEF-4469
+ command = "pkgadd -n -d #{@new_resource.source} #{@new_resource.package_name}"
+ else
+ command = "pkgadd -n -d #{@new_resource.source} all"
+ end
run_command_with_systems_locale(
- :command => "pkgadd -n -d #{@new_resource.source} all"
+ :command => command
)
Chef::Log.debug("#{@new_resource} installed version #{@new_resource.version} from: #{@new_resource.source}")
else
+ if ::File.directory?(@new_resource.source) # CHEF-4469
+ command = "pkgadd -n#{expand_options(@new_resource.options)} -d #{@new_resource.source} #{@new_resource.package_name}"
+ else
+ command = "pkgadd -n#{expand_options(@new_resource.options)} -d #{@new_resource.source} all"
+ end
run_command_with_systems_locale(
- :command => "pkgadd -n#{expand_options(@new_resource.options)} -d #{@new_resource.source} all"
+ :command => command
)
Chef::Log.debug("#{@new_resource} installed version #{@new_resource.version} from: #{@new_resource.source}")
end
diff --git a/lib/chef/provider/package/yum-dump.py b/lib/chef/provider/package/yum-dump.py
index 407eb8f408..a8f3995e8c 100644
--- a/lib/chef/provider/package/yum-dump.py
+++ b/lib/chef/provider/package/yum-dump.py
@@ -6,9 +6,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -249,8 +249,8 @@ def yum_dump(options):
# Preserve order of enable/disable repo args like yum does
def gather_repo_opts(option, opt, value, parser):
- if getattr(parser.values, option.dest, None) is None:
- setattr(parser.values, option.dest, [])
+ if getattr(parser.values, option.dest, None) is None:
+ setattr(parser.values, option.dest, [])
getattr(parser.values, option.dest).append((opt, value.split(',')))
def main():
diff --git a/lib/chef/provider/package/yum.rb b/lib/chef/provider/package/yum.rb
index 233e949e12..f56d3140b6 100644
--- a/lib/chef/provider/package/yum.rb
+++ b/lib/chef/provider/package/yum.rb
@@ -667,7 +667,7 @@ class Chef
@allow_multi_install = []
- @extra_repo_control = nil
+ @extra_repo_control = nil
# these are for subsequent runs if we are on an interval
Chef::Client.when_run_starts do
@@ -1046,7 +1046,7 @@ class Chef
end
# At this point package_name could be:
- #
+ #
# 1) a package name, eg: "foo"
# 2) a package name.arch, eg: "foo.i386"
# 3) or a dependency, eg: "foo >= 1.1"
@@ -1154,7 +1154,7 @@ class Chef
# Hacky - better overall solution? Custom compare in Package provider?
def action_upgrade
# Could be uninstalled or have no candidate
- if @current_resource.version.nil? || candidate_version.nil?
+ if @current_resource.version.nil? || candidate_version.nil?
super
# Ensure the candidate is newer
elsif RPMVersion.parse(candidate_version) > RPMVersion.parse(@current_resource.version)
diff --git a/lib/chef/provider/powershell_script.rb b/lib/chef/provider/powershell_script.rb
index 700eb88c11..c459cdf678 100644
--- a/lib/chef/provider/powershell_script.rb
+++ b/lib/chef/provider/powershell_script.rb
@@ -6,9 +6,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -23,7 +23,7 @@ class Chef
class PowershellScript < Chef::Provider::WindowsScript
protected
-
+
EXIT_STATUS_NORMALIZATION_SCRIPT = "\nif ($? -eq $true) {exit 0} elseif ( $LASTEXITCODE -ne 0) {exit $LASTEXITCODE} else { exit 1 }"
EXIT_STATUS_RESET_SCRIPT = "$LASTEXITCODE=0\n"
@@ -41,12 +41,12 @@ class Chef
end
public
-
+
def initialize (new_resource, run_context)
super(new_resource, run_context, '.ps1')
NormalizeScriptExitStatus(new_resource.code)
end
-
+
def flags
default_flags = [
"-NoLogo",
@@ -60,8 +60,8 @@ class Chef
# file created by the base class that contains the script
# code -- otherwise, powershell.exe does not propagate the
# error status of a failed Windows process that ran at the
- # end of the script, it gets changed to '1'.
- "-File"
+ # end of the script, it gets changed to '1'.
+ "-File"
]
interpreter_flags = default_flags.join(' ')
diff --git a/lib/chef/provider/remote_file/ftp.rb b/lib/chef/provider/remote_file/ftp.rb
index d75fb7a52c..7f3fdbf383 100644
--- a/lib/chef/provider/remote_file/ftp.rb
+++ b/lib/chef/provider/remote_file/ftp.rb
@@ -143,6 +143,7 @@ class Chef
ftp.voidcmd("TYPE #{typecode.upcase}")
end
ftp.getbinaryfile(filename, tempfile.path)
+ tempfile.close if tempfile
tempfile
end
diff --git a/lib/chef/provider/remote_file/http.rb b/lib/chef/provider/remote_file/http.rb
index 6ffd83f438..8949e6ab04 100644
--- a/lib/chef/provider/remote_file/http.rb
+++ b/lib/chef/provider/remote_file/http.rb
@@ -17,7 +17,7 @@
# limitations under the License.
#
-require 'chef/rest'
+require 'chef/http/simple'
require 'chef/digester'
require 'chef/provider/remote_file'
require 'chef/provider/remote_file/cache_control_data'
@@ -58,9 +58,9 @@ class Chef
def fetch
tempfile = nil
begin
- rest = Chef::REST.new(uri, nil, nil, http_client_opts)
- tempfile = rest.streaming_request(uri, headers)
- update_cache_control_data(tempfile, rest.last_response)
+ http = Chef::HTTP::Simple.new(uri, http_client_opts)
+ tempfile = http.streaming_request(uri, headers)
+ update_cache_control_data(tempfile, http.last_response)
rescue Net::HTTPRetriableError => e
if e.response.is_a? Net::HTTPNotModified
tempfile = nil
@@ -68,7 +68,7 @@ class Chef
raise e
end
end
-
+ tempfile.close if tempfile
tempfile
end
diff --git a/lib/chef/provider/remote_file/local_file.rb b/lib/chef/provider/remote_file/local_file.rb
index 87f498e053..b3b2301b81 100644
--- a/lib/chef/provider/remote_file/local_file.rb
+++ b/lib/chef/provider/remote_file/local_file.rb
@@ -38,6 +38,7 @@ class Chef
tempfile = Chef::FileContentManagement::Tempfile.new(new_resource).tempfile
Chef::Log.debug("#{new_resource} staging #{uri.path} to #{tempfile.path}")
FileUtils.cp(uri.path, tempfile.path)
+ tempfile.close if tempfile
tempfile
end
diff --git a/lib/chef/provider/resource_update.rb b/lib/chef/provider/resource_update.rb
index e2c6bffca4..54f25738ed 100644
--- a/lib/chef/provider/resource_update.rb
+++ b/lib/chef/provider/resource_update.rb
@@ -4,27 +4,27 @@ class Chef
# {
# "run_id" : "1000",
- # "resource" : {
+ # "resource" : {
# "type" : "file",
- # "name" : "/etc/passwd",
+ # "name" : "/etc/passwd",
# "start_time" : "2012-01-09T08:15:30-05:00",
# "end_time" : "2012-01-09T08:15:30-05:00",
# "status" : "modified",
- # "initial_state" : "exists",
- # "final_state" : "modified",
- # "before" : {
- # "group" : "root",
+ # "initial_state" : "exists",
+ # "final_state" : "modified",
+ # "before" : {
+ # "group" : "root",
# "owner" : "root",
# "checksum" : "xyz"
# },
- # "after" : {
- # "group" : "root",
+ # "after" : {
+ # "group" : "root",
# "owner" : "root",
# "checksum" : "abc"
# },
# "delta" : "escaped delta goes here"
# },
- # "event_data" : ""
+ # "event_data" : ""
# }
class ResourceUpdate
diff --git a/lib/chef/provider/ruby_block.rb b/lib/chef/provider/ruby_block.rb
index 16908b0eff..b0d94a3f8d 100644
--- a/lib/chef/provider/ruby_block.rb
+++ b/lib/chef/provider/ruby_block.rb
@@ -7,9 +7,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -29,7 +29,7 @@ class Chef
end
def action_run
- converge_by("execute the ruby block #{@new_resource.name}") do
+ converge_by("execute the ruby block #{@new_resource.name}") do
@new_resource.block.call
Chef::Log.info("#{@new_resource} called")
end
diff --git a/lib/chef/provider/script.rb b/lib/chef/provider/script.rb
index 1b459f36cf..4aacf4f524 100644
--- a/lib/chef/provider/script.rb
+++ b/lib/chef/provider/script.rb
@@ -27,7 +27,7 @@ class Chef
super
@code = @new_resource.code
end
-
+
def action_run
script_file.puts(@code)
script_file.close
diff --git a/lib/chef/provider/service.rb b/lib/chef/provider/service.rb
index 8d76927676..968f9bff9c 100644
--- a/lib/chef/provider/service.rb
+++ b/lib/chef/provider/service.rb
@@ -35,7 +35,7 @@ class Chef
end
def load_new_resource_state
- # If the user didn't specify a change in enabled state,
+ # If the user didn't specify a change in enabled state,
# it will be the same as the old resource
if ( @new_resource.enabled.nil? )
@new_resource.enabled(@current_resource.enabled)
@@ -54,7 +54,7 @@ class Chef
a.failure_message Chef::Exceptions::UnsupportedAction, "#{self.to_s} does not support :reload"
# if a service is not declared to support reload, that won't
# typically change during the course of a run - so no whyrun
- # alternative here.
+ # alternative here.
end
end
diff --git a/lib/chef/provider/service/debian.rb b/lib/chef/provider/service/debian.rb
index e2a0f60d91..d788d58c00 100644
--- a/lib/chef/provider/service/debian.rb
+++ b/lib/chef/provider/service/debian.rb
@@ -41,17 +41,17 @@ class Chef
shared_resource_requirements
requirements.assert(:all_actions) do |a|
update_rcd = "/usr/sbin/update-rc.d"
- a.assertion { ::File.exists? update_rcd }
+ a.assertion { ::File.exists? update_rcd }
a.failure_message Chef::Exceptions::Service, "#{update_rcd} does not exist!"
# no whyrun recovery - this is a base system component of debian
- # distros and must be present
- end
+ # distros and must be present
+ end
requirements.assert(:all_actions) do |a|
- a.assertion { @priority_success }
+ a.assertion { @priority_success }
a.failure_message Chef::Exceptions::Service, "/usr/sbin/update-rc.d -n -f #{@current_resource.service_name} failed - #{@rcd_status.inspect}"
- # This can happen if the service is not yet installed,so we'll fake it.
- a.whyrun ["Unable to determine priority of service, assuming service would have been correctly installed earlier in the run.",
+ # This can happen if the service is not yet installed,so we'll fake it.
+ a.whyrun ["Unable to determine priority of service, assuming service would have been correctly installed earlier in the run.",
"Assigning temporary priorities to continue.",
"If this service is not properly installed prior to this point, this will fail."] do
temp_priorities = {"6"=>[:stop, "20"],
@@ -74,7 +74,7 @@ class Chef
[stdout, stderr].each do |iop|
iop.each_line do |line|
if UPDATE_RC_D_PRIORITIES =~ line
- # priority[runlevel] = [ S|K, priority ]
+ # priority[runlevel] = [ S|K, priority ]
# S = Start, K = Kill
# debian runlevels: 0 Halt, 1 Singleuser, 2 Multiuser, 3-5 == 2, 6 Reboot
priority[$1] = [($2 == "S" ? :start : :stop), $3]
@@ -86,6 +86,12 @@ class Chef
end
end
+ # Reduce existing priority back to an integer if appropriate, picking
+ # runlevel 2 as a baseline
+ if priority[2] && [2..5].all? { |runlevel| priority[runlevel] == priority[2] }
+ priority = priority[2].last
+ end
+
unless @rcd_status.exitstatus == 0
@priority_success = false
end
@@ -105,14 +111,28 @@ class Chef
enabled
end
- def enable_service()
+ # Override method from parent to ensure priority is up-to-date
+ def action_enable
+ if @current_resource.enabled && @current_resource.priority == @new_resource.priority
+ Chef::Log.debug("#{@new_resource} already enabled - nothing to do")
+ else
+ converge_by("enable service #{@new_resource}") do
+ enable_service
+ Chef::Log.info("#{@new_resource} enabled")
+ end
+ end
+ load_new_resource_state
+ @new_resource.enabled(true)
+ end
+
+ def enable_service
if @new_resource.priority.is_a? Integer
run_command(:command => "/usr/sbin/update-rc.d -f #{@new_resource.service_name} remove")
run_command(:command => "/usr/sbin/update-rc.d #{@new_resource.service_name} defaults #{@new_resource.priority} #{100 - @new_resource.priority}")
elsif @new_resource.priority.is_a? Hash
- # we call the same command regardless of we're enabling or disabling
+ # we call the same command regardless of we're enabling or disabling
# users passing a Hash are responsible for setting their own start priorities
- set_priority()
+ set_priority
else # No priority, go with update-rc.d defaults
run_command(:command => "/usr/sbin/update-rc.d -f #{@new_resource.service_name} remove")
run_command(:command => "/usr/sbin/update-rc.d #{@new_resource.service_name} defaults")
@@ -120,23 +140,23 @@ class Chef
end
- def disable_service()
+ def disable_service
if @new_resource.priority.is_a? Integer
# Stop processes in reverse order of start using '100 - start_priority'
run_command(:command => "/usr/sbin/update-rc.d -f #{@new_resource.service_name} remove")
run_command(:command => "/usr/sbin/update-rc.d -f #{@new_resource.service_name} stop #{100 - @new_resource.priority} 2 3 4 5 .")
elsif @new_resource.priority.is_a? Hash
- # we call the same command regardless of we're enabling or disabling
+ # we call the same command regardless of we're enabling or disabling
# users passing a Hash are responsible for setting their own stop priorities
- set_priority()
- else
+ set_priority
+ else
# no priority, using '100 - 20 (update-rc.d default)' to stop in reverse order of start
run_command(:command => "/usr/sbin/update-rc.d -f #{@new_resource.service_name} remove")
run_command(:command => "/usr/sbin/update-rc.d -f #{@new_resource.service_name} stop 80 2 3 4 5 .")
end
end
- def set_priority()
+ def set_priority
args = ""
@new_resource.priority.each do |level, o|
action = o[0]
diff --git a/lib/chef/provider/service/freebsd.rb b/lib/chef/provider/service/freebsd.rb
index b875838ec2..cb0f6b0fc4 100644
--- a/lib/chef/provider/service/freebsd.rb
+++ b/lib/chef/provider/service/freebsd.rb
@@ -38,13 +38,13 @@ class Chef
elsif ::File.exists?("/usr/local/etc/rc.d/#{current_resource.service_name}")
@init_command = "/usr/local/etc/rc.d/#{current_resource.service_name}"
else
- @rcd_script_found = false
+ @rcd_script_found = false
return
end
Chef::Log.debug("#{@current_resource} found at #{@init_command}")
determine_current_status!
# Default to disabled if the service doesn't currently exist
- # at all
+ # at all
var_name = service_enable_variable_name
if ::File.exists?("/etc/rc.conf") && var_name
read_rc_conf.each do |line|
@@ -70,19 +70,19 @@ class Chef
def define_resource_requirements
shared_resource_requirements
requirements.assert(:start, :enable, :reload, :restart) do |a|
- a.assertion { @rcd_script_found }
+ a.assertion { @rcd_script_found }
a.failure_message Chef::Exceptions::Service, "#{@new_resource}: unable to locate the rc.d script"
end
- requirements.assert(:all_actions) do |a|
- a.assertion { @enabled_state_found }
- # for consistentcy with original behavior, this will not fail in non-whyrun mode;
+ requirements.assert(:all_actions) do |a|
+ a.assertion { @enabled_state_found }
+ # for consistentcy with original behavior, this will not fail in non-whyrun mode;
# rather it will silently set enabled state=>false
- a.whyrun "Unable to determine enabled/disabled state, assuming this will be correct for an actual run. Assuming disabled."
+ a.whyrun "Unable to determine enabled/disabled state, assuming this will be correct for an actual run. Assuming disabled."
end
requirements.assert(:start, :enable, :reload, :restart) do |a|
- a.assertion { @rcd_script_found && service_enable_variable_name != nil }
+ a.assertion { @rcd_script_found && service_enable_variable_name != nil }
a.failure_message Chef::Exceptions::Service, "Could not find the service name in #{@init_command} and rcvar"
# No recovery in whyrun mode - the init file is present but not correct.
end
@@ -133,7 +133,7 @@ class Chef
# corresponding to this service
# For example: to enable the service mysql-server with the init command /usr/local/etc/rc.d/mysql-server, you need
# to set mysql_enable="YES" in /etc/rc.conf$
- if @rcd_script_found
+ if @rcd_script_found
::File.open(@init_command) do |rcscript|
rcscript.each_line do |line|
if line =~ /^name="?(\w+)"?/
diff --git a/lib/chef/provider/service/gentoo.rb b/lib/chef/provider/service/gentoo.rb
index 45b5a21f9b..ba4edc5807 100644
--- a/lib/chef/provider/service/gentoo.rb
+++ b/lib/chef/provider/service/gentoo.rb
@@ -44,7 +44,7 @@ class Chef::Provider::Service::Gentoo < Chef::Provider::Service::Init
def define_resource_requirements
requirements.assert(:all_actions) do |a|
- a.assertion { ::File.exists?("/sbin/rc-update") }
+ a.assertion { ::File.exists?("/sbin/rc-update") }
a.failure_message Chef::Exceptions::Service, "/sbin/rc-update does not exist"
# no whyrun recovery -t his is a core component whose presence is
# unlikely to be affected by what we do in the course of a chef run
@@ -52,15 +52,15 @@ class Chef::Provider::Service::Gentoo < Chef::Provider::Service::Init
requirements.assert(:all_actions) do |a|
a.assertion { @found_script }
- # No failure, just informational output from whyrun
+ # No failure, just informational output from whyrun
a.whyrun "Could not find service #{@new_resource.service_name} under any runlevel"
end
end
-
+
def enable_service()
run_command(:command => "/sbin/rc-update add #{@new_resource.service_name} default")
end
-
+
def disable_service()
run_command(:command => "/sbin/rc-update del #{@new_resource.service_name} default")
end
diff --git a/lib/chef/provider/service/init.rb b/lib/chef/provider/service/init.rb
index 09f47e866f..63ba8fa6ab 100644
--- a/lib/chef/provider/service/init.rb
+++ b/lib/chef/provider/service/init.rb
@@ -47,7 +47,7 @@ class Chef
end
end
end
-
+
def start_service
if @new_resource.start_command
super
diff --git a/lib/chef/provider/service/insserv.rb b/lib/chef/provider/service/insserv.rb
index 32152376ee..cb9c28e17e 100644
--- a/lib/chef/provider/service/insserv.rb
+++ b/lib/chef/provider/service/insserv.rb
@@ -32,9 +32,9 @@ class Chef
if Dir.glob("/etc/rc**/S*#{@current_resource.service_name}").empty?
@current_resource.enabled false
else
- @current_resource.enabled true
+ @current_resource.enabled true
end
-
+
@current_resource
end
diff --git a/lib/chef/provider/service/invokercd.rb b/lib/chef/provider/service/invokercd.rb
index 69a17bb4fb..ee2719d75a 100644
--- a/lib/chef/provider/service/invokercd.rb
+++ b/lib/chef/provider/service/invokercd.rb
@@ -24,7 +24,7 @@ class Chef
class Provider
class Service
class Invokercd < Chef::Provider::Service::Init
-
+
def initialize(new_resource, run_context)
super
@init_command = "/usr/sbin/invoke-rc.d #{@new_resource.service_name}"
diff --git a/lib/chef/provider/service/redhat.rb b/lib/chef/provider/service/redhat.rb
index 629e4ee0c3..06be9f3207 100644
--- a/lib/chef/provider/service/redhat.rb
+++ b/lib/chef/provider/service/redhat.rb
@@ -48,7 +48,7 @@ class Chef
requirements.assert(:start, :enable, :reload, :restart) do |a|
a.assertion { !@service_missing }
a.failure_message Chef::Exceptions::Service, "#{@new_resource}: unable to locate the init.d script!"
- a.whyrun "Assuming service would be disabled. The init script is not presently installed."
+ a.whyrun "Assuming service would be disabled. The init script is not presently installed."
end
end
@@ -59,7 +59,7 @@ class Chef
chkconfig = shell_out!("/sbin/chkconfig --list #{@current_resource.service_name}", :returns => [0,1])
@current_resource.enabled(!!(chkconfig.stdout =~ CHKCONFIG_ON))
@service_missing = !!(chkconfig.stderr =~ CHKCONFIG_MISSING)
- end
+ end
@current_resource
end
diff --git a/lib/chef/provider/service/simple.rb b/lib/chef/provider/service/simple.rb
index bcb85230d0..288b5f5456 100644
--- a/lib/chef/provider/service/simple.rb
+++ b/lib/chef/provider/service/simple.rb
@@ -45,8 +45,8 @@ class Chef
def shared_resource_requirements
super
- requirements.assert(:all_actions) do |a|
- a.assertion { @status_load_success }
+ requirements.assert(:all_actions) do |a|
+ a.assertion { @status_load_success }
a.whyrun ["Service status not available. Assuming a prior action would have installed the service.", "Assuming status of not running."]
end
end
@@ -74,12 +74,12 @@ class Chef
end
requirements.assert(:all_actions) do |a|
- a.assertion { @new_resource.status_command or @new_resource.supports[:status] or
- (!ps_cmd.nil? and !ps_cmd.empty?) }
+ a.assertion { @new_resource.status_command or @new_resource.supports[:status] or
+ (!ps_cmd.nil? and !ps_cmd.empty?) }
a.failure_message Chef::Exceptions::Service, "#{@new_resource} could not determine how to inspect the process table, please set this node's 'command.ps' attribute"
end
- requirements.assert(:all_actions) do |a|
- a.assertion { !@ps_command_failed }
+ requirements.assert(:all_actions) do |a|
+ a.assertion { !@ps_command_failed }
a.failure_message Chef::Exceptions::Service, "Command #{ps_cmd} failed to execute, cannot determine service current status"
end
end
diff --git a/lib/chef/provider/service/solaris.rb b/lib/chef/provider/service/solaris.rb
index 33a29da109..4bdb6fbfd1 100644
--- a/lib/chef/provider/service/solaris.rb
+++ b/lib/chef/provider/service/solaris.rb
@@ -31,7 +31,7 @@ class Chef
@init_command = "/usr/sbin/svcadm"
@status_command = "/bin/svcs -l"
end
-
+
def load_current_resource
@current_resource = Chef::Resource::Service.new(@new_resource.name)
diff --git a/lib/chef/provider/service/systemd.rb b/lib/chef/provider/service/systemd.rb
index 59b4fe1564..89077c5feb 100644
--- a/lib/chef/provider/service/systemd.rb
+++ b/lib/chef/provider/service/systemd.rb
@@ -50,7 +50,7 @@ class Chef::Provider::Service::Systemd < Chef::Provider::Service::Simple
def define_resource_requirements
shared_resource_requirements
requirements.assert(:all_actions) do |a|
- a.assertion { @status_check_success }
+ a.assertion { @status_check_success }
# We won't stop in any case, but in whyrun warn and tell what we're doing.
a.whyrun ["Failed to determine status of #{@new_resource}, using command #{@new_resource.status_command}.",
"Assuming service would have been installed and is disabled"]
@@ -99,11 +99,11 @@ class Chef::Provider::Service::Systemd < Chef::Provider::Service::Simple
def enable_service
run_command_with_systems_locale(:command => "/bin/systemctl enable #{@new_resource.service_name}")
- end
+ end
def disable_service
run_command_with_systems_locale(:command => "/bin/systemctl disable #{@new_resource.service_name}")
- end
+ end
def is_active?
run_command_with_systems_locale({:command => "/bin/systemctl is-active #{@new_resource.service_name}", :ignore_failure => true}) == 0
diff --git a/lib/chef/provider/service/upstart.rb b/lib/chef/provider/service/upstart.rb
index 763a2aa92b..67ca649b6d 100644
--- a/lib/chef/provider/service/upstart.rb
+++ b/lib/chef/provider/service/upstart.rb
@@ -26,7 +26,7 @@ class Chef
class Service
class Upstart < Chef::Provider::Service::Simple
UPSTART_STATE_FORMAT = /\w+ \(?(\w+)\)?[\/ ](\w+)/
-
+
# Upstart does more than start or stop a service, creating multiple 'states' [1] that a service can be in.
# In chef, when we ask a service to start, we expect it to have started before performing the next step
# since we have top down dependencies. Which is to say we may follow witha resource next that requires
@@ -40,17 +40,17 @@ class Chef
# TODO: re-evaluate if this is needed after integrating cookbook fix
raise ArgumentError, "run_context cannot be nil" unless run_context
super
-
+
run_context.node
-
+
@job = @new_resource.service_name
-
+
if @new_resource.parameters
@new_resource.parameters.each do |key, value|
@job << " #{key}=#{value}"
end
end
-
+
platform, version = Chef::Platform.find_platform_and_version(run_context.node)
if platform == "ubuntu" && (8.04..9.04).include?(version.to_f)
@upstart_job_dir = "/etc/event.d"
@@ -60,8 +60,8 @@ class Chef
@upstart_conf_suffix = ".conf"
end
- @command_success = true # new_resource.status_command= false, means upstart used
- @config_file_found = true
+ @command_success = true # new_resource.status_command= false, means upstart used
+ @config_file_found = true
@upstart_command_success = true
end
@@ -70,18 +70,18 @@ class Chef
shared_resource_requirements
requirements.assert(:all_actions) do |a|
if !@command_success
- whyrun_msg = @new_resource.status_command ? "Provided status command #{@new_resource.status_command} failed." :
+ whyrun_msg = @new_resource.status_command ? "Provided status command #{@new_resource.status_command} failed." :
"Could not determine upstart state for service"
end
a.assertion { @command_success }
- # no failure here, just document the assumptions made.
- a.whyrun "#{whyrun_msg} Assuming service installed and not running."
+ # no failure here, just document the assumptions made.
+ a.whyrun "#{whyrun_msg} Assuming service installed and not running."
end
- requirements.assert(:all_actions) do |a|
- a.assertion { @config_file_found }
- # no failure here, just document the assumptions made.
- a.whyrun "Could not find #{@upstart_job_dir}/#{@new_resource.service_name}#{@upstart_conf_suffix}. Assuming service is disabled."
+ requirements.assert(:all_actions) do |a|
+ a.assertion { @config_file_found }
+ # no failure here, just document the assumptions made.
+ a.whyrun "Could not find #{@upstart_job_dir}/#{@new_resource.service_name}#{@upstart_conf_suffix}. Assuming service is disabled."
end
end
@@ -176,7 +176,7 @@ class Chef
super
# Upstart always provides restart functionality so we don't need to mimic it with stop/sleep/start.
# Older versions of upstart would fail on restart if the service was currently stopped, check for that. LP:430883
- else @new_resource.supports[:restart]
+ else
if @current_resource.running
run_command_with_systems_locale(:command => "/sbin/restart #{@job}")
else
diff --git a/lib/chef/provider/subversion.rb b/lib/chef/provider/subversion.rb
index e1f87b4dd8..6ceb3e592a 100644
--- a/lib/chef/provider/subversion.rb
+++ b/lib/chef/provider/subversion.rb
@@ -17,7 +17,7 @@
#
-#TODO subversion and git should both extend from a base SCM provider.
+#TODO subversion and git should both extend from a base SCM provider.
require 'chef/log'
require 'chef/provider'
@@ -52,7 +52,7 @@ class Chef
# for why run, print a message explaining the potential error.
parent_directory = ::File.dirname(@new_resource.destination)
a.assertion { ::File.directory?(parent_directory) }
- a.failure_message(Chef::Exceptions::MissingParentDirectory,
+ a.failure_message(Chef::Exceptions::MissingParentDirectory,
"Cannot clone #{@new_resource} to #{@new_resource.destination}, the enclosing directory #{parent_directory} does not exist")
a.whyrun("Directory #{parent_directory} does not exist, assuming it would have been created")
end
@@ -91,13 +91,13 @@ class Chef
converge_by("sync #{@new_resource.destination} from #{@new_resource.repository}") do
run_command(run_options(:command => sync_command))
Chef::Log.info "#{@new_resource} updated to revision: #{revision_int}"
- end
+ end
end
else
action_checkout
end
end
-
+
def sync_command
c = scm :update, @new_resource.svn_arguments, verbose, authentication, "-r#{revision_int}", @new_resource.destination
Chef::Log.debug "#{@new_resource} updated working copy #{@new_resource.destination} to revision #{@new_resource.revision}"
@@ -156,6 +156,7 @@ class Chef
def run_options(run_opts={})
run_opts[:user] = @new_resource.user if @new_resource.user
run_opts[:group] = @new_resource.group if @new_resource.group
+ run_opts[:timeout] = @new_resource.timeout if @new_resource.timeout
run_opts
end
@@ -197,7 +198,7 @@ class Chef
def scm(*args)
['svn', *args].compact.join(" ")
end
-
+
def target_dir_non_existent_or_empty?
!::File.exist?(@new_resource.destination) || Dir.entries(@new_resource.destination).sort == ['.','..']
diff --git a/lib/chef/provider/user.rb b/lib/chef/provider/user.rb
index e815ba9c9e..738f7660f8 100644
--- a/lib/chef/provider/user.rb
+++ b/lib/chef/provider/user.rb
@@ -6,9 +6,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -79,9 +79,7 @@ class Chef
end
end
- if @new_resource.gid
- convert_group_name
- end
+ convert_group_name if @new_resource.gid
end
@current_resource
@@ -89,14 +87,14 @@ class Chef
def define_resource_requirements
requirements.assert(:all_actions) do |a|
- a.assertion { @group_name_resolved }
+ a.assertion { @group_name_resolved }
a.failure_message Chef::Exceptions::User, "Couldn't lookup integer GID for group name #{@new_resource.gid}"
a.whyrun "group name #{@new_resource.gid} does not exist. This will cause group assignment to fail. Assuming this group will have been created previously."
end
requirements.assert(:all_actions) do |a|
- a.assertion { @shadow_lib_ok }
+ a.assertion { @shadow_lib_ok }
a.failure_message Chef::Exceptions::MissingLibrary, "You must have ruby-shadow installed for password support!"
- a.whyrun "ruby-shadow is not installed. Attempts to set user password will cause failure. Assuming that this gem will have been previously installed." +
+ a.whyrun "ruby-shadow is not installed. Attempts to set user password will cause failure. Assuming that this gem will have been previously installed." +
"Note that user update converge may report false-positive on the basis of mismatched password. "
end
requirements.assert(:modify, :lock, :unlock) do |a|
@@ -112,9 +110,15 @@ class Chef
# <true>:: If a change is required
# <false>:: If the users are identical
def compare_user
- [ :uid, :gid, :comment, :home, :shell, :password ].any? do |user_attrib|
+ changed = [ :comment, :home, :shell, :password ].select do |user_attrib|
!@new_resource.send(user_attrib).nil? && @new_resource.send(user_attrib) != @current_resource.send(user_attrib)
end
+
+ changed += [ :uid, :gid ].select do |user_attrib|
+ !@new_resource.send(user_attrib).nil? && @new_resource.send(user_attrib).to_s != @current_resource.send(user_attrib).to_s
+ end
+
+ changed.any?
end
def action_create
diff --git a/lib/chef/provider/user/dscl.rb b/lib/chef/provider/user/dscl.rb
index 94e8420c43..b01931609e 100644
--- a/lib/chef/provider/user/dscl.rb
+++ b/lib/chef/provider/user/dscl.rb
@@ -6,9 +6,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -25,10 +25,10 @@ class Chef
class User
class Dscl < Chef::Provider::User
include Chef::Mixin::ShellOut
-
+
NFS_HOME_DIRECTORY = %r{^NFSHomeDirectory: (.*)$}
AUTHENTICATION_AUTHORITY = %r{^AuthenticationAuthority: (.*)$}
-
+
def dscl(*args)
shell_out("dscl . -#{args.join(' ')}")
end
@@ -80,7 +80,7 @@ class Chef
return safe_dscl("delete /Users/#{@new_resource.username} NFSHomeDirectory") if (@new_resource.home.nil? || @new_resource.home.empty?)
if @new_resource.supports[:manage_home]
validate_home_dir_specification!
-
+
if (@current_resource.home == @new_resource.home) && !new_home_exists?
ditto_home
elsif !current_home_exists? && !new_home_exists?
@@ -105,7 +105,7 @@ class Chef
end
def shadow_hash_set?
- user_data = safe_dscl("read /Users/#{@new_resource.username}")
+ user_data = safe_dscl("read /Users/#{@new_resource.username}")
if user_data =~ /AuthenticationAuthority: / && user_data =~ /ShadowHash/
true
else
@@ -116,7 +116,7 @@ class Chef
def modify_password
if @new_resource.password
shadow_hash = nil
-
+
Chef::Log.debug("#{new_resource} updating password")
if osx_shadow_hash?(@new_resource.password)
shadow_hash = @new_resource.password.upcase
@@ -134,11 +134,11 @@ class Chef
shadow_hash = String.new("00000000"*155)
shadow_hash[168] = salted_sha1
end
-
+
::File.open("/var/db/shadow/hash/#{guid}",'w',0600) do |output|
output.puts shadow_hash
end
-
+
unless shadow_hash_set?
safe_dscl("append /Users/#{@new_resource.username} AuthenticationAuthority ';ShadowHash;'")
end
@@ -159,7 +159,7 @@ class Chef
dscl_set_shell
modify_password
end
-
+
def manage_user
dscl_create_user if diverged?(:username)
dscl_create_comment if diverged?(:comment)
@@ -169,15 +169,15 @@ class Chef
dscl_set_shell if diverged?(:shell)
modify_password if diverged?(:password)
end
-
+
def dscl_create_user
- safe_dscl("create /Users/#{@new_resource.username}")
+ safe_dscl("create /Users/#{@new_resource.username}")
end
-
+
def dscl_create_comment
safe_dscl("create /Users/#{@new_resource.username} RealName '#{@new_resource.comment}'")
end
-
+
def dscl_set_gid
unless @new_resource.gid && @new_resource.gid.to_s.match(/^\d+$/)
begin
@@ -189,7 +189,7 @@ class Chef
end
safe_dscl("create /Users/#{@new_resource.username} PrimaryGroupID '#{@new_resource.gid}'")
end
-
+
def dscl_set_shell
if @new_resource.password || ::File.exists?("#{@new_resource.shell}")
safe_dscl("create /Users/#{@new_resource.username} UserShell '#{@new_resource.shell}'")
@@ -197,10 +197,10 @@ class Chef
safe_dscl("create /Users/#{@new_resource.username} UserShell '/usr/bin/false'")
end
end
-
+
def remove_user
if @new_resource.supports[:manage_home]
- user_info = safe_dscl("read /Users/#{@new_resource.username}")
+ user_info = safe_dscl("read /Users/#{@new_resource.username}")
if nfs_home_match = user_info.match(NFS_HOME_DIRECTORY)
#nfs_home = safe_dscl("read /Users/#{@new_resource.username} NFSHomeDirectory")
#nfs_home.gsub!(/NFSHomeDirectory: /,"").gsub!(/\n$/,"")
@@ -228,7 +228,7 @@ class Chef
false
end
end
-
+
def check_lock
return @locked = locked?
end
@@ -236,27 +236,27 @@ class Chef
def lock_user
safe_dscl("append /Users/#{@new_resource.username} AuthenticationAuthority ';DisabledUser;'")
end
-
+
def unlock_user
auth_info = safe_dscl("read /Users/#{@new_resource.username} AuthenticationAuthority")
auth_string = auth_info.gsub(/AuthenticationAuthority: /,"").gsub(/;DisabledUser;/,"").strip#.gsub!(/[; ]*$/,"")
safe_dscl("create /Users/#{@new_resource.username} AuthenticationAuthority '#{auth_string}'")
end
-
+
def validate_home_dir_specification!
unless @new_resource.home =~ /^\//
- raise(Chef::Exceptions::InvalidHomeDirectory,"invalid path spec for User: '#{@new_resource.username}', home directory: '#{@new_resource.home}'")
+ raise(Chef::Exceptions::InvalidHomeDirectory,"invalid path spec for User: '#{@new_resource.username}', home directory: '#{@new_resource.home}'")
end
end
-
+
def current_home_exists?
::File.exist?("#{@current_resource.home}")
end
-
+
def new_home_exists?
- ::File.exist?("#{@new_resource.home}")
+ ::File.exist?("#{@new_resource.home}")
end
-
+
def ditto_home
skel = "/System/Library/User Template/English.lproj"
raise(Chef::Exceptions::User,"can't find skel at: #{skel}") unless ::File.exists?(skel)
@@ -266,7 +266,7 @@ class Chef
def move_home
Chef::Log.debug("#{@new_resource} moving #{self} home from #{@current_resource.home} to #{@new_resource.home}")
-
+
src = @current_resource.home
FileUtils.mkdir_p(@new_resource.home)
files = ::Dir.glob("#{src}/*", ::File::FNM_DOTMATCH) - ["#{src}/.","#{src}/.."]
@@ -274,11 +274,11 @@ class Chef
::FileUtils.rmdir(src)
::FileUtils.chown_R(@new_resource.username,@new_resource.gid.to_s,@new_resource.home)
end
-
+
def diverged?(parameter)
parameter_updated?(parameter) && (not @new_resource.send(parameter).nil?)
end
-
+
def parameter_updated?(parameter)
not (@new_resource.send(parameter) == @current_resource.send(parameter))
end
diff --git a/lib/chef/provider/user/pw.rb b/lib/chef/provider/user/pw.rb
index 4f6393da89..9f7a169892 100644
--- a/lib/chef/provider/user/pw.rb
+++ b/lib/chef/provider/user/pw.rb
@@ -6,9 +6,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -34,20 +34,20 @@ class Chef
run_command(:command => command)
modify_password
end
-
+
def manage_user
command = "pw usermod"
command << set_options
run_command(:command => command)
modify_password
end
-
+
def remove_user
command = "pw userdel #{@new_resource.username}"
command << " -r" if @new_resource.supports[:manage_home]
run_command(:command => command)
end
-
+
def check_lock
case @current_resource.password
when /^\*LOCKED\*/
@@ -57,18 +57,18 @@ class Chef
end
@locked
end
-
+
def lock_user
run_command(:command => "pw lock #{@new_resource.username}")
end
-
+
def unlock_user
run_command(:command => "pw unlock #{@new_resource.username}")
end
-
+
def set_options
opts = " #{@new_resource.username}"
-
+
field_list = {
'comment' => "-c",
'home' => "-d",
@@ -91,7 +91,7 @@ class Chef
end
opts
end
-
+
def modify_password
if @current_resource.password != @new_resource.password
Chef::Log.debug("#{new_resource} updating password")
@@ -99,7 +99,7 @@ class Chef
status = popen4(command, :waitlast => true) do |pid, stdin, stdout, stderr|
stdin.puts "#{@new_resource.password}"
end
-
+
unless status.exitstatus == 0
raise Chef::Exceptions::User, "pw failed - #{status.inspect}!"
end
diff --git a/lib/chef/provider/user/useradd.rb b/lib/chef/provider/user/useradd.rb
index 41455007dc..1789a4e5ff 100644
--- a/lib/chef/provider/user/useradd.rb
+++ b/lib/chef/provider/user/useradd.rb
@@ -124,7 +124,7 @@ class Chef
end
def update_options(field, option, opts)
- if @current_resource.send(field) != new_resource.send(field)
+ if @current_resource.send(field).to_s != new_resource.send(field).to_s
if new_resource.send(field)
Chef::Log.debug("#{new_resource} setting #{field} to #{new_resource.send(field)}")
opts << option << new_resource.send(field).to_s
diff --git a/lib/chef/provider/user/windows.rb b/lib/chef/provider/user/windows.rb
index 6bbb2a088c..350f3ff4c0 100644
--- a/lib/chef/provider/user/windows.rb
+++ b/lib/chef/provider/user/windows.rb
@@ -6,9 +6,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -71,23 +71,23 @@ class Chef
def create_user
@net_user.add(set_options)
end
-
+
def manage_user
@net_user.update(set_options)
end
-
+
def remove_user
@net_user.delete
end
-
+
def check_lock
@net_user.check_enabled
end
-
+
def lock_user
@net_user.disable_account
end
-
+
def unlock_user
@net_user.enable_account
end
diff --git a/lib/chef/provider/windows_script.rb b/lib/chef/provider/windows_script.rb
index 398e1aee6e..08a2ea74df 100644
--- a/lib/chef/provider/windows_script.rb
+++ b/lib/chef/provider/windows_script.rb
@@ -6,9 +6,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -24,7 +24,7 @@ class Chef
class WindowsScript < Chef::Provider::Script
protected
-
+
include Chef::Mixin::WindowsArchitectureHelper
def initialize( new_resource, run_context, script_extension='')
@@ -43,14 +43,14 @@ class Chef
end
public
-
+
def action_run
wow64_redirection_state = nil
if @is_wow64
wow64_redirection_state = disable_wow64_file_redirection(@run_context.node)
end
-
+
begin
super
rescue
@@ -61,11 +61,11 @@ class Chef
end
end
end
-
+
def script_file
base_script_name = "chef-script"
temp_file_arguments = [ base_script_name, @script_extension ]
-
+
@script_file ||= Tempfile.open(temp_file_arguments)
end
end
diff --git a/lib/chef/providers.rb b/lib/chef/providers.rb
index e0039428f2..50099e8afc 100644
--- a/lib/chef/providers.rb
+++ b/lib/chef/providers.rb
@@ -21,6 +21,7 @@ require 'chef/provider/breakpoint'
require 'chef/provider/cookbook_file'
require 'chef/provider/cron'
require 'chef/provider/cron/solaris'
+require 'chef/provider/cron/aix'
require 'chef/provider/deploy'
require 'chef/provider/directory'
require 'chef/provider/env'
@@ -64,6 +65,7 @@ require 'chef/provider/package/yum'
require 'chef/provider/package/zypper'
require 'chef/provider/package/solaris'
require 'chef/provider/package/smartos'
+require 'chef/provider/package/aix'
require 'chef/provider/service/arch'
require 'chef/provider/service/debian'
@@ -97,6 +99,7 @@ require 'chef/provider/group/usermod'
require 'chef/provider/group/windows'
require 'chef/provider/mount/mount'
+require 'chef/provider/mount/aix'
require 'chef/provider/mount/windows'
require 'chef/provider/deploy/revision'
@@ -117,3 +120,4 @@ require 'chef/provider/template/content'
require 'chef/provider/ifconfig/redhat'
require 'chef/provider/ifconfig/debian'
+require 'chef/provider/ifconfig/aix'
diff --git a/lib/chef/recipe.rb b/lib/chef/recipe.rb
index 6ea69360b8..0c688cb5f8 100644
--- a/lib/chef/recipe.rb
+++ b/lib/chef/recipe.rb
@@ -81,26 +81,9 @@ class Chef
run_context.resource_collection.find(*args)
end
- # Sets a tag, or list of tags, for this node. Syntactic sugar for
- # run_context.node[:tags].
- #
- # With no arguments, returns the list of tags.
- #
- # === Parameters
- # tags<Array>:: A list of tags to add - can be a single string
- #
- # === Returns
- # tags<Array>:: The contents of run_context.node[:tags]
+ # This was moved to Chef::Node#tag, redirecting here for compatability
def tag(*tags)
- if tags.length > 0
- tags.each do |tag|
- tag = tag.to_s
- run_context.node.normal[:tags] << tag unless run_context.node[:tags].include?(tag)
- end
- run_context.node[:tags]
- else
- run_context.node[:tags]
- end
+ run_context.node.tag(*tags)
end
# Returns true if the node is tagged with *all* of the supplied +tags+.
diff --git a/lib/chef/resource/apt_package.rb b/lib/chef/resource/apt_package.rb
index 524abbb370..050cf838ae 100644
--- a/lib/chef/resource/apt_package.rb
+++ b/lib/chef/resource/apt_package.rb
@@ -6,9 +6,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -22,7 +22,7 @@ require 'chef/provider/package/apt'
class Chef
class Resource
class AptPackage < Chef::Resource::Package
-
+
def initialize(name, run_context=nil)
super
@resource_name = :apt_package
diff --git a/lib/chef/resource/bash.rb b/lib/chef/resource/bash.rb
index 374bca9e11..c56de5fe20 100644
--- a/lib/chef/resource/bash.rb
+++ b/lib/chef/resource/bash.rb
@@ -6,9 +6,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -21,7 +21,7 @@ require 'chef/resource/script'
class Chef
class Resource
class Bash < Chef::Resource::Script
-
+
def initialize(name, run_context=nil)
super
@resource_name = :bash
diff --git a/lib/chef/resource/batch.rb b/lib/chef/resource/batch.rb
index 705260bbce..576e6b4c6b 100644
--- a/lib/chef/resource/batch.rb
+++ b/lib/chef/resource/batch.rb
@@ -6,9 +6,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -21,11 +21,11 @@ require 'chef/resource/windows_script'
class Chef
class Resource
class Batch < Chef::Resource::WindowsScript
-
+
def initialize(name, run_context=nil)
super(name, run_context, :batch, "cmd.exe")
end
-
+
end
end
end
diff --git a/lib/chef/resource/bff_package.rb b/lib/chef/resource/bff_package.rb
new file mode 100644
index 0000000000..2d78483e4b
--- /dev/null
+++ b/lib/chef/resource/bff_package.rb
@@ -0,0 +1,36 @@
+#
+# Author:: Deepali Jagtap (<deepali.jagtap@clogeny.com>)
+# Copyright:: Copyright (c) 2013 Opscode, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require 'chef/resource/package'
+require 'chef/provider/package/aix'
+
+class Chef
+ class Resource
+ class BffPackage < Chef::Resource::Package
+
+ def initialize(name, run_context=nil)
+ super
+ @resource_name = :bff_package
+ @provider = Chef::Provider::Package::Aix
+ end
+
+ end
+ end
+end
+
+
diff --git a/lib/chef/resource/breakpoint.rb b/lib/chef/resource/breakpoint.rb
index 34aeae6b47..83c397bd5b 100644
--- a/lib/chef/resource/breakpoint.rb
+++ b/lib/chef/resource/breakpoint.rb
@@ -6,9 +6,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -22,7 +22,7 @@ require 'chef/resource'
class Chef
class Resource
class Breakpoint < Chef::Resource
-
+
def initialize(action="break", *args)
@name = caller.first
super(@name, *args)
diff --git a/lib/chef/resource/cron.rb b/lib/chef/resource/cron.rb
index 5f858cec81..dfbb91f80c 100644
--- a/lib/chef/resource/cron.rb
+++ b/lib/chef/resource/cron.rb
@@ -7,9 +7,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -22,7 +22,7 @@ require 'chef/resource'
class Chef
class Resource
class Cron < Chef::Resource
-
+
identity_attr :command
state_attrs :minute, :hour, :day, :month, :weekday, :user
@@ -186,9 +186,9 @@ class Chef
:kind_of => Hash
)
end
-
+
private
-
+
# On Ruby 1.8, Kernel#Integer will happily do this for you. On 1.9, no.
def integerize(integerish)
Integer(integerish)
diff --git a/lib/chef/resource/csh.rb b/lib/chef/resource/csh.rb
index 6e871e8605..95aa8afd7a 100644
--- a/lib/chef/resource/csh.rb
+++ b/lib/chef/resource/csh.rb
@@ -6,9 +6,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -21,7 +21,7 @@ require 'chef/resource/script'
class Chef
class Resource
class Csh < Chef::Resource::Script
-
+
def initialize(name, run_context=nil)
super
@resource_name = :csh
diff --git a/lib/chef/resource/deploy.rb b/lib/chef/resource/deploy.rb
index 8b614028bf..76478ed07c 100644
--- a/lib/chef/resource/deploy.rb
+++ b/lib/chef/resource/deploy.rb
@@ -50,9 +50,9 @@ class Chef
# release directory. Callback files can contain chef code (resources, etc.)
#
class Deploy < Chef::Resource
-
+
provider_base Chef::Provider::Deploy
-
+
identity_attr :repository
state_attrs :deploy_to, :revision
@@ -389,7 +389,7 @@ class Chef
arg ||= block
set_or_return(:after_restart, arg, :kind_of => [Proc, String])
end
-
+
def additional_remotes(arg=nil)
set_or_return(
:additional_remotes,
@@ -398,6 +398,19 @@ class Chef
)
end
+ # FIXME The Deploy resource may be passed to an SCM provider as its
+ # resource. The SCM provider knows that SCM resources can specify a
+ # timeout for SCM operations. The deploy resource must therefore support
+ # a timeout method, but the timeout it describes is for SCM operations,
+ # not the overall deployment. This is potentially confusing.
+ def timeout(arg=nil)
+ set_or_return(
+ :timeout,
+ arg,
+ :kind_of => Integer
+ )
+ end
+
end
end
end
diff --git a/lib/chef/resource/deploy_revision.rb b/lib/chef/resource/deploy_revision.rb
index 55a3e38130..ceac26e91a 100644
--- a/lib/chef/resource/deploy_revision.rb
+++ b/lib/chef/resource/deploy_revision.rb
@@ -6,9 +6,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -18,9 +18,9 @@
class Chef
class Resource
-
+
# Convenience class for using the deploy resource with the revision
- # deployment strategy (provider)
+ # deployment strategy (provider)
class DeployRevision < Chef::Resource::Deploy
def initialize(*args, &block)
super
@@ -28,13 +28,13 @@ class Chef
@provider = Chef::Provider::Deploy::Revision
end
end
-
+
class DeployBranch < Chef::Resource::DeployRevision
def initialize(*args, &block)
super
@resource_name = :deploy_branch
end
end
-
+
end
end
diff --git a/lib/chef/resource/directory.rb b/lib/chef/resource/directory.rb
index a5d5ea7366..423c0bbe27 100644
--- a/lib/chef/resource/directory.rb
+++ b/lib/chef/resource/directory.rb
@@ -25,11 +25,11 @@ require 'chef/mixin/securable'
class Chef
class Resource
class Directory < Chef::Resource
-
+
identity_attr :path
state_attrs :group, :mode, :owner
-
+
include Chef::Mixin::Securable
provides :directory, :on_platforms => :all
diff --git a/lib/chef/resource/dpkg_package.rb b/lib/chef/resource/dpkg_package.rb
index 02886e8649..2fb5b5c249 100644
--- a/lib/chef/resource/dpkg_package.rb
+++ b/lib/chef/resource/dpkg_package.rb
@@ -6,9 +6,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -22,13 +22,13 @@ require 'chef/provider/package/dpkg'
class Chef
class Resource
class DpkgPackage < Chef::Resource::Package
-
+
def initialize(name, run_context=nil)
super
@resource_name = :dpkg_package
@provider = Chef::Provider::Package::Dpkg
end
-
+
end
end
end
diff --git a/lib/chef/resource/easy_install_package.rb b/lib/chef/resource/easy_install_package.rb
index 10e80bdd3b..f25e1ac22f 100644
--- a/lib/chef/resource/easy_install_package.rb
+++ b/lib/chef/resource/easy_install_package.rb
@@ -21,7 +21,7 @@ require 'chef/resource/package'
class Chef
class Resource
class EasyInstallPackage < Chef::Resource::Package
-
+
def initialize(name, run_context=nil)
super
@resource_name = :easy_install_package
diff --git a/lib/chef/resource/erl_call.rb b/lib/chef/resource/erl_call.rb
index e0e38926bb..959856af66 100644
--- a/lib/chef/resource/erl_call.rb
+++ b/lib/chef/resource/erl_call.rb
@@ -24,7 +24,7 @@ class Chef
class ErlCall < Chef::Resource
# erl_call : http://erlang.org/doc/man/erl_call.html
-
+
identity_attr :code
def initialize(name, run_context=nil)
diff --git a/lib/chef/resource/freebsd_package.rb b/lib/chef/resource/freebsd_package.rb
index 9a9a84900e..94286eae18 100644
--- a/lib/chef/resource/freebsd_package.rb
+++ b/lib/chef/resource/freebsd_package.rb
@@ -6,9 +6,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -22,13 +22,13 @@ require 'chef/provider/package/freebsd'
class Chef
class Resource
class FreebsdPackage < Chef::Resource::Package
-
+
def initialize(name, run_context=nil)
super
@resource_name = :freebsd_package
@provider = Chef::Provider::Package::Freebsd
end
-
+
end
end
end
diff --git a/lib/chef/resource/group.rb b/lib/chef/resource/group.rb
index 76f3a779ae..17f14c8387 100644
--- a/lib/chef/resource/group.rb
+++ b/lib/chef/resource/group.rb
@@ -7,9 +7,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -20,7 +20,7 @@
class Chef
class Resource
class Group < Chef::Resource
-
+
identity_attr :group_name
state_attrs :members
@@ -33,9 +33,10 @@ class Chef
@members = []
@action = :create
@append = false
+ @non_unique = false
@allowed_actions.push(:create, :remove, :modify, :manage)
end
-
+
def group_name(arg=nil)
set_or_return(
:group_name,
@@ -43,7 +44,7 @@ class Chef
:kind_of => [ String ]
)
end
-
+
def gid(arg=nil)
set_or_return(
:gid,
@@ -62,7 +63,7 @@ class Chef
end
alias_method :users, :members
-
+
def append(arg=nil)
set_or_return(
:append,
@@ -78,6 +79,14 @@ class Chef
:kind_of => [ TrueClass, FalseClass ]
)
end
+
+ def non_unique(arg=nil)
+ set_or_return(
+ :non_unique,
+ arg,
+ :kind_of => [ TrueClass, FalseClass ]
+ )
+ end
end
end
end
diff --git a/lib/chef/resource/http_request.rb b/lib/chef/resource/http_request.rb
index fc64121f4e..47f6286fb4 100644
--- a/lib/chef/resource/http_request.rb
+++ b/lib/chef/resource/http_request.rb
@@ -7,9 +7,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -22,7 +22,7 @@ require 'chef/resource'
class Chef
class Resource
class HttpRequest < Chef::Resource
-
+
identity_attr :url
def initialize(name, run_context=nil)
@@ -34,7 +34,7 @@ class Chef
@headers = {}
@allowed_actions.push(:get, :put, :post, :delete, :head, :options)
end
-
+
def url(args=nil)
set_or_return(
:url,
@@ -42,7 +42,7 @@ class Chef
:kind_of => String
)
end
-
+
def message(args=nil, &block)
args = block if block_given?
set_or_return(
@@ -59,7 +59,7 @@ class Chef
:kind_of => Hash
)
end
-
+
end
end
end
diff --git a/lib/chef/resource/ifconfig.rb b/lib/chef/resource/ifconfig.rb
index daa8a572a0..c289ddadbe 100644
--- a/lib/chef/resource/ifconfig.rb
+++ b/lib/chef/resource/ifconfig.rb
@@ -7,9 +7,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -22,7 +22,7 @@ require 'chef/resource'
class Chef
class Resource
class Ifconfig < Chef::Resource
-
+
identity_attr :device
state_attrs :inet_addr, :mask
@@ -39,7 +39,7 @@ class Chef
@bcast = nil
@mtu = nil
@metric = nil
- @device = nil
+ @device = nil
@onboot = nil
@network = nil
@bootproto = nil
diff --git a/lib/chef/resource/ips_package.rb b/lib/chef/resource/ips_package.rb
index f82e0877df..88c6e9a538 100644
--- a/lib/chef/resource/ips_package.rb
+++ b/lib/chef/resource/ips_package.rb
@@ -6,9 +6,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
diff --git a/lib/chef/resource/log.rb b/lib/chef/resource/log.rb
index 30a5bb93c6..391c3b5393 100644
--- a/lib/chef/resource/log.rb
+++ b/lib/chef/resource/log.rb
@@ -7,9 +7,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -19,7 +19,7 @@
class Chef
class Resource
class Log < Chef::Resource
-
+
identity_attr :message
# Sends a string from a recipe to a log provider
@@ -27,16 +27,16 @@ class Chef
# log "some string to log" do
# level :info # (default) also supports :warn, :debug, and :error
# end
- #
+ #
# === Example
- # log "your string to log"
+ # log "your string to log"
#
- # or
+ # or
#
# log "a debug string" { level :debug }
#
-
- # Initialize log resource with a name as the string to log
+
+ # Initialize log resource with a name as the string to log
#
# === Parameters
# name<String>:: Message to log
@@ -47,6 +47,7 @@ class Chef
@resource_name = :log
@level = :info
@action = :write
+ @allowed_actions.push(:write)
@message = name
end
@@ -57,7 +58,7 @@ class Chef
:kind_of => String
)
end
-
+
# <Symbol> Log level, one of :debug, :info, :warn, :error or :fatal
def level(arg=nil)
set_or_return(
@@ -66,9 +67,9 @@ class Chef
:equal_to => [ :debug, :info, :warn, :error, :fatal ]
)
end
-
+
end
- end
+ end
end
diff --git a/lib/chef/resource/macports_package.rb b/lib/chef/resource/macports_package.rb
index 911d3c19cb..c9434c9e69 100644
--- a/lib/chef/resource/macports_package.rb
+++ b/lib/chef/resource/macports_package.rb
@@ -6,9 +6,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
diff --git a/lib/chef/resource/mount.rb b/lib/chef/resource/mount.rb
index ad68391fe4..49984630c0 100644
--- a/lib/chef/resource/mount.rb
+++ b/lib/chef/resource/mount.rb
@@ -7,9 +7,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -22,7 +22,7 @@ require 'chef/resource'
class Chef
class Resource
class Mount < Chef::Resource
-
+
identity_attr :device
state_attrs :mount_point, :device_type, :fstype, :username, :password, :domain
@@ -46,7 +46,7 @@ class Chef
@password = nil
@domain = nil
end
-
+
def mount_point(arg=nil)
set_or_return(
:mount_point,
@@ -54,7 +54,7 @@ class Chef
:kind_of => [ String ]
)
end
-
+
def device(arg=nil)
set_or_return(
:device,
@@ -62,7 +62,7 @@ class Chef
:kind_of => [ String ]
)
end
-
+
def device_type(arg=nil)
real_arg = arg.kind_of?(String) ? arg.to_sym : arg
set_or_return(
@@ -79,7 +79,7 @@ class Chef
:kind_of => [ String ]
)
end
-
+
def options(arg=nil)
if arg.is_a?(String)
converted_arg = arg.gsub(/,/, ' ').split(/ /)
@@ -92,7 +92,7 @@ class Chef
:kind_of => [ Array ]
)
end
-
+
def dump(arg=nil)
set_or_return(
:dump,
@@ -100,7 +100,7 @@ class Chef
:kind_of => [ Integer, FalseClass ]
)
end
-
+
def pass(arg=nil)
set_or_return(
:pass,
@@ -108,7 +108,7 @@ class Chef
:kind_of => [ Integer, FalseClass ]
)
end
-
+
def mounted(arg=nil)
set_or_return(
:mounted,
@@ -124,7 +124,7 @@ class Chef
:kind_of => [ TrueClass, FalseClass ]
)
end
-
+
def supports(args={})
if args.is_a? Array
args.each { |arg| @supports[arg] = true }
@@ -163,4 +163,3 @@ class Chef
end
end
-
diff --git a/lib/chef/resource/ohai.rb b/lib/chef/resource/ohai.rb
index 48e55e9f01..b567db40f9 100644
--- a/lib/chef/resource/ohai.rb
+++ b/lib/chef/resource/ohai.rb
@@ -7,9 +7,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -20,7 +20,7 @@
class Chef
class Resource
class Ohai < Chef::Resource
-
+
identity_attr :name
state_attrs :plugin
diff --git a/lib/chef/resource/pacman_package.rb b/lib/chef/resource/pacman_package.rb
index d66c93be66..2894e415ac 100644
--- a/lib/chef/resource/pacman_package.rb
+++ b/lib/chef/resource/pacman_package.rb
@@ -6,9 +6,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -21,13 +21,13 @@ require 'chef/resource/package'
class Chef
class Resource
class PacmanPackage < Chef::Resource::Package
-
+
def initialize(name, run_context=nil)
super
@resource_name = :pacman_package
@provider = Chef::Provider::Package::Pacman
end
-
+
end
end
end
diff --git a/lib/chef/resource/perl.rb b/lib/chef/resource/perl.rb
index d3cf696cbb..546f639e1f 100644
--- a/lib/chef/resource/perl.rb
+++ b/lib/chef/resource/perl.rb
@@ -6,9 +6,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -21,7 +21,7 @@ require 'chef/resource/script'
class Chef
class Resource
class Perl < Chef::Resource::Script
-
+
def initialize(name, run_context=nil)
super
@resource_name = :perl
diff --git a/lib/chef/resource/portage_package.rb b/lib/chef/resource/portage_package.rb
index fc72381482..42c03560b6 100644
--- a/lib/chef/resource/portage_package.rb
+++ b/lib/chef/resource/portage_package.rb
@@ -6,9 +6,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -21,13 +21,13 @@ require 'chef/resource/package'
class Chef
class Resource
class PortagePackage < Chef::Resource::Package
-
+
def initialize(name, run_context=nil)
super
@resource_name = :portage_package
@provider = Chef::Provider::Package::Portage
end
-
+
end
end
end
diff --git a/lib/chef/resource/powershell_script.rb b/lib/chef/resource/powershell_script.rb
index e257eb2fb1..cbd81b1259 100644
--- a/lib/chef/resource/powershell_script.rb
+++ b/lib/chef/resource/powershell_script.rb
@@ -6,9 +6,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -25,7 +25,7 @@ class Chef
def initialize(name, run_context=nil)
super(name, run_context, :powershell_script, "powershell.exe")
end
-
+
end
end
end
diff --git a/lib/chef/resource/python.rb b/lib/chef/resource/python.rb
index 85a5348d27..f340afdb39 100644
--- a/lib/chef/resource/python.rb
+++ b/lib/chef/resource/python.rb
@@ -6,9 +6,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -21,7 +21,7 @@ require 'chef/resource/script'
class Chef
class Resource
class Python < Chef::Resource::Script
-
+
def initialize(name, run_context=nil)
super
@resource_name = :python
diff --git a/lib/chef/resource/route.rb b/lib/chef/resource/route.rb
index c8680697af..942905d138 100644
--- a/lib/chef/resource/route.rb
+++ b/lib/chef/resource/route.rb
@@ -7,9 +7,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -26,7 +26,7 @@ class Chef
identity_attr :target
state_attrs :netmask, :gateway
-
+
def initialize(name, run_context=nil)
super
@resource_name = :route
@@ -36,7 +36,7 @@ class Chef
@netmask = nil
@gateway = nil
@metric = nil
- @device = nil
+ @device = nil
@route_type = :host
@networking = nil
@networking_ipv6 = nil
diff --git a/lib/chef/resource/rpm_package.rb b/lib/chef/resource/rpm_package.rb
index 7ab1202ef2..200a9633ce 100644
--- a/lib/chef/resource/rpm_package.rb
+++ b/lib/chef/resource/rpm_package.rb
@@ -6,9 +6,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
diff --git a/lib/chef/resource/ruby.rb b/lib/chef/resource/ruby.rb
index 7617839bab..605d27b00d 100644
--- a/lib/chef/resource/ruby.rb
+++ b/lib/chef/resource/ruby.rb
@@ -6,9 +6,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -21,7 +21,7 @@ require 'chef/resource/script'
class Chef
class Resource
class Ruby < Chef::Resource::Script
-
+
def initialize(name, run_context=nil)
super
@resource_name = :ruby
diff --git a/lib/chef/resource/ruby_block.rb b/lib/chef/resource/ruby_block.rb
index 296345bde3..d9b8954a90 100644
--- a/lib/chef/resource/ruby_block.rb
+++ b/lib/chef/resource/ruby_block.rb
@@ -7,9 +7,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -20,7 +20,7 @@
class Chef
class Resource
class RubyBlock < Chef::Resource
-
+
identity_attr :block_name
def initialize(name, run_context=nil)
diff --git a/lib/chef/resource/scm.rb b/lib/chef/resource/scm.rb
index 781e09a2c9..d9a372900e 100644
--- a/lib/chef/resource/scm.rb
+++ b/lib/chef/resource/scm.rb
@@ -23,8 +23,8 @@ class Chef
class Resource
class Scm < Chef::Resource
- identity_attr :destination
-
+ identity_attr :destination
+
state_attrs :revision
def initialize(name, run_context=nil)
@@ -146,6 +146,14 @@ class Chef
)
end
+ def timeout(arg=nil)
+ set_or_return(
+ :timeout,
+ arg,
+ :kind_of => Integer
+ )
+ end
+
end
end
end
diff --git a/lib/chef/resource/script.rb b/lib/chef/resource/script.rb
index 6a7c8e0d5e..8cc9c6f0c5 100644
--- a/lib/chef/resource/script.rb
+++ b/lib/chef/resource/script.rb
@@ -7,9 +7,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -22,7 +22,7 @@ require 'chef/resource/execute'
class Chef
class Resource
class Script < Chef::Resource::Execute
-
+
identity_attr :command
def initialize(name, run_context=nil)
@@ -33,7 +33,7 @@ class Chef
@interpreter = nil
@flags = nil
end
-
+
def code(arg=nil)
set_or_return(
:code,
@@ -41,7 +41,7 @@ class Chef
:kind_of => [ String ]
)
end
-
+
def interpreter(arg=nil)
set_or_return(
:interpreter,
diff --git a/lib/chef/resource/service.rb b/lib/chef/resource/service.rb
index ea43baa414..befa4be1c9 100644
--- a/lib/chef/resource/service.rb
+++ b/lib/chef/resource/service.rb
@@ -7,9 +7,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -22,7 +22,7 @@ require 'chef/resource'
class Chef
class Resource
class Service < Chef::Resource
-
+
identity_attr :service_name
state_attrs :enabled, :running
@@ -47,7 +47,7 @@ class Chef
@supports = { :restart => false, :reload => false, :status => false }
@allowed_actions.push(:enable, :disable, :start, :stop, :restart, :reload)
end
-
+
def service_name(arg=nil)
set_or_return(
:service_name,
@@ -55,7 +55,7 @@ class Chef
:kind_of => [ String ]
)
end
-
+
# regex for match against ps -ef when !supports[:has_status] && status == nil
def pattern(arg=nil)
set_or_return(
diff --git a/lib/chef/resource/smartos_package.rb b/lib/chef/resource/smartos_package.rb
index 315481bd93..0f4f6d8b0a 100644
--- a/lib/chef/resource/smartos_package.rb
+++ b/lib/chef/resource/smartos_package.rb
@@ -6,9 +6,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -21,16 +21,18 @@ require 'chef/provider/package/smartos'
class Chef
class Resource
- class SmartOSPackage < Chef::Resource::Package
-
+ class SmartosPackage < Chef::Resource::Package
+
def initialize(name, run_context=nil)
super
@resource_name = :smartos_package
@provider = Chef::Provider::Package::SmartOS
end
-
+
end
end
end
-
+# Backwards compatability
+# @todo remove in Chef 12
+Chef::Resource::SmartOSPackage = Chef::Resource::SmartosPackage
diff --git a/lib/chef/resource/solaris_package.rb b/lib/chef/resource/solaris_package.rb
index becf0236ad..3513703076 100644
--- a/lib/chef/resource/solaris_package.rb
+++ b/lib/chef/resource/solaris_package.rb
@@ -1,14 +1,15 @@
#
# Author:: Toomas Pelberg (<toomasp@gmx.net>)
-# Copyright:: Copyright (c) 2010 Opscode, Inc.
+# Author:: Prabhu Das (<prabhu.das@clogeny.com>)
+# Copyright:: Copyright (c) 2013 Opscode, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -22,13 +23,13 @@ require 'chef/provider/package/solaris'
class Chef
class Resource
class SolarisPackage < Chef::Resource::Package
-
- def initialize(name, collection=nil, node=nil)
- super(name, collection, node)
+
+ def initialize(name, run_context=nil)
+ super
@resource_name = :solaris_package
@provider = Chef::Provider::Package::Solaris
end
-
+
end
end
end
diff --git a/lib/chef/resource/subversion.rb b/lib/chef/resource/subversion.rb
index e3226d8b3b..04fec9b1d8 100644
--- a/lib/chef/resource/subversion.rb
+++ b/lib/chef/resource/subversion.rb
@@ -7,9 +7,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -31,7 +31,7 @@ class Chef
@provider = Chef::Provider::Subversion
allowed_actions << :force_export
end
-
+
end
end
end
diff --git a/lib/chef/resource/timestamped_deploy.rb b/lib/chef/resource/timestamped_deploy.rb
index d89274bb44..4032ae9854 100644
--- a/lib/chef/resource/timestamped_deploy.rb
+++ b/lib/chef/resource/timestamped_deploy.rb
@@ -6,9 +6,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -18,9 +18,9 @@
class Chef
class Resource
-
+
# Convenience class for using the deploy resource with the timestamped
- # deployment strategy (provider)
+ # deployment strategy (provider)
class TimestampedDeploy < Chef::Resource::Deploy
def initialize(*args, &block)
super(*args, &block)
diff --git a/lib/chef/resource/user.rb b/lib/chef/resource/user.rb
index 4d8c4ac11b..357d6d12ea 100644
--- a/lib/chef/resource/user.rb
+++ b/lib/chef/resource/user.rb
@@ -6,9 +6,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -25,7 +25,7 @@ class Chef
identity_attr :username
state_attrs :uid, :gid, :home
-
+
def initialize(name, run_context=nil)
super
@resource_name = :user
@@ -40,13 +40,13 @@ class Chef
@manage_home = false
@non_unique = false
@action = :create
- @supports = {
+ @supports = {
:manage_home => false,
:non_unique => false
}
@allowed_actions.push(:create, :remove, :modify, :manage, :lock, :unlock)
end
-
+
def username(arg=nil)
set_or_return(
:username,
@@ -54,7 +54,7 @@ class Chef
:kind_of => [ String ]
)
end
-
+
def comment(arg=nil)
set_or_return(
:comment,
@@ -62,7 +62,7 @@ class Chef
:kind_of => [ String ]
)
end
-
+
def uid(arg=nil)
set_or_return(
:uid,
@@ -70,7 +70,7 @@ class Chef
:kind_of => [ String, Integer ]
)
end
-
+
def gid(arg=nil)
set_or_return(
:gid,
@@ -78,9 +78,9 @@ class Chef
:kind_of => [ String, Integer ]
)
end
-
+
alias_method :group, :gid
-
+
def home(arg=nil)
set_or_return(
:home,
@@ -88,7 +88,7 @@ class Chef
:kind_of => [ String ]
)
end
-
+
def shell(arg=nil)
set_or_return(
:shell,
@@ -96,7 +96,7 @@ class Chef
:kind_of => [ String ]
)
end
-
+
def password(arg=nil)
set_or_return(
:password,
@@ -128,7 +128,7 @@ class Chef
:kind_of => [ TrueClass, FalseClass ]
)
end
-
+
end
end
end
diff --git a/lib/chef/resource/windows_script.rb b/lib/chef/resource/windows_script.rb
index 5f2311a5bb..2b563f5bec 100644
--- a/lib/chef/resource/windows_script.rb
+++ b/lib/chef/resource/windows_script.rb
@@ -6,9 +6,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -27,14 +27,14 @@ class Chef
def initialize(name, run_context, resource_name, interpreter_command)
super(name, run_context)
- @interpreter = interpreter_command
+ @interpreter = interpreter_command
@resource_name = resource_name
end
include Chef::Mixin::WindowsArchitectureHelper
public
-
+
def architecture(arg=nil)
assert_architecture_compatible!(arg) if ! arg.nil?
result = set_or_return(
@@ -43,7 +43,7 @@ class Chef
:kind_of => Symbol
)
end
-
+
protected
def assert_architecture_compatible!(desired_architecture)
@@ -56,7 +56,7 @@ class Chef
def node
run_context && run_context.node
end
-
+
end
end
end
diff --git a/lib/chef/resource/yum_package.rb b/lib/chef/resource/yum_package.rb
index bcb1f65667..dff70bcf62 100644
--- a/lib/chef/resource/yum_package.rb
+++ b/lib/chef/resource/yum_package.rb
@@ -6,9 +6,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
diff --git a/lib/chef/resource_collection.rb b/lib/chef/resource_collection.rb
index 7460a185b4..a528a18aed 100644
--- a/lib/chef/resource_collection.rb
+++ b/lib/chef/resource_collection.rb
@@ -183,7 +183,7 @@ class Chef
"The string `#{query_object}' is not valid for resource collection lookup. Correct syntax is `resource_type[resource_name]'"
else
raise Chef::Exceptions::InvalidResourceSpecification,
- "The object `#{query_object.inspect}' is not valid for resource collection lookup. " +
+ "The object `#{query_object.inspect}' is not valid for resource collection lookup. " +
"Use a String like `resource_type[resource_name]' or a Chef::Resource object"
end
end
diff --git a/lib/chef/resource_collection/stepable_iterator.rb b/lib/chef/resource_collection/stepable_iterator.rb
index ec1e244758..4d5fc1f497 100644
--- a/lib/chef/resource_collection/stepable_iterator.rb
+++ b/lib/chef/resource_collection/stepable_iterator.rb
@@ -5,9 +5,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -18,94 +18,94 @@
class Chef
class ResourceCollection
class StepableIterator
-
+
def self.for_collection(new_collection)
instance = new(new_collection)
instance
end
-
+
attr_accessor :collection
attr_reader :position
-
+
def initialize(collection=[])
@position = 0
@paused = false
@collection = collection
end
-
+
def size
collection.size
end
-
+
def each(&block)
reset_iteration(block)
@iterator_type = :element
iterate
end
-
+
def each_index(&block)
reset_iteration(block)
@iterator_type = :index
iterate
end
-
+
def each_with_index(&block)
reset_iteration(block)
@iterator_type = :element_with_index
iterate
end
-
+
def paused?
@paused
end
-
+
def pause
@paused = true
end
-
+
def resume
@paused = false
iterate
end
-
+
def rewind
@position = 0
end
-
+
def skip_back(skips=1)
@position -= skips
end
-
+
def skip_forward(skips=1)
@position += skips
end
-
+
def step
return nil if @position == size
call_iterator_block
@position += 1
end
-
+
def iterate_on(iteration_type, &block)
@iterator_type = iteration_type
@iterator_block = block
end
-
+
private
-
+
def reset_iteration(iterator_block)
@iterator_block = iterator_block
@position = 0
@paused = false
end
-
+
def iterate
while @position < size && !paused?
step
end
collection
end
-
+
def call_iterator_block
case @iterator_type
when :element
@@ -118,7 +118,7 @@ class Chef
raise "42error: someone forgot to set @iterator_type, wtf?"
end
end
-
+
end
end
end
diff --git a/lib/chef/resource_definition.rb b/lib/chef/resource_definition.rb
index a0160c5885..278114e209 100644
--- a/lib/chef/resource_definition.rb
+++ b/lib/chef/resource_definition.rb
@@ -6,9 +6,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -21,19 +21,19 @@ require 'chef/mixin/params_validate'
class Chef
class ResourceDefinition
-
+
include Chef::Mixin::FromFile
include Chef::Mixin::ParamsValidate
-
+
attr_accessor :name, :params, :recipe, :node
-
+
def initialize(node=nil)
@name = nil
@params = Hash.new
@recipe = nil
@node = node
end
-
+
def define(resource_name, prototype_params=nil, &block)
unless resource_name.kind_of?(Symbol)
raise ArgumentError, "You must use a symbol when defining a new resource!"
@@ -52,14 +52,14 @@ class Chef
end
true
end
-
+
# When we do the resource definition, we're really just setting new values for
# the paramaters we prototyped at the top. This method missing is as simple as
# it gets.
def method_missing(symbol, *args)
@params[symbol] = args.length == 1 ? args[0] : args
end
-
+
def to_s
"#{name.to_s}"
end
diff --git a/lib/chef/resource_definition_list.rb b/lib/chef/resource_definition_list.rb
index b958624208..55014090d4 100644
--- a/lib/chef/resource_definition_list.rb
+++ b/lib/chef/resource_definition_list.rb
@@ -6,9 +6,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
diff --git a/lib/chef/resource_reporter.rb b/lib/chef/resource_reporter.rb
index 434150e83d..d29949086e 100644
--- a/lib/chef/resource_reporter.rb
+++ b/lib/chef/resource_reporter.rb
@@ -52,8 +52,8 @@ class Chef
as_hash["type"] = new_resource.class.dsl_name
as_hash["name"] = new_resource.name
as_hash["id"] = new_resource.identity
- as_hash["after"] = new_resource.state
- as_hash["before"] = current_resource ? current_resource.state : {}
+ as_hash["after"] = state(new_resource)
+ as_hash["before"] = current_resource ? state(current_resource) : {}
as_hash["duration"] = (elapsed_time * 1000).to_i.to_s
as_hash["delta"] = new_resource.diff if new_resource.respond_to?("diff")
as_hash["delta"] = "" if as_hash["delta"].nil?
@@ -80,6 +80,12 @@ class Chef
!self.exception
end
+ def state(r)
+ r.class.state_attrs.inject({}) do |state_attrs, attr_name|
+ state_attrs[attr_name] = r.send(attr_name)
+ state_attrs
+ end
+ end
end # End class ResouceReport
attr_reader :updated_resources
diff --git a/lib/chef/resources.rb b/lib/chef/resources.rb
index 55c6a0dbf3..d0a27d8922 100644
--- a/lib/chef/resources.rb
+++ b/lib/chef/resources.rb
@@ -56,6 +56,7 @@ require 'chef/resource/registry_key'
require 'chef/resource/remote_directory'
require 'chef/resource/remote_file'
require 'chef/resource/rpm_package'
+require 'chef/resource/solaris_package'
require 'chef/resource/route'
require 'chef/resource/ruby'
require 'chef/resource/ruby_block'
@@ -69,3 +70,4 @@ require 'chef/resource/timestamped_deploy'
require 'chef/resource/user'
require 'chef/resource/yum_package'
require 'chef/resource/lwrp_base'
+require 'chef/resource/bff_package'
diff --git a/lib/chef/rest.rb b/lib/chef/rest.rb
index 6c74412839..4168cd63be 100644
--- a/lib/chef/rest.rb
+++ b/lib/chef/rest.rb
@@ -20,15 +20,18 @@
# limitations under the License.
#
-require 'zlib'
-require 'net/https'
-require 'uri'
-require 'chef/json_compat'
require 'tempfile'
-require 'chef/rest/auth_credentials'
-require 'chef/rest/rest_request'
-require 'chef/monkey_patches/string'
-require 'chef/monkey_patches/net_http'
+require 'chef/http'
+class Chef
+ class HTTP; end
+ class REST < HTTP; end
+end
+
+require 'chef/http/authenticator'
+require 'chef/http/decompressor'
+require 'chef/http/json_input'
+require 'chef/http/json_to_model_output'
+require 'chef/http/cookie_manager'
require 'chef/config'
require 'chef/exceptions'
require 'chef/platform/query_helpers'
@@ -37,54 +40,53 @@ class Chef
# == Chef::REST
# Chef's custom REST client with built-in JSON support and RSA signed header
# authentication.
- class REST
+ class REST < HTTP
- class NoopInflater
- def inflate(chunk)
- chunk
- end
- end
+ # Backwards compatibility for things that use
+ # Chef::REST::RESTRequest or its constants
+ RESTRequest = HTTP::HTTPRequest
- attr_reader :auth_credentials
attr_accessor :url, :cookies, :sign_on_redirect, :redirect_limit
- CONTENT_ENCODING = "content-encoding".freeze
- GZIP = "gzip".freeze
- DEFLATE = "deflate".freeze
- IDENTITY = "identity".freeze
+ attr_reader :authenticator
# Create a REST client object. The supplied +url+ is used as the base for
# all subsequent requests. For example, when initialized with a base url
# http://localhost:4000, a call to +get_rest+ with 'nodes' will make an
# HTTP GET request to http://localhost:4000/nodes
def initialize(url, client_name=Chef::Config[:node_name], signing_key_filename=Chef::Config[:client_key], options={})
- @url = url
- @cookies = CookieJar.instance
- @default_headers = options[:headers] || {}
- @signing_key_filename = signing_key_filename
- @key = load_signing_key(@signing_key_filename, options[:raw_key])
- @auth_credentials = AuthCredentials.new(client_name, @key)
- @sign_on_redirect, @sign_request = true, true
- @redirects_followed = 0
- @redirect_limit = 10
- @disable_gzip = false
- handle_options(options)
+ options[:client_name] = client_name
+ options[:signing_key_filename] = signing_key_filename
+ super(url, options)
+
+ @decompressor = Decompressor.new(options)
+ @authenticator = Authenticator.new(options)
+
+ @middlewares << JSONInput.new(options)
+ @middlewares << JSONToModelOutput.new(options)
+ @middlewares << CookieManager.new(options)
+ @middlewares << @decompressor
+ @middlewares << @authenticator
end
def signing_key_filename
- @signing_key_filename
+ authenticator.signing_key_filename
+ end
+
+ def auth_credentials
+ authenticator.auth_credentials
end
def client_name
- @auth_credentials.client_name
+ authenticator.client_name
end
def signing_key
- @raw_key
+ authenticator.raw_key
end
- def last_response
- @last_response
+ def sign_requests?
+ authenticator.sign_requests?
end
# Send an HTTP GET request to the path
@@ -97,37 +99,18 @@ class Chef
# to JSON inflated.
def get(path, raw=false, headers={})
if raw
- streaming_request(create_url(path), headers)
+ streaming_request(path, headers)
else
- api_request(:GET, create_url(path), headers)
+ request(:GET, path, headers)
end
end
- def head(path, headers={})
- api_request(:HEAD, create_url(path), headers)
- end
-
alias :get_rest :get
- # Send an HTTP DELETE request to the path
- def delete(path, headers={})
- api_request(:DELETE, create_url(path), headers)
- end
-
alias :delete_rest :delete
- # Send an HTTP POST request to the path
- def post(path, json, headers={})
- api_request(:POST, create_url(path), headers, json)
- end
-
alias :post_rest :post
- # Send an HTTP PUT request to the path
- def put(path, json, headers={})
- api_request(:PUT, create_url(path), headers, json)
- end
-
alias :put_rest :put
# Streams a download to a tempfile, then yields the tempfile to a block.
@@ -139,308 +122,59 @@ class Chef
streaming_request(create_url(path), headers) {|tmp_file| yield tmp_file }
end
- def create_url(path)
- if path =~ /^(http|https):\/\//
- URI.parse(path)
- else
- URI.parse("#{@url}/#{path}")
- end
- end
-
- def sign_requests?
- auth_credentials.sign_requests? && @sign_request
- end
-
- # Runs an HTTP request to a JSON API with JSON body. File Download not supported.
- def api_request(method, url, headers={}, data=false)
- json_body = data ? Chef::JSONCompat.to_json(data) : nil
- # Force encoding to binary to fix SSL related EOFErrors
- # cf. http://tickets.opscode.com/browse/CHEF-2363
- # http://redmine.ruby-lang.org/issues/5233
- json_body.force_encoding(Encoding::BINARY) if json_body.respond_to?(:force_encoding)
- raw_http_request(method, url, headers, json_body)
- end
-
- # Runs an HTTP request to a JSON API with raw body. File Download not supported.
- def raw_http_request(method, url, headers, body)
- headers = build_headers(method, url, headers, body)
- retriable_rest_request(method, url, body, headers) do |rest_request|
- begin
- response = rest_request.call {|r| r.read_body}
- @last_response = response
-
- Chef::Log.debug("---- HTTP Status and Header Data: ----")
- Chef::Log.debug("HTTP #{response.http_version} #{response.code} #{response.msg}")
-
- response.each do |header, value|
- Chef::Log.debug("#{header}: #{value}")
- end
- Chef::Log.debug("---- End HTTP Status/Header Data ----")
-
- response_body = decompress_body(response)
-
- if response.kind_of?(Net::HTTPSuccess)
- if response['content-type'] =~ /json/
- Chef::JSONCompat.from_json(response_body.chomp)
- else
- Chef::Log.warn("Expected JSON response, but got content-type '#{response['content-type']}'")
- response_body.to_s
- end
- elsif response.kind_of?(Net::HTTPNotModified) # Must be tested before Net::HTTPRedirection because it's subclass.
- false
- elsif redirect_location = redirected_to(response)
- if [:GET, :HEAD].include?(method)
- follow_redirect {api_request(method, create_url(redirect_location))}
- else
- raise Exceptions::InvalidRedirect, "#{method} request was redirected from #{url} to #{redirect_location}. Only GET and HEAD support redirects."
- end
- else
- # have to decompress the body before making an exception for it. But the body could be nil.
- response.body.replace(response_body) if response.body.respond_to?(:replace)
-
- if response['content-type'] =~ /json/
- exception = Chef::JSONCompat.from_json(response_body)
- msg = "HTTP Request Returned #{response.code} #{response.message}: "
- msg << (exception["error"].respond_to?(:join) ? exception["error"].join(", ") : exception["error"].to_s)
- Chef::Log.info(msg)
- end
- response.error!
- end
- rescue Exception => e
- if e.respond_to?(:chef_rest_request=)
- e.chef_rest_request = rest_request
- end
- raise
- end
- end
- end
-
- def decompress_body(response)
- if gzip_disabled? || response.body.nil?
- response.body
- else
- case response[CONTENT_ENCODING]
- when GZIP
- Chef::Log.debug "decompressing gzip response"
- Zlib::Inflate.new(Zlib::MAX_WBITS + 16).inflate(response.body)
- when DEFLATE
- Chef::Log.debug "decompressing deflate response"
- Zlib::Inflate.inflate(response.body)
- else
- response.body
- end
- end
- end
+ alias :api_request :request
- # Makes a streaming download request. <b>Doesn't speak JSON.</b>
- # Streams the response body to a tempfile. If a block is given, it's
- # passed to Tempfile.open(), which means that the tempfile will automatically
- # be unlinked after the block is executed.
- #
- # If no block is given, the tempfile is returned, which means it's up to
- # you to unlink the tempfile when you're done with it.
- def streaming_request(url, headers, &block)
- headers = build_headers(:GET, url, headers, nil, true)
- retriable_rest_request(:GET, url, nil, headers) do |rest_request|
- begin
- tempfile = nil
- response = rest_request.call do |r|
- if block_given? && r.kind_of?(Net::HTTPSuccess)
- begin
- tempfile = stream_to_tempfile(url, r, &block)
- yield tempfile
- ensure
- tempfile.close!
- end
- else
- tempfile = stream_to_tempfile(url, r)
- end
- end
- @last_response = response
- if response.kind_of?(Net::HTTPSuccess)
- tempfile
- elsif redirect_location = redirected_to(response)
- # TODO: test tempfile unlinked when following redirects.
- tempfile && tempfile.close!
- follow_redirect {streaming_request(create_url(redirect_location), {}, &block)}
- else
- tempfile && tempfile.close!
- response.error!
- end
- rescue Exception => e
- if e.respond_to?(:chef_rest_request=)
- e.chef_rest_request = rest_request
- end
- raise
- end
- end
- end
+ alias :raw_http_request :send_http_request
- def retriable_rest_request(method, url, req_body, headers)
- rest_request = Chef::REST::RESTRequest.new(method, url, req_body, headers)
+ # Deprecated:
+ # Responsibilities of this method have been split up. The #http_client is
+ # now responsible for making individual requests, while
+ # #retrying_http_errors handles error/retry logic.
+ def retriable_http_request(method, url, req_body, headers)
+ rest_request = Chef::HTTP::HTTPRequest.new(method, url, req_body, headers)
Chef::Log.debug("Sending HTTP Request via #{method} to #{url.host}:#{url.port}#{rest_request.path}")
- http_attempts = 0
-
- begin
- http_attempts += 1
-
+ retrying_http_errors(url) do
yield rest_request
-
- rescue SocketError, Errno::ETIMEDOUT => e
- e.message.replace "Error connecting to #{url} - #{e.message}"
- raise e
- rescue Errno::ECONNREFUSED
- if http_retry_count - http_attempts + 1 > 0
- Chef::Log.error("Connection refused connecting to #{url.host}:#{url.port} for #{rest_request.path}, retry #{http_attempts}/#{http_retry_count}")
- sleep(http_retry_delay)
- retry
- end
- raise Errno::ECONNREFUSED, "Connection refused connecting to #{url.host}:#{url.port} for #{rest_request.path}, giving up"
- rescue Timeout::Error
- if http_retry_count - http_attempts + 1 > 0
- Chef::Log.error("Timeout connecting to #{url.host}:#{url.port} for #{rest_request.path}, retry #{http_attempts}/#{http_retry_count}")
- sleep(http_retry_delay)
- retry
- end
- raise Timeout::Error, "Timeout connecting to #{url.host}:#{url.port} for #{rest_request.path}, giving up"
- rescue Net::HTTPFatalError => e
- if http_retry_count - http_attempts + 1 > 0
- sleep_time = 1 + (2 ** http_attempts) + rand(2 ** http_attempts)
- Chef::Log.error("Server returned error for #{url}, retrying #{http_attempts}/#{http_retry_count} in #{sleep_time}s")
- sleep(sleep_time)
- retry
- end
- raise
end
end
- def authentication_headers(method, url, json_body=nil)
- request_params = {:http_method => method, :path => url.path, :body => json_body, :host => "#{url.host}:#{url.port}"}
- request_params[:body] ||= ""
- auth_credentials.signature_headers(request_params)
- end
-
- def http_retry_delay
- config[:http_retry_delay]
- end
-
- def http_retry_count
- config[:http_retry_count]
+ # Customized streaming behavior; sets the accepted content type to "*/*"
+ # if not otherwise specified for compatibility purposes
+ def streaming_request(url, headers, &block)
+ headers["Accept"] ||= "*/*"
+ super
end
- def config
- Chef::Config
- end
+ alias :retriable_rest_request :retriable_http_request
def follow_redirect
- raise Chef::Exceptions::RedirectLimitExceeded if @redirects_followed >= redirect_limit
- @redirects_followed += 1
- Chef::Log.debug("Following redirect #{@redirects_followed}/#{redirect_limit}")
- if @sign_on_redirect
- yield
- else
- @sign_request = false
- yield
+ unless @sign_on_redirect
+ @authenticator.sign_request = false
end
+ super
ensure
- @redirects_followed = 0
- @sign_request = true
+ @authenticator.sign_request = true
end
- private
+ public :create_url
- def redirected_to(response)
- return nil unless response.kind_of?(Net::HTTPRedirection)
- # Net::HTTPNotModified is undesired subclass of Net::HTTPRedirection so test for this
- return nil if response.kind_of?(Net::HTTPNotModified)
- response['location']
+ def http_client(base_url=nil)
+ base_url ||= url
+ BasicClient.new(base_url, :ssl_policy => Chef::HTTP::APISSLPolicy)
end
- def build_headers(method, url, headers={}, json_body=false, raw=false)
- headers = @default_headers.merge(headers)
- #headers['Accept'] = "application/json" unless raw
- headers['Accept'] = "application/json" unless raw
- headers["Content-Type"] = 'application/json' if json_body
- headers['Content-Length'] = json_body.bytesize.to_s if json_body
- headers[RESTRequest::ACCEPT_ENCODING] = RESTRequest::ENCODING_GZIP_DEFLATE unless gzip_disabled?
- headers.merge!(authentication_headers(method, url, json_body)) if sign_requests?
- headers.merge!(Chef::Config[:custom_http_headers]) if Chef::Config[:custom_http_headers]
- headers
- end
-
- def stream_to_tempfile(url, response)
- tf = Tempfile.open("chef-rest")
- if Chef::Platform.windows?
- tf.binmode # required for binary files on Windows platforms
- end
- Chef::Log.debug("Streaming download from #{url.to_s} to tempfile #{tf.path}")
- # Stolen from http://www.ruby-forum.com/topic/166423
- # Kudos to _why!
-
- inflater = if gzip_disabled?
- NoopInflater.new
- else
- case response[CONTENT_ENCODING]
- when GZIP
- Chef::Log.debug "decompressing gzip stream"
- Zlib::Inflate.new(Zlib::MAX_WBITS + 16)
- when DEFLATE
- Chef::Log.debug "decompressing inflate stream"
- Zlib::Inflate.new
- else
- NoopInflater.new
- end
- end
+ ############################################################################
+ # DEPRECATED
+ ############################################################################
- response.read_body do |chunk|
- tf.write(inflater.inflate(chunk))
- end
- tf.close
- tf
- rescue Exception
- tf.close!
- raise
+ def decompress_body(body)
+ @decompressor.decompress_body(body)
end
- # gzip is disabled using the disable_gzip => true option in the
- # constructor. When gzip is disabled, no 'Accept-Encoding' header will be
- # set, and the response will not be decompressed, no matter what the
- # Content-Encoding header of the response is. The intended use case for
- # this is to work around situations where you request +file.tar.gz+, but
- # the server responds with a content type of tar and a content encoding of
- # gzip, tricking the client into decompressing the response so you end up
- # with a tar archive (no gzip) named file.tar.gz
- def gzip_disabled?
- @disable_gzip
- end
-
- def handle_options(opts)
- opts.each do |name, value|
- case name.to_s
- when 'disable_gzip'
- @disable_gzip = value
- end
- end
- end
-
- def load_signing_key(key_file, raw_key = nil)
- if (!!key_file)
- @raw_key = IO.read(key_file).strip
- elsif (!!raw_key)
- @raw_key = raw_key.strip
- else
- return nil
- end
- @key = OpenSSL::PKey::RSA.new(@raw_key)
- rescue SystemCallError, IOError => e
- Chef::Log.warn "Failed to read the private key #{key_file}: #{e.inspect}"
- raise Chef::Exceptions::PrivateKeyMissing, "I cannot read #{key_file}, which you told me to use to sign requests!"
- rescue OpenSSL::PKey::RSAError
- msg = "The file #{key_file} or :raw_key option does not contain a correctly formatted private key.\n"
- msg << "The key file should begin with '-----BEGIN RSA PRIVATE KEY-----' and end with '-----END RSA PRIVATE KEY-----'"
- raise Chef::Exceptions::InvalidPrivateKey, msg
+ def authentication_headers(method, url, json_body=nil)
+ authenticator.authentication_headers(method, url, json_body)
end
end
diff --git a/lib/chef/role.rb b/lib/chef/role.rb
index 78bbfadb88..6ad58b816d 100644
--- a/lib/chef/role.rb
+++ b/lib/chef/role.rb
@@ -233,20 +233,24 @@ class Chef
# Load a role from disk - prefers to load the JSON, but will happily load
# the raw rb files as well.
def self.from_disk(name, force=nil)
- js_file = File.join(Chef::Config[:role_path], "#{name}.json")
- rb_file = File.join(Chef::Config[:role_path], "#{name}.rb")
-
- if File.exists?(js_file) || force == "json"
- # from_json returns object.class => json_class in the JSON.
- Chef::JSONCompat.from_json(IO.read(js_file))
- elsif File.exists?(rb_file) || force == "ruby"
- role = Chef::Role.new
- role.name(name)
- role.from_file(rb_file)
- role
- else
- raise Chef::Exceptions::RoleNotFound, "Role '#{name}' could not be loaded from disk"
+ paths = Array(Chef::Config[:role_path])
+
+ paths.each do |p|
+ js_file = File.join(p, "#{name}.json")
+ rb_file = File.join(p, "#{name}.rb")
+
+ if File.exists?(js_file) || force == "json"
+ # from_json returns object.class => json_class in the JSON.
+ return Chef::JSONCompat.from_json(IO.read(js_file))
+ elsif File.exists?(rb_file) || force == "ruby"
+ role = Chef::Role.new
+ role.name(name)
+ role.from_file(rb_file)
+ return role
+ end
end
+
+ raise Chef::Exceptions::RoleNotFound, "Role '#{name}' could not be loaded from disk"
end
end
diff --git a/lib/chef/run_context.rb b/lib/chef/run_context.rb
index 6477431967..4d431116f9 100644
--- a/lib/chef/run_context.rb
+++ b/lib/chef/run_context.rb
@@ -204,6 +204,20 @@ class Chef
@loaded_attributes["#{cookbook}::#{attribute_file}"] = true
end
+ ##
+ # Cookbook File Introspection
+
+ def has_template_in_cookbook?(cookbook, template_name)
+ cookbook = cookbook_collection[cookbook]
+ cookbook.has_template_for_node?(node, template_name)
+ end
+
+ def has_cookbook_file_in_cookbook?(cookbook, cb_file_name)
+ cookbook = cookbook_collection[cookbook]
+ cookbook.has_cookbook_file_for_node?(node, cb_file_name)
+ end
+
+
private
def loaded_recipe(cookbook, recipe)
diff --git a/lib/chef/run_context/cookbook_compiler.rb b/lib/chef/run_context/cookbook_compiler.rb
index d1b93f6652..0a05061152 100644
--- a/lib/chef/run_context/cookbook_compiler.rb
+++ b/lib/chef/run_context/cookbook_compiler.rb
@@ -6,9 +6,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -259,7 +259,7 @@ class Chef
cookbook_collection[cookbook].segment_filenames(segment).sort
end
- # Yields the name, as a symbol, of each cookbook depended on by
+ # Yields the name, as a symbol, of each cookbook depended on by
# +cookbook_name+ in lexical sort order.
def each_cookbook_dep(cookbook_name, &block)
cookbook = cookbook_collection[cookbook_name]
diff --git a/lib/chef/run_lock.rb b/lib/chef/run_lock.rb
index 50046c2396..972db1a4e1 100644
--- a/lib/chef/run_lock.rb
+++ b/lib/chef/run_lock.rb
@@ -17,6 +17,9 @@
require 'chef/mixin/create_path'
require 'fcntl'
+if Chef::Platform.windows?
+ require 'chef/win32/mutex'
+end
class Chef
@@ -30,20 +33,16 @@ class Chef
include Chef::Mixin::CreatePath
attr_reader :runlock
+ attr_reader :mutex
attr_reader :runlock_file
# Create a new instance of RunLock
# === Arguments
- # * config::: This will generally be the `Chef::Config`, but any Hash-like
- # object with Symbol keys will work. See 'Parameters' section.
- # === Parameters/Config
- # * :lockfile::: if set, this will be used as the full path to the lockfile.
- # * :file_cache_path::: if `:lockfile` is not set, the lock file will be
- # named "chef-client-running.pid" and be placed in the directory given by
- # `:file_cache_path`
- def initialize(config)
- @runlock_file = config[:lockfile] || "#{config[:file_cache_path]}/chef-client-running.pid"
+ # * :lockfile::: the full path to the lockfile.
+ def initialize(lockfile)
+ @runlock_file = lockfile
@runlock = nil
+ @mutex = nil
end
# Acquire the system-wide lock. Will block indefinitely if another process
@@ -52,31 +51,73 @@ class Chef
# Each call to acquire should have a corresponding call to #release.
#
# The implementation is based on File#flock (see also: flock(2)).
+ #
+ # Either acquire() or test() methods should be called in order to
+ # get the ownership of run_lock.
def acquire
+ wait unless test
+ end
+
+ #
+ # Tests and if successful acquires the system-wide lock.
+ # Returns true if the lock is acquired, false otherwise.
+ #
+ # Either acquire() or test() methods should be called in order to
+ # get the ownership of run_lock.
+ def test
# ensure the runlock_file path exists
create_path(File.dirname(runlock_file))
- @runlock = File.open(runlock_file,'w+')
- # if we support FD_CLOEXEC (linux, !windows), then use it.
- # NB: ruby-2.0.0-p195 sets FD_CLOEXEC by default, but not ruby-1.8.7/1.9.3
- if Fcntl.const_defined?('F_SETFD') && Fcntl.const_defined?('FD_CLOEXEC')
- runlock.fcntl(Fcntl::F_SETFD, runlock.fcntl(Fcntl::F_GETFD, 0) | Fcntl::FD_CLOEXEC)
+ @runlock = File.open(runlock_file,'a+')
+
+ if Chef::Platform.windows?
+ acquire_win32_mutex
+ else
+ # If we support FD_CLOEXEC, then use it.
+ # NB: ruby-2.0.0-p195 sets FD_CLOEXEC by default, but not
+ # ruby-1.8.7/1.9.3
+ if Fcntl.const_defined?('F_SETFD') && Fcntl.const_defined?('FD_CLOEXEC')
+ runlock.fcntl(Fcntl::F_SETFD, runlock.fcntl(Fcntl::F_GETFD, 0) | Fcntl::FD_CLOEXEC)
+ end
+ # Flock will return 0 if it can acquire the lock otherwise it
+ # will return false
+ if runlock.flock(File::LOCK_NB|File::LOCK_EX) == 0
+ true
+ else
+ false
+ end
end
- unless runlock.flock(File::LOCK_EX|File::LOCK_NB)
- # Another chef client running...
- runpid = runlock.read.strip.chomp
- Chef::Log.warn("Chef client #{runpid} is running, will wait for it to finish and then run.")
+ end
+
+ #
+ # Waits until acquiring the system-wide lock.
+ #
+ def wait
+ runpid = runlock.read.strip.chomp
+ Chef::Log.warn("Chef client #{runpid} is running, will wait for it to finish and then run.")
+ if Chef::Platform.windows?
+ mutex.wait
+ else
runlock.flock(File::LOCK_EX)
end
- # We grabbed the run lock. Save the pid.
+ end
+
+ def save_pid
runlock.truncate(0)
runlock.rewind # truncate doesn't reset position to 0.
runlock.write(Process.pid.to_s)
+ # flush the file fsync flushes the system buffers
+ # in addition to ruby buffers
+ runlock.fsync
end
# Release the system-wide lock.
def release
if runlock
- runlock.flock(File::LOCK_UN)
+ if Chef::Platform.windows?
+ mutex.release
+ else
+ runlock.flock(File::LOCK_UN)
+ end
runlock.close
# Don't unlink the pid file, if another chef-client was waiting, it
# won't be recreated. Better to leave a "dead" pid file than not have
@@ -89,8 +130,20 @@ class Chef
def reset
@runlock = nil
+ @mutex = nil
end
+ # Since flock mechanism doesn't exist on windows we are using
+ # platform Mutex.
+ # We are creating a "Global" mutex here so that non-admin
+ # users can not DoS chef-client by creating the same named
+ # mutex we are using locally.
+ # Mutex name is case-sensitive contrary to other things in
+ # windows. "\" is the only invalid character.
+ def acquire_win32_mutex
+ @mutex = Chef::ReservedNames::Win32::Mutex.new("Global\\#{runlock_file.gsub(/[\\]/, "/").downcase}")
+ mutex.test
+ end
end
end
diff --git a/lib/chef/server_api.rb b/lib/chef/server_api.rb
new file mode 100644
index 0000000000..e9e7593dd6
--- /dev/null
+++ b/lib/chef/server_api.rb
@@ -0,0 +1,41 @@
+#
+# Author:: John Keiser (<jkeiser@opscode.com>)
+# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require 'chef/http'
+require 'chef/http/authenticator'
+require 'chef/http/cookie_manager'
+require 'chef/http/decompressor'
+require 'chef/http/json_input'
+require 'chef/http/json_output'
+
+class Chef
+ class ServerAPI < Chef::HTTP
+
+ def initialize(url = Chef::Config[:chef_server_url], options = {})
+ options[:client_name] ||= Chef::Config[:node_name]
+ options[:signing_key_filename] ||= Chef::Config[:client_key]
+ super(url, options)
+ end
+
+ use Chef::HTTP::JSONInput
+ use Chef::HTTP::JSONOutput
+ use Chef::HTTP::CookieManager
+ use Chef::HTTP::Decompressor
+ use Chef::HTTP::Authenticator
+ end
+end \ No newline at end of file
diff --git a/lib/chef/shell.rb b/lib/chef/shell.rb
index 4c86f96616..0788962e62 100644
--- a/lib/chef/shell.rb
+++ b/lib/chef/shell.rb
@@ -24,6 +24,7 @@ require 'chef'
require 'chef/version'
require 'chef/client'
require 'chef/config'
+require 'chef/config_fetcher'
require 'chef/shell/shell_session'
require 'chef/shell/ext'
@@ -151,26 +152,9 @@ module Shell
end
def self.parse_json
- # HACK: copied verbatim from chef/application/client, because it's not
- # reusable as written there :(
if Chef::Config[:json_attribs]
- begin
- json_io = open(Chef::Config[:json_attribs])
- rescue SocketError => error
- fatal!("I cannot connect to #{Chef::Config[:json_attribs]}", 2)
- rescue Errno::ENOENT => error
- fatal!("I cannot find #{Chef::Config[:json_attribs]}", 2)
- rescue Errno::EACCES => error
- fatal!("Permissions are incorrect on #{Chef::Config[:json_attribs]}. Please chmod a+r #{Chef::Config[:json_attribs]}", 2)
- rescue Exception => error
- fatal!("Got an unexpected error reading #{Chef::Config[:json_attribs]}: #{error.message}", 2)
- end
-
- begin
- @json_attribs = Chef::JSONCompat.from_json(json_io.read)
- rescue JSON::ParserError => error
- fatal!("Could not parse the provided JSON file (#{Chef::Config[:json_attribs]})!: " + error.message, 2)
- end
+ config_fetcher = Chef::ConfigFetcher.new(Chef::Config[:json_attribs])
+ @json_attribs = config_fetcher.fetch_json
end
end
diff --git a/lib/chef/shell/shell_session.rb b/lib/chef/shell/shell_session.rb
index cf147e778d..2f4d9375eb 100644
--- a/lib/chef/shell/shell_session.rb
+++ b/lib/chef/shell/shell_session.rb
@@ -173,7 +173,7 @@ module Shell
cl = Chef::CookbookLoader.new(Chef::Config[:cookbook_path])
cl.load_cookbooks
cookbook_collection = Chef::CookbookCollection.new(cl)
- @run_context = Chef::RunContext.new(node, cookbook_collection, @events)
+ @run_context = Chef::RunContext.new(node, cookbook_collection, @events)
@run_context.load(Chef::RunList::RunListExpansionFromDisk.new("_default", []))
@run_status.run_context = run_context
end
diff --git a/lib/chef/streaming_cookbook_uploader.rb b/lib/chef/streaming_cookbook_uploader.rb
index df90e0003d..9e638f6367 100644
--- a/lib/chef/streaming_cookbook_uploader.rb
+++ b/lib/chef/streaming_cookbook_uploader.rb
@@ -15,22 +15,23 @@ class Chef
class StreamingCookbookUploader
DefaultHeaders = { 'accept' => 'application/json', 'x-chef-version' => ::Chef::VERSION }
-
+
class << self
def post(to_url, user_id, secret_key_filename, params = {}, headers = {})
make_request(:post, to_url, user_id, secret_key_filename, params, headers)
end
-
+
def put(to_url, user_id, secret_key_filename, params = {}, headers = {})
make_request(:put, to_url, user_id, secret_key_filename, params, headers)
end
-
+
def make_request(http_verb, to_url, user_id, secret_key_filename, params = {}, headers = {})
+ Chef::Log.warn('[DEPRECATED] StreamingCookbookUploader class is deprecated. It will be removed in Chef 12. Please use CookbookSiteStreamingUploader instead.')
boundary = '----RubyMultipartClient' + rand(1000000).to_s + 'ZZZZZ'
parts = []
content_file = nil
-
+
timestamp = Time.now.utc.iso8601
secret_key = OpenSSL::PKey::RSA.new(File.read(secret_key_filename))
@@ -53,31 +54,31 @@ class Chef
end
parts << StringPart.new("--" + boundary + "--\r\n")
end
-
+
body_stream = MultipartStream.new(parts)
-
+
timestamp = Time.now.utc.iso8601
-
+
url = URI.parse(to_url)
-
+
Chef::Log.logger.debug("Signing: method: #{http_verb}, path: #{url.path}, file: #{content_file}, User-id: #{user_id}, Timestamp: #{timestamp}")
-
+
# We use the body for signing the request if the file parameter
- # wasn't a valid file or wasn't included. Extract the body (with
+ # wasn't a valid file or wasn't included. Extract the body (with
# multi-part delimiters intact) to sign the request.
# TODO: tim: 2009-12-28: It'd be nice to remove this special case, and
# always hash the entire request body. In the file case it would just be
# expanded multipart text - the entire body of the POST.
content_body = parts.inject("") { |result,part| result + part.read(0, part.size) }
content_file.rewind if content_file # we consumed the file for the above operation, so rewind it.
-
+
signing_options = {
:http_method=>http_verb,
:path=>url.path,
:user_id=>user_id,
:timestamp=>timestamp}
(content_file && signing_options[:file] = content_file) || (signing_options[:body] = (content_body || ""))
-
+
headers.merge!(Mixlib::Authentication::SignedHeaderAuth.signing_object(signing_options).sign(secret_key))
content_file.rewind if content_file
@@ -90,11 +91,11 @@ class Chef
Net::HTTP::Put.new(url.path, headers)
when :post
Net::HTTP::Post.new(url.path, headers)
- end
+ end
req.content_length = body_stream.size
req.content_type = 'multipart/form-data; boundary=' + boundary unless parts.empty?
req.body_stream = body_stream
-
+
http = Net::HTTP.new(url.host, url.port)
if url.scheme == "https"
http.use_ssl = true
@@ -107,30 +108,31 @@ class Chef
# TODO: stop the following madness!
class << res
alias :to_s :body
-
+
# BUGBUG this makes the response compatible with what respsonse_steps expects to test headers (response.headers[] -> response[])
def headers
self
end
-
+
def status
code.to_i
end
end
res
end
-
+
end
class StreamPart
def initialize(stream, size)
+ Chef::Log.warn('[DEPRECATED] StreamingCookbookUploader::StreamPart class is deprecated. It will be removed in Chef 12. Please use CookbookSiteStreamingUploader::StreamPart instead.')
@stream, @size = stream, size
end
-
+
def size
@size
end
-
+
# read the specified amount from the stream
def read(offset, how_much)
@stream.read(how_much)
@@ -139,9 +141,10 @@ class Chef
class StringPart
def initialize(str)
+ Chef::Log.warn('[DEPRECATED] StreamingCookbookUploader::StringPart class is deprecated. It will be removed in Chef 12. Please use CookbookSiteStreamingUploader::StringPart instead.')
@str = str
end
-
+
def size
@str.length
end
@@ -154,30 +157,31 @@ class Chef
class MultipartStream
def initialize(parts)
+ Chef::Log.warn('[DEPRECATED] StreamingCookbookUploader::MultipartStream class is deprecated. It will be removed in Chef 12. Please use CookbookSiteStreamingUploader::MultipartStream instead.')
@parts = parts
@part_no = 0
@part_offset = 0
end
-
+
def size
@parts.inject(0) {|size, part| size + part.size}
end
-
+
def read(how_much)
return nil if @part_no >= @parts.size
how_much_current_part = @parts[@part_no].size - @part_offset
-
+
how_much_current_part = if how_much_current_part > how_much
how_much
else
how_much_current_part
end
-
+
how_much_next_part = how_much - how_much_current_part
current_part = @parts[@part_no].read(@part_offset, how_much_current_part)
-
+
# recurse into the next part if the current one was not large enough
if how_much_next_part > 0
@part_no += 1
@@ -194,7 +198,7 @@ class Chef
end
end
end
-
+
end
diff --git a/lib/chef/tasks/chef_repo.rake b/lib/chef/tasks/chef_repo.rake
index 6f839a486f..704557ebb3 100644
--- a/lib/chef/tasks/chef_repo.rake
+++ b/lib/chef/tasks/chef_repo.rake
@@ -6,9 +6,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -51,7 +51,7 @@ task :update do
pull = true if line =~ /\[remote "origin"\]/
end
if pull
- sh %{git pull}
+ sh %{git pull}
else
puts "* Skipping git pull, no origin specified"
end
@@ -86,14 +86,14 @@ end
def create_cookbook(dir)
raise "Must provide a COOKBOOK=" unless ENV["COOKBOOK"]
puts "** Creating cookbook #{ENV["COOKBOOK"]}"
- sh "mkdir -p #{File.join(dir, ENV["COOKBOOK"], "attributes")}"
- sh "mkdir -p #{File.join(dir, ENV["COOKBOOK"], "recipes")}"
- sh "mkdir -p #{File.join(dir, ENV["COOKBOOK"], "definitions")}"
- sh "mkdir -p #{File.join(dir, ENV["COOKBOOK"], "libraries")}"
- sh "mkdir -p #{File.join(dir, ENV["COOKBOOK"], "resources")}"
- sh "mkdir -p #{File.join(dir, ENV["COOKBOOK"], "providers")}"
- sh "mkdir -p #{File.join(dir, ENV["COOKBOOK"], "files", "default")}"
- sh "mkdir -p #{File.join(dir, ENV["COOKBOOK"], "templates", "default")}"
+ sh "mkdir -p #{File.join(dir, ENV["COOKBOOK"], "attributes")}"
+ sh "mkdir -p #{File.join(dir, ENV["COOKBOOK"], "recipes")}"
+ sh "mkdir -p #{File.join(dir, ENV["COOKBOOK"], "definitions")}"
+ sh "mkdir -p #{File.join(dir, ENV["COOKBOOK"], "libraries")}"
+ sh "mkdir -p #{File.join(dir, ENV["COOKBOOK"], "resources")}"
+ sh "mkdir -p #{File.join(dir, ENV["COOKBOOK"], "providers")}"
+ sh "mkdir -p #{File.join(dir, ENV["COOKBOOK"], "files", "default")}"
+ sh "mkdir -p #{File.join(dir, ENV["COOKBOOK"], "templates", "default")}"
unless File.exists?(File.join(dir, ENV["COOKBOOK"], "recipes", "default.rb"))
open(File.join(dir, ENV["COOKBOOK"], "recipes", "default.rb"), "w") do |file|
file.puts <<-EOH
@@ -110,9 +110,9 @@ EOH
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -156,7 +156,7 @@ end
def create_metadata(dir)
raise "Must provide a COOKBOOK=" unless ENV["COOKBOOK"]
puts "** Creating metadata for cookbook: #{ENV["COOKBOOK"]}"
-
+
case NEW_COOKBOOK_LICENSE
when :apachev2
license = "Apache 2.0"
@@ -188,8 +188,8 @@ task :ssl_cert do
fqdn =~ /^(.+?)\.(.+)$/
hostname = $1
domain = $2
- keyfile = fqdn.gsub("*", "wildcard")
raise "Must provide FQDN!" unless fqdn && hostname && domain
+ keyfile = fqdn.gsub("*", "wildcard")
puts "** Creating self signed SSL Certificate for #{fqdn}"
sh("(cd #{CADIR} && openssl genrsa 2048 > #{keyfile}.key)")
sh("(cd #{CADIR} && chmod 644 #{keyfile}.key)")
@@ -288,7 +288,7 @@ namespace :databag do
end
end
else
- puts "ERROR: Could not find any databags, skipping it"
+ puts "ERROR: Could not find any databags, skipping it"
end
end
@@ -327,7 +327,7 @@ EOH
end
else
puts "ERROR: Could not find your databag (#{databag}), skipping it"
- end
+ end
end
end
diff --git a/lib/chef/util/backup.rb b/lib/chef/util/backup.rb
index 95c85d9751..43e3434050 100644
--- a/lib/chef/util/backup.rb
+++ b/lib/chef/util/backup.rb
@@ -47,7 +47,8 @@ class Chef
def backup_filename
@backup_filename ||= begin
time = Time.now
- savetime = time.strftime("%Y%m%d%H%M%S")
+ nanoseconds = sprintf("%6f", time.to_f).split('.')[1]
+ savetime = time.strftime("%Y%m%d%H%M%S.#{nanoseconds}")
backup_filename = "#{path}.chef-#{savetime}"
backup_filename = backup_filename.sub(/^([A-Za-z]:)/, "") #strip drive letter on Windows
end
diff --git a/lib/chef/util/diff.rb b/lib/chef/util/diff.rb
index 6f76a2fabd..7bce52d874 100644
--- a/lib/chef/util/diff.rb
+++ b/lib/chef/util/diff.rb
@@ -14,14 +14,38 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
-
-require 'chef/mixin/shell_out'
+# Some portions of this file are derived from material in the diff-lcs
+# project licensed under the terms of the MIT license, provided below.
+#
+# Copyright:: Copyright (c) 2004-2013 Austin Ziegler
+# License:: MIT
+#
+# Permission is hereby granted, free of charge, to any person
+# obtaining a copy of this software and associated documentation files
+# (the "Software"), to deal in the Software without restriction,
+# including without limitation the rights to use, copy, modify, merge,
+# publish, distribute, sublicense, and/or sell copies of the Software,
+# and to permit persons to whom the Software is furnished to do so,
+# subject the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of this Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OF OTHER DEALINGS IN THE
+# SOFTWARE.
+
+require 'diff/lcs'
+require 'diff/lcs/hunk'
class Chef
class Util
class Diff
- include Chef::Mixin::ShellOut
-
# @todo: to_a, to_s, to_json, inspect defs, accessors for @diff and @error
# @todo: move coercion to UTF-8 into to_json
# @todo: replace shellout to diff -u with diff-lcs gem
@@ -58,6 +82,43 @@ class Chef
end
end
end
+
+ # produces a unified-output-format diff with 3 lines of context
+ # ChefFS uses udiff() directly
+ def udiff(old_file, new_file)
+ diff_str = ""
+ file_length_difference = 0
+
+ old_data = IO.readlines(old_file).map { |e| e.chomp }
+ new_data = IO.readlines(new_file).map { |e| e.chomp }
+ diff_data = ::Diff::LCS.diff(old_data, new_data)
+
+ return diff_str if old_data.empty? && new_data.empty?
+ return "No differences encountered\n" if diff_data.empty?
+
+ # write diff header (standard unified format)
+ ft = File.stat(old_file).mtime.localtime.strftime('%Y-%m-%d %H:%M:%S.%N %z')
+ diff_str << "--- #{old_file}\t#{ft}\n"
+ ft = File.stat(new_file).mtime.localtime.strftime('%Y-%m-%d %H:%M:%S.%N %z')
+ diff_str << "+++ #{new_file}\t#{ft}\n"
+
+ # loop over diff hunks. if a hunk overlaps with the last hunk,
+ # join them. otherwise, print out the old one.
+ old_hunk = hunk = nil
+ diff_data.each do |piece|
+ begin
+ hunk = ::Diff::LCS::Hunk.new(old_data, new_data, piece, 3, file_length_difference)
+ file_length_difference = hunk.file_length_difference
+ next unless old_hunk
+ next if hunk.merge(old_hunk)
+ diff_str << old_hunk.diff(:unified) << "\n"
+ ensure
+ old_hunk = hunk
+ end
+ end
+ diff_str << old_hunk.diff(:unified) << "\n"
+ return diff_str
+ end
private
@@ -78,13 +139,8 @@ class Chef
return "(new content is binary, diff output suppressed)" if is_binary?(new_file)
begin
- # -u: Unified diff format
- # LC_ALL: in ruby 1.9 we want to set nil which is a magic option to mixlib-shellout to
- # pass through the LC_ALL locale. in ruby 1.8 we force to 7-bit 'C' locale
- # (which is the mixlib-shellout default for all rubies all the time).
Chef::Log.debug("running: diff -u #{old_file} #{new_file}")
- locale = ( Object.const_defined? :Encoding ) ? nil : 'C'
- result = shell_out("diff -u #{old_file} #{new_file}", :env => {'LC_ALL' => locale})
+ diff_str = udiff(old_file, new_file)
rescue Exception => e
# Should *not* receive this, but in some circumstances it seems that
@@ -92,34 +148,14 @@ class Chef
return "Could not determine diff. Error: #{e.message}"
end
- # diff will set a non-zero return code even when there's
- # valid stdout results, if it encounters something unexpected
- # So as long as we have output, we'll show it.
- #
- # Also on some platforms (Solaris) diff outputs a single line
- # when there are no differences found. Look for this line
- # before analyzing diff output.
- if !result.stdout.empty? && result.stdout != "No differences encountered\n"
- if result.stdout.length > diff_output_threshold
+ if !diff_str.empty? && diff_str != "No differences encountered\n"
+ if diff_str.length > diff_output_threshold
return "(long diff of over #{diff_output_threshold} characters, diff output suppressed)"
else
- diff_str = result.stdout
- if Object.const_defined? :Encoding # ruby >= 1.9
- if ( diff_str.encoding == Encoding::ASCII_8BIT &&
- diff_str.encoding != Encoding.default_external &&
- RUBY_VERSION.to_f < 2.0 )
- # @todo mixlib-shellout under ruby 1.9 hands back an ASCII-8BIT encoded string, which needs to
- # be fixed to the default external encoding -- this should be moved into mixlib-shellout
- diff_str = diff_str.force_encoding(Encoding.default_external)
- end
- diff_str.encode!('UTF-8', :invalid => :replace, :undef => :replace, :replace => '?')
- end
+ diff_str = encode_diff_for_json(diff_str)
@diff = diff_str.split("\n")
- @diff.delete("\\ No newline at end of file")
return "(diff available)"
end
- elsif !result.stderr.empty?
- return "Could not determine diff. Error: #{result.stderr}"
else
return "(no diff)"
end
@@ -139,6 +175,13 @@ class Chef
end
end
+ def encode_diff_for_json(diff_str)
+ if Object.const_defined? :Encoding
+ diff_str.encode!('UTF-8', :invalid => :replace, :undef => :replace, :replace => '?')
+ end
+ return diff_str
+ end
+
end
end
end
diff --git a/lib/chef/util/windows.rb b/lib/chef/util/windows.rb
index cba2c2a1b7..777fe4adbb 100644
--- a/lib/chef/util/windows.rb
+++ b/lib/chef/util/windows.rb
@@ -6,9 +6,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
diff --git a/lib/chef/util/windows/net_group.rb b/lib/chef/util/windows/net_group.rb
index 9da0dc6557..817e47efa8 100644
--- a/lib/chef/util/windows/net_group.rb
+++ b/lib/chef/util/windows/net_group.rb
@@ -6,9 +6,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
diff --git a/lib/chef/util/windows/net_use.rb b/lib/chef/util/windows/net_use.rb
index 1979e095bd..37efc02fcc 100644
--- a/lib/chef/util/windows/net_use.rb
+++ b/lib/chef/util/windows/net_use.rb
@@ -6,9 +6,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
diff --git a/lib/chef/util/windows/net_user.rb b/lib/chef/util/windows/net_user.rb
index eb68f6cebc..5cca348c8e 100644
--- a/lib/chef/util/windows/net_user.rb
+++ b/lib/chef/util/windows/net_user.rb
@@ -6,9 +6,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -198,7 +198,7 @@ class Chef::Util::Windows::NetUser < Chef::Util::Windows
def enable_account
user_modify do |user|
user[:flags] &= ~UF_ACCOUNTDISABLE
- #This does not set the password to nil. It (for some reason) means to ignore updating the field.
+ #This does not set the password to nil. It (for some reason) means to ignore updating the field.
#See similar behavior for the logon_hours field documented at
#http://msdn.microsoft.com/en-us/library/windows/desktop/aa371338%28v=vs.85%29.aspx
user[:password] = nil
diff --git a/lib/chef/util/windows/volume.rb b/lib/chef/util/windows/volume.rb
index dff082e929..08c3a53793 100644
--- a/lib/chef/util/windows/volume.rb
+++ b/lib/chef/util/windows/volume.rb
@@ -6,9 +6,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -35,7 +35,7 @@ class Chef::Util::Windows::Volume < Chef::Util::Windows
name += "\\" unless name =~ /\\$/ #trailing slash required
@name = name
end
-
+
def device
buffer = 0.chr * 256
if GetVolumeNameForVolumeMountPoint(@name, buffer, buffer.size)
diff --git a/lib/chef/version.rb b/lib/chef/version.rb
index 70a22f7d27..259c267035 100644
--- a/lib/chef/version.rb
+++ b/lib/chef/version.rb
@@ -6,9 +6,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
-#
+#
# http://www.apache.org/licenses/LICENSE-2.0
-#
+#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -17,7 +17,7 @@
class Chef
CHEF_ROOT = File.dirname(File.expand_path(File.dirname(__FILE__)))
- VERSION = '11.6.0.hotfix.1'
+ VERSION = '11.8.0.alpha.0'
end
# NOTE: the Chef::Version class is defined in version_class.rb
diff --git a/lib/chef/win32/api/file.rb b/lib/chef/win32/api/file.rb
index afa746efce..7a8dafd8b5 100644
--- a/lib/chef/win32/api/file.rb
+++ b/lib/chef/win32/api/file.rb
@@ -474,7 +474,7 @@ BOOL WINAPI DeviceIoControl(
# Workaround for CHEF-4419:
# Make sure paths starting with "/" has a drive letter
# assigned from the current working diretory.
- # Note: In chef 11.8 and beyond this issue will be fixed with a
+ # Note: With CHEF-4427 this issue will be fixed with a
# broader fix to map all the paths starting with "/" to
# SYSTEM_DRIVE on windows.
path = ::File.expand_path(path) if path.start_with? "/"
diff --git a/lib/chef/win32/api/synchronization.rb b/lib/chef/win32/api/synchronization.rb
new file mode 100644
index 0000000000..9c148d7e2b
--- /dev/null
+++ b/lib/chef/win32/api/synchronization.rb
@@ -0,0 +1,89 @@
+#
+# Author:: Serdar Sutay (<serdar@opscode.com>)
+# Copyright:: Copyright 2011 Opscode, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require 'chef/win32/api'
+
+class Chef
+ module ReservedNames::Win32
+ module API
+ module Synchronization
+ extend Chef::ReservedNames::Win32::API
+
+ ffi_lib 'kernel32'
+
+ # Constant synchronization functions use to indicate wait
+ # forever.
+ INFINITE = 0xFFFFFFFF
+
+ # Return codes
+ # http://msdn.microsoft.com/en-us/library/windows/desktop/ms687032(v=vs.85).aspx
+ WAIT_FAILED = 0xFFFFFFFF
+ WAIT_TIMEOUT = 0x00000102
+ WAIT_OBJECT_0 = 0x00000000
+ WAIT_ABANDONED = 0x00000080
+
+ # Security and access rights for synchronization objects
+ # http://msdn.microsoft.com/en-us/library/windows/desktop/ms686670(v=vs.85).aspx
+ DELETE = 0x00010000
+ READ_CONTROL = 0x00020000
+ SYNCHRONIZE = 0x00100000
+ WRITE_DAC = 0x00040000
+ WRITE_OWNER = 0x00080000
+
+ # Mutex specific rights
+ MUTEX_ALL_ACCESS = 0x001F0001
+ MUTEX_MODIFY_STATE = 0x00000001
+
+=begin
+HANDLE WINAPI CreateMutex(
+ _In_opt_ LPSECURITY_ATTRIBUTES lpMutexAttributes,
+ _In_ BOOL bInitialOwner,
+ _In_opt_ LPCTSTR lpName
+);
+=end
+ safe_attach_function :CreateMutexW, [ :LPSECURITY_ATTRIBUTES, :BOOL, :LPCTSTR ], :HANDLE
+ safe_attach_function :CreateMutexA, [ :LPSECURITY_ATTRIBUTES, :BOOL, :LPCTSTR ], :HANDLE
+
+=begin
+DWORD WINAPI WaitForSingleObject(
+ _In_ HANDLE hHandle,
+ _In_ DWORD dwMilliseconds
+);
+=end
+ safe_attach_function :WaitForSingleObject, [ :HANDLE, :DWORD ], :DWORD
+
+=begin
+BOOL WINAPI ReleaseMutex(
+ _In_ HANDLE hMutex
+);
+=end
+ safe_attach_function :ReleaseMutex, [ :HANDLE ], :BOOL
+
+=begin
+HANDLE WINAPI OpenMutex(
+ _In_ DWORD dwDesiredAccess,
+ _In_ BOOL bInheritHandle,
+ _In_ LPCTSTR lpName
+);
+=end
+ safe_attach_function :OpenMutexW, [ :DWORD, :BOOL, :LPCTSTR ], :HANDLE
+ safe_attach_function :OpenMutexA, [ :DWORD, :BOOL, :LPCTSTR ], :HANDLE
+ end
+ end
+ end
+end
diff --git a/lib/chef/win32/handle.rb b/lib/chef/win32/handle.rb
index 3e92703db9..21a8fdf339 100644
--- a/lib/chef/win32/handle.rb
+++ b/lib/chef/win32/handle.rb
@@ -29,7 +29,7 @@ class Chef
# See http://msdn.microsoft.com/en-us/library/windows/desktop/ms683179(v=vs.85).aspx
# The handle value returned by the GetCurrentProcess function is the pseudo handle (HANDLE)-1 (which is 0xFFFFFFFF)
CURRENT_PROCESS_HANDLE = 4294967295
-
+
def initialize(handle)
@handle = handle
ObjectSpace.define_finalizer(self, Handle.close_handle_finalizer(handle))
diff --git a/lib/chef/win32/mutex.rb b/lib/chef/win32/mutex.rb
new file mode 100644
index 0000000000..b0a9ba210e
--- /dev/null
+++ b/lib/chef/win32/mutex.rb
@@ -0,0 +1,94 @@
+#
+# Author:: Serdar Sutay (<serdar@opscode.com>)
+# Copyright:: Copyright 2013 Opscode, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require 'chef/win32/api/synchronization'
+
+class Chef
+ module ReservedNames::Win32
+ class Mutex
+ include Chef::ReservedNames::Win32::API::Synchronization
+ extend Chef::ReservedNames::Win32::API::Synchronization
+
+ def initialize(name)
+ @name = name
+ # First check if there exists a mutex in the system with the
+ # given name.
+
+ # In the initial creation of the mutex initial_owner is set to
+ # false so that mutex will not be acquired until someone calls
+ # acquire.
+ # In order to call "*W" windows apis, strings needs to be
+ # encoded as wide strings.
+ @handle = CreateMutexW(nil, false, name.to_wstring)
+
+ # Fail early if we can't get a handle to the named mutex
+ if @handle == 0
+ Chef::Log.error("Failed to create system mutex with name'#{name}'")
+ Chef::ReservedNames::Win32::Error.raise!
+ end
+ end
+
+ attr_reader :handle
+ attr_reader :name
+
+ #####################################################
+ # Attempts to grab the mutex.
+ # Returns true if the mutex is grabbed or if it's already
+ # owned; false otherwise.
+ def test
+ WaitForSingleObject(handle, 0) == WAIT_OBJECT_0
+ end
+
+ #####################################################
+ # Attempts to grab the mutex and waits until it is acquired.
+ def wait
+ wait_result = WaitForSingleObject(handle, INFINITE)
+ case wait_result
+ when WAIT_ABANDONED
+ # Previous owner of the mutex died before it can release the
+ # mutex. Log a warning and continue.
+ Chef::Log.debug "Existing owner of the mutex exited prematurely."
+ when WAIT_OBJECT_0
+ # Mutex is successfully acquired.
+ else
+ Chef::Log.error("Failed to acquire system mutex '#{name}'. Return code: #{wait_result}")
+ Chef::ReservedNames::Win32::Error.raise!
+ end
+ end
+
+ #####################################################
+ # Releaes the mutex
+ def release
+ # http://msdn.microsoft.com/en-us/library/windows/desktop/ms685066(v=vs.85).aspx
+ # Note that release method needs to be called more than once
+ # if mutex is acquired more than once.
+ unless ReleaseMutex(handle)
+ # Don't fail things in here if we can't release the mutex.
+ # Because it will be automatically released when the owner
+ # of the process goes away and this class is only being used
+ # to synchronize chef-clients runs on a node.
+ Chef::Log.error("Can not release mutex '#{name}'. This might cause issues \
+if the mutex is attempted to be acquired by other threads.")
+ Chef::ReservedNames::Win32::Error.raise!
+ end
+ end
+ end
+ end
+end
+
+
diff --git a/lib/chef/win32/security/ace.rb b/lib/chef/win32/security/ace.rb
index efd44b1c85..3aeae35532 100644
--- a/lib/chef/win32/security/ace.rb
+++ b/lib/chef/win32/security/ace.rb
@@ -122,4 +122,4 @@ class Chef
end
end
end
-end \ No newline at end of file
+end
diff --git a/lib/chef/win32/security/sid.rb b/lib/chef/win32/security/sid.rb
index 7ca21eee79..e1b20224bb 100644
--- a/lib/chef/win32/security/sid.rb
+++ b/lib/chef/win32/security/sid.rb
@@ -196,4 +196,4 @@ class Chef
end
end
end
-end \ No newline at end of file
+end
diff --git a/lib/chef/win32/version.rb b/lib/chef/win32/version.rb
index c8c923a6f2..62f817503e 100644
--- a/lib/chef/win32/version.rb
+++ b/lib/chef/win32/version.rb
@@ -30,14 +30,16 @@ class Chef
# http://msdn.microsoft.com/en-us/library/ms724358(v=vs.85).aspx
private
-
+
def self.get_system_metrics(n_index)
Win32API.new('user32', 'GetSystemMetrics', 'I', 'I').call(n_index)
end
public
-
+
WIN_VERSIONS = {
+ "Windows 8.1" => {:major => 6, :minor => 3, :callable => lambda{ @product_type == VER_NT_WORKSTATION }},
+ "Windows Server 2012 R2" => {:major => 6, :minor => 3, :callable => lambda{ @product_type != VER_NT_WORKSTATION }},
"Windows 8" => {:major => 6, :minor => 2, :callable => lambda{ @product_type == VER_NT_WORKSTATION }},
"Windows Server 2012" => {:major => 6, :minor => 2, :callable => lambda{ @product_type != VER_NT_WORKSTATION }},
"Windows 7" => {:major => 6, :minor => 1, :callable => lambda{ @product_type == VER_NT_WORKSTATION }},
@@ -68,7 +70,7 @@ class Chef
# The get_product_info API is not supported on Win2k3,
# use an alternative to identify datacenter skus
@sku = get_datacenter_product_info_windows_server_2003(ver_info)
- end
+ end
end
marketing_names = Array.new