summaryrefslogtreecommitdiff
path: root/lib/chef
diff options
context:
space:
mode:
Diffstat (limited to 'lib/chef')
-rw-r--r--lib/chef/cookbook/metadata.rb4
-rw-r--r--lib/chef/deprecation/warnings.rb4
-rw-r--r--lib/chef/exceptions.rb2
-rw-r--r--lib/chef/http.rb19
-rw-r--r--lib/chef/http/api_versions.rb2
-rw-r--r--lib/chef/http/http_request.rb3
-rw-r--r--lib/chef/knife/core/bootstrap_context.rb1
-rw-r--r--lib/chef/knife/core/status_presenter.rb2
-rw-r--r--lib/chef/knife/core/ui.rb2
-rw-r--r--lib/chef/knife/search.rb2
-rw-r--r--lib/chef/knife/ssh.rb4
-rw-r--r--lib/chef/mash.rb6
-rw-r--r--lib/chef/mixin/deep_merge.rb2
-rw-r--r--lib/chef/mixin/user_context.rb52
-rw-r--r--lib/chef/node/attribute.rb94
-rw-r--r--lib/chef/node/immutable_collections.rb35
-rw-r--r--lib/chef/provider/apt_preference.rb94
-rw-r--r--lib/chef/provider/apt_repository.rb28
-rw-r--r--lib/chef/provider/apt_update.rb8
-rw-r--r--lib/chef/provider/execute.rb3
-rw-r--r--lib/chef/provider/git.rb23
-rw-r--r--lib/chef/provider/http_request.rb14
-rw-r--r--lib/chef/provider/ifconfig/redhat.rb4
-rw-r--r--lib/chef/provider/launchd.rb20
-rw-r--r--lib/chef/provider/package.rb15
-rw-r--r--lib/chef/provider/package/dnf.rb4
-rw-r--r--lib/chef/provider/package/dnf/dnf_helper.py1
-rw-r--r--lib/chef/provider/package/windows/registry_uninstall_entry.rb2
-rw-r--r--lib/chef/provider/package/zypper.rb10
-rw-r--r--lib/chef/provider/remote_file.rb19
-rw-r--r--lib/chef/provider/remote_file/fetcher.rb3
-rw-r--r--lib/chef/provider/remote_file/network_file.rb23
-rw-r--r--lib/chef/provider/route.rb33
-rw-r--r--lib/chef/provider/service/macosx.rb7
-rw-r--r--lib/chef/provider/service/systemd.rb23
-rw-r--r--lib/chef/provider/support/yum_repo.erb6
-rw-r--r--lib/chef/provider/support/zypper_repo.erb17
-rw-r--r--lib/chef/provider/systemd_unit.rb5
-rw-r--r--lib/chef/provider/windows_path.rb62
-rw-r--r--lib/chef/provider/windows_task.rb293
-rw-r--r--lib/chef/provider/yum_repository.rb2
-rw-r--r--lib/chef/provider/zypper_repository.rb81
-rw-r--r--lib/chef/providers.rb3
-rw-r--r--lib/chef/resource.rb6
-rw-r--r--lib/chef/resource/apt_package.rb2
-rw-r--r--lib/chef/resource/apt_preference.rb36
-rw-r--r--lib/chef/resource/apt_repository.rb4
-rw-r--r--lib/chef/resource/execute.rb14
-rw-r--r--lib/chef/resource/http_request.rb2
-rw-r--r--lib/chef/resource/ifconfig.rb36
-rw-r--r--lib/chef/resource/remote_file.rb60
-rw-r--r--lib/chef/resource/windows_path.rb41
-rw-r--r--lib/chef/resource/yum_repository.rb21
-rw-r--r--lib/chef/resource/zypper_repository.rb52
-rw-r--r--lib/chef/resources.rb3
-rw-r--r--lib/chef/search/query.rb7
-rw-r--r--lib/chef/server_api_versions.rb23
-rw-r--r--lib/chef/shell.rb1
-rw-r--r--lib/chef/shell/shell_session.rb8
-rw-r--r--lib/chef/util/dsc/local_configuration_manager.rb24
-rw-r--r--lib/chef/util/windows/logon_session.rb126
-rw-r--r--lib/chef/version.rb2
-rw-r--r--lib/chef/win32/api/file.rb1
-rw-r--r--lib/chef/win32/api/security.rb2
-rw-r--r--lib/chef/win32/file.rb2
-rw-r--r--lib/chef/win32/version.rb6
66 files changed, 1255 insertions, 261 deletions
diff --git a/lib/chef/cookbook/metadata.rb b/lib/chef/cookbook/metadata.rb
index 5efadd6f62..b23c01e622 100644
--- a/lib/chef/cookbook/metadata.rb
+++ b/lib/chef/cookbook/metadata.rb
@@ -100,8 +100,8 @@ class Chef
@long_description = ""
@license = "All rights reserved"
- @maintainer = nil
- @maintainer_email = nil
+ @maintainer = ""
+ @maintainer_email = ""
@platforms = Mash.new
@dependencies = Mash.new
diff --git a/lib/chef/deprecation/warnings.rb b/lib/chef/deprecation/warnings.rb
index f5feb91063..c227739a8d 100644
--- a/lib/chef/deprecation/warnings.rb
+++ b/lib/chef/deprecation/warnings.rb
@@ -20,10 +20,12 @@ class Chef
module Deprecation
module Warnings
+ require "chef/version"
+
def add_deprecation_warnings_for(method_names)
method_names.each do |name|
define_method(name) do |*args|
- message = "Method '#{name}' of '#{self.class}' is deprecated. It will be removed in Chef 13."
+ message = "Method '#{name}' of '#{self.class}' is deprecated. It will be removed in Chef #{Chef::VERSION.to_i.next}."
message << " Please update your cookbooks accordingly."
Chef.deprecated(:internal_api, message)
super(*args)
diff --git a/lib/chef/exceptions.rb b/lib/chef/exceptions.rb
index 91402bc6c2..a73062b676 100644
--- a/lib/chef/exceptions.rb
+++ b/lib/chef/exceptions.rb
@@ -515,7 +515,7 @@ This error is most often caused by network issues (proxies, etc) outside of chef
"Resource #{r['Name']} is a binary resource"
end
end
- super "Found multiple matching resources. #{matches_info.join("\n")}"
+ super "Found multiple resources matching #{matches_info[0]["Module"]["Name"]}:\n#{(matches_info.map { |f| f["Module"]["Version"] }).uniq.join("\n")}"
end
end
diff --git a/lib/chef/http.rb b/lib/chef/http.rb
index c741dcca97..14dd8b93a5 100644
--- a/lib/chef/http.rb
+++ b/lib/chef/http.rb
@@ -5,7 +5,7 @@
# Author:: Christopher Brown (<cb@chef.io>)
# Author:: Christopher Walters (<cw@chef.io>)
# Author:: Daniel DeLeo (<dan@chef.io>)
-# Copyright:: Copyright 2009-2016 Chef Software, Inc.
+# Copyright:: Copyright 2009-2017, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -144,9 +144,9 @@ class Chef
def request(method, path, headers = {}, data = false)
http_attempts ||= 0
url = create_url(path)
- method, url, headers, data = apply_request_middleware(method, url, headers, data)
+ processed_method, url, processed_headers, processed_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 = send_http_request(processed_method, url, processed_headers, processed_data)
response, rest_request, return_value = apply_response_middleware(response, rest_request, return_value)
response.error! unless success_response?(response)
@@ -157,7 +157,6 @@ class Chef
response = e.response
if response.kind_of?(Net::HTTPNotAcceptable) && version_retries - http_attempts > 0
Chef::Log.debug("Negotiating protocol version with #{url}, retry #{http_attempts}/#{version_retries}")
- sleep(http_retry_delay)
retry
else
raise
@@ -176,11 +175,12 @@ class Chef
url = create_url(path)
response, rest_request, return_value = nil, nil, nil
tempfile = nil
+ data = nil
method = :GET
- method, url, headers, data = apply_request_middleware(method, url, headers, data)
+ method, url, processed_headers, data = apply_request_middleware(method, url, headers, data)
- response, rest_request, return_value = send_http_request(method, url, headers, data) do |http_response|
+ response, rest_request, return_value = send_http_request(method, url, processed_headers, data) do |http_response|
if http_response.kind_of?(Net::HTTPSuccess)
tempfile = stream_to_tempfile(url, http_response, &progress_block)
end
@@ -196,7 +196,6 @@ class Chef
response = e.response
if response.kind_of?(Net::HTTPNotAcceptable) && version_retries - http_attempts > 0
Chef::Log.debug("Negotiating protocol version with #{url}, retry #{http_attempts}/#{version_retries}")
- sleep(http_retry_delay)
retry
else
raise
@@ -223,11 +222,12 @@ class Chef
url = create_url(path)
response, rest_request, return_value = nil, nil, nil
tempfile = nil
+ data = nil
method = :GET
- method, url, headers, data = apply_request_middleware(method, url, headers, data)
+ method, url, processed_headers, data = apply_request_middleware(method, url, headers, data)
- response, rest_request, return_value = send_http_request(method, url, headers, data) do |http_response|
+ response, rest_request, return_value = send_http_request(method, url, processed_headers, data) do |http_response|
if http_response.kind_of?(Net::HTTPSuccess)
tempfile = stream_to_tempfile(url, http_response)
end
@@ -252,7 +252,6 @@ class Chef
response = e.response
if response.kind_of?(Net::HTTPNotAcceptable) && version_retries - http_attempts > 0
Chef::Log.debug("Negotiating protocol version with #{url}, retry #{http_attempts}/#{version_retries}")
- sleep(http_retry_delay)
retry
else
raise
diff --git a/lib/chef/http/api_versions.rb b/lib/chef/http/api_versions.rb
index 674d8f85a7..6c5ede40aa 100644
--- a/lib/chef/http/api_versions.rb
+++ b/lib/chef/http/api_versions.rb
@@ -37,6 +37,8 @@ class Chef
end
if http_response.key?("x-ops-server-api-version")
ServerAPIVersions.instance.set_versions(JSONCompat.parse(http_response["x-ops-server-api-version"]))
+ else
+ ServerAPIVersions.instance.unversioned!
end
[http_response, rest_request, return_value]
end
diff --git a/lib/chef/http/http_request.rb b/lib/chef/http/http_request.rb
index 20c46aaa8d..7fc1acb889 100644
--- a/lib/chef/http/http_request.rb
+++ b/lib/chef/http/http_request.rb
@@ -49,6 +49,7 @@ class Chef
ENCODING_GZIP_DEFLATE = "gzip;q=1.0,deflate;q=0.6,identity;q=0.3".freeze
GET = "get".freeze
+ PATCH = "patch".freeze
PUT = "put".freeze
POST = "post".freeze
DELETE = "delete".freeze
@@ -161,6 +162,8 @@ class Chef
Net::HTTP::Post.new(req_path, headers)
when PUT
Net::HTTP::Put.new(req_path, headers)
+ when PATCH
+ Net::HTTP::Patch.new(req_path, headers)
when DELETE
Net::HTTP::Delete.new(req_path, headers)
when HEAD
diff --git a/lib/chef/knife/core/bootstrap_context.rb b/lib/chef/knife/core/bootstrap_context.rb
index c395ebcfa0..9b16b94910 100644
--- a/lib/chef/knife/core/bootstrap_context.rb
+++ b/lib/chef/knife/core/bootstrap_context.rb
@@ -223,6 +223,7 @@ validation_client_name "#{@chef_config[:validation_client_name]}"
attributes[:run_list] = @run_list
end
+ attributes.delete(:run_list) if attributes[:policy_name] && !attributes[:policy_name].empty?
attributes.merge!(:tags => @config[:tags]) if @config[:tags] && !@config[:tags].empty?
end
end
diff --git a/lib/chef/knife/core/status_presenter.rb b/lib/chef/knife/core/status_presenter.rb
index df6c2fe942..f55f9abcbb 100644
--- a/lib/chef/knife/core/status_presenter.rb
+++ b/lib/chef/knife/core/status_presenter.rb
@@ -123,7 +123,7 @@ class Chef
line_parts << run_list if run_list
if node["platform"]
- platform = node["platform"]
+ platform = node["platform"].dup
if node["platform_version"]
platform << " #{node['platform_version']}"
end
diff --git a/lib/chef/knife/core/ui.rb b/lib/chef/knife/core/ui.rb
index d809a8fc45..484c3ab3de 100644
--- a/lib/chef/knife/core/ui.rb
+++ b/lib/chef/knife/core/ui.rb
@@ -172,7 +172,7 @@ class Chef
tf.sync = true
tf.puts output
tf.close
- raise "Please set EDITOR environment variable" unless system("#{config[:editor]} #{tf.path}")
+ raise "Please set EDITOR environment variable. See https://docs.chef.io/knife_using.html for details." unless system("#{config[:editor]} #{tf.path}")
output = IO.read(tf.path)
end
diff --git a/lib/chef/knife/search.rb b/lib/chef/knife/search.rb
index c4c3380734..2a68ec5108 100644
--- a/lib/chef/knife/search.rb
+++ b/lib/chef/knife/search.rb
@@ -91,6 +91,8 @@ class Chef
search_args[:filter_result] = create_result_filter(config[:filter_result])
elsif (not ui.config[:attribute].nil?) && (not ui.config[:attribute].empty?)
search_args[:filter_result] = create_result_filter_from_attributes(ui.config[:attribute])
+ elsif config[:id_only]
+ search_args[:filter_result] = create_result_filter_from_attributes([])
end
begin
diff --git a/lib/chef/knife/ssh.rb b/lib/chef/knife/ssh.rb
index 380a60fdd6..ae14ce9954 100644
--- a/lib/chef/knife/ssh.rb
+++ b/lib/chef/knife/ssh.rb
@@ -273,6 +273,10 @@ class Chef
opts[:paranoid] = false
opts[:user_known_hosts_file] = "/dev/null"
end
+ if ssh_config[:keepalive]
+ opts[:keepalive] = true
+ opts[:keepalive_interval] = ssh_config[:keepalive_interval]
+ end
end
end
diff --git a/lib/chef/mash.rb b/lib/chef/mash.rb
index 4e4f06634d..8b9e115dd1 100644
--- a/lib/chef/mash.rb
+++ b/lib/chef/mash.rb
@@ -105,6 +105,12 @@ class Mash < Hash
regular_writer(convert_key(key), convert_value(value))
end
+ # internal API for use by Chef's deep merge cache
+ # @api private
+ def internal_set(key, value)
+ regular_writer(key, convert_value(value))
+ end
+
# @param other_hash<Hash>
# A hash to update values in the mash with. The keys and the values will be
# converted to Mash format.
diff --git a/lib/chef/mixin/deep_merge.rb b/lib/chef/mixin/deep_merge.rb
index 7016b08ff7..9ec2b397d4 100644
--- a/lib/chef/mixin/deep_merge.rb
+++ b/lib/chef/mixin/deep_merge.rb
@@ -64,7 +64,7 @@ class Chef
when Hash
if dest.kind_of?(Hash)
source.each do |src_key, src_value|
- if dest[src_key]
+ if dest.key?(src_key)
dest[src_key] = deep_merge!(src_value, dest[src_key])
else # dest[src_key] doesn't exist so we take whatever source has
dest[src_key] = src_value
diff --git a/lib/chef/mixin/user_context.rb b/lib/chef/mixin/user_context.rb
new file mode 100644
index 0000000000..40a72912a3
--- /dev/null
+++ b/lib/chef/mixin/user_context.rb
@@ -0,0 +1,52 @@
+#
+# Author:: Adam Edwards (<adamed@chef.io>)
+# Copyright:: Copyright (c) 2016 Chef Software, 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/util/windows/logon_session" if Chef::Platform.windows?
+
+class Chef
+ module Mixin
+ module UserContext
+
+ def with_user_context(user, password, domain = nil, &block)
+ if node["platform_family"] != "windows"
+ raise Exceptions::UnsupportedPlatform, "User context impersonation is supported only on the Windows platform"
+ end
+
+ if ! block_given?
+ raise ArgumentError, "You must supply a block to `with_user_context`"
+ end
+
+ login_session = nil
+
+ begin
+ if user
+ logon_session = Chef::Util::Windows::LogonSession.new(user, password, domain)
+ logon_session.open
+ logon_session.set_user_context
+ end
+ yield
+ ensure
+ logon_session.close if logon_session
+ end
+ end
+
+ protected(:with_user_context)
+
+ end
+ end
+end
diff --git a/lib/chef/node/attribute.rb b/lib/chef/node/attribute.rb
index 57d1b0a4d3..2998866bb2 100644
--- a/lib/chef/node/attribute.rb
+++ b/lib/chef/node/attribute.rb
@@ -399,7 +399,7 @@ class Chef
#
def merged_attributes(*path)
- immutablize(merge_all(path))
+ merge_all(path)
end
def combined_override(*path)
@@ -536,15 +536,10 @@ class Chef
apply_path(@automatic, path),
]
- components.map! do |component|
- safe_dup(component)
- end
-
- return nil if components.compact.empty?
-
- components.inject(ImmutableMash.new({}, self, __node__, :merged)) do |merged, component|
- Chef::Mixin::DeepMerge.hash_only_merge!(merged, component)
+ ret = components.inject(NIL) do |merged, component|
+ hash_only_merge!(merged, component)
end
+ ret == NIL ? nil : ret
end
# Deep merge the default attribute levels with array merging.
@@ -554,10 +549,11 @@ class Chef
# @param path [Array] Array of args to method chain to descend into the node object
# @return [attr] Deep Merged values (may be VividMash, Hash, Array, etc) from the node object
def merge_defaults(path)
- DEFAULT_COMPONENTS.inject(nil) do |merged, component_ivar|
+ ret = DEFAULT_COMPONENTS.inject(NIL) do |merged, component_ivar|
component_value = apply_path(instance_variable_get(component_ivar), path)
- Chef::Mixin::DeepMerge.deep_merge(component_value, merged)
+ deep_merge!(merged, component_value)
end
+ ret == NIL ? nil : ret
end
# Deep merge the override attribute levels with array merging.
@@ -567,10 +563,11 @@ class Chef
# @param path [Array] Array of args to method chain to descend into the node object
# @return [attr] Deep Merged values (may be VividMash, Hash, Array, etc) from the node object
def merge_overrides(path)
- OVERRIDE_COMPONENTS.inject(nil) do |merged, component_ivar|
+ ret = OVERRIDE_COMPONENTS.inject(NIL) do |merged, component_ivar|
component_value = apply_path(instance_variable_get(component_ivar), path)
- Chef::Mixin::DeepMerge.deep_merge(component_value, merged)
+ deep_merge!(merged, component_value)
end
+ ret == NIL ? nil : ret
end
# needed for __path__
@@ -578,7 +575,76 @@ class Chef
key.kind_of?(Symbol) ? key.to_s : key
end
- end
+ NIL = Object.new
+
+ # @api private
+ def deep_merge!(merge_onto, merge_with)
+ # If there are two Hashes, recursively merge.
+ if merge_onto.kind_of?(Hash) && merge_with.kind_of?(Hash)
+ merge_with.each do |key, merge_with_value|
+ value =
+ if merge_onto.has_key?(key)
+ deep_merge!(safe_dup(merge_onto[key]), merge_with_value)
+ else
+ merge_with_value
+ end
+
+ # internal_set bypasses converting keys, does convert values and allows writing to immutable mashes
+ merge_onto.internal_set(key, value)
+ end
+ merge_onto
+
+ elsif merge_onto.kind_of?(Array) && merge_with.kind_of?(Array)
+ merge_onto |= merge_with
+
+ # If merge_with is nil, don't replace merge_onto
+ elsif merge_with.nil?
+ merge_onto
+
+ # In all other cases, replace merge_onto with merge_with
+ else
+ if merge_with.kind_of?(Hash)
+ Chef::Node::VividMash.new(merge_with)
+ elsif merge_with.kind_of?(Array)
+ Chef::Node::AttrArray.new(merge_with)
+ else
+ merge_with
+ end
+ end
+ end
+ # @api private
+ def hash_only_merge!(merge_onto, merge_with)
+ # If there are two Hashes, recursively merge.
+ if merge_onto.kind_of?(Hash) && merge_with.kind_of?(Hash)
+ merge_with.each do |key, merge_with_value|
+ value =
+ if merge_onto.has_key?(key)
+ hash_only_merge!(safe_dup(merge_onto[key]), merge_with_value)
+ else
+ merge_with_value
+ end
+
+ # internal_set bypasses converting keys, does convert values and allows writing to immutable mashes
+ merge_onto.internal_set(key, value)
+ end
+ merge_onto
+
+ # If merge_with is nil, don't replace merge_onto
+ elsif merge_with.nil?
+ merge_onto
+
+ # In all other cases, replace merge_onto with merge_with
+ else
+ if merge_with.kind_of?(Hash)
+ Chef::Node::ImmutableMash.new(merge_with)
+ elsif merge_with.kind_of?(Array)
+ Chef::Node::ImmutableArray.new(merge_with)
+ else
+ merge_with
+ end
+ end
+ end
+ end
end
end
diff --git a/lib/chef/node/immutable_collections.rb b/lib/chef/node/immutable_collections.rb
index be9285a755..848e12d2df 100644
--- a/lib/chef/node/immutable_collections.rb
+++ b/lib/chef/node/immutable_collections.rb
@@ -30,16 +30,22 @@ class Chef
e
end
- def immutablize(value)
+ def convert_value(value)
case value
when Hash
ImmutableMash.new(value, __root__, __node__, __precedence__)
when Array
ImmutableArray.new(value, __root__, __node__, __precedence__)
+ when ImmutableMash, ImmutableArray
+ value
else
safe_dup(value).freeze
end
end
+
+ def immutablize(value)
+ convert_value(value)
+ end
end
# == ImmutableArray
@@ -90,7 +96,9 @@ class Chef
alias_method :to_array, :to_a
- # for consistency's sake -- integers 'converted' to integers
+ private
+
+ # needed for __path__
def convert_key(key)
key
end
@@ -115,31 +123,20 @@ class Chef
include Immutablize
include CommonAPI
- alias :internal_set :[]=
- private :internal_set
+ # this is for deep_merge usage, chef users must never touch this API
+ # @api private
+ def internal_set(key, value)
+ regular_writer(key, convert_value(value))
+ end
def initialize(mash_data = {})
mash_data.each do |key, value|
- internal_set(key, immutablize(value))
+ internal_set(key, value)
end
end
- def public_method_that_only_deep_merge_should_use(key, value)
- internal_set(key, immutablize(value))
- end
-
alias :attribute? :has_key?
- # Mash uses #convert_value to mashify values on input.
- # Since we're handling this ourselves, override it to be a no-op
- #
- # FIXME? this seems wrong to do and i think is responsible for
- # #dup needing to be more complicated than Mash.new(self)?
- #
- def convert_value(value)
- value
- end
-
# NOTE: #default and #default= are likely to be pretty confusing. For a
# regular ruby Hash, they control what value is returned for, e.g.,
# hash[:no_such_key] #=> hash.default
diff --git a/lib/chef/provider/apt_preference.rb b/lib/chef/provider/apt_preference.rb
new file mode 100644
index 0000000000..ff4ea02ff0
--- /dev/null
+++ b/lib/chef/provider/apt_preference.rb
@@ -0,0 +1,94 @@
+#
+# Author:: Tim Smith (<tsmith@chef.io>)
+# Copyright:: 2016-2017, Chef Software, 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"
+require "chef/dsl/declare_resource"
+require "chef/provider/noop"
+require "chef/log"
+
+class Chef
+ class Provider
+ class AptPreference < Chef::Provider
+ provides :apt_preference, os: "linux", platform_family: "debian"
+
+ APT_PREFERENCE_DIR = "/etc/apt/preferences.d".freeze
+
+ def load_current_resource
+ end
+
+ action :add do
+ preference = build_pref(
+ new_resource.glob || new_resource.package_name,
+ new_resource.pin,
+ new_resource.pin_priority
+ )
+
+ declare_resource(:directory, APT_PREFERENCE_DIR) do
+ mode "0755"
+ action :create
+ end
+
+ sanitized_prefname = safe_name(new_resource.package_name)
+
+ # cleanup any existing pref files w/o the sanitized name (created by old apt cookbook)
+ if (sanitized_prefname != new_resource.package_name) && ::File.exist?("#{APT_PREFERENCE_DIR}/#{new_resource.package_name}.pref")
+ Chef::Log.warn "Replacing legacy #{new_resource.package_name}.pref with #{sanitized_prefname}.pref in #{APT_PREFERENCE_DIR}"
+ declare_resource(:file, "#{APT_PREFERENCE_DIR}/#{new_resource.package_name}.pref") do
+ action :delete
+ end
+ end
+
+ # cleanup any existing pref files without the .pref extension (created by old apt cookbook)
+ if ::File.exist?("#{APT_PREFERENCE_DIR}/#{new_resource.package_name}")
+ Chef::Log.warn "Replacing legacy #{new_resource.package_name} with #{sanitized_prefname}.pref in #{APT_PREFERENCE_DIR}"
+ declare_resource(:file, "#{APT_PREFERENCE_DIR}/#{new_resource.package_name}") do
+ action :delete
+ end
+ end
+
+ declare_resource(:file, "#{APT_PREFERENCE_DIR}/#{sanitized_prefname}.pref") do
+ mode "0644"
+ content preference
+ action :create
+ end
+ end
+
+ action :remove do
+ sanitized_prefname = safe_name(new_resource.package_name)
+
+ if ::File.exist?("#{APT_PREFERENCE_DIR}/#{sanitized_prefname}.pref")
+ Chef::Log.info "Un-pinning #{sanitized_prefname} from #{APT_PREFERENCE_DIR}"
+ declare_resource(:file, "#{APT_PREFERENCE_DIR}/#{sanitized_prefname}.pref") do
+ action :delete
+ end
+ end
+ end
+
+ # Build preferences.d file contents
+ def build_pref(package_name, pin, pin_priority)
+ "Package: #{package_name}\nPin: #{pin}\nPin-Priority: #{pin_priority}\n"
+ end
+
+ def safe_name(name)
+ name.tr(".", "_").gsub("*", "wildcard")
+ end
+ end
+ end
+end
+
+Chef::Provider::Noop.provides :apt_preference
diff --git a/lib/chef/provider/apt_repository.rb b/lib/chef/provider/apt_repository.rb
index 05172c9f98..2d86a6fce4 100644
--- a/lib/chef/provider/apt_repository.rb
+++ b/lib/chef/provider/apt_repository.rb
@@ -19,7 +19,6 @@
require "chef/resource"
require "chef/dsl/declare_resource"
require "chef/mixin/shell_out"
-require "chef/mixin/which"
require "chef/http/simple"
require "chef/provider/noop"
@@ -27,11 +26,8 @@ class Chef
class Provider
class AptRepository < Chef::Provider
include Chef::Mixin::ShellOut
- extend Chef::Mixin::Which
- provides :apt_repository do
- which("apt-get")
- end
+ provides :apt_repository, os: "linux", platform_family: "debian"
LIST_APT_KEYS = "apt-key list".freeze
LIST_APT_KEY_FINGERPRINTS = "apt-key adv --list-public-keys --with-fingerprint --with-colons".freeze
@@ -41,10 +37,12 @@ class Chef
action :add do
unless new_resource.key.nil?
- if is_key_id?(new_resource.key) && !has_cookbook_file?(new_resource.key)
- install_key_from_keyserver
- else
- install_key_from_uri
+ new_resource.key.each do |k|
+ if is_key_id?(k) && !has_cookbook_file?(k)
+ install_key_from_keyserver(k)
+ else
+ install_key_from_uri(k)
+ end
end
end
@@ -151,19 +149,19 @@ class Chef
(installed_keys & proposed_keys).sort == proposed_keys.sort
end
- def install_key_from_uri
- key_name = new_resource.key.gsub(/[^0-9A-Za-z\-]/, "_")
+ def install_key_from_uri(key)
+ key_name = key.gsub(/[^0-9A-Za-z\-]/, "_")
cached_keyfile = ::File.join(Chef::Config[:file_cache_path], key_name)
- type = if new_resource.key.start_with?("http")
+ type = if key.start_with?("http")
:remote_file
- elsif has_cookbook_file?(new_resource.key)
+ elsif has_cookbook_file?(key)
:cookbook_file
else
raise Chef::Exceptions::FileNotFound, "Cannot locate key file"
end
declare_resource(type, cached_keyfile) do
- source new_resource.key
+ source key
mode "0644"
sensitive new_resource.sensitive
action :create
@@ -181,7 +179,7 @@ class Chef
end
end
- def install_key_from_keyserver(key = new_resource.key, keyserver = new_resource.keyserver)
+ def install_key_from_keyserver(key, keyserver = new_resource.keyserver)
cmd = "apt-key adv --recv"
cmd << " --keyserver-options http-proxy=#{new_resource.key_proxy}" if new_resource.key_proxy
cmd << " --keyserver "
diff --git a/lib/chef/provider/apt_update.rb b/lib/chef/provider/apt_update.rb
index 670f3ad7f6..bfd9603e4e 100644
--- a/lib/chef/provider/apt_update.rb
+++ b/lib/chef/provider/apt_update.rb
@@ -18,16 +18,12 @@
require "chef/provider"
require "chef/provider/noop"
-require "chef/mixin/which"
+require "chef/dsl/declare_resource"
class Chef
class Provider
class AptUpdate < Chef::Provider
- extend Chef::Mixin::Which
-
- provides :apt_update do
- which("apt-get")
- end
+ provides :apt_update, os: "linux", platform_family: "debian"
APT_CONF_DIR = "/etc/apt/apt.conf.d"
STAMP_DIR = "/var/lib/apt/periodic"
diff --git a/lib/chef/provider/execute.rb b/lib/chef/provider/execute.rb
index d19a95b4ae..d5a0bdfa11 100644
--- a/lib/chef/provider/execute.rb
+++ b/lib/chef/provider/execute.rb
@@ -27,7 +27,7 @@ class Chef
provides :execute
- def_delegators :new_resource, :command, :returns, :environment, :user, :domain, :password, :group, :cwd, :umask, :creates
+ def_delegators :new_resource, :command, :returns, :environment, :user, :domain, :password, :group, :cwd, :umask, :creates, :elevated
def load_current_resource
current_resource = Chef::Resource::Execute.new(new_resource.name)
@@ -102,6 +102,7 @@ class Chef
opts[:live_stream] = STDOUT
end
end
+ opts[:elevated] = elevated if elevated
opts
end
diff --git a/lib/chef/provider/git.rb b/lib/chef/provider/git.rb
index db83e0aea6..bdbeca5941 100644
--- a/lib/chef/provider/git.rb
+++ b/lib/chef/provider/git.rb
@@ -28,6 +28,8 @@ class Chef
extend Forwardable
provides :git
+ GIT_VERSION_PATTERN = Regexp.compile('git version (\d+\.\d+.\d+)')
+
def_delegator :new_resource, :destination, :cwd
def load_current_resource
@@ -103,8 +105,21 @@ class Chef
end
end
- def git_minor_version
- @git_minor_version ||= Gem::Version.new( git("--version").stdout.split.last )
+ def git_has_single_branch_option?
+ @git_has_single_branch_option ||= !git_gem_version.nil? && git_gem_version >= Gem::Version.new("1.7.10")
+ end
+
+ def git_gem_version
+ return @git_gem_version if defined?(@git_gem_version)
+ output = git("--version").stdout
+ match = GIT_VERSION_PATTERN.match(output)
+ if match
+ @git_gem_version = Gem::Version.new(match[1])
+ else
+ Chef::Log.warn "Unable to parse git version from '#{output}'"
+ @git_gem_version = nil
+ end
+ @git_gem_version
end
def existing_git_clone?
@@ -142,7 +157,7 @@ class Chef
clone_cmd = ["clone"]
clone_cmd << "-o #{remote}" unless remote == "origin"
clone_cmd << "--depth #{new_resource.depth}" if new_resource.depth
- clone_cmd << "--no-single-branch" if new_resource.depth && git_minor_version >= Gem::Version.new("1.7.10")
+ clone_cmd << "--no-single-branch" if new_resource.depth && git_has_single_branch_option?
clone_cmd << "\"#{new_resource.repository}\""
clone_cmd << "\"#{cwd}\""
@@ -285,6 +300,8 @@ class Chef
refs.find_all { |m| m[1] == pattern }
end
+ alias git_minor_version git_gem_version
+
private
def run_options(run_opts = {})
diff --git a/lib/chef/provider/http_request.rb b/lib/chef/provider/http_request.rb
index 8370c2375c..cafdc1e007 100644
--- a/lib/chef/provider/http_request.rb
+++ b/lib/chef/provider/http_request.rb
@@ -62,6 +62,20 @@ class Chef
end
end
+ # Send a PATCH request to new_resource.url, with the message as the payload
+ def action_patch
+ converge_by("#{new_resource} PATCH to #{new_resource.url}") do
+ message = check_message(new_resource.message)
+ body = @http.patch(
+ "#{new_resource.url}",
+ message,
+ new_resource.headers
+ )
+ Chef::Log.info("#{new_resource} PATCH to #{new_resource.url} successful")
+ Chef::Log.debug("#{new_resource} PATCH request response: #{body}")
+ end
+ end
+
# Send a PUT request to new_resource.url, with the message as the payload
def action_put
converge_by("#{new_resource} PUT to #{new_resource.url}") do
diff --git a/lib/chef/provider/ifconfig/redhat.rb b/lib/chef/provider/ifconfig/redhat.rb
index 8af9f10f67..bf3d979e86 100644
--- a/lib/chef/provider/ifconfig/redhat.rb
+++ b/lib/chef/provider/ifconfig/redhat.rb
@@ -38,6 +38,10 @@ class Chef
<% if new_resource.hwaddr %>HWADDR=<%= new_resource.hwaddr %><% end %>
<% if new_resource.metric %>METRIC=<%= new_resource.metric %><% end %>
<% if new_resource.mtu %>MTU=<%= new_resource.mtu %><% end %>
+<% if new_resource.ethtool_opts %>ETHTOOL_OPTS="<%= new_resource.ethtool_opts %>"<% end %>
+<% if new_resource.bonding_opts %>BONDING_OPTS="<%= new_resource.bonding_opts %>"<% end %>
+<% if new_resource.master %>MASTER=<%= new_resource.master %><% end %>
+<% if new_resource.slave %>SLAVE=<%= new_resource.slave %><% end %>
}
@config_path = "/etc/sysconfig/network-scripts/ifcfg-#{new_resource.device}"
end
diff --git a/lib/chef/provider/launchd.rb b/lib/chef/provider/launchd.rb
index 9c368c2b48..8281410d42 100644
--- a/lib/chef/provider/launchd.rb
+++ b/lib/chef/provider/launchd.rb
@@ -90,6 +90,7 @@ class Chef
end
def manage_plist(action)
+ return unless manage_agent?(action)
if source
res = cookbook_file_resource
else
@@ -101,11 +102,30 @@ class Chef
end
def manage_service(action)
+ return unless manage_agent?(action)
res = service_resource
res.run_action(action)
new_resource.updated_by_last_action(true) if res.updated?
end
+ def manage_agent?(action)
+ # Gets UID of console_user and converts to string.
+ console_user = Etc.getpwuid(::File.stat("/dev/console").uid).name
+ root = console_user == "root"
+ agent = type == "agent"
+ invalid_action = [:delete, :disable, :enable, :restart].include?(action)
+ lltstype = ""
+ if new_resource.limit_load_to_session_type
+ lltstype = new_resource.limit_load_to_session_type
+ end
+ invalid_type = lltstype != "LoginWindow"
+ if root && agent && invalid_action && invalid_type
+ Chef::Log.debug("#{label}: Aqua LaunchAgents shouldn't be loaded as root")
+ return false
+ end
+ true
+ end
+
def service_resource
res = Chef::Resource::MacosxService.new(label, run_context)
res.name(label) if label
diff --git a/lib/chef/provider/package.rb b/lib/chef/provider/package.rb
index 4b73f47ed3..4810728524 100644
--- a/lib/chef/provider/package.rb
+++ b/lib/chef/provider/package.rb
@@ -311,18 +311,19 @@ class Chef
#
# This MUST have 'equality' semantics -- the exact thing matches the exact thing.
#
- # The current_version should probably be dropped out of the method signature, it should
- # always be the first argument.
- #
# The name is not just bad, but i find it completely misleading, consider:
#
# target_version_already_installed?(current_version, new_version)
# target_version_already_installed?(current_version, candidate_version)
#
- # which of those is the 'target_version'? i'd say the new_version and i'm confused when
+ # Which of those is the 'target_version'? I'd say the new_version and I'm confused when
# i see it called with the candidate_version.
#
- # `current_version_equals?(version)` would be a better name
+ # `version_equals?(v1, v2)` would be a better name.
+ #
+ # Note that most likely we need a spaceship operator on versions that subclasses can implement
+ # and we should have `version_compare(v1, v2)` that returns `v1 <=> v2`.
+ #
def target_version_already_installed?(current_version, target_version)
return false unless current_version && target_version
current_version == target_version
@@ -333,10 +334,8 @@ class Chef
#
# Subclasses MAY override this to provide fuzzy matching on the resource ('>=' and '~>' stuff)
#
- # This should only ever be offered the same arguments (so they should most likely be
- # removed from the method signature).
+ # `version_satisfied_by?(version, constraint)` might be a better name to make this generic.
#
- # `new_version_satisfied?()` might be a better name
def version_requirement_satisfied?(current_version, new_version)
target_version_already_installed?(current_version, new_version)
end
diff --git a/lib/chef/provider/package/dnf.rb b/lib/chef/provider/package/dnf.rb
index 42d679c940..31279e8312 100644
--- a/lib/chef/provider/package/dnf.rb
+++ b/lib/chef/provider/package/dnf.rb
@@ -35,10 +35,12 @@ class Chef
use_multipackage_api
use_package_name_for_source
- provides :package, platform_family: %w{rhel fedora amazon} do
+ provides :package, platform_family: %w{fedora amazon} do
which("dnf") && shell_out("rpm -q dnf").stdout =~ /^dnf-[1-9]/
end
+ provides :package, platform_family: %w{rhel}, platform_version: ">= 8"
+
provides :dnf_package, os: "linux"
#
diff --git a/lib/chef/provider/package/dnf/dnf_helper.py b/lib/chef/provider/package/dnf/dnf_helper.py
index ef08bb54c2..eb4d238f65 100644
--- a/lib/chef/provider/package/dnf/dnf_helper.py
+++ b/lib/chef/provider/package/dnf/dnf_helper.py
@@ -72,7 +72,6 @@ def exit_handler(signal, frame):
signal.signal(signal.SIGINT, exit_handler)
signal.signal(signal.SIGHUP, exit_handler)
signal.signal(signal.SIGPIPE, exit_handler)
-signal.signal(signal.SIGCHLD, exit_handler)
while 1:
# kill self if we get orphaned (tragic)
diff --git a/lib/chef/provider/package/windows/registry_uninstall_entry.rb b/lib/chef/provider/package/windows/registry_uninstall_entry.rb
index 03f6ff318e..64889e1649 100644
--- a/lib/chef/provider/package/windows/registry_uninstall_entry.rb
+++ b/lib/chef/provider/package/windows/registry_uninstall_entry.rb
@@ -40,7 +40,7 @@ class Chef
begin
entry = reg.open(key, desired)
display_name = read_registry_property(entry, "DisplayName")
- if display_name == package_name
+ if display_name.to_s.rstrip == package_name
quiet_uninstall_string = RegistryUninstallEntry.read_registry_property(entry, "QuietUninstallString")
entries.push(quiet_uninstall_string_key?(quiet_uninstall_string, hkey, key, entry))
end
diff --git a/lib/chef/provider/package/zypper.rb b/lib/chef/provider/package/zypper.rb
index 7b8fd6c426..41e8433046 100644
--- a/lib/chef/provider/package/zypper.rb
+++ b/lib/chef/provider/package/zypper.rb
@@ -103,7 +103,7 @@ class Chef
end
def install_package(name, version)
- zypper_package("install", "--auto-agree-with-licenses", name, version)
+ zypper_package("install", *options, "--auto-agree-with-licenses", name, version)
end
def upgrade_package(name, version)
@@ -112,19 +112,19 @@ class Chef
end
def remove_package(name, version)
- zypper_package("remove", name, version)
+ zypper_package("remove", *options, name, version)
end
def purge_package(name, version)
- zypper_package("remove", "--clean-deps", name, version)
+ zypper_package("remove", *options, "--clean-deps", name, version)
end
def lock_package(name, version)
- zypper_package("addlock", name, version)
+ zypper_package("addlock", *options, name, version)
end
def unlock_package(name, version)
- zypper_package("removelock", name, version)
+ zypper_package("removelock", *options, name, version)
end
private
diff --git a/lib/chef/provider/remote_file.rb b/lib/chef/provider/remote_file.rb
index c0a0f9433c..d2de3d0b5f 100644
--- a/lib/chef/provider/remote_file.rb
+++ b/lib/chef/provider/remote_file.rb
@@ -29,6 +29,25 @@ class Chef
super
end
+ def define_resource_requirements
+ [ new_resource.remote_user, new_resource.remote_domain,
+ new_resource.remote_password ].each do |prop|
+ requirements.assert(:all_actions) do |a|
+ a.assertion do
+ if prop
+ node[:platform_family] == "windows"
+ else
+ true
+ end
+ end
+ a.failure_message Chef::Exceptions::UnsupportedPlatform, "'remote_user', 'remote_domain' and 'remote_password' properties are supported only for Windows platform"
+ a.whyrun("Assuming that the platform is Windows while passing 'remote_user', 'remote_domain' and 'remote_password' properties")
+ end
+ end
+
+ super
+ end
+
def load_current_resource
@current_resource = Chef::Resource::RemoteFile.new(new_resource.name)
super
diff --git a/lib/chef/provider/remote_file/fetcher.rb b/lib/chef/provider/remote_file/fetcher.rb
index 563d135d6a..3011dd80a0 100644
--- a/lib/chef/provider/remote_file/fetcher.rb
+++ b/lib/chef/provider/remote_file/fetcher.rb
@@ -24,6 +24,9 @@ class Chef
def self.for_resource(uri, new_resource, current_resource)
if network_share?(uri)
+ if !Chef::Platform.windows?
+ raise Exceptions::UnsupportedPlatform, "Fetching the file on a network share is supported only on the Windows platform. Please change your source: #{uri}"
+ end
Chef::Provider::RemoteFile::NetworkFile.new(uri, new_resource, current_resource)
else
case uri.scheme
diff --git a/lib/chef/provider/remote_file/network_file.rb b/lib/chef/provider/remote_file/network_file.rb
index 44046132a9..a08bfd2453 100644
--- a/lib/chef/provider/remote_file/network_file.rb
+++ b/lib/chef/provider/remote_file/network_file.rb
@@ -19,14 +19,18 @@
require "uri"
require "tempfile"
require "chef/provider/remote_file"
+require "chef/mixin/user_context"
class Chef
class Provider
class RemoteFile
class NetworkFile
+ include Chef::Mixin::UserContext
attr_reader :new_resource
+ TRANSFER_CHUNK_SIZE = 1048576
+
def initialize(source, new_resource, current_resource)
@new_resource = new_resource
@source = source
@@ -35,13 +39,22 @@ class Chef
# Fetches the file on a network share, returning a Tempfile-like File handle
# windows only
def fetch
- tempfile = Chef::FileContentManagement::Tempfile.new(new_resource).tempfile
- Chef::Log.debug("#{new_resource} staging #{@source} to #{tempfile.path}")
- FileUtils.cp(@source, tempfile.path)
- tempfile.close if tempfile
+ begin
+ tempfile = Chef::FileContentManagement::Tempfile.new(new_resource).tempfile
+ Chef::Log.debug("#{new_resource} staging #{@source} to #{tempfile.path}")
+
+ with_user_context(new_resource.remote_user, new_resource.remote_password, new_resource.remote_domain) do
+ ::File.open(@source, "rb") do |remote_file|
+ while data = remote_file.read(TRANSFER_CHUNK_SIZE)
+ tempfile.write(data)
+ end
+ end
+ end
+ ensure
+ tempfile.close if tempfile
+ end
tempfile
end
-
end
end
end
diff --git a/lib/chef/provider/route.rb b/lib/chef/provider/route.rb
index 59d516be6a..2439f45eda 100644
--- a/lib/chef/provider/route.rb
+++ b/lib/chef/provider/route.rb
@@ -86,7 +86,9 @@ class Chef
self.is_running = false
# cidr or quad dot mask
- new_ip = if new_resource.netmask
+ new_ip = if new_resource.target == "default"
+ IPAddr.new(new_resource.gateway)
+ elsif new_resource.netmask
IPAddr.new("#{new_resource.target}/#{new_resource.netmask}")
else
IPAddr.new(new_resource.target)
@@ -180,12 +182,29 @@ class Chef
end
end
conf.each do |k, v|
- network_file_name = "/etc/sysconfig/network-scripts/route-#{k}"
- converge_by("write route route.#{k}\n#{conf[k]} to #{network_file_name}") do
- network_file = ::File.new(network_file_name, "w")
- network_file.puts(conf[k])
- Chef::Log.debug("#{new_resource} writing route.#{k}\n#{conf[k]}")
- network_file.close
+ if new_resource.target == "default"
+ network_file_name = "/etc/sysconfig/network"
+ converge_by("write route default route to #{network_file_name}") do
+ Chef::Log.debug("#{new_resource} writing default route #{new_resource.gateway} to #{network_file_name}")
+ if ::File.exists?(network_file_name)
+ network_file = ::Chef::Util::FileEdit.new(network_file_name)
+ network_file.search_file_replace_line /^GATEWAY=/, "GATEWAY=#{new_resource.gateway}"
+ network_file.insert_line_if_no_match /^GATEWAY=/, "GATEWAY=#{new_resource.gateway}"
+ network_file.write_file
+ else
+ network_file = ::File.new(network_file_name, "w")
+ network_file.puts("GATEWAY=#{new_resource.gateway}")
+ network_file.close
+ end
+ end
+ else
+ network_file_name = "/etc/sysconfig/network-scripts/route-#{k}"
+ converge_by("write route route.#{k}\n#{conf[k]} to #{network_file_name}") do
+ network_file = ::File.new(network_file_name, "w")
+ network_file.puts(conf[k])
+ Chef::Log.debug("#{new_resource} writing route.#{k}\n#{conf[k]}")
+ network_file.close
+ end
end
end
end
diff --git a/lib/chef/provider/service/macosx.rb b/lib/chef/provider/service/macosx.rb
index 4056b72649..9dc7b81a29 100644
--- a/lib/chef/provider/service/macosx.rb
+++ b/lib/chef/provider/service/macosx.rb
@@ -52,17 +52,18 @@ class Chef
@plist_size = 0
@plist = @new_resource.plist ? @new_resource.plist : find_service_plist
@service_label = find_service_label
- # LauchAgents should be loaded as the console user.
+ # LaunchAgents should be loaded as the console user.
@console_user = @plist ? @plist.include?("LaunchAgents") : false
@session_type = @new_resource.session_type
if @console_user
- @console_user = Etc.getlogin
+ @console_user = Etc.getpwuid(::File.stat("/dev/console").uid).name
Chef::Log.debug("#{new_resource} console_user: '#{@console_user}'")
cmd = "su "
param = this_version_or_newer?("10.10") ? "" : "-l "
+ param = "-l " if this_version_or_newer?("10.12")
@base_user_cmd = cmd + param + "#{@console_user} -c"
- # Default LauchAgent session should be Aqua
+ # Default LaunchAgent session should be Aqua
@session_type = "Aqua" if @session_type.nil?
end
diff --git a/lib/chef/provider/service/systemd.rb b/lib/chef/provider/service/systemd.rb
index deec25b187..2da35b3b9e 100644
--- a/lib/chef/provider/service/systemd.rb
+++ b/lib/chef/provider/service/systemd.rb
@@ -20,6 +20,7 @@
require "chef/resource/service"
require "chef/provider/service/simple"
require "chef/mixin/which"
+require "shellwords"
class Chef::Provider::Service::Systemd < Chef::Provider::Service::Simple
@@ -100,7 +101,7 @@ class Chef::Provider::Service::Systemd < Chef::Provider::Service::Simple
super
else
options, args = get_systemctl_options_args
- shell_out_with_systems_locale!("#{systemctl_path} #{args} start #{new_resource.service_name}", options)
+ shell_out_with_systems_locale!("#{systemctl_path} #{args} start #{Shellwords.escape(new_resource.service_name)}", options)
end
end
end
@@ -113,7 +114,7 @@ class Chef::Provider::Service::Systemd < Chef::Provider::Service::Simple
super
else
options, args = get_systemctl_options_args
- shell_out_with_systems_locale!("#{systemctl_path} #{args} stop #{new_resource.service_name}", options)
+ shell_out_with_systems_locale!("#{systemctl_path} #{args} stop #{Shellwords.escape(new_resource.service_name)}", options)
end
end
end
@@ -123,7 +124,7 @@ class Chef::Provider::Service::Systemd < Chef::Provider::Service::Simple
super
else
options, args = get_systemctl_options_args
- shell_out_with_systems_locale!("#{systemctl_path} #{args} restart #{new_resource.service_name}", options)
+ shell_out_with_systems_locale!("#{systemctl_path} #{args} restart #{Shellwords.escape(new_resource.service_name)}", options)
end
end
@@ -133,7 +134,7 @@ class Chef::Provider::Service::Systemd < Chef::Provider::Service::Simple
else
if current_resource.running
options, args = get_systemctl_options_args
- shell_out_with_systems_locale!("#{systemctl_path} #{args} reload #{new_resource.service_name}", options)
+ shell_out_with_systems_locale!("#{systemctl_path} #{args} reload #{Shellwords.escape(new_resource.service_name)}", options)
else
start_service
end
@@ -142,37 +143,37 @@ class Chef::Provider::Service::Systemd < Chef::Provider::Service::Simple
def enable_service
options, args = get_systemctl_options_args
- shell_out!("#{systemctl_path} #{args} enable #{new_resource.service_name}", options)
+ shell_out!("#{systemctl_path} #{args} enable #{Shellwords.escape(new_resource.service_name)}", options)
end
def disable_service
options, args = get_systemctl_options_args
- shell_out!("#{systemctl_path} #{args} disable #{new_resource.service_name}", options)
+ shell_out!("#{systemctl_path} #{args} disable #{Shellwords.escape(new_resource.service_name)}", options)
end
def mask_service
options, args = get_systemctl_options_args
- shell_out!("#{systemctl_path} #{args} mask #{new_resource.service_name}", options)
+ shell_out!("#{systemctl_path} #{args} mask #{Shellwords.escape(new_resource.service_name)}", options)
end
def unmask_service
options, args = get_systemctl_options_args
- shell_out!("#{systemctl_path} #{args} unmask #{new_resource.service_name}", options)
+ shell_out!("#{systemctl_path} #{args} unmask #{Shellwords.escape(new_resource.service_name)}", options)
end
def is_active?
options, args = get_systemctl_options_args
- shell_out("#{systemctl_path} #{args} is-active #{new_resource.service_name} --quiet", options).exitstatus == 0
+ shell_out("#{systemctl_path} #{args} is-active #{Shellwords.escape(new_resource.service_name)} --quiet", options).exitstatus == 0
end
def is_enabled?
options, args = get_systemctl_options_args
- shell_out("#{systemctl_path} #{args} is-enabled #{new_resource.service_name} --quiet", options).exitstatus == 0
+ shell_out("#{systemctl_path} #{args} is-enabled #{Shellwords.escape(new_resource.service_name)} --quiet", options).exitstatus == 0
end
def is_masked?
options, args = get_systemctl_options_args
- s = shell_out("#{systemctl_path} #{args} is-enabled #{new_resource.service_name}", options)
+ s = shell_out("#{systemctl_path} #{args} is-enabled #{Shellwords.escape(new_resource.service_name)}", options)
s.exitstatus != 0 && s.stdout.include?("masked")
end
diff --git a/lib/chef/provider/support/yum_repo.erb b/lib/chef/provider/support/yum_repo.erb
index 6f1325573d..f60d8688da 100644
--- a/lib/chef/provider/support/yum_repo.erb
+++ b/lib/chef/provider/support/yum_repo.erb
@@ -61,6 +61,9 @@ keepalive=1
<% if @config.metadata_expire %>
metadata_expire=<%= @config.metadata_expire %>
<% end %>
+<% if @config.metalink %>
+metalink=<%= @config.metalink %>
+<% end %>
<% if @config.mirrorlist %>
mirrorlist=<%= @config.mirrorlist %>
<% end %>
@@ -112,6 +115,9 @@ sslclientkey=<%= @config.sslclientkey %>
<% unless @config.sslverify.nil? %>
sslverify=<%= ( @config.sslverify ) ? 'true' : 'false' %>
<% end %>
+<% if @config.throttle %>
+throttle=<%= @config.throttle %>
+<% end %>
<% if @config.timeout %>
timeout=<%= @config.timeout %>
<% end %>
diff --git a/lib/chef/provider/support/zypper_repo.erb b/lib/chef/provider/support/zypper_repo.erb
new file mode 100644
index 0000000000..6d508fa77f
--- /dev/null
+++ b/lib/chef/provider/support/zypper_repo.erb
@@ -0,0 +1,17 @@
+# This file was generated by Chef
+# Do NOT modify this file by hand.
+
+[<%= @config.repo_name %>]
+<% %w{ type enabled autorefresh gpgcheck gpgkey baseurl mirrorlist path priority keeppackages mode refresh_cache }.each do |prop| -%>
+<% next if @config.send(prop.to_sym).nil? -%>
+<%= prop %>=<%=
+ case @config.send(prop.to_sym)
+ when TrueClass
+ '1'
+ when FalseClass
+ '0'
+ else
+ @config.send(prop.to_sym)
+ end %>
+<% end -%>
+name=<%= @config.description || @config.repo_name %>
diff --git a/lib/chef/provider/systemd_unit.rb b/lib/chef/provider/systemd_unit.rb
index 143efe7b91..a2ef64044b 100644
--- a/lib/chef/provider/systemd_unit.rb
+++ b/lib/chef/provider/systemd_unit.rb
@@ -22,6 +22,7 @@ require "chef/mixin/shell_out"
require "chef/resource/file"
require "chef/resource/file/verification/systemd_unit"
require "iniparse"
+require "shellwords"
class Chef
class Provider
@@ -203,11 +204,11 @@ class Chef
end
def systemctl_execute!(action, unit)
- shell_out_with_systems_locale!("#{systemctl_cmd} #{action} #{unit}", systemctl_opts)
+ shell_out_with_systems_locale!("#{systemctl_cmd} #{action} #{Shellwords.escape(unit)}", systemctl_opts)
end
def systemctl_execute(action, unit)
- shell_out("#{systemctl_cmd} #{action} #{unit}", systemctl_opts)
+ shell_out("#{systemctl_cmd} #{action} #{Shellwords.escape(unit)}", systemctl_opts)
end
def systemctl_cmd
diff --git a/lib/chef/provider/windows_path.rb b/lib/chef/provider/windows_path.rb
new file mode 100644
index 0000000000..b31789b4b9
--- /dev/null
+++ b/lib/chef/provider/windows_path.rb
@@ -0,0 +1,62 @@
+#
+# Author:: Nimisha Sharad (<nimisha.sharad@msystechnologies.com>)
+# Copyright:: Copyright 2008-2017, Chef Software 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/mixin/windows_env_helper" if Chef::Platform.windows?
+require "chef/mixin/wide_string"
+require "chef/exceptions"
+
+class Chef
+ class Provider
+ class WindowsPath < Chef::Provider
+
+ include Chef::Mixin::WindowsEnvHelper if Chef::Platform.windows?
+
+ def load_current_resource
+ @current_resource = Chef::Resource::WindowsPath.new(new_resource.name)
+ @current_resource.path(new_resource.path)
+ @current_resource
+ end
+
+ action :add do
+ # The windows Env provider does not correctly expand variables in
+ # the PATH environment variable. Ruby expects these to be expanded.
+ #
+ path = expand_path(new_resource.path)
+ converge_by "Adding #{new_resource.path} to path environment variable" do
+ declare_resource(:env, "path") do
+ action :modify
+ delim ::File::PATH_SEPARATOR
+ value path.tr("/", '\\')
+ end
+ end
+ end
+
+ action :remove do
+ # The windows Env provider does not correctly expand variables in
+ # the PATH environment variable. Ruby expects these to be expanded.
+ #
+ path = expand_path(new_resource.path)
+ declare_resource(:env, "path") do
+ action :delete
+ delim ::File::PATH_SEPARATOR
+ value path.tr("/", '\\')
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/provider/windows_task.rb b/lib/chef/provider/windows_task.rb
index a96d4b2b7e..8703c30da9 100644
--- a/lib/chef/provider/windows_task.rb
+++ b/lib/chef/provider/windows_task.rb
@@ -7,7 +7,7 @@
# 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,
@@ -30,129 +30,153 @@ class Chef
provides :windows_task, os: "windows"
def load_current_resource
- @current_resource = Chef::Resource::WindowsTask.new(new_resource.name)
+ self.current_resource = Chef::Resource::WindowsTask.new(new_resource.name)
pathed_task_name = new_resource.task_name.start_with?('\\') ? new_resource.task_name : "\\#{new_resource.task_name}"
- @current_resource.task_name(pathed_task_name)
+ current_resource.task_name(pathed_task_name)
task_hash = load_task_hash(pathed_task_name)
set_current_resource(task_hash) if task_hash.respond_to?(:[]) && task_hash[:TaskName] == pathed_task_name
- @current_resource
+ current_resource
end
def set_current_resource(task_hash)
- @current_resource.exists = true
- @current_resource.command(task_hash[:TaskToRun])
- @current_resource.cwd(task_hash[:StartIn]) unless task_hash[:StartIn] == "N/A"
- @current_resource.user(task_hash[:RunAsUser])
+ current_resource.exists = true
+ current_resource.command(task_hash[:TaskToRun])
+ current_resource.cwd(task_hash[:StartIn]) unless task_hash[:StartIn] == "N/A"
+ current_resource.user(task_hash[:RunAsUser])
set_current_run_level task_hash[:run_level]
set_current_frequency task_hash
- @current_resource.day(task_hash[:day]) if task_hash[:day]
- @current_resource.months(task_hash[:months]) if task_hash[:months]
+ current_resource.day(task_hash[:day]) if task_hash[:day]
+ current_resource.months(task_hash[:months]) if task_hash[:months]
set_current_idle_time(task_hash[:idle_time]) if task_hash[:idle_time]
- @current_resource.random_delay(task_hash[:random_delay]) if task_hash[:random_delay]
- @current_resource.execution_time_limit(task_hash[:execution_time_limit]) if task_hash[:execution_time_limit]
+ current_resource.random_delay(task_hash[:random_delay]) if task_hash[:random_delay]
+ # schtask sets execution_time_limit as PT72H by default
+ current_resource.execution_time_limit(task_hash[:execution_time_limit] || "PT72H")
+ current_resource.status = :running if task_hash[:Status] == "Running"
+ current_resource.enabled = true if task_hash[:ScheduledTaskState] == "Enabled"
+ current_resource.start_time = task_hash[:StartTime] if task_hash[:StartTime]
+ current_resource.start_day = task_hash[:StartDate] if task_hash[:StartDate]
+ end
- @current_resource.status = :running if task_hash[:Status] == "Running"
- @current_resource.enabled = true if task_hash[:ScheduledTaskState] == "Enabled"
+ # This method checks if task and command attributes exist since those two are mandatory attributes to create a schedules task.
+ def basic_validation
+ validate = []
+ validate << "Command" if new_resource.command.nil? || new_resource.command.empty?
+ validate << "Task Name" if new_resource.task_name.nil? || new_resource.task_name.empty?
+ return true if validate.empty?
+ raise Chef::Exceptions::ValidationFailed.new "Value for '#{validate.join(', ')}' option cannot be empty"
end
- def action_create
- if @current_resource.exists && !(task_need_update? || @new_resource.force)
- Chef::Log.info "#{@new_resource} task already exists - nothing to do"
- else
- options = {}
- options["F"] = "" if @new_resource.force || task_need_update?
- options["SC"] = schedule
- options["MO"] = @new_resource.frequency_modifier if frequency_modifier_allowed
- options["I"] = @new_resource.idle_time unless @new_resource.idle_time.nil?
- options["SD"] = @new_resource.start_day unless @new_resource.start_day.nil?
- options["ST"] = @new_resource.start_time unless @new_resource.start_time.nil?
- options["TR"] = @new_resource.command
- options["RU"] = @new_resource.user
- options["RP"] = @new_resource.password if use_password?
- options["RL"] = "HIGHEST" if @new_resource.run_level == :highest
- options["IT"] = "" if @new_resource.interactive_enabled
- options["D"] = @new_resource.day if @new_resource.day
- options["M"] = @new_resource.months unless @new_resource.months.nil?
-
- run_schtasks "CREATE", options
- xml_options = []
- xml_options << "cwd" if new_resource.cwd
- xml_options << "random_delay" if new_resource.random_delay
- xml_options << "execution_time_limit" if new_resource.execution_time_limit
- update_task_xml(xml_options) unless xml_options.empty?
+ # get array of windows task resource attributes
+ def resource_attributes
+ %w{ command user run_level cwd frequency_modifier frequency idle_time random_delay execution_time_limit start_day start_time }
+ end
- new_resource.updated_by_last_action true
- Chef::Log.info "#{@new_resource} task created"
+ def action_create
+ if current_resource.exists
+ if !(task_need_update? || new_resource.force)
+ Chef::Log.info "#{new_resource} task already exists - nothing to do"
+ return
+ end
+ # To merge current resource and new resource attributes
+ resource_attributes.each do |attribute|
+ new_resource_attribute = new_resource.send(attribute)
+ current_resource_attribute = current_resource.send(attribute)
+ new_resource.send("#{attribute}=", current_resource_attribute ) if current_resource_attribute && new_resource_attribute.nil?
+ end
end
+ basic_validation
+ options = {}
+ options["F"] = "" if new_resource.force || task_need_update?
+ options["SC"] = schedule
+ options["MO"] = new_resource.frequency_modifier if frequency_modifier_allowed
+ options["I"] = new_resource.idle_time unless new_resource.idle_time.nil?
+ options["SD"] = convert_user_date_to_system_date new_resource.start_day unless new_resource.start_day.nil?
+ options["ST"] = new_resource.start_time unless new_resource.start_time.nil?
+ options["TR"] = new_resource.command
+ options["RU"] = new_resource.user
+ options["RP"] = new_resource.password if use_password?
+ options["RL"] = "HIGHEST" if new_resource.run_level == :highest
+ options["IT"] = "" if new_resource.interactive_enabled
+ options["D"] = new_resource.day if new_resource.day
+ options["M"] = new_resource.months unless new_resource.months.nil?
+ run_schtasks "CREATE", options
+ xml_options = []
+ xml_options << "cwd" if new_resource.cwd
+ xml_options << "random_delay" if new_resource.random_delay
+ xml_options << "execution_time_limit" if new_resource.execution_time_limit
+ update_task_xml(xml_options) unless xml_options.empty?
+
+ new_resource.updated_by_last_action true
+ Chef::Log.info "#{new_resource} task created"
end
def action_run
- if @current_resource.exists
- if @current_resource.status == :running
- Chef::Log.info "#{@new_resource} task is currently running, skipping run"
+ if current_resource.exists
+ if current_resource.status == :running
+ Chef::Log.info "#{new_resource} task is currently running, skipping run"
else
run_schtasks "RUN"
new_resource.updated_by_last_action true
- Chef::Log.info "#{@new_resource} task ran"
+ Chef::Log.info "#{new_resource} task ran"
end
else
- Chef::Log.warn "#{@new_resource} task doesn't exists - nothing to do"
+ Chef::Log.warn "#{new_resource} task doesn't exists - nothing to do"
end
end
def action_delete
- if @current_resource.exists
+ if current_resource.exists
# always need to force deletion
run_schtasks "DELETE", "F" => ""
new_resource.updated_by_last_action true
- Chef::Log.info "#{@new_resource} task deleted"
+ Chef::Log.info "#{new_resource} task deleted"
else
- Chef::Log.warn "#{@new_resource} task doesn't exists - nothing to do"
+ Chef::Log.warn "#{new_resource} task doesn't exists - nothing to do"
end
end
def action_end
- if @current_resource.exists
- if @current_resource.status != :running
- Chef::Log.debug "#{@new_resource} is not running - nothing to do"
+ if current_resource.exists
+ if current_resource.status != :running
+ Chef::Log.debug "#{new_resource} is not running - nothing to do"
else
run_schtasks "END"
- @new_resource.updated_by_last_action true
- Chef::Log.info "#{@new_resource} task ended"
+ new_resource.updated_by_last_action true
+ Chef::Log.info "#{new_resource} task ended"
end
else
- Chef::Log.warn "#{@new_resource} task doesn't exist - nothing to do"
+ Chef::Log.warn "#{new_resource} task doesn't exist - nothing to do"
end
end
def action_enable
- if @current_resource.exists
- if @current_resource.enabled
- Chef::Log.debug "#{@new_resource} already enabled - nothing to do"
+ if current_resource.exists
+ if current_resource.enabled
+ Chef::Log.debug "#{new_resource} already enabled - nothing to do"
else
run_schtasks "CHANGE", "ENABLE" => ""
- @new_resource.updated_by_last_action true
- Chef::Log.info "#{@new_resource} task enabled"
+ new_resource.updated_by_last_action true
+ Chef::Log.info "#{new_resource} task enabled"
end
else
- Chef::Log.fatal "#{@new_resource} task doesn't exist - nothing to do"
- raise Errno::ENOENT, "#{@new_resource}: task does not exist, cannot enable"
+ Chef::Log.fatal "#{new_resource} task doesn't exist - nothing to do"
+ raise Errno::ENOENT, "#{new_resource}: task does not exist, cannot enable"
end
end
def action_disable
- if @current_resource.exists
- if @current_resource.enabled
+ if current_resource.exists
+ if current_resource.enabled
run_schtasks "CHANGE", "DISABLE" => ""
- @new_resource.updated_by_last_action true
- Chef::Log.info "#{@new_resource} task disabled"
+ new_resource.updated_by_last_action true
+ Chef::Log.info "#{new_resource} task disabled"
else
- Chef::Log.warn "#{@new_resource} already disabled - nothing to do"
+ Chef::Log.warn "#{new_resource} already disabled - nothing to do"
end
else
- Chef::Log.warn "#{@new_resource} task doesn't exist - nothing to do"
+ Chef::Log.warn "#{new_resource} task doesn't exist - nothing to do"
end
end
@@ -160,7 +184,7 @@ class Chef
# rubocop:disable Style/StringLiteralsInInterpolation
def run_schtasks(task_action, options = {})
- cmd = "schtasks /#{task_action} /TN \"#{@new_resource.task_name}\" "
+ cmd = "schtasks /#{task_action} /TN \"#{new_resource.task_name}\" "
options.keys.each do |option|
cmd += "/#{option} "
cmd += "\"#{options[option].to_s.gsub('"', "\\\"")}\" " unless options[option] == ""
@@ -172,20 +196,21 @@ class Chef
# rubocop:enable Style/StringLiteralsInInterpolation
def task_need_update?
- return true if @current_resource.command != @new_resource.command.tr("'", '"') ||
- @current_resource.user != @new_resource.user ||
- @current_resource.run_level != @new_resource.run_level ||
- @current_resource.cwd != @new_resource.cwd ||
- @current_resource.frequency_modifier != @new_resource.frequency_modifier ||
- @current_resource.frequency != @new_resource.frequency ||
- @current_resource.idle_time != @new_resource.idle_time ||
- @current_resource.random_delay != @new_resource.random_delay ||
- @current_resource.execution_time_limit != @new_resource.execution_time_limit ||
- !@new_resource.start_day.nil? || !@new_resource.start_time.nil?
-
+ return true if (new_resource.command &&
+ current_resource.command != new_resource.command.tr("'", '"')) ||
+ current_resource.user != new_resource.user ||
+ current_resource.run_level != new_resource.run_level ||
+ current_resource.cwd != new_resource.cwd ||
+ current_resource.frequency_modifier != new_resource.frequency_modifier ||
+ current_resource.frequency != new_resource.frequency ||
+ current_resource.idle_time != new_resource.idle_time ||
+ current_resource.random_delay != new_resource.random_delay ||
+ !new_resource.execution_time_limit.include?(current_resource.execution_time_limit) ||
+ (new_resource.start_day && start_day_updated?) ||
+ (new_resource.start_time && start_time_updated?)
begin
- return true if @new_resource.day.to_s.casecmp(@current_resource.day.to_s) != 0 ||
- @new_resource.months.to_s.casecmp(@current_resource.months.to_s) != 0
+ return true if new_resource.day.to_s.casecmp(current_resource.day.to_s) != 0 ||
+ new_resource.months.to_s.casecmp(current_resource.months.to_s) != 0
rescue
Chef::Log.debug "caught a raise in task_needs_update?"
end
@@ -193,6 +218,56 @@ class Chef
false
end
+ def start_day_updated?
+ current_day = DateTime.strptime(current_resource.start_day, convert_system_date_format_to_ruby_date_format)
+ new_day = DateTime.parse(new_resource.start_day)
+ current_day != new_day
+ end
+
+ def start_time_updated?
+ time = DateTime.parse(current_resource.start_time).strftime("%H:%M")
+ time != new_resource.start_time
+ end
+
+ def convert_user_date_to_system_date(date_in_string)
+ DateTime.parse(date_in_string).strftime(convert_system_date_format_to_ruby_long_date)
+ end
+
+ def convert_system_date_format_to_ruby_long_date
+ date_format = get_system_short_date_format.dup
+ date_format.sub!("MMM", "%m")
+ common_date_format_conversion(date_format)
+ date_format.sub!("yy", "%Y")
+ date_format
+ end
+
+ def convert_system_date_format_to_ruby_date_format
+ date_format = get_system_short_date_format.dup
+ date_format.sub!("MMM", "%b")
+ common_date_format_conversion(date_format)
+ date_format.sub!("yy", "%y")
+ date_format
+ end
+
+ def common_date_format_conversion(date_format)
+ date_format.sub!("dd", "d")
+ date_format.sub!("d", "%d")
+ date_format.sub!("MM", "%m")
+ date_format.sub!("M", "%m")
+ date_format.sub!("yyyy", "%Y")
+ end
+
+ def get_system_short_date_format
+ return @system_short_date_format if @system_short_date_format
+ Chef::Log.debug "Finding system date format"
+ task_script = <<-EOH
+ [Console]::OutputEncoding = [Text.UTF8Encoding]::UTF8
+ [Globalization.Cultureinfo]::CurrentCulture.DateTimeFormat.ShortDatePattern
+ EOH
+ @system_short_date_format = powershell_out(task_script).stdout.force_encoding("UTF-8").gsub(/[\s+\uFEFF]/, "")
+ @system_short_date_format
+ end
+
def update_task_xml(options = [])
# random_delay xml element is different for different frequencies
random_delay_xml_element = {
@@ -206,7 +281,7 @@ class Chef
xml_element_mapping = {
"cwd" => "Actions/Exec/WorkingDirectory",
- "random_delay" => random_delay_xml_element[@new_resource.frequency],
+ "random_delay" => random_delay_xml_element[new_resource.frequency],
"execution_time_limit" => "Settings/ExecutionTimeLimit",
}
@@ -214,7 +289,7 @@ class Chef
task_script = <<-EOH
[Console]::OutputEncoding = [Text.UTF8Encoding]::UTF8
- schtasks /Query /TN \"#{@new_resource.task_name}\" /XML
+ schtasks /Query /TN \"#{new_resource.task_name}\" /XML
EOH
xml_cmd = powershell_out(task_script)
@@ -225,7 +300,7 @@ class Chef
options.each do |option|
Chef::Log.debug 'Removing former #{option} if any'
doc.root.elements.delete(xml_element_mapping[option])
- option_value = @new_resource.send("#{option}")
+ option_value = new_resource.send("#{option}")
if option_value
Chef::Log.debug "Setting #option as #option_value"
@@ -246,9 +321,9 @@ class Chef
end
options = {}
- options["RU"] = @new_resource.user if @new_resource.user
- options["RP"] = @new_resource.password if @new_resource.password
- options["IT"] = "" if @new_resource.interactive_enabled
+ options["RU"] = new_resource.user if new_resource.user
+ options["RP"] = new_resource.password if new_resource.password
+ options["IT"] = "" if new_resource.interactive_enabled
options["XML"] = temp_task_file
run_schtasks("DELETE", "F" => "")
@@ -345,26 +420,26 @@ class Chef
SYSTEM_USERS = ['NT AUTHORITY\SYSTEM', "SYSTEM", 'NT AUTHORITY\LOCALSERVICE', 'NT AUTHORITY\NETWORKSERVICE', 'BUILTIN\USERS', "USERS"].freeze
def use_password?
- @use_password ||= !SYSTEM_USERS.include?(@new_resource.user.upcase)
+ @use_password ||= !SYSTEM_USERS.include?(new_resource.user.upcase)
end
def schedule
- case @new_resource.frequency
+ case new_resource.frequency
when :on_logon
"ONLOGON"
when :on_idle
"ONIDLE"
else
- @new_resource.frequency
+ new_resource.frequency
end
end
def frequency_modifier_allowed
- case @new_resource.frequency
+ case new_resource.frequency
when :minute, :hourly, :daily, :weekly
true
when :monthly
- @new_resource.months.nil? || %w{ FIRST SECOND THIRD FOURTH LAST LASTDAY }.include?(@new_resource.frequency_modifier)
+ new_resource.months.nil? || %w{ FIRST SECOND THIRD FOURTH LAST LASTDAY }.include?(new_resource.frequency_modifier)
else
false
end
@@ -373,9 +448,9 @@ class Chef
def set_current_run_level(run_level)
case run_level
when "HighestAvailable"
- @current_resource.run_level(:highest)
+ current_resource.run_level(:highest)
when "LeastPrivilege"
- @current_resource.run_level(:limited)
+ current_resource.run_level(:limited)
end
end
@@ -383,34 +458,34 @@ class Chef
if task_hash[:repetition_interval]
duration = ISO8601::Duration.new(task_hash[:repetition_interval])
if task_hash[:repetition_interval].include?("M")
- @current_resource.frequency(:minute)
- @current_resource.frequency_modifier(duration.minutes.atom.to_i)
+ current_resource.frequency(:minute)
+ current_resource.frequency_modifier(duration.minutes.atom.to_i)
elsif task_hash[:repetition_interval].include?("H")
- @current_resource.frequency(:hourly)
- @current_resource.frequency_modifier(duration.hours.atom.to_i)
+ current_resource.frequency(:hourly)
+ current_resource.frequency_modifier(duration.hours.atom.to_i)
end
end
if task_hash[:schedule_by_day]
- @current_resource.frequency(:daily)
- @current_resource.frequency_modifier(task_hash[:schedule_by_day].to_i)
+ current_resource.frequency(:daily)
+ current_resource.frequency_modifier(task_hash[:schedule_by_day].to_i)
end
if task_hash[:schedule_by_week]
- @current_resource.frequency(:weekly)
- @current_resource.frequency_modifier(task_hash[:schedule_by_week].to_i)
+ current_resource.frequency(:weekly)
+ current_resource.frequency_modifier(task_hash[:schedule_by_week].to_i)
end
- @current_resource.frequency(:monthly) if task_hash[:schedule_by_month]
- @current_resource.frequency(:on_logon) if task_hash[:on_logon]
- @current_resource.frequency(:onstart) if task_hash[:onstart]
- @current_resource.frequency(:on_idle) if task_hash[:on_idle]
- @current_resource.frequency(:once) if task_hash[:once]
+ current_resource.frequency(:monthly) if task_hash[:schedule_by_month]
+ current_resource.frequency(:on_logon) if task_hash[:on_logon]
+ current_resource.frequency(:onstart) if task_hash[:onstart]
+ current_resource.frequency(:on_idle) if task_hash[:on_idle]
+ current_resource.frequency(:once) if task_hash[:once]
end
def set_current_idle_time(idle_time)
duration = ISO8601::Duration.new(idle_time)
- @current_resource.idle_time(duration.minutes.atom.to_i)
+ current_resource.idle_time(duration.minutes.atom.to_i)
end
end
diff --git a/lib/chef/provider/yum_repository.rb b/lib/chef/provider/yum_repository.rb
index a5d3c2bc39..957ee9f0f3 100644
--- a/lib/chef/provider/yum_repository.rb
+++ b/lib/chef/provider/yum_repository.rb
@@ -18,9 +18,7 @@
require "chef/resource"
require "chef/dsl/declare_resource"
-require "chef/mixin/shell_out"
require "chef/mixin/which"
-require "chef/http/simple"
require "chef/provider/noop"
class Chef
diff --git a/lib/chef/provider/zypper_repository.rb b/lib/chef/provider/zypper_repository.rb
new file mode 100644
index 0000000000..e6fd917d77
--- /dev/null
+++ b/lib/chef/provider/zypper_repository.rb
@@ -0,0 +1,81 @@
+#
+# Author:: Tim Smith (<tsmith@chef.io>)
+# Copyright:: Copyright (c) 2017, Chef Software 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"
+require "chef/dsl/declare_resource"
+require "chef/mixin/which"
+require "chef/provider/noop"
+require "shellwords"
+
+class Chef
+ class Provider
+ class ZypperRepository < Chef::Provider
+
+ extend Chef::Mixin::Which
+
+ provides :zypper_repository do
+ which "zypper"
+ end
+
+ def load_current_resource
+ end
+
+ action :create do
+ declare_resource(:template, "/etc/zypp/repos.d/#{escaped_repo_name}.repo") do
+ if template_available?(new_resource.source)
+ source new_resource.source
+ else
+ source ::File.expand_path("../support/zypper_repo.erb", __FILE__)
+ local true
+ end
+ sensitive new_resource.sensitive
+ variables(config: new_resource)
+ mode new_resource.mode
+ notifies :refresh, new_resource, :immediately if new_resource.refresh_cache
+ end
+ end
+
+ action :delete do
+ declare_resource(:execute, "zypper removerepo #{escaped_repo_name}") do
+ only_if "zypper lr #{escaped_repo_name}"
+ end
+ end
+
+ action :refresh do
+ declare_resource(:execute, "zypper#{' --gpg-auto-import-keys' if new_resource.gpgautoimportkeys} --quiet --no-confirm refresh --force #{escaped_repo_name}") do
+ only_if "zypper lr #{escaped_repo_name}"
+ end
+ end
+
+ alias_method :action_add, :action_create
+ alias_method :action_remove, :action_delete
+
+ # zypper repos are allowed to have spaces in the names
+ def escaped_repo_name
+ Shellwords.escape(new_resource.repo_name)
+ end
+
+ def template_available?(path)
+ !path.nil? && run_context.has_template_in_cookbook?(new_resource.cookbook_name, path)
+ end
+
+ end
+ end
+end
+
+Chef::Provider::Noop.provides :zypper_repository
diff --git a/lib/chef/providers.rb b/lib/chef/providers.rb
index 0ea1786594..a3332477e7 100644
--- a/lib/chef/providers.rb
+++ b/lib/chef/providers.rb
@@ -17,6 +17,7 @@
#
require "chef/provider/apt_update"
+require "chef/provider/apt_preference"
require "chef/provider/apt_repository"
require "chef/provider/batch"
require "chef/provider/cookbook_file"
@@ -59,6 +60,8 @@ require "chef/provider/user"
require "chef/provider/whyrun_safe_ruby_block"
require "chef/provider/yum_repository"
require "chef/provider/windows_task"
+require "chef/provider/zypper_repository"
+require "chef/provider/windows_path"
require "chef/provider/env/windows"
diff --git a/lib/chef/resource.rb b/lib/chef/resource.rb
index ca6603c06a..5436e3ceb3 100644
--- a/lib/chef/resource.rb
+++ b/lib/chef/resource.rb
@@ -641,7 +641,11 @@ class Chef
all_props = {}
self.class.state_properties.map do |p|
- all_props[p.name.to_s] = p.sensitive? ? '"*sensitive value suppressed*"' : value_to_text(p.get(self))
+ begin
+ all_props[p.name.to_s] = p.sensitive? ? '"*sensitive value suppressed*"' : value_to_text(p.get(self))
+ rescue Chef::Exceptions::ValidationFailed
+ # This space left intentionally blank, the property was probably required or had an invalid default.
+ end
end
ivars = instance_variables.map { |ivar| ivar.to_sym } - HIDDEN_IVARS
diff --git a/lib/chef/resource/apt_package.rb b/lib/chef/resource/apt_package.rb
index 069fefcb2b..8397f84c71 100644
--- a/lib/chef/resource/apt_package.rb
+++ b/lib/chef/resource/apt_package.rb
@@ -23,7 +23,7 @@ class Chef
class Resource
class AptPackage < Chef::Resource::Package
resource_name :apt_package
- provides :package, os: "linux", platform_family: [ "debian" ]
+ provides :package, os: "linux", platform_family: "debian"
property :default_release, String, desired_state: false
diff --git a/lib/chef/resource/apt_preference.rb b/lib/chef/resource/apt_preference.rb
new file mode 100644
index 0000000000..603766d76b
--- /dev/null
+++ b/lib/chef/resource/apt_preference.rb
@@ -0,0 +1,36 @@
+#
+# Author:: Tim Smith (<tsmith@chef.io>)
+# Copyright:: 2016-2017, Chef Software, 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"
+
+class Chef
+ class Resource
+ class AptPreference < Chef::Resource
+ resource_name :apt_preference
+ provides :apt_preference
+
+ property :package_name, String, name_property: true, regex: [/^([a-z]|[A-Z]|[0-9]|_|-|\.|\*|\+)+$/]
+ property :glob, String
+ property :pin, String, required: true
+ property :pin_priority, [String, Integer], required: true
+
+ default_action :add
+ allowed_actions :add, :remove
+ end
+ end
+end
diff --git a/lib/chef/resource/apt_repository.rb b/lib/chef/resource/apt_repository.rb
index b38bd1c8ec..8b69435246 100644
--- a/lib/chef/resource/apt_repository.rb
+++ b/lib/chef/resource/apt_repository.rb
@@ -1,6 +1,6 @@
#
# Author:: Thom May (<thom@chef.io>)
-# Copyright:: Copyright (c) 2016 Chef Software, Inc.
+# Copyright:: 2016-2017, Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -33,7 +33,7 @@ class Chef
# whether or not to add the repository as a source repo, too
property :deb_src, [TrueClass, FalseClass], default: false
property :keyserver, [String, nil, false], default: "keyserver.ubuntu.com", nillable: true, coerce: proc { |x| x ? x : nil }
- property :key, [String, nil, false], default: nil, nillable: true, coerce: proc { |x| x ? x : nil }
+ property :key, [String, Array, nil, false], default: [], coerce: proc { |x| x ? Array(x) : nil }
property :key_proxy, [String, nil, false], default: nil, nillable: true, coerce: proc { |x| x ? x : nil }
property :cookbook, [String, nil, false], default: nil, desired_state: false, nillable: true, coerce: proc { |x| x ? x : nil }
diff --git a/lib/chef/resource/execute.rb b/lib/chef/resource/execute.rb
index dee497e74f..ba1b8ae6e3 100644
--- a/lib/chef/resource/execute.rb
+++ b/lib/chef/resource/execute.rb
@@ -132,6 +132,8 @@ class Chef
property :sensitive, [ TrueClass, FalseClass ], default: false, coerce: proc { |x| password ? true : x }
+ property :elevated, [ TrueClass, FalseClass ], default: false
+
def self.set_guard_inherited_attributes(*inherited_attributes)
@class_inherited_attributes = inherited_attributes
end
@@ -149,21 +151,29 @@ class Chef
end
def after_created
- validate_identity_platform(user, password, domain)
+ validate_identity_platform(user, password, domain, elevated)
identity = qualify_user(user, password, domain)
domain(identity[:domain])
user(identity[:user])
end
- def validate_identity_platform(specified_user, password = nil, specified_domain = nil)
+ def validate_identity_platform(specified_user, password = nil, specified_domain = nil, elevated = false)
if node[:platform_family] == "windows"
if specified_user && password.nil?
raise ArgumentError, "A value for `password` must be specified when a value for `user` is specified on the Windows platform"
end
+
+ if elevated && !specified_user && !password
+ raise ArgumentError, "`elevated` option should be passed only with `username` and `password`."
+ end
else
if password || specified_domain
raise Exceptions::UnsupportedPlatform, "Values for `domain` and `password` are only supported on the Windows platform"
end
+
+ if elevated
+ raise Exceptions::UnsupportedPlatform, "Value for `elevated` is only supported on the Windows platform"
+ end
end
end
diff --git a/lib/chef/resource/http_request.rb b/lib/chef/resource/http_request.rb
index fcc48470bc..9fac3562f3 100644
--- a/lib/chef/resource/http_request.rb
+++ b/lib/chef/resource/http_request.rb
@@ -27,7 +27,7 @@ class Chef
identity_attr :url
default_action :get
- allowed_actions :get, :put, :post, :delete, :head, :options
+ allowed_actions :get, :patch, :put, :post, :delete, :head, :options
def initialize(name, run_context = nil)
super
diff --git a/lib/chef/resource/ifconfig.rb b/lib/chef/resource/ifconfig.rb
index fd523d9580..3673311348 100644
--- a/lib/chef/resource/ifconfig.rb
+++ b/lib/chef/resource/ifconfig.rb
@@ -44,6 +44,10 @@ class Chef
@network = nil
@bootproto = nil
@onparent = nil
+ @ethtool_opts = nil
+ @bonding_opts = nil
+ @master = nil
+ @slave = nil
end
def target(arg = nil)
@@ -141,6 +145,38 @@ class Chef
:kind_of => String
)
end
+
+ def ethtool_opts(arg = nil)
+ set_or_return(
+ :ethtool_opts,
+ arg,
+ :kind_of => String
+ )
+ end
+
+ def bonding_opts(arg = nil)
+ set_or_return(
+ :bonding_opts,
+ arg,
+ :kind_of => String
+ )
+ end
+
+ def master(arg = nil)
+ set_or_return(
+ :master,
+ arg,
+ :kind_of => String
+ )
+ end
+
+ def slave(arg = nil)
+ set_or_return(
+ :slave,
+ arg,
+ :kind_of => String
+ )
+ end
end
end
diff --git a/lib/chef/resource/remote_file.rb b/lib/chef/resource/remote_file.rb
index 4a1d1c6cff..25586af702 100644
--- a/lib/chef/resource/remote_file.rb
+++ b/lib/chef/resource/remote_file.rb
@@ -131,6 +131,66 @@ class Chef
)
end
+ property :remote_user, String
+
+ property :remote_domain, String
+
+ property :remote_password, String, sensitive: true
+
+ def after_created
+ validate_identity_platform(remote_user, remote_password, remote_domain)
+ identity = qualify_user(remote_user, remote_password, remote_domain)
+ remote_domain(identity[:domain])
+ remote_user(identity[:user])
+ end
+
+ def validate_identity_platform(specified_user, password = nil, specified_domain = nil)
+ if node[:platform_family] == "windows"
+ if specified_user && password.nil?
+ raise ArgumentError, "A value for `remote_password` must be specified when a value for `user` is specified on the Windows platform"
+ end
+ end
+ end
+
+ def qualify_user(specified_user, password = nil, specified_domain = nil)
+ domain = specified_domain
+ user = specified_user
+
+ if specified_user.nil? && ! specified_domain.nil?
+ raise ArgumentError, "The domain `#{specified_domain}` was specified, but no user name was given"
+ end
+
+ # if domain is provided in both username and domain
+ if specified_user && ((specified_user.include? '\\') || (specified_user.include? "@")) && specified_domain
+ raise ArgumentError, "The domain is provided twice. Username: `#{specified_user}`, Domain: `#{specified_domain}`. Please specify domain only once."
+ end
+
+ if ! specified_user.nil? && specified_domain.nil?
+ # Splitting username of format: Domain\Username
+ domain_and_user = user.split('\\')
+
+ if domain_and_user.length == 2
+ domain = domain_and_user[0]
+ user = domain_and_user[1]
+ elsif domain_and_user.length == 1
+ # Splitting username of format: Username@Domain
+ domain_and_user = user.split("@")
+ if domain_and_user.length == 2
+ domain = domain_and_user[1]
+ user = domain_and_user[0]
+ elsif domain_and_user.length != 1
+ raise ArgumentError, "The specified user name `#{user}` is not a syntactically valid user name"
+ end
+ end
+ end
+
+ if ( password || domain ) && user.nil?
+ raise ArgumentError, "A value for `password` or `domain` was specified without specification of a value for `user`"
+ end
+
+ { domain: domain, user: user }
+ end
+
private
include Chef::Mixin::Uris
diff --git a/lib/chef/resource/windows_path.rb b/lib/chef/resource/windows_path.rb
new file mode 100644
index 0000000000..5472a7e4fd
--- /dev/null
+++ b/lib/chef/resource/windows_path.rb
@@ -0,0 +1,41 @@
+#
+# Author:: Nimisha Sharad (<nimisha.sharad@msystechnologies.com>)
+# Copyright:: Copyright 2008-2017, Chef Software 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"
+
+class Chef
+ class Resource
+ class WindowsPath < Chef::Resource
+
+ provides :windows_path, os: "windows"
+
+ allowed_actions :add, :remove
+ default_action :add
+
+ def initialize(name, run_context = nil)
+ super
+ @resource_name = :windows_path
+ @path = name
+ @provider = Chef::Provider::WindowsPath
+ @action = :add
+ end
+
+ property :path, String, name_property: true
+ end
+ end
+end
diff --git a/lib/chef/resource/yum_repository.rb b/lib/chef/resource/yum_repository.rb
index f59ad56d16..012a74908a 100644
--- a/lib/chef/resource/yum_repository.rb
+++ b/lib/chef/resource/yum_repository.rb
@@ -24,11 +24,12 @@ class Chef
resource_name :yum_repository
provides :yum_repository
- # http://linux.die.net/man/5/yum.conf
+ # http://linux.die.net/man/5/yum.conf as well as
+ # http://dnf.readthedocs.io/en/latest/conf_ref.html
property :baseurl, [String, Array], regex: /.*/
- property :cost, String, regex: /^\d+$/
property :clean_headers, [TrueClass, FalseClass], default: false # deprecated
property :clean_metadata, [TrueClass, FalseClass], default: true
+ property :cost, String, regex: /^\d+$/
property :description, String, regex: /.*/, default: "Yum Repository"
property :enabled, [TrueClass, FalseClass], default: true
property :enablegroups, [TrueClass, FalseClass]
@@ -44,17 +45,18 @@ class Chef
property :make_cache, [TrueClass, FalseClass], default: true
property :max_retries, [String, Integer]
property :metadata_expire, String, regex: [/^\d+$/, /^\d+[mhd]$/, /never/]
- property :mirrorexpire, String, regex: /.*/
- property :mirrorlist, String, regex: /.*/
+ property :metalink, String, regex: /.*/
property :mirror_expire, String, regex: [/^\d+$/, /^\d+[mhd]$/]
+ property :mirrorexpire, String, regex: /.*/
property :mirrorlist_expire, String, regex: [/^\d+$/, /^\d+[mhd]$/]
+ property :mirrorlist, String, regex: /.*/
property :mode, default: "0644"
+ property :options, Hash
+ property :password, String, regex: /.*/
property :priority, String, regex: /^(\d?[0-9]|[0-9][0-9])$/
- property :proxy, String, regex: /.*/
- property :proxy_username, String, regex: /.*/
property :proxy_password, String, regex: /.*/
- property :username, String, regex: /.*/
- property :password, String, regex: /.*/
+ property :proxy_username, String, regex: /.*/
+ property :proxy, String, regex: /.*/
property :repo_gpgcheck, [TrueClass, FalseClass]
property :report_instanceid, [TrueClass, FalseClass]
property :repositoryid, String, regex: /.*/, name_property: true
@@ -65,7 +67,8 @@ class Chef
property :sslclientkey, String, regex: /.*/
property :sslverify, [TrueClass, FalseClass]
property :timeout, String, regex: /^\d+$/
- property :options, Hash
+ property :throttle, [String, Integer]
+ property :username, String, regex: /.*/
default_action :create
allowed_actions :create, :remove, :makecache, :add, :delete
diff --git a/lib/chef/resource/zypper_repository.rb b/lib/chef/resource/zypper_repository.rb
new file mode 100644
index 0000000000..69a96b42cf
--- /dev/null
+++ b/lib/chef/resource/zypper_repository.rb
@@ -0,0 +1,52 @@
+#
+# Author:: Tim Smith (<tsmith@chef.io>)
+# Copyright:: Copyright (c) 2017 Chef Software, 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"
+
+class Chef
+ class Resource
+ class ZypperRepository < Chef::Resource
+ resource_name :zypper_repository
+ provides :zypper_repo
+
+ property :repo_name, String, name_property: true
+ property :description, String
+ property :type, String, default: "NONE"
+ property :enabled, [true, false], default: true
+ property :autorefresh, [true, false], default: true
+ property :gpgcheck, [true, false], default: true
+ property :gpgkey, String
+ property :baseurl, String
+ property :mirrorlist, String
+ property :path, String
+ property :priority, Integer, default: 99
+ property :keeppackages, [true, false], default: false
+ property :mode, default: "0644"
+ property :refresh_cache, [true, false], default: true
+ property :source, String, regex: /.*/
+ property :gpgautoimportkeys, [true, false], default: true
+
+ default_action :create
+ allowed_actions :create, :remove, :add, :refresh
+
+ # provide compatibility with the zypper cookbook
+ alias_method :key, :gpgkey
+ alias_method :uri, :baseurl
+ end
+ end
+end
diff --git a/lib/chef/resources.rb b/lib/chef/resources.rb
index 9f87cb2454..54d21fd53c 100644
--- a/lib/chef/resources.rb
+++ b/lib/chef/resources.rb
@@ -17,6 +17,7 @@
#
require "chef/resource/apt_package"
+require "chef/resource/apt_preference"
require "chef/resource/apt_repository"
require "chef/resource/apt_update"
require "chef/resource/bash"
@@ -95,7 +96,9 @@ require "chef/resource/yum_repository"
require "chef/resource/lwrp_base"
require "chef/resource/bff_package"
require "chef/resource/zypper_package"
+require "chef/resource/zypper_repository"
require "chef/resource/cab_package"
require "chef/resource/powershell_package"
require "chef/resource/msu_package"
require "chef/resource/windows_task"
+require "chef/resource/windows_path"
diff --git a/lib/chef/search/query.rb b/lib/chef/search/query.rb
index 6f494819ba..a2663d111d 100644
--- a/lib/chef/search/query.rb
+++ b/lib/chef/search/query.rb
@@ -71,6 +71,11 @@ class Chef
args_h = args_h.reject { |k, v| k == :fuzz }
end
+ # Set default rows parameter to 1000. This is the default in
+ # Chef Server, but we set it explicitly here so that we can
+ # confidently advance our start parameter.
+ args_h[:rows] ||= 1000
+
response = call_rest_service(type, query: query, **args_h)
if block
@@ -87,7 +92,7 @@ class Chef
# args_h[:rows] to avoid asking the search backend for
# overlapping pages (which could result in duplicates).
#
- next_start = response["start"] + (args_h[:rows] || response["rows"].length)
+ next_start = response["start"] + args_h[:rows]
unless next_start >= response["total"]
args_h[:start] = next_start
search(type, query, args_h, &block)
diff --git a/lib/chef/server_api_versions.rb b/lib/chef/server_api_versions.rb
index 2a4d0e6a5b..40fb6385e1 100644
--- a/lib/chef/server_api_versions.rb
+++ b/lib/chef/server_api_versions.rb
@@ -26,15 +26,34 @@ class Chef
end
def min_server_version
- !@versions.nil? ? Integer(@versions["min_version"]) : nil
+ # If we're working with a pre-api-versioning server, always claim to be zero
+ if @versions.nil?
+ unversioned? ? 0 : nil
+ else
+ Integer(@versions["min_version"])
+ end
end
def max_server_version
- !@versions.nil? ? Integer(@versions["max_version"]) : nil
+ # If we're working with a pre-api-versioning server, always claim to be zero
+ if @versions.nil?
+ unversioned? ? 0 : nil
+ else
+ Integer(@versions["max_version"])
+ end
+ end
+
+ def unversioned!
+ @unversioned = true
+ end
+
+ def unversioned?
+ @unversioned
end
def reset!
@versions = nil
+ @unversioned = false
end
end
end
diff --git a/lib/chef/shell.rb b/lib/chef/shell.rb
index b4c0277c57..40bdf01762 100644
--- a/lib/chef/shell.rb
+++ b/lib/chef/shell.rb
@@ -138,6 +138,7 @@ module Shell
def self.session
unless client_type.instance.node_built?
puts "Session type: #{client_type.session_type}"
+ client_type.instance.json_configuration = @json_attribs
client_type.instance.reset!
end
client_type.instance
diff --git a/lib/chef/shell/shell_session.rb b/lib/chef/shell/shell_session.rb
index 41d5bd64a0..dfed5372c1 100644
--- a/lib/chef/shell/shell_session.rb
+++ b/lib/chef/shell/shell_session.rb
@@ -38,7 +38,7 @@ module Shell
@session_type
end
- attr_accessor :node, :compile, :recipe, :run_context
+ attr_accessor :node, :compile, :recipe, :run_context, :json_configuration
attr_reader :node_attributes, :client
def initialize
@node_built = false
@@ -151,7 +151,7 @@ module Shell
def rebuild_node
Chef::Config[:solo_legacy_mode] = true
- @client = Chef::Client.new(nil, Chef::Config[:shell_config])
+ @client = Chef::Client.new(json_configuration, Chef::Config[:shell_config])
@client.run_ohai
@client.load_node
@client.build_node
@@ -183,7 +183,7 @@ module Shell
def rebuild_node
# Tell the client we're chef solo so it won't try to contact the server
Chef::Config[:solo_legacy_mode] = true
- @client = Chef::Client.new(nil, Chef::Config[:shell_config])
+ @client = Chef::Client.new(json_configuration, Chef::Config[:shell_config])
@client.run_ohai
@client.load_node
@client.build_node
@@ -218,7 +218,7 @@ module Shell
def rebuild_node
# Make sure the client knows this is not chef solo
Chef::Config[:solo_legacy_mode] = false
- @client = Chef::Client.new(nil, Chef::Config[:shell_config])
+ @client = Chef::Client.new(json_configuration, Chef::Config[:shell_config])
@client.run_ohai
@client.register
@client.load_node
diff --git a/lib/chef/util/dsc/local_configuration_manager.rb b/lib/chef/util/dsc/local_configuration_manager.rb
index d837a16185..1f154b1c71 100644
--- a/lib/chef/util/dsc/local_configuration_manager.rb
+++ b/lib/chef/util/dsc/local_configuration_manager.rb
@@ -47,15 +47,13 @@ class Chef::Util::DSC
def run_configuration_cmdlet(configuration_document, apply_configuration, shellout_flags)
Chef::Log.debug("DSC: Calling DSC Local Config Manager to #{apply_configuration ? "set" : "test"} configuration document.")
- test_only_parameters = ! apply_configuration ? "-whatif; if (! $?) { exit 1 }" : ""
start_operation_timing
- command_code = lcm_command_code(@configuration_path, test_only_parameters)
status = nil
begin
save_configuration_document(configuration_document)
- cmdlet = ::Chef::Util::Powershell::Cmdlet.new(@node, "#{command_code}")
+ cmdlet = ::Chef::Util::Powershell::Cmdlet.new(@node, lcm_command(apply_configuration))
if apply_configuration
status = cmdlet.run!({}, shellout_flags)
else
@@ -72,10 +70,22 @@ class Chef::Util::DSC
status
end
- def lcm_command_code(configuration_path, test_only_parameters)
- <<-EOH
-$ProgressPreference = 'SilentlyContinue';start-dscconfiguration -path #{@configuration_path} -wait -erroraction 'stop' -force #{test_only_parameters}
-EOH
+ def lcm_command(apply_configuration)
+ common_command_prefix = "$ProgressPreference = 'SilentlyContinue';"
+ ps4_base_command = "#{common_command_prefix} Start-DscConfiguration -path #{@configuration_path} -wait -erroraction 'stop' -force"
+ if apply_configuration
+ ps4_base_command
+ else
+ if ps_version_gte_5?
+ "#{common_command_prefix} Test-DscConfiguration -path #{@configuration_path}"
+ else
+ ps4_base_command + " -whatif; if (! $?) { exit 1 }"
+ end
+ end
+ end
+
+ def ps_version_gte_5?
+ Chef::Platform.supported_powershell_version?(@node, 5)
end
def log_what_if_exception(what_if_exception_output)
diff --git a/lib/chef/util/windows/logon_session.rb b/lib/chef/util/windows/logon_session.rb
new file mode 100644
index 0000000000..ef80b113b1
--- /dev/null
+++ b/lib/chef/util/windows/logon_session.rb
@@ -0,0 +1,126 @@
+#
+# Author:: Adam Edwards (<adamed@chef.io>)
+#
+# Copyright:: Copyright (c) 2015 Chef Software, Inc.
+#
+# 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/security" if Chef::Platform.windows?
+require "chef/mixin/wide_string"
+
+class Chef
+ class Util
+ class Windows
+ class LogonSession
+ include Chef::Mixin::WideString
+
+ def initialize(username, password, domain = nil)
+ if username.nil? || password.nil?
+ raise ArgumentError, "The logon session must be initialize with non-nil user name and password parameters"
+ end
+
+ @original_username = username
+ @original_password = password
+ @original_domain = domain
+ @token = FFI::Buffer.new(:pointer)
+ @session_opened = false
+ @impersonating = false
+ end
+
+ def open
+ if session_opened
+ raise "Attempted to open a logon session that was already open."
+ end
+
+ username = wstring(original_username)
+ password = wstring(original_password)
+ domain = wstring(original_domain)
+
+ status = Chef::ReservedNames::Win32::API::Security.LogonUserW(username, domain, password, Chef::ReservedNames::Win32::API::Security::LOGON32_LOGON_NEW_CREDENTIALS, Chef::ReservedNames::Win32::API::Security::LOGON32_PROVIDER_DEFAULT, token)
+
+ if !status
+ last_error = FFI::LastError.error
+ raise Chef::Exceptions::Win32APIError, "Logon for user `#{original_username}` failed with Win32 status #{last_error}."
+ end
+
+ @session_opened = true
+ end
+
+ def close
+ validate_session_open!
+
+ if impersonating
+ restore_user_context
+ end
+
+ Chef::ReservedNames::Win32::API::System.CloseHandle(token.read_ulong)
+ @token = nil
+ @session_opened = false
+ end
+
+ def set_user_context
+ validate_session_open!
+
+ if ! session_opened
+ raise "Attempted to set the user context before opening a session."
+ end
+
+ if impersonating
+ raise "Attempt to set the user context when the user context is already set."
+ end
+
+ status = Chef::ReservedNames::Win32::API::Security.ImpersonateLoggedOnUser(token.read_ulong)
+
+ if !status
+ last_error = FFI::LastError.error
+ raise Chef::Exceptions::Win32APIError, "Attempt to impersonate user `#{original_username}` failed with Win32 status #{last_error}."
+ end
+
+ @impersonating = true
+ end
+
+ def restore_user_context
+ validate_session_open!
+
+ if impersonating
+ status = Chef::ReservedNames::Win32::API::Security.RevertToSelf
+
+ if !status
+ last_error = FFI::LastError.error
+ raise Chef::Exceptions::Win32APIError, "Unable to restore user context with Win32 status #{last_error}."
+ end
+ end
+
+ @impersonating = false
+ end
+
+ protected
+
+ attr_reader :original_username
+ attr_reader :original_password
+ attr_reader :original_domain
+
+ attr_reader :token
+ attr_reader :session_opened
+ attr_reader :impersonating
+
+ def validate_session_open!
+ if ! session_opened
+ raise "Attempted to set the user context before opening a session."
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/version.rb b/lib/chef/version.rb
index b969e726a5..e30285d620 100644
--- a/lib/chef/version.rb
+++ b/lib/chef/version.rb
@@ -23,7 +23,7 @@ require "chef/version_string"
class Chef
CHEF_ROOT = File.expand_path("../..", __FILE__)
- VERSION = Chef::VersionString.new("13.3.1")
+ VERSION = Chef::VersionString.new("13.4.33")
end
#
diff --git a/lib/chef/win32/api/file.rb b/lib/chef/win32/api/file.rb
index 355cc81378..6aa2927e1f 100644
--- a/lib/chef/win32/api/file.rb
+++ b/lib/chef/win32/api/file.rb
@@ -67,6 +67,7 @@ class Chef
MAX_PATH = 260
SYMBOLIC_LINK_FLAG_DIRECTORY = 0x1
+ SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE = 0x2
FILE_NAME_NORMALIZED = 0x0
FILE_NAME_OPENED = 0x8
diff --git a/lib/chef/win32/api/security.rb b/lib/chef/win32/api/security.rb
index a2cfe35dad..a6f79f5d7d 100644
--- a/lib/chef/win32/api/security.rb
+++ b/lib/chef/win32/api/security.rb
@@ -453,6 +453,8 @@ class Chef
safe_attach_function :SetSecurityDescriptorSacl, [ :pointer, :BOOL, :pointer, :BOOL ], :BOOL
safe_attach_function :GetTokenInformation, [ :HANDLE, :TOKEN_INFORMATION_CLASS, :pointer, :DWORD, :PDWORD ], :BOOL
safe_attach_function :LogonUserW, [:LPTSTR, :LPTSTR, :LPTSTR, :DWORD, :DWORD, :PHANDLE], :BOOL
+ safe_attach_function :ImpersonateLoggedOnUser, [:HANDLE], :BOOL
+ safe_attach_function :RevertToSelf, [], :BOOL
end
end
diff --git a/lib/chef/win32/file.rb b/lib/chef/win32/file.rb
index fa3d0f7a9d..03d4496fa8 100644
--- a/lib/chef/win32/file.rb
+++ b/lib/chef/win32/file.rb
@@ -22,6 +22,7 @@ require "chef/win32/api/file"
require "chef/win32/api/security"
require "chef/win32/error"
require "chef/win32/unicode"
+require "chef/win32/version"
class Chef
module ReservedNames::Win32
@@ -60,6 +61,7 @@ class Chef
# TODO do a check for CreateSymbolicLinkW and
# raise NotImplemented exception on older Windows
flags = ::File.directory?(old_name) ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0
+ flags |= SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE if Chef::ReservedNames::Win32::Version.new.win_10_creators_or_higher?
old_name = encode_path(old_name)
new_name = encode_path(new_name)
unless CreateSymbolicLinkW(new_name, old_name, flags)
diff --git a/lib/chef/win32/version.rb b/lib/chef/win32/version.rb
index 3e2d6bc1fe..f8228d40b3 100644
--- a/lib/chef/win32/version.rb
+++ b/lib/chef/win32/version.rb
@@ -30,6 +30,8 @@ class Chef
include Chef::ReservedNames::Win32::API::Macros
include Chef::ReservedNames::Win32::API::System
+ attr_reader :major_version, :minor_version, :build_number
+
# Ruby implementation of
# http://msdn.microsoft.com/en-us/library/ms724833(v=vs.85).aspx
# http://msdn.microsoft.com/en-us/library/ms724358(v=vs.85).aspx
@@ -114,6 +116,10 @@ class Chef
end
end
+ def win_10_creators_or_higher?
+ windows_10? && build_number >= 15063
+ end
+
private
def get_version