summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md17
-rw-r--r--CHEF_MVPS.md17
-rw-r--r--Gemfile.lock30
-rw-r--r--VERSION2
-rw-r--r--chef-config/lib/chef-config/version.rb2
-rw-r--r--lib/chef/api_client/registration.rb12
-rw-r--r--lib/chef/chef_fs/chef_fs_data_store.rb45
-rw-r--r--lib/chef/chef_fs/data_handler/organization_invites_data_handler.rb2
-rw-r--r--lib/chef/exceptions.rb2
-rw-r--r--lib/chef/knife/configure.rb4
-rw-r--r--lib/chef/knife/ssh.rb9
-rw-r--r--lib/chef/mixin/params_validate.rb28
-rw-r--r--lib/chef/mixin/properties.rb13
-rw-r--r--lib/chef/node_map.rb26
-rw-r--r--lib/chef/property.rb22
-rw-r--r--lib/chef/provider.rb14
-rw-r--r--lib/chef/provider/env/windows.rb76
-rw-r--r--lib/chef/provider/registry_key.rb20
-rw-r--r--lib/chef/provider/remote_file/http.rb11
-rw-r--r--lib/chef/provider/systemd_unit.rb20
-rw-r--r--lib/chef/provider/windows_env.rb (renamed from lib/chef/provider/env.rb)60
-rw-r--r--lib/chef/providers.rb4
-rw-r--r--lib/chef/resource.rb25
-rw-r--r--lib/chef/resource/hostname.rb252
-rw-r--r--lib/chef/resource/rhsm_errata.rb45
-rw-r--r--lib/chef/resource/rhsm_errata_level.rb53
-rw-r--r--lib/chef/resource/rhsm_register.rb170
-rw-r--r--lib/chef/resource/rhsm_repo.rb63
-rw-r--r--lib/chef/resource/rhsm_subscription.rb96
-rw-r--r--lib/chef/resource/systemd_unit.rb5
-rw-r--r--lib/chef/resource/windows_env.rb (renamed from lib/chef/resource/env.rb)6
-rw-r--r--lib/chef/resources.rb8
-rw-r--r--lib/chef/version.rb2
-rw-r--r--omnibus/Gemfile.lock32
-rwxr-xr-xspec/functional/resource/env_spec.rb192
-rw-r--r--spec/functional/resource/windows_env_spec.rb285
-rw-r--r--spec/integration/knife/chef_fs_data_store_spec.rb27
-rw-r--r--spec/unit/exceptions_spec.rb2
-rw-r--r--spec/unit/knife/configure_spec.rb3
-rw-r--r--spec/unit/mixin/params_validate_spec.rb13
-rw-r--r--spec/unit/mixin/properties_spec.rb14
-rw-r--r--spec/unit/node_map_spec.rb29
-rw-r--r--spec/unit/property/validation_spec.rb9
-rw-r--r--spec/unit/provider/env/windows_spec.rb103
-rw-r--r--spec/unit/provider/remote_file/http_spec.rb14
-rw-r--r--spec/unit/provider/systemd_unit_spec.rb51
-rw-r--r--spec/unit/provider/windows_env_spec.rb (renamed from spec/unit/provider/env_spec.rb)114
-rw-r--r--spec/unit/provider_resolver_spec.rb2
-rw-r--r--spec/unit/resource/hostname_spec.rb43
-rw-r--r--spec/unit/resource/rhsm_errata_level_spec.rb46
-rw-r--r--spec/unit/resource/rhsm_errata_spec.rb35
-rw-r--r--spec/unit/resource/rhsm_register_spec.rb199
-rw-r--r--spec/unit/resource/rhsm_repo_spec.rb59
-rw-r--r--spec/unit/resource/rhsm_subscription_spec.rb93
-rw-r--r--spec/unit/resource/systemd_unit_spec.rb5
-rw-r--r--spec/unit/resource/windows_env_spec.rb (renamed from spec/unit/resource/env_spec.rb)12
-rw-r--r--spec/unit/resource_spec.rb31
57 files changed, 2048 insertions, 526 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 074b4fdaff..ae45e5e667 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,15 +1,26 @@
<!-- usage documentation: http://expeditor-docs.es.chef.io/configuration/changelog/ -->
-<!-- latest_release 14.0.50 -->
-## [v14.0.50](https://github.com/chef/chef/tree/v14.0.50) (2018-02-09)
+<!-- latest_release 14.0.61 -->
+## [v14.0.61](https://github.com/chef/chef/tree/v14.0.61) (2018-02-19)
#### Merged Pull Requests
-- Use the license_scout that comes with Omnibus gem [#6839](https://github.com/chef/chef/pull/6839) ([tduffield](https://github.com/tduffield))
+- Add hostname resource from chef_hostname cookbook [#6795](https://github.com/chef/chef/pull/6795) ([tas50](https://github.com/tas50))
<!-- latest_release -->
<!-- release_rollup since=13.7.16 -->
### Changes since 13.7.16 release
#### Merged Pull Requests
+- Add hostname resource from chef_hostname cookbook [#6795](https://github.com/chef/chef/pull/6795) ([tas50](https://github.com/tas50)) <!-- 14.0.61 -->
+- registry_key: Add sensitive property support for suppressing output (fixes #5695) [#6496](https://github.com/chef/chef/pull/6496) ([shoekstra](https://github.com/shoekstra)) <!-- 14.0.60 -->
+- Use the updated inspec gem - 1.51.18 [#6845](https://github.com/chef/chef/pull/6845) ([tas50](https://github.com/tas50)) <!-- 14.0.59 -->
+- add Chef::NodeMap#delete_class API [#6846](https://github.com/chef/chef/pull/6846) ([lamont-granquist](https://github.com/lamont-granquist)) <!-- 14.0.58 -->
+- only run windows env specs on windows [#6850](https://github.com/chef/chef/pull/6850) ([thommay](https://github.com/thommay)) <!-- 14.0.57 -->
+- RemoteFile: unlink tempfile when using cache control shows unchanged [#6822](https://github.com/chef/chef/pull/6822) ([lamont-granquist](https://github.com/lamont-granquist)) <!-- 14.0.56 -->
+- [MSYS-726] Allow setting environment variables at the user level [#6612](https://github.com/chef/chef/pull/6612) ([harikesh-kolekar](https://github.com/harikesh-kolekar)) <!-- 14.0.55 -->
+- Fix issue #2351, chef-client doesn&#39;t make /etc/chef if the directory … [#6429](https://github.com/chef/chef/pull/6429) ([jseely](https://github.com/jseely)) <!-- 14.0.54 -->
+- invites_sort_fail: Clean the invites array before sorting it [#6463](https://github.com/chef/chef/pull/6463) ([MarkGibbons](https://github.com/MarkGibbons)) <!-- 14.0.53 -->
+- Implement resource enhancement RFCs [#6818](https://github.com/chef/chef/pull/6818) ([thommay](https://github.com/thommay)) <!-- 14.0.52 -->
+- add additional systemd_unit actions [#6835](https://github.com/chef/chef/pull/6835) ([nathwill](https://github.com/nathwill)) <!-- 14.0.51 -->
- Use the license_scout that comes with Omnibus gem [#6839](https://github.com/chef/chef/pull/6839) ([tduffield](https://github.com/tduffield)) <!-- 14.0.50 -->
- Simplify powershell_out calls in powershell_package [#6837](https://github.com/chef/chef/pull/6837) ([Happycoil](https://github.com/Happycoil)) <!-- 14.0.49 -->
- Don&#39;t rely on the Passwd Ohai plugin in resources [#6833](https://github.com/chef/chef/pull/6833) ([thommay](https://github.com/thommay)) <!-- 14.0.48 -->
diff --git a/CHEF_MVPS.md b/CHEF_MVPS.md
index dd46ea9174..a5abe07a56 100644
--- a/CHEF_MVPS.md
+++ b/CHEF_MVPS.md
@@ -2,7 +2,8 @@
Every release of Chef we pick someone from the community to name as the Most Valuable Player for that release. It could be someone who provided a big feature, reported a security vulnerability, or someone doing great things in the community that we want to highlight.
-In addition to the Hall of Fame and MVP recipients, three individuals are awarded the distinction of "Awesome Community Chef" each year at ChefConf.
+In addition to the Hall of Fame and MVP recipients, a number of individuals are awarded the distinction
+of "Awesome Community Chef" each year at ChefConf.
#### Hall of Fame
@@ -91,7 +92,7 @@ After receiving three MVP awards, we add someone to the hall of fame. We want to
#### Awesome Community Chefs
-Each year at ChefConf, three individuals are awarded the Awesome Community Chef award. The Awesome Community Chef awards are a way for the community to recognize a few of the individuals who have made a dramatic impact and have helped further the cause.
+Each year at ChefConf, a number of individuals are awarded the Awesome Community Chef award. The Awesome Community Chef awards are a way for the community to recognize a few of the individuals who have made a dramatic impact and have helped further the cause.
* 2013
* [Bryan Berry](https://github.com/bryanwb)
@@ -105,4 +106,14 @@ Each year at ChefConf, three individuals are awarded the Awesome Community Chef
* 2015
* [Jon Cowie](https://github.com/jonlives)
* [Noah Kantrowitz](https://github.com/coderanger)
- * [Matt Wrock](https://github.com/mwrock) \ No newline at end of file
+ * [Matt Wrock](https://github.com/mwrock)
+* 2016
+ * [Mike Fiedler](https://github.com/miketheman)
+ * [Doug Ireton](https://github.com/dougireton)
+ * [Stuart Preston](https://github.com/stuartpreston)
+ * [Seth Thomas](https://github.com/cheeseplus)
+* 2017
+ * [Ben Dang](https://github.com/bdangit)
+ * [Annie Hedgpeth](https://github.com/anniehedgpeth)
+ * [Sean O'Meara](https://github.com/someara)
+ * [Nell Shamrell-Harrington](https://github.com/nellshamrell) \ No newline at end of file
diff --git a/Gemfile.lock b/Gemfile.lock
index 1486a29e7a..c942c1f214 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -8,11 +8,11 @@ GIT
GIT
remote: https://github.com/chef/ohai.git
- revision: 849a4caf9926a4e11f12f9175b6f4dcd8a9ccaf1
+ revision: 034a8a2f2ebccfc50657b8a79d73deeca4c27b17
branch: master
specs:
- ohai (14.0.1)
- chef-config (>= 12.5.0.alpha.1, < 15)
+ ohai (14.0.12)
+ chef-config (>= 12.8, < 15)
ffi (~> 1.9)
ffi-yajl (~> 2.2)
ipaddress
@@ -35,10 +35,10 @@ GIT
PATH
remote: .
specs:
- chef (14.0.50)
+ chef (14.0.61)
addressable
bundler (>= 1.10)
- chef-config (= 14.0.50)
+ chef-config (= 14.0.61)
chef-zero (>= 13.0)
diff-lcs (~> 1.2, >= 1.2.4)
erubis (~> 2.7)
@@ -65,10 +65,10 @@ PATH
specinfra (~> 2.10)
syslog-logger (~> 1.6)
uuidtools (~> 2.1.5)
- chef (14.0.50-universal-mingw32)
+ chef (14.0.61-universal-mingw32)
addressable
bundler (>= 1.10)
- chef-config (= 14.0.50)
+ chef-config (= 14.0.61)
chef-zero (>= 13.0)
diff-lcs (~> 1.2, >= 1.2.4)
erubis (~> 2.7)
@@ -110,7 +110,7 @@ PATH
PATH
remote: chef-config
specs:
- chef-config (14.0.50)
+ chef-config (14.0.61)
addressable
fuzzyurl
mixlib-config (~> 2.0)
@@ -123,12 +123,12 @@ GEM
addressable (2.4.0)
appbundler (0.10.0)
mixlib-cli (~> 1.4)
- ast (2.3.0)
- backports (3.11.0)
+ ast (2.4.0)
+ backports (3.11.1)
binding_of_caller (0.8.0)
debug_inspector (>= 0.0.1)
builder (3.2.3)
- byebug (9.1.0)
+ byebug (10.0.0)
chef-vault (3.3.0)
chef-zero (13.1.0)
ffi-yajl (~> 2.2)
@@ -181,7 +181,7 @@ GEM
htmlentities (4.3.4)
httpclient (2.8.3)
iniparse (1.4.4)
- inspec (1.50.1)
+ inspec (1.51.18)
addressable (~> 2.4)
faraday (>= 0.9.0)
hashie (~> 3.4)
@@ -215,7 +215,7 @@ GEM
mixlib-log
mixlib-authentication (1.4.2)
mixlib-cli (1.7.0)
- mixlib-config (2.2.4)
+ mixlib-config (2.2.5)
mixlib-log (1.7.1)
mixlib-shellout (2.3.2)
mixlib-shellout (2.3.2-universal-mingw32)
@@ -250,8 +250,8 @@ GEM
pry (0.11.3)
coderay (~> 1.1.0)
method_source (~> 0.9.0)
- pry-byebug (3.5.1)
- byebug (~> 9.1)
+ pry-byebug (3.6.0)
+ byebug (~> 10.0)
pry (~> 0.10)
pry-remote (0.1.8)
pry (~> 0.9)
diff --git a/VERSION b/VERSION
index 42db1d0a59..a60fc27d90 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-14.0.50 \ No newline at end of file
+14.0.61 \ No newline at end of file
diff --git a/chef-config/lib/chef-config/version.rb b/chef-config/lib/chef-config/version.rb
index f5c4062739..cc34f28910 100644
--- a/chef-config/lib/chef-config/version.rb
+++ b/chef-config/lib/chef-config/version.rb
@@ -21,7 +21,7 @@
module ChefConfig
CHEFCONFIG_ROOT = File.expand_path("../..", __FILE__)
- VERSION = "14.0.50"
+ VERSION = "14.0.61"
end
#
diff --git a/lib/chef/api_client/registration.rb b/lib/chef/api_client/registration.rb
index e8ab0149e8..27e1f18c17 100644
--- a/lib/chef/api_client/registration.rb
+++ b/lib/chef/api_client/registration.rb
@@ -19,6 +19,7 @@
require "chef/config"
require "chef/server_api"
require "chef/exceptions"
+require "fileutils"
class Chef
class ApiClient
@@ -69,8 +70,15 @@ class Chef
end
def assert_destination_writable!
- if (File.exists?(destination) && !File.writable?(destination)) || !File.writable?(File.dirname(destination))
- abs_path = File.expand_path(destination)
+ abs_path = File.expand_path(destination)
+ if !File.exists?(File.dirname(abs_path))
+ begin
+ FileUtils.mkdir_p(File.dirname(abs_path))
+ rescue Errno::EACCES
+ raise Chef::Exceptions::CannotWritePrivateKey, "I can't create the configuration directory at #{File.dirname(abs_path)} - check permissions?"
+ end
+ end
+ if (File.exists?(abs_path) && !File.writable?(abs_path)) || !File.writable?(File.dirname(abs_path))
raise Chef::Exceptions::CannotWritePrivateKey, "I can't write your private key to #{abs_path} - check permissions?"
end
end
diff --git a/lib/chef/chef_fs/chef_fs_data_store.rb b/lib/chef/chef_fs/chef_fs_data_store.rb
index 0c8f12f1be..4f248625b3 100644
--- a/lib/chef/chef_fs/chef_fs_data_store.rb
+++ b/lib/chef/chef_fs/chef_fs_data_store.rb
@@ -307,11 +307,13 @@ class Chef
# GET /cookbooks/NAME/VERSION or /cookbook_artifacts/NAME/IDENTIFIER
elsif %w{cookbooks cookbook_artifacts}.include?(path[0]) && path.length == 3
- with_entry(path) do |entry|
+ with_entry([path[0]]) do |entry|
cookbook_type = path[0]
+ cookbook_entry = entry.children.select { |child| child.chef_object.full_name == "#{path[1]}-#{path[2]}" }[0]
+ raise ChefZero::DataStore::DataNotFoundError.new(path) if cookbook_entry.nil?
result = nil
begin
- result = Chef::CookbookManifest.new(entry.chef_object, policy_mode: cookbook_type == "cookbook_artifacts").to_hash
+ result = Chef::CookbookManifest.new(cookbook_entry.chef_object, policy_mode: cookbook_type == "cookbook_artifacts").to_hash
rescue Chef::ChefFS::FileSystem::NotFoundError => e
raise ChefZero::DataStore::DataNotFoundError.new(to_zero_path(e.entry), e)
end
@@ -320,12 +322,7 @@ class Chef
if value.is_a?(Array)
value.each do |file|
if file.is_a?(Hash) && file.has_key?("checksum")
- relative = ["file_store", "repo", cookbook_type]
- if chef_fs.versioned_cookbooks || cookbook_type == "cookbook_artifacts"
- relative << "#{path[1]}-#{path[2]}"
- else
- relative << path[1]
- end
+ relative = ["file_store", "repo", cookbook_type, cookbook_entry.name ]
relative += file[:path].split("/")
file["url"] = ChefZero::RestBase.build_uri(request.base_uri, relative)
end
@@ -519,14 +516,7 @@ class Chef
elsif %w{cookbooks cookbook_artifacts}.include?(path[0]) && path.length == 1
with_entry(path) do |entry|
begin
- if path[0] == "cookbook_artifacts"
- entry.children.map { |child| child.name.rpartition("-")[0] }.uniq
- elsif chef_fs.versioned_cookbooks
- # /cookbooks/name-version -> /cookbooks/name
- entry.children.map { |child| split_name_version(child.name)[0] }.uniq
- else
- entry.children.map { |child| child.name }
- end
+ entry.children.map { |child| child.chef_object.name.to_s }.uniq
rescue Chef::ChefFS::FileSystem::NotFoundError
# If the cookbooks dir doesn't exist, we have no cookbooks (not 404)
[]
@@ -534,22 +524,15 @@ class Chef
end
elsif %w{cookbooks cookbook_artifacts}.include?(path[0]) && path.length == 2
- if chef_fs.versioned_cookbooks || path[0] == "cookbook_artifacts"
- result = with_entry([ path[0] ]) do |entry|
- # list /cookbooks/name = filter /cookbooks/name-version down to name
- entry.children.map { |child| split_name_version(child.name) }.
- select { |name, version| name == path[1] }.
- map { |name, version| version }
- end
- if result.empty?
- raise ChefZero::DataStore::DataNotFoundError.new(path)
- end
- result
- else
- # list /cookbooks/name = <single version>
- version = get_single_cookbook_version(path)
- [version]
+ result = with_entry([ path[0] ]) do |entry|
+ cookbooks = entry.children.map { |child| child.chef_object }
+ cookbooks.select { |cookbook| cookbook.name.to_s == path[1] }.
+ map { |cookbook| cookbook.version }
end
+ if result.empty?
+ raise ChefZero::DataStore::DataNotFoundError.new(path)
+ end
+ result
else
result = with_entry(path) do |entry|
diff --git a/lib/chef/chef_fs/data_handler/organization_invites_data_handler.rb b/lib/chef/chef_fs/data_handler/organization_invites_data_handler.rb
index c5a5f873c5..7ae08823b8 100644
--- a/lib/chef/chef_fs/data_handler/organization_invites_data_handler.rb
+++ b/lib/chef/chef_fs/data_handler/organization_invites_data_handler.rb
@@ -5,7 +5,7 @@ class Chef
module DataHandler
class OrganizationInvitesDataHandler < DataHandlerBase
def normalize(invites, entry)
- invites.map { |invite| invite.is_a?(Hash) ? invite["username"] : invite }.sort.uniq
+ invites.map { |invite| invite.is_a?(Hash) ? invite["username"] : invite }.compact.sort.uniq
end
def minimize(invites, entry)
diff --git a/lib/chef/exceptions.rb b/lib/chef/exceptions.rb
index 5b470f574e..1ed71d2a55 100644
--- a/lib/chef/exceptions.rb
+++ b/lib/chef/exceptions.rb
@@ -45,7 +45,7 @@ class Chef
class SigInt < RuntimeError; end
class SigTerm < RuntimeError; end
class Cron < RuntimeError; end
- class Env < RuntimeError; end
+ class WindowsEnv < RuntimeError; end
class Exec < RuntimeError; end
class Execute < RuntimeError; end
class ErlCall < RuntimeError; end
diff --git a/lib/chef/knife/configure.rb b/lib/chef/knife/configure.rb
index 10ae62b6c9..b277a14a3e 100644
--- a/lib/chef/knife/configure.rb
+++ b/lib/chef/knife/configure.rb
@@ -131,9 +131,7 @@ EOH
def guess_servername
o = Ohai::System.new
- o.load_plugins
- o.require_plugin "os"
- o.require_plugin "hostname"
+ o.all_plugins(%w{ os hostname fqdn })
o[:fqdn] || o[:machinename] || o[:hostname] || "localhost"
end
diff --git a/lib/chef/knife/ssh.rb b/lib/chef/knife/ssh.rb
index 8e13425f82..885ebc4faa 100644
--- a/lib/chef/knife/ssh.rb
+++ b/lib/chef/knife/ssh.rb
@@ -576,8 +576,13 @@ class Chef
configure_user
configure_password
@password = config[:ssh_password] if config[:ssh_password]
- configure_ssh_identity_file
- configure_ssh_gateway_identity
+
+ # If a password was not given, check for SSH identity file.
+ if !@password
+ configure_ssh_identity_file
+ configure_ssh_gateway_identity
+ end
+
configure_gateway
configure_session
diff --git a/lib/chef/mixin/params_validate.rb b/lib/chef/mixin/params_validate.rb
index d90e38b916..c955dd3b12 100644
--- a/lib/chef/mixin/params_validate.rb
+++ b/lib/chef/mixin/params_validate.rb
@@ -1,6 +1,6 @@
#
# Author:: Adam Jacob (<adam@chef.io>)
-# Copyright:: Copyright 2008-2017, Chef Software Inc.
+# Copyright:: Copyright 2008-2018, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -35,6 +35,8 @@ class Chef
# map options are:
#
# @param opts [Hash<Symbol,Object>] Validation opts.
+ # @option opts [String] :validation_message A custom message to return
+ # should validation fail.
# @option opts [Object,Array] :is An object, or list of
# objects, that must match the value using Ruby's `===` operator
# (`opts[:is].any? { |v| v === value }`). (See #_pv_is.)
@@ -91,16 +93,20 @@ class Chef
raise ArgumentError, "Options must be a hash" unless opts.kind_of?(Hash)
raise ArgumentError, "Validation Map must be a hash" unless map.kind_of?(Hash)
+ @validation_message ||= {}
+
map.each do |key, validation|
unless key.kind_of?(Symbol) || key.kind_of?(String)
raise ArgumentError, "Validation map keys must be symbols or strings!"
end
+
case validation
when true
_pv_required(opts, key)
when false
true
when Hash
+ @validation_message[key] = validation.delete(:validation_message) if validation.has_key?(:validation_message)
validation.each do |check, carg|
check_method = "_pv_#{check}"
if respond_to?(check_method, true)
@@ -129,6 +135,10 @@ class Chef
validation.has_key?(:is) && _pv_is({ key => nil }, key, validation[:is], raise_error: false)
end
+ def _validation_message(key, default)
+ @validation_message.has_key?(key) ? @validation_message[key] : default
+ end
+
# Return the value of a parameter, or nil if it doesn't exist.
def _pv_opts_lookup(opts, key)
if opts.has_key?(key.to_s)
@@ -145,7 +155,7 @@ class Chef
if is_required
return true if opts.has_key?(key.to_s) && (explicitly_allows_nil || !opts[key.to_s].nil?)
return true if opts.has_key?(key.to_sym) && (explicitly_allows_nil || !opts[key.to_sym].nil?)
- raise Exceptions::ValidationFailed, "Required argument #{key.inspect} is missing!"
+ raise Exceptions::ValidationFailed, _validation_message(key, "Required argument #{key.inspect} is missing!")
end
true
end
@@ -168,7 +178,7 @@ class Chef
to_be.each do |tb|
return true if value == tb
end
- raise Exceptions::ValidationFailed, "Option #{key} must be equal to one of: #{to_be.join(", ")}! You passed #{value.inspect}."
+ raise Exceptions::ValidationFailed, _validation_message(key, "Option #{key} must be equal to one of: #{to_be.join(", ")}! You passed #{value.inspect}.")
end
end
@@ -187,7 +197,7 @@ class Chef
to_be.each do |tb|
return true if value.kind_of?(tb)
end
- raise Exceptions::ValidationFailed, "Option #{key} must be a kind of #{to_be}! You passed #{value.inspect}."
+ raise Exceptions::ValidationFailed, _validation_message(key, "Option #{key} must be a kind of #{to_be}! You passed #{value.inspect}.")
end
end
@@ -202,7 +212,7 @@ class Chef
unless value.nil?
Array(method_name_list).each do |method_name|
unless value.respond_to?(method_name)
- raise Exceptions::ValidationFailed, "Option #{key} must have a #{method_name} method!"
+ raise Exceptions::ValidationFailed, _validation_message(key, "Option #{key} must have a #{method_name} method!")
end
end
end
@@ -234,7 +244,7 @@ class Chef
if value.respond_to?(predicate_method)
if value.send(predicate_method)
- raise Exceptions::ValidationFailed, "Option #{key} cannot be #{predicate_method_base_name}"
+ raise Exceptions::ValidationFailed, _validation_message(key, "Option #{key} cannot be #{predicate_method_base_name}")
end
end
end
@@ -294,7 +304,7 @@ class Chef
Array(regex).flatten.each do |r|
return true if r.match(value.to_s)
end
- raise Exceptions::ValidationFailed, "Option #{key}'s value #{value} does not match regular expression #{regex.inspect}"
+ raise Exceptions::ValidationFailed, _validation_message(key, "Option #{key}'s value #{value} does not match regular expression #{regex.inspect}")
end
end
@@ -316,7 +326,7 @@ class Chef
if !value.nil?
callbacks.each do |message, zeproc|
unless zeproc.call(value)
- raise Exceptions::ValidationFailed, "Option #{key}'s value #{value} #{message}!"
+ raise Exceptions::ValidationFailed, _validation_message(key, "Option #{key}'s value #{value} #{message}!")
end
end
end
@@ -428,7 +438,7 @@ class Chef
unless errors.empty?
message << " Errors:\n#{errors.map { |m| "- #{m}" }.join("\n")}"
end
- raise Exceptions::ValidationFailed, message
+ raise Exceptions::ValidationFailed, _validation_message(key, message)
end
end
diff --git a/lib/chef/mixin/properties.rb b/lib/chef/mixin/properties.rb
index 8ff2cc4501..6b95b87063 100644
--- a/lib/chef/mixin/properties.rb
+++ b/lib/chef/mixin/properties.rb
@@ -75,6 +75,8 @@ class Chef
# will return if the user does not set one. If this is `lazy`, it will
# be run in the context of the instance (and able to access other
# properties).
+ # @option options [String] :description A description of the property.
+ # @option options [String] :introduced The release that introduced this property
# @option options [Boolean] :desired_state `true` if this property is
# part of desired state. Defaults to `true`.
# @option options [Boolean] :identity `true` if this property
@@ -301,6 +303,17 @@ class Chef
raise ArgumentError, "Property #{name} is not defined in class #{self}" if !property
property.reset(self)
end
+
+ #
+ # The description of the property
+ #
+ # @param name [Symbol] The name of the property.
+ # @return [String] The description of the property.
+ def property_description(name)
+ property = self.class.properties[name.to_sym]
+ raise ArgumentError, "Property #{name} is not defined in class #{self}" if !property
+ property.description
+ end
end
end
end
diff --git a/lib/chef/node_map.rb b/lib/chef/node_map.rb
index ecd5c9df8f..0406b3c1d6 100644
--- a/lib/chef/node_map.rb
+++ b/lib/chef/node_map.rb
@@ -118,6 +118,32 @@ class Chef
end.map { |matcher| matcher[:klass] }
end
+ # Remove a class from all its matchers in the node_map, will remove mappings completely if its the last matcher left
+ #
+ # Note that this leaks the internal structure out a bit, but the main consumer of this (poise/halite) cares only about
+ # the keys in the returned Hash.
+ #
+ # @param klass [Class] the class to seek and destroy
+ #
+ # @return [Hash] deleted entries in the same format as the @map
+ def delete_class(klass)
+ raise "please use a Class type for the klass argument" unless klass.is_a?(Class)
+ deleted = {}
+ map.each do |key, matchers|
+ deleted_matchers = []
+ matchers.delete_if do |matcher|
+ # because matcher[:klass] may be a string (which needs to die), coerce both to strings to compare somewhat canonically
+ if matcher[:klass].to_s == klass.to_s
+ deleted_matchers << matcher
+ true
+ end
+ end
+ deleted[key] = deleted_matchers unless deleted_matchers.empty?
+ map.delete(key) if matchers.empty?
+ end
+ deleted
+ end
+
# Seriously, don't use this, it's nearly certain to change on you
# @return remaining
# @api private
diff --git a/lib/chef/property.rb b/lib/chef/property.rb
index 9d0957dcdf..be54c8bfa1 100644
--- a/lib/chef/property.rb
+++ b/lib/chef/property.rb
@@ -60,10 +60,12 @@ class Chef
# options).
# @option options [Symbol] :name The name of this property.
# @option options [Class] :declared_in The class this property comes from.
+ # @option options [String] :description A description of the property.
# @option options [Symbol] :instance_variable_name The instance variable
# tied to this property. Must include a leading `@`. Defaults to `@<name>`.
# `nil` means the property is opaque and not tied to a specific instance
# variable.
+ # @option options [String] :introduced The release that introduced this property
# @option options [Boolean] :desired_state `true` if this property is part of desired
# state. Defaults to `true`.
# @option options [Boolean] :identity `true` if this property is part of object
@@ -158,6 +160,24 @@ class Chef
end
#
+ # A description of this property.
+ #
+ # @return [String]
+ #
+ def description
+ options[:description]
+ end
+
+ #
+ # When this property was introduced
+ #
+ # @return [String]
+ #
+ def introduced
+ options[:introduced]
+ end
+
+ #
# The instance variable associated with this property.
#
# Defaults to `@<name>`
@@ -252,7 +272,7 @@ class Chef
#
def validation_options
@validation_options ||= options.reject do |k, v|
- [:declared_in, :name, :instance_variable_name, :desired_state, :identity, :default, :name_property, :coerce, :required, :nillable, :sensitive].include?(k)
+ [:declared_in, :name, :instance_variable_name, :desired_state, :identity, :default, :name_property, :coerce, :required, :nillable, :sensitive, :description, :introduced].include?(k)
end
end
diff --git a/lib/chef/provider.rb b/lib/chef/provider.rb
index 327bf52a13..7cb2301772 100644
--- a/lib/chef/provider.rb
+++ b/lib/chef/provider.rb
@@ -197,6 +197,20 @@ class Chef
@requirements ||= ResourceRequirements.new(@new_resource, run_context)
end
+ def description(description = "NOT_PASSED")
+ if description != "NOT_PASSED"
+ @description = description
+ end
+ @description
+ end
+
+ def introduced(introduced = "NOT_PASSED")
+ if introduced != "NOT_PASSED"
+ @introduced = introduced
+ end
+ @introduced
+ end
+
def converge_by(descriptions, &block)
converge_actions.add_action(descriptions, &block)
end
diff --git a/lib/chef/provider/env/windows.rb b/lib/chef/provider/env/windows.rb
deleted file mode 100644
index e813025c81..0000000000
--- a/lib/chef/provider/env/windows.rb
+++ /dev/null
@@ -1,76 +0,0 @@
-#
-# Author:: Doug MacEachern (<dougm@vmware.com>)
-# Copyright:: Copyright 2010-2016, VMware, 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"
-
-class Chef
- class Provider
- class Env
- class Windows < Chef::Provider::Env
- include Chef::Mixin::WindowsEnvHelper
-
- provides :env, os: "windows"
-
- def whyrun_supported?
- false
- end
-
- def create_env
- obj = env_obj(@new_resource.key_name)
- unless obj
- obj = WIN32OLE.connect("winmgmts://").get("Win32_Environment").spawninstance_
- obj.name = @new_resource.key_name
- obj.username = "<System>"
- end
- obj.variablevalue = @new_resource.value
- obj.put_
- value = @new_resource.value
- value = expand_path(value) if @new_resource.key_name.casecmp("PATH") == 0
- ENV[@new_resource.key_name] = value
- broadcast_env_change
- end
-
- def delete_env
- obj = env_obj(@new_resource.key_name)
- if obj
- obj.delete_
- broadcast_env_change
- end
- if ENV[@new_resource.key_name]
- ENV.delete(@new_resource.key_name)
- end
- end
-
- def env_value(key_name)
- obj = env_obj(key_name)
- obj ? obj.variablevalue : ENV[key_name]
- end
-
- def env_obj(key_name)
- wmi = WmiLite::Wmi.new
- # Note that by design this query is case insensitive with regard to key_name
- environment_variables = wmi.query("select * from Win32_Environment where name = '#{key_name}'")
- if environment_variables && environment_variables.length > 0
- environment_variables[0].wmi_ole_object
- end
- end
-
- end
- end
- end
-end
diff --git a/lib/chef/provider/registry_key.rb b/lib/chef/provider/registry_key.rb
index f196154986..a4a0465e11 100644
--- a/lib/chef/provider/registry_key.rb
+++ b/lib/chef/provider/registry_key.rb
@@ -126,12 +126,18 @@ class Chef
value[:data] = value[:data].to_i
end
unless current_value[:type] == value[:type] && current_value[:data] == value[:data]
- converge_by("set value #{value}") do
+ converge_by_value = value
+ converge_by_value[:data] = "*sensitive value suppressed*" if new_resource.sensitive
+
+ converge_by("set value #{converge_by_value}") do
registry.set_value(new_resource.key, value)
end
end
else
- converge_by("set value #{value}") do
+ converge_by_value = value
+ converge_by_value[:data] = "*sensitive value suppressed*" if new_resource.sensitive
+
+ converge_by("set value #{converge_by_value}") do
registry.set_value(new_resource.key, value)
end
end
@@ -146,7 +152,10 @@ class Chef
end
new_resource.unscrubbed_values.each do |value|
unless @name_hash.has_key?(value[:name].downcase)
- converge_by("create value #{value}") do
+ converge_by_value = value
+ converge_by_value[:data] = "*sensitive value suppressed*" if new_resource.sensitive
+
+ converge_by("create value #{converge_by_value}") do
registry.set_value(new_resource.key, value)
end
end
@@ -157,7 +166,10 @@ class Chef
if registry.key_exists?(new_resource.key)
new_resource.unscrubbed_values.each do |value|
if @name_hash.has_key?(value[:name].downcase)
- converge_by("delete value #{value}") do
+ converge_by_value = value
+ converge_by_value[:data] = "*sensitive value suppressed*" if new_resource.sensitive
+
+ converge_by("delete value #{converge_by_value}") do
registry.delete_value(new_resource.key, value)
end
end
diff --git a/lib/chef/provider/remote_file/http.rb b/lib/chef/provider/remote_file/http.rb
index 4732253e5b..8dfa84ee2a 100644
--- a/lib/chef/provider/remote_file/http.rb
+++ b/lib/chef/provider/remote_file/http.rb
@@ -61,17 +61,22 @@ class Chef
def fetch
http = Chef::HTTP::Simple.new(uri, http_client_opts)
- tempfile = Chef::FileContentManagement::Tempfile.new(@new_resource).tempfile
+ orig_tempfile = Chef::FileContentManagement::Tempfile.new(@new_resource).tempfile
if want_progress?
- tempfile = http.streaming_request_with_progress(uri, headers, tempfile) do |size, total|
+ tempfile = http.streaming_request_with_progress(uri, headers, orig_tempfile) do |size, total|
events.resource_update_progress(new_resource, size, total, progress_interval)
end
else
- tempfile = http.streaming_request(uri, headers, tempfile)
+ tempfile = http.streaming_request(uri, headers, orig_tempfile)
end
if tempfile
update_cache_control_data(tempfile, http.last_response)
tempfile.close
+ else
+ # cache_control shows the file is unchanged, so we got back nil from the streaming_request above, and it is
+ # now our responsibility to unlink the tempfile we created
+ orig_tempfile.close
+ orig_tempfile.unlink
end
tempfile
end
diff --git a/lib/chef/provider/systemd_unit.rb b/lib/chef/provider/systemd_unit.rb
index dcef93bfde..420438775c 100644
--- a/lib/chef/provider/systemd_unit.rb
+++ b/lib/chef/provider/systemd_unit.rb
@@ -1,6 +1,6 @@
#
# Author:: Nathan Williams (<nath.e.will@gmail.com>)
-# Copyright:: Copyright 2016, Nathan Williams
+# Copyright:: Copyright 2016-2018, Nathan Williams
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -74,6 +74,18 @@ class Chef
end
end
+ def action_preset
+ converge_by("restoring enable/disable preset configuration for unit: #{new_resource.unit_name}") do
+ systemctl_execute!(:preset, new_resource.unit_name)
+ end
+ end
+
+ def action_revert
+ converge_by("reverting to vendor version of unit: #{new_resource.unit_name}") do
+ systemctl_execute!(:revert, new_resource.unit_name)
+ end
+ end
+
def action_enable
if current_resource.static
Chef::Log.debug("#{new_resource.unit_name} is a static unit, enabling is a NOP.")
@@ -98,6 +110,12 @@ class Chef
end
end
+ def action_reenable
+ converge_by("reenabling unit: #{new_resource.unit_name}") do
+ systemctl_execute!(:reenable, new_resource.unit_name)
+ end
+ end
+
def action_mask
unless current_resource.masked
converge_by("masking unit: #{new_resource.unit_name}") do
diff --git a/lib/chef/provider/env.rb b/lib/chef/provider/windows_env.rb
index 490fa31146..b5b06666f3 100644
--- a/lib/chef/provider/env.rb
+++ b/lib/chef/provider/windows_env.rb
@@ -17,14 +17,17 @@
#
require "chef/provider"
-require "chef/resource/env"
+require "chef/resource/windows_env"
+require "chef/mixin/windows_env_helper"
class Chef
class Provider
- class Env < Chef::Provider
+ class WindowsEnv < Chef::Provider
+ include Chef::Mixin::WindowsEnvHelper
attr_accessor :key_exists
- provides :env, os: "!windows"
+ provides :env, os: "windows"
+ provides :windows_env, os: "windows"
def whyrun_supported?
false
@@ -36,7 +39,7 @@ class Chef
end
def load_current_resource
- @current_resource = Chef::Resource::Env.new(new_resource.name)
+ @current_resource = Chef::Resource::WindowsEnv.new(new_resource.name)
current_resource.key_name(new_resource.key_name)
if env_key_exists(new_resource.key_name)
@@ -49,10 +52,6 @@ class Chef
current_resource
end
- def env_value(key_name)
- raise Chef::Exceptions::Env, "#{self} provider does not implement env_value!"
- end
-
def env_key_exists(key_name)
env_value(key_name) ? true : false
end
@@ -123,7 +122,7 @@ class Chef
end
def action_delete
- if @key_exists && !delete_element
+ if ( ENV[new_resource.key_name] || @key_exists ) && !delete_element
delete_env
Chef::Log.info("#{new_resource} deleted")
new_resource.updated_by_last_action(true)
@@ -138,16 +137,34 @@ class Chef
new_resource.updated_by_last_action(true)
end
else
- raise Chef::Exceptions::Env, "Cannot modify #{new_resource} - key does not exist!"
+ raise Chef::Exceptions::WindowsEnv, "Cannot modify #{new_resource} - key does not exist!"
end
end
def create_env
- raise Chef::Exceptions::UnsupportedAction, "#{self} does not support :#{new_resource.action}"
+ obj = env_obj(@new_resource.key_name)
+ unless obj
+ obj = WIN32OLE.connect("winmgmts://").get("Win32_Environment").spawninstance_
+ obj.name = @new_resource.key_name
+ obj.username = new_resource.user
+ end
+ obj.variablevalue = @new_resource.value
+ obj.put_
+ value = @new_resource.value
+ value = expand_path(value) if @new_resource.key_name.casecmp("PATH") == 0
+ ENV[@new_resource.key_name] = value
+ broadcast_env_change
end
def delete_env
- raise Chef::Exceptions::UnsupportedAction, "#{self} does not support :delete"
+ obj = env_obj(@new_resource.key_name)
+ if obj
+ obj.delete_
+ broadcast_env_change
+ end
+ if ENV[@new_resource.key_name]
+ ENV.delete(@new_resource.key_name)
+ end
end
def modify_env
@@ -166,6 +183,25 @@ class Chef
def new_values
@new_values ||= new_resource.value.split(new_resource.delim)
end
+
+ def env_value(key_name)
+ obj = env_obj(key_name)
+ obj.variablevalue if obj
+ end
+
+ def env_obj(key_name)
+ return @env_obj if @env_obj
+ wmi = WmiLite::Wmi.new
+ # Note that by design this query is case insensitive with regard to key_name
+ environment_variables = wmi.query("select * from Win32_Environment where name = '#{key_name}'")
+ if environment_variables && environment_variables.length > 0
+ environment_variables.each do |env|
+ @env_obj = env.wmi_ole_object
+ return @env_obj if @env_obj.username.split('\\').last.casecmp(new_resource.user) == 0
+ end
+ end
+ @env_obj = nil
+ end
end
end
end
diff --git a/lib/chef/providers.rb b/lib/chef/providers.rb
index 507203fd28..8b07e1b405 100644
--- a/lib/chef/providers.rb
+++ b/lib/chef/providers.rb
@@ -27,7 +27,6 @@ require "chef/provider/cron/aix"
require "chef/provider/directory"
require "chef/provider/dsc_script"
require "chef/provider/dsc_resource"
-require "chef/provider/env"
require "chef/provider/execute"
require "chef/provider/file"
require "chef/provider/git"
@@ -56,13 +55,12 @@ require "chef/provider/systemd_unit"
require "chef/provider/template"
require "chef/provider/user"
require "chef/provider/whyrun_safe_ruby_block"
+require "chef/provider/windows_env"
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"
-
require "chef/provider/package/apt"
require "chef/provider/package/chocolatey"
require "chef/provider/package/dpkg"
diff --git a/lib/chef/resource.rb b/lib/chef/resource.rb
index ac1146a647..77e735bbce 100644
--- a/lib/chef/resource.rb
+++ b/lib/chef/resource.rb
@@ -1174,8 +1174,8 @@ class Chef
# Internal Resource Interface (for Chef)
#
- FORBIDDEN_IVARS = [:@run_context, :@not_if, :@only_if, :@enclosing_provider]
- HIDDEN_IVARS = [:@allowed_actions, :@resource_name, :@source_line, :@run_context, :@name, :@not_if, :@only_if, :@elapsed_time, :@enclosing_provider]
+ FORBIDDEN_IVARS = [:@run_context, :@not_if, :@only_if, :@enclosing_provider, :@description, :@introduced, :@examples, :@validation_message]
+ HIDDEN_IVARS = [:@allowed_actions, :@resource_name, :@source_line, :@run_context, :@name, :@not_if, :@only_if, :@elapsed_time, :@enclosing_provider, :@description, :@introduced, :@examples, :@validation_message]
include Chef::Mixin::ConvertToClassName
extend Chef::Mixin::ConvertToClassName
@@ -1374,6 +1374,27 @@ class Chef
end
end
+ def self.description(description = "NOT_PASSED")
+ if description != "NOT_PASSED"
+ @description = description
+ end
+ @description
+ end
+
+ def self.introduced(introduced = "NOT_PASSED")
+ if introduced != "NOT_PASSED"
+ @introduced = introduced
+ end
+ @introduced
+ end
+
+ def self.examples(examples = "NOT_PASSED")
+ if examples != "NOT_PASSED"
+ @examples = examples
+ end
+ @examples
+ end
+
#
# The cookbook in which this Resource was defined (if any).
#
diff --git a/lib/chef/resource/hostname.rb b/lib/chef/resource/hostname.rb
new file mode 100644
index 0000000000..16986c09a3
--- /dev/null
+++ b/lib/chef/resource/hostname.rb
@@ -0,0 +1,252 @@
+class Chef
+ class Resource
+ # Sets the hostname and updates /etc/hosts on *nix systems
+ # @since 14.0.0
+ class Hostname < Chef::Resource
+ provides :hostname
+ resource_name :hostname
+
+ description "Sets the systems hostname, ensures that reboot will preserve the hostname, and re-runs the ohai plugin so the hostname will be available in subsequent cookbooks."
+ introduced "14.0"
+
+ property :hostname,
+ String,
+ description: "The hostname if different than the resource's name",
+ name_property: true
+
+ property :compile_time,
+ [ TrueClass, FalseClass ],
+ description: "Should the resource run at compile time or not.",
+ default: true
+
+ property :ipaddress,
+ String,
+ description: "The ip address to use when configuring the hosts file",
+ default: lazy { node["ipaddress"] }
+
+ property :aliases,
+ [ Array, nil ],
+ description: "An array of hostname aliases to use when configuring the hosts file",
+ default: nil
+
+ property :windows_reboot,
+ [ TrueClass, FalseClass ],
+ description: "Should Windows nodes be rebooted upon changing the name so it can take effect",
+ default: true
+
+ action_class do
+ def append_replacing_matching_lines(path, regex, string)
+ text = IO.read(path).split("\n")
+ text.reject! { |s| s =~ regex }
+ text += [ string ]
+ file path do
+ content text.join("\n") + "\n"
+ owner "root"
+ group node["root_group"]
+ mode "0644"
+ not_if { IO.read(path).split("\n").include?(string) }
+ end
+ end
+
+ # read in the xml file used by Ec2ConfigService and update the Ec2SetComputerName
+ # setting to disable updating the computer name so we don't revert our change on reboot
+ # @return [String]
+ def updated_ec2_config_xml
+ begin
+ require "rexml/document"
+ config_file = 'C:\Program Files\Amazon\Ec2ConfigService\Settings\config.xml'
+ config = REXML::Document.new(::File.read(config_file))
+ # find an element named State with a sibling element whose value is Ec2SetComputerName
+ REXML::XPath.each(config, "//Plugin/State[../Name/text() = 'Ec2SetComputerName']") do |element|
+ element.text = "Disabled"
+ end
+ rescue
+ return ""
+ end
+ config.to_s
+ end
+ end
+
+ action :set do
+ description "Sets the node's hostname"
+
+ ohai "reload hostname" do
+ plugin "hostname"
+ action :nothing
+ end
+
+ if node["platform_family"] != "windows"
+ # set the hostname via /bin/hostname
+ declare_resource(:execute, "set hostname to #{new_resource.hostname}") do
+ command "/bin/hostname #{new_resource.hostname}"
+ not_if { shell_out!("hostname").stdout.chomp == new_resource.hostname }
+ notifies :reload, "ohai[reload hostname]"
+ end
+
+ # make sure node['fqdn'] resolves via /etc/hosts
+ unless new_resource.ipaddress.nil?
+ newline = "#{new_resource.ipaddress} #{new_resource.hostname}"
+ newline << " #{new_resource.aliases.join(" ")}" if new_resource.aliases && !new_resource.aliases.empty?
+ newline << " #{new_resource.hostname[/[^\.]*/]}"
+ r = append_replacing_matching_lines("/etc/hosts", /^#{new_resource.ipaddress}\s+|\s+#{new_resource.hostname}\s+/, newline)
+ r.atomic_update false if docker?
+ r.notifies :reload, "ohai[reload hostname]"
+ end
+
+ # setup the hostname to perist on a reboot
+ case
+ when ::File.exist?("/usr/sbin/scutil")
+ # darwin
+ declare_resource(:execute, "set HostName via scutil") do
+ command "/usr/sbin/scutil --set HostName #{new_resource.hostname}"
+ not_if { shell_out!("/usr/sbin/scutil --get HostName").stdout.chomp == new_resource.hostname }
+ notifies :reload, "ohai[reload hostname]"
+ end
+ declare_resource(:execute, "set ComputerName via scutil") do
+ command "/usr/sbin/scutil --set ComputerName #{new_resource.hostname}"
+ not_if { shell_out!("/usr/sbin/scutil --get ComputerName").stdout.chomp == new_resource.hostname }
+ notifies :reload, "ohai[reload hostname]"
+ end
+ shortname = new_resource.hostname[/[^\.]*/]
+ declare_resource(:execute, "set LocalHostName via scutil") do
+ command "/usr/sbin/scutil --set LocalHostName #{shortname}"
+ not_if { shell_out!("/usr/sbin/scutil --get LocalHostName").stdout.chomp == shortname }
+ notifies :reload, "ohai[reload hostname]"
+ end
+ when node["os"] == "linux"
+ case
+ when ::File.exist?("/usr/bin/hostnamectl") && !docker?
+ # use hostnamectl whenever we find it on linux (as systemd takes over the world)
+ # this must come before other methods like /etc/hostname and /etc/sysconfig/network
+ declare_resource(:execute, "hostnamectl set-hostname #{new_resource.hostname}") do
+ notifies :reload, "ohai[reload hostname]"
+ not_if { shell_out!("hostnamectl status", { :returns => [0, 1] }).stdout =~ /Static hostname:\s+#{new_resource.hostname}/ }
+ end
+ when ::File.exist?("/etc/hostname")
+ # debian family uses /etc/hostname
+ # arch also uses /etc/hostname
+ # the "platform: iox_xr, platform_family: wrlinux, os: linux" platform also hits this
+ # the "platform: nexus, platform_family: wrlinux, os: linux" platform also hits this
+ # this is also fallback for any linux systemd host in a docker container (where /usr/bin/hostnamectl will fail)
+ declare_resource(:file, "/etc/hostname") do
+ atomic_update false if docker?
+ content "#{new_resource.hostname}\n"
+ owner "root"
+ group node["root_group"]
+ mode "0644"
+ end
+ when ::File.file?("/etc/sysconfig/network")
+ # older non-systemd RHEL/Fedora derived
+ append_replacing_matching_lines("/etc/sysconfig/network", /^HOSTNAME\s*=/, "HOSTNAME=#{new_resource.hostname}")
+ when ::File.exist?("/etc/HOSTNAME")
+ # SuSE/OpenSUSE uses /etc/HOSTNAME
+ declare_resource(:file, "/etc/HOSTNAME") do
+ content "#{new_resource.hostname}\n"
+ owner "root"
+ group node["root_group"]
+ mode "0644"
+ end
+ when ::File.exist?("/etc/conf.d/hostname")
+ # Gentoo
+ declare_resource(:file, "/etc/conf.d/hostname") do
+ content "hostname=\"#{new_resource.hostname}\"\n"
+ owner "root"
+ group node["root_group"]
+ mode "0644"
+ end
+ else
+ # This is a failsafe for all other linux distributions where we set the hostname
+ # via /etc/sysctl.conf on reboot. This may get into a fight with other cookbooks
+ # that manage sysctls on linux.
+ append_replacing_matching_lines("/etc/sysctl.conf", /^\s+kernel\.hostname\s+=/, "kernel.hostname=#{new_resource.hostname}")
+ end
+ when ::File.exist?("/etc/rc.conf")
+ # *BSD systems with /etc/rc.conf + /etc/myname
+ append_replacing_matching_lines("/etc/rc.conf", /^\s+hostname\s+=/, "hostname=#{new_resource.hostname}")
+
+ declare_resource(:file, "/etc/myname") do
+ content "#{new_resource.hostname}\n"
+ owner "root"
+ group node["root_group"]
+ mode "0644"
+ end
+ when ::File.exist?("/etc/nodename")
+ # Solaris <= 5.10 systems prior to svccfg taking over this functionality (must come before svccfg handling)
+ declare_resource(:file, "/etc/nodename") do
+ content "#{new_resource.hostname}\n"
+ owner "root"
+ group node["root_group"]
+ mode "0644"
+ end
+ # Solaris also has /etc/inet/hosts (copypasta alert)
+ unless new_resource.ipaddress.nil?
+ newline = "#{new_resource.ipaddress} #{new_resource.hostname}"
+ newline << " #{new_resource.aliases.join(" ")}" if new_resource.aliases && !new_resource.aliases.empty?
+ newline << " #{new_resource.hostname[/[^\.]*/]}"
+ r = append_replacing_matching_lines("/etc/inet/hosts", /^#{new_resource.ipaddress}\s+|\s+#{new_resource.hostname}\s+/, newline)
+ r.notifies :reload, "ohai[reload hostname]"
+ end
+ when ::File.exist?("/usr/sbin/svccfg")
+ # Solaris >= 5.11 systems using svccfg (must come after /etc/nodename handling)
+ declare_resource(:execute, "svccfg -s system/identity:node setprop config/nodename=\'#{new_resource.hostname}\'") do
+ notifies :run, "execute[svcadm refresh]", :immediately
+ notifies :run, "execute[svcadm restart]", :immediately
+ not_if { shell_out!("svccfg -s system/identity:node listprop config/nodename").stdout.chomp =~ /config\/nodename\s+astring\s+#{new_resource.hostname}/ }
+ end
+ declare_resource(:execute, "svcadm refresh") do
+ command "svcadm refresh system/identity:node"
+ action :nothing
+ end
+ declare_resource(:execute, "svcadm restart") do
+ command "svcadm restart system/identity:node"
+ action :nothing
+ end
+ else
+ raise "Do not know how to set hostname on os #{node["os"]}, platform #{node["platform"]},"\
+ "platform_version #{node["platform_version"]}, platform_family #{node["platform_family"]}"
+ end
+
+ else # windows
+
+ # suppress EC2 config service from setting our hostname
+ if ::File.exist?('C:\Program Files\Amazon\Ec2ConfigService\Settings\config.xml')
+ xml_contents = updated_ec2_config_xml
+ if xml_contents.empty?
+ Chef::Log.warn('Unable to properly parse and update C:\Program Files\Amazon\Ec2ConfigService\Settings\config.xml contents. Skipping file update.')
+ else
+ declare_resource(:file, 'C:\Program Files\Amazon\Ec2ConfigService\Settings\config.xml') do
+ content xml_contents
+ end
+ end
+ end
+
+ # update via netdom
+ declare_resource(:powershell_script, "set hostname") do
+ code <<-EOH
+ $sysInfo = Get-WmiObject -Class Win32_ComputerSystem
+ $sysInfo.Rename("#{new_resource.hostname}")
+ EOH
+ notifies :request_reboot, "reboot[setting hostname]"
+ not_if { Socket.gethostbyname(Socket.gethostname).first == new_resource.hostname }
+ end
+
+ # reboot because $windows
+ declare_resource(:reboot, "setting hostname") do
+ reason "chef setting hostname"
+ action :nothing
+ only_if { new_resource.windows_reboot }
+ end
+ end
+ end
+
+ # this resource forces itself to run at compile_time
+ def after_created
+ if compile_time
+ Array(action).each do |action|
+ run_action(action)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/resource/rhsm_errata.rb b/lib/chef/resource/rhsm_errata.rb
new file mode 100644
index 0000000000..56779909f5
--- /dev/null
+++ b/lib/chef/resource/rhsm_errata.rb
@@ -0,0 +1,45 @@
+#
+# Copyright:: 2015-2018 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 RhsmErrata < Chef::Resource
+ resource_name :rhsm_errata
+
+ description "A resource for installing packages associated with a given Red"\
+ " Hat Subscription Manager Errata ID. This is helpful if packages"\
+ " to mitigate a single vulnerability must be installed on your hosts."
+ introduced "14.0"
+
+ property :errata_id,
+ String,
+ description: "An optional property for specifying the errata ID if not using the resource's name.",
+ name_property: true
+
+ action :install do
+ description "Installs a package for a specific errata ID"
+
+ execute "Install errata packages for #{new_resource.errata_id}" do
+ command "yum update --advisory #{new_resource.errata_id} -y"
+ action :run
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/resource/rhsm_errata_level.rb b/lib/chef/resource/rhsm_errata_level.rb
new file mode 100644
index 0000000000..3aa289ac2e
--- /dev/null
+++ b/lib/chef/resource/rhsm_errata_level.rb
@@ -0,0 +1,53 @@
+#
+# Copyright:: 2015-2018 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 RhsmErrataLevel < Chef::Resource
+ resource_name :rhsm_errata_level
+
+ description "A resource for installing all packages of a specified errata level"\
+ " from the Red Hat Subscript Manager. For example, you can ensure"\
+ " that all packages associated with errata marked at a 'Critical'"\
+ " security level are installed."
+ introduced "14.0"
+
+ property :errata_level,
+ String,
+ coerce: proc { |x| x.downcase },
+ equal_to: %w{critical moderate important low},
+ description: "The errata level of packages to install.",
+ name_property: true
+
+ action :install do
+ descripton "Install all packages of the specified errata level"
+
+ yum_package "yum-plugin-security" do
+ action :install
+ only_if { node["platform_version"].to_i == 6 }
+ end
+
+ execute "Install any #{new_resource.errata_level} errata" do
+ command "yum update --sec-severity=#{new_resource.errata_level.capitalize} -y"
+ action :run
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/resource/rhsm_register.rb b/lib/chef/resource/rhsm_register.rb
new file mode 100644
index 0000000000..47fe67d1cf
--- /dev/null
+++ b/lib/chef/resource/rhsm_register.rb
@@ -0,0 +1,170 @@
+#
+# Copyright:: 2015-2018 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 "shellwords"
+
+class Chef
+ class Resource
+ class RhsmRegister < Chef::Resource
+ resource_name :rhsm_register
+
+ description "A resource for registering a node with the Red Hat Subscription Manager"\
+ " or a local Red Hat Satellite server."
+ introduced "14.0"
+
+ property :activation_key,
+ [String, Array],
+ coerce: proc { |x| Array(x) },
+ description: "A String or array of the activation keys to use when registering. You must also specify the organization property if using activation_key."
+
+ property :satellite_host,
+ String,
+ description: "The FQDN of the Satellite host to register with. If not specified, the host will be registered with Red Hat's public RHSM service."
+
+ property :organization,
+ String,
+ description: "The organization to use when registering, required when using an activation key"
+
+ property :environment,
+ String,
+ description: "The environment to use when registering, required when using username and password"
+
+ property :username,
+ String,
+ description: "The username to use when registering. Not applicable if using an activation key. If specified, password and environment are also required."
+
+ property :password,
+ String,
+ description: "The password to use when registering. Not applicable if using an activation key. If specified, username and environment are also required."
+
+ property :auto_attach,
+ [TrueClass, FalseClass],
+ description: "If true, RHSM will attempt to automatically attach the host to applicable subscriptions. It is generally better to use an activation key with the subscriptions pre-defined.",
+ default: false
+
+ property :install_katello_agent,
+ [TrueClass, FalseClass],
+ description: "If true, the 'katello-agent' RPM will be installed.",
+ default: true
+
+ property :force,
+ [TrueClass, FalseClass],
+ description: "If true, the system will be registered even if it is already registered. Normally, any register operations will fail if the machine is has already registered.",
+ default: false
+
+ action :register do
+ description "Register the node with RHSM"
+
+ package "subscription-manager"
+
+ unless new_resource.satellite_host.nil? || registered_with_rhsm?
+ remote_file "#{Chef::Config[:file_cache_path]}/katello-package.rpm" do
+ source "http://#{new_resource.satellite_host}/pub/katello-ca-consumer-latest.noarch.rpm"
+ action :create
+ notifies :install, "yum_package[katello-ca-consumer-latest]", :immediately
+ not_if { katello_cert_rpm_installed? }
+ end
+
+ yum_package "katello-ca-consumer-latest" do
+ options "--nogpgcheck"
+ source "#{Chef::Config[:file_cache_path]}/katello-package.rpm"
+ action :nothing
+ end
+
+ file "#{Chef::Config[:file_cache_path]}/katello-package.rpm" do
+ action :delete
+ end
+ end
+
+ execute "Register to RHSM" do
+ sensitive new_resource.sensitive
+ command register_command
+ action :run
+ not_if { registered_with_rhsm? }
+ end
+
+ yum_package "katello-agent" do
+ action :install
+ only_if { new_resource.install_katello_agent && !new_resource.satellite_host.nil? }
+ end
+ end
+
+ action :unregister do
+ description "Unregister the node from RHSM"
+
+ execute "Unregister from RHSM" do
+ command "subscription-manager unregister"
+ action :run
+ only_if { registered_with_rhsm? }
+ notifies :run, "execute[Clean RHSM Config]", :immediately
+ end
+
+ execute "Clean RHSM Config" do
+ command "subscription-manager clean"
+ action :nothing
+ end
+ end
+
+ action_class do
+ def registered_with_rhsm?
+ cmd = Mixlib::ShellOut.new("subscription-manager status", env: { LANG: "en_US" })
+ cmd.run_command
+ !cmd.stdout.match(/Overall Status: Unknown/)
+ end
+
+ def katello_cert_rpm_installed?
+ cmd = Mixlib::ShellOut.new("rpm -qa | grep katello-ca-consumer")
+ cmd.run_command
+ !cmd.stdout.match(/katello-ca-consumer/).nil?
+ end
+
+ def register_command
+ command = %w{subscription-manager register}
+
+ unless new_resource.activation_key.empty?
+ raise "Unable to register - you must specify organization when using activation keys" if new_resource.organization.nil?
+
+ command << new_resource.activation_key.map { |key| "--activationkey=#{Shellwords.shellescape(key)}" }
+ command << "--org=#{Shellwords.shellescape(new_resource.organization)}"
+ command << "--force" if new_resource.force
+
+ return command.join(" ")
+ end
+
+ if new_resource.username && new_resource.password
+ raise "Unable to register - you must specify environment when using username/password" if new_resource.environment.nil? && using_satellite_host?
+
+ command << "--username=#{Shellwords.shellescape(new_resource.username)}"
+ command << "--password=#{Shellwords.shellescape(new_resource.password)}"
+ command << "--environment=#{Shellwords.shellescape(new_resource.environment)}" if using_satellite_host?
+ command << "--auto-attach" if new_resource.auto_attach
+ command << "--force" if new_resource.force
+
+ return command.join(" ")
+ end
+
+ raise "Unable to create register command - you must specify activation_key or username/password"
+ end
+
+ def using_satellite_host?
+ !new_resource.satellite_host.nil?
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/resource/rhsm_repo.rb b/lib/chef/resource/rhsm_repo.rb
new file mode 100644
index 0000000000..aef4dd43d6
--- /dev/null
+++ b/lib/chef/resource/rhsm_repo.rb
@@ -0,0 +1,63 @@
+#
+# Copyright:: 2015-2018 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 RhsmRepo < Chef::Resource
+ resource_name :rhsm_repo
+
+ description "A resource for enabling and disabling Red Hat Subscription Manager"\
+ " repositories that are made available via attached subscriptions."
+ introduced "14.0"
+
+ property :repo_name,
+ String,
+ description: "An optional property for specifying the repository name if not using the resource's name.",
+ name_property: true
+
+ action :enable do
+ description "Enable a RHSM repository"
+
+ execute "Enable repository #{repo_name}" do
+ command "subscription-manager repos --enable=#{repo_name}"
+ action :run
+ not_if { repo_enabled?(repo_name) }
+ end
+ end
+
+ action :disable do
+ description "Disable a RHSM repository"
+
+ execute "Enable repository #{repo_name}" do
+ command "subscription-manager repos --disable=#{repo_name}"
+ action :run
+ only_if { repo_enabled?(repo_name) }
+ end
+ end
+
+ action_class do
+ def repo_enabled?(repo)
+ cmd = Mixlib::ShellOut.new("subscription-manager repos --list-enabled", env: { LANG: "en_US" })
+ cmd.run_command
+ !cmd.stdout.match(/Repo ID:\s+#{repo}$/).nil?
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/resource/rhsm_subscription.rb b/lib/chef/resource/rhsm_subscription.rb
new file mode 100644
index 0000000000..41dd398cd5
--- /dev/null
+++ b/lib/chef/resource/rhsm_subscription.rb
@@ -0,0 +1,96 @@
+#
+# Copyright:: 2015-2018 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 RhsmSubscription < Chef::Resource
+ resource_name :rhsm_subscription
+
+ description "A resource for adding additional Redhat Subscription Manager subscriptions"\
+ " to your host. This can be used when a host's activation_key"\
+ " does not attach all necessary subscriptions to your host."
+ introduced "14.0"
+
+ property :pool_id,
+ String,
+ description: "An optional property for specifying the Pool ID if not using the resource's name.",
+ name_property: true
+
+ action :attach do
+ description "Attach the node to a subscription pool"
+
+ execute "Attach subscription pool #{new_resource.pool_id}" do
+ command "subscription-manager attach --pool=#{new_resource.pool_id}"
+ action :run
+ not_if { subscription_attached?(new_resource.pool_id) }
+ end
+ end
+
+ action :remove do
+ description "Remove the node from a subscription pool"
+
+ execute "Remove subscription pool #{new_resource.pool_id}" do
+ command "subscription-manager remove --serial=#{pool_serial(new_resource.pool_id)}"
+ action :run
+ only_if { subscription_attached?(new_resource.pool_id) }
+ end
+ end
+
+ action_class do
+ def subscription_attached?(subscription)
+ cmd = Mixlib::ShellOut.new("subscription-manager list --consumed | grep #{subscription}", env: { LANG: "en_US" })
+ cmd.run_command
+ !cmd.stdout.match(/Pool ID:\s+#{subscription}$/).nil?
+ end
+
+ def serials_by_pool
+ serials = {}
+ pool = nil
+ serial = nil
+
+ cmd = Mixlib::ShellOut.new("subscription-manager list --consumed", env: { LANG: "en_US" })
+ cmd.run_command
+ cmd.stdout.lines.each do |line|
+ line.strip!
+ key, value = line.split(/:\s+/, 2)
+ next unless ["Pool ID", "Serial"].include?(key)
+
+ if key == "Pool ID"
+ pool = value
+ elsif key == "Serial"
+ serial = value
+ end
+
+ next unless pool && serial
+
+ serials[pool] = serial
+ pool = nil
+ serial = nil
+ end
+
+ serials
+ end
+
+ def pool_serial(pool_id)
+ serials_by_pool[pool_id]
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/resource/systemd_unit.rb b/lib/chef/resource/systemd_unit.rb
index b08b26efa7..baf7e4cfa8 100644
--- a/lib/chef/resource/systemd_unit.rb
+++ b/lib/chef/resource/systemd_unit.rb
@@ -1,6 +1,6 @@
#
# Author:: Nathan Williams (<nath.e.will@gmail.com>)
-# Copyright:: Copyright 2016, Nathan Williams
+# Copyright:: Copyright 2016-2018, Nathan Williams
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -29,7 +29,8 @@ class Chef
default_action :nothing
allowed_actions :create, :delete,
- :enable, :disable,
+ :preset, :revert,
+ :enable, :disable, :reenable,
:mask, :unmask,
:start, :stop,
:restart, :reload,
diff --git a/lib/chef/resource/env.rb b/lib/chef/resource/windows_env.rb
index 12133f4368..d25fe9326b 100644
--- a/lib/chef/resource/env.rb
+++ b/lib/chef/resource/windows_env.rb
@@ -21,8 +21,9 @@ class Chef
class Resource
# Use the env resource to manage environment keys in Microsoft Windows. After an environment key is set, Microsoft
# Windows must be restarted before the environment key will be available to the Task Scheduler.
- class Env < Chef::Resource
- resource_name :env
+ class WindowsEnv < Chef::Resource
+ resource_name :windows_env
+ provides :windows_env, os: "windows"
provides :env, os: "windows"
default_action :create
@@ -31,6 +32,7 @@ class Chef
property :key_name, String, identity: true, name_property: true
property :value, String, required: true
property :delim, [ String, nil, false ], desired_state: false
+ property :user, String, default: "<System>"
end
end
end
diff --git a/lib/chef/resources.rb b/lib/chef/resources.rb
index 9fee978432..d54e7815c4 100644
--- a/lib/chef/resources.rb
+++ b/lib/chef/resources.rb
@@ -33,7 +33,6 @@ require "chef/resource/dpkg_package"
require "chef/resource/dnf_package"
require "chef/resource/dsc_script"
require "chef/resource/dsc_resource"
-require "chef/resource/env"
require "chef/resource/execute"
require "chef/resource/file"
require "chef/resource/freebsd_package"
@@ -42,6 +41,7 @@ require "chef/resource/gem_package"
require "chef/resource/git"
require "chef/resource/group"
require "chef/resource/http_request"
+require "chef/resource/hostname"
require "chef/resource/homebrew_package"
require "chef/resource/ifconfig"
require "chef/resource/ksh"
@@ -68,6 +68,11 @@ require "chef/resource/reboot"
require "chef/resource/registry_key"
require "chef/resource/remote_directory"
require "chef/resource/remote_file"
+require "chef/resource/rhsm_errata_level"
+require "chef/resource/rhsm_errata"
+require "chef/resource/rhsm_register"
+require "chef/resource/rhsm_repo"
+require "chef/resource/rhsm_subscription"
require "chef/resource/rpm_package"
require "chef/resource/solaris_package"
require "chef/resource/route"
@@ -89,6 +94,7 @@ require "chef/resource/user/pw_user"
require "chef/resource/user/solaris_user"
require "chef/resource/user/windows_user"
require "chef/resource/whyrun_safe_ruby_block"
+require "chef/resource/windows_env"
require "chef/resource/windows_package"
require "chef/resource/yum_package"
require "chef/resource/yum_repository"
diff --git a/lib/chef/version.rb b/lib/chef/version.rb
index 6af0290cbc..72efa3b085 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("14.0.50")
+ VERSION = Chef::VersionString.new("14.0.61")
end
#
diff --git a/omnibus/Gemfile.lock b/omnibus/Gemfile.lock
index 0a400af685..a36078d763 100644
--- a/omnibus/Gemfile.lock
+++ b/omnibus/Gemfile.lock
@@ -1,8 +1,8 @@
GIT
remote: https://github.com/chef/omnibus
- revision: 68c301587d8856c6ec4445a24ec49365bb22a314
+ revision: 63e908114e460d47609869ece898c45d7250247b
specs:
- omnibus (5.6.8)
+ omnibus (5.6.9)
aws-sdk (~> 2)
chef-sugar (~> 3.3)
cleanroom (~> 1.0)
@@ -29,13 +29,13 @@ GEM
addressable (2.5.2)
public_suffix (>= 2.0.2, < 4.0)
awesome_print (1.8.0)
- aws-sdk (2.10.128)
- aws-sdk-resources (= 2.10.128)
- aws-sdk-core (2.10.128)
+ aws-sdk (2.10.129)
+ aws-sdk-resources (= 2.10.129)
+ aws-sdk-core (2.10.129)
aws-sigv4 (~> 1.0)
jmespath (~> 1.0)
- aws-sdk-resources (2.10.128)
- aws-sdk-core (= 2.10.128)
+ aws-sdk-resources (2.10.129)
+ aws-sdk-core (= 2.10.129)
aws-sigv4 (1.0.2)
berkshelf (4.3.5)
addressable (~> 2.3, >= 2.3.4)
@@ -91,6 +91,8 @@ GEM
faraday (0.9.2)
multipart-post (>= 1.2, < 3)
ffi (1.9.21)
+ ffi (1.9.21-x64-mingw32)
+ ffi (1.9.21-x86-mingw32)
ffi-yajl (2.3.1)
libyajl2 (~> 1.2)
fuzzyurl (0.9.0)
@@ -100,6 +102,7 @@ GEM
builder (>= 2.1.2)
hashie (3.5.7)
hitimes (1.2.6)
+ hitimes (1.2.6-x86-mingw32)
httpclient (2.7.2)
iostruct (0.0.4)
ipaddress (0.8.3)
@@ -122,13 +125,16 @@ GEM
mixlib-log
mixlib-authentication (1.4.2)
mixlib-cli (1.7.0)
- mixlib-config (2.2.4)
- mixlib-install (3.9.0)
+ mixlib-config (2.2.5)
+ mixlib-install (3.9.3)
mixlib-shellout
mixlib-versioning
thor
mixlib-log (1.7.1)
mixlib-shellout (2.3.2)
+ mixlib-shellout (2.3.2-universal-mingw32)
+ win32-process (~> 0.8.2)
+ wmi-lite (~> 1.0)
mixlib-versioning (1.2.2)
molinillo (0.4.5)
multi_json (1.13.1)
@@ -171,7 +177,7 @@ GEM
pry-stack_explorer (0.4.9.2)
binding_of_caller (>= 0.7)
pry (>= 0.9.11)
- public_suffix (3.0.1)
+ public_suffix (3.0.2)
retryable (2.0.4)
ridley (4.6.1)
addressable
@@ -221,6 +227,8 @@ GEM
varia_model (0.4.1)
buff-extensions (~> 1.0)
hashie (>= 2.0.2, < 4.0.0)
+ win32-process (0.8.3)
+ ffi (>= 1.0.0)
winrm (2.2.3)
builder (>= 2.1.2)
erubis (~> 2.7)
@@ -243,6 +251,8 @@ GEM
PLATFORMS
ruby
+ x64-mingw32
+ x86-mingw32
DEPENDENCIES
berkshelf (~> 4.0)
@@ -257,4 +267,4 @@ DEPENDENCIES
winrm-fs (~> 1.0)
BUNDLED WITH
- 1.15.1
+ 1.16.1
diff --git a/spec/functional/resource/env_spec.rb b/spec/functional/resource/env_spec.rb
deleted file mode 100755
index 4b0ff70c0b..0000000000
--- a/spec/functional/resource/env_spec.rb
+++ /dev/null
@@ -1,192 +0,0 @@
-#
-# Author:: Adam Edwards (<adamed@chef.io>)
-# Copyright:: Copyright 2014-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 "spec_helper"
-
-describe Chef::Resource::Env, :windows_only do
- context "when running on Windows" do
- let(:chef_env_test_lower_case) { "chefenvtest" }
- let(:chef_env_test_mixed_case) { "chefENVtest" }
- let(:env_dne_key) { "env_dne_key" }
- let(:env_value1) { "value1" }
- let(:env_value2) { "value2" }
-
- let(:env_value_expandable) { "%SystemRoot%" }
- let(:test_run_context) do
- node = Chef::Node.new
- node.default["os"] = "windows"
- node.default["platform"] = "windows"
- node.default["platform_version"] = "6.1"
- empty_events = Chef::EventDispatch::Dispatcher.new
- Chef::RunContext.new(node, {}, empty_events)
- end
- let(:test_resource) do
- Chef::Resource::Env.new("unknown", test_run_context)
- end
-
- before(:each) do
- resource_lower = Chef::Resource::Env.new(chef_env_test_lower_case, test_run_context)
- resource_lower.run_action(:delete)
- resource_mixed = Chef::Resource::Env.new(chef_env_test_mixed_case, test_run_context)
- resource_mixed.run_action(:delete)
- end
-
- context "when the create action is invoked" do
- it "should create an environment variable for action create" do
- expect(ENV[chef_env_test_lower_case]).to eq(nil)
- test_resource.key_name(chef_env_test_lower_case)
- test_resource.value(env_value1)
- test_resource.run_action(:create)
- expect(ENV[chef_env_test_lower_case]).to eq(env_value1)
- end
-
- it "should modify an existing variable's value to a new value" do
- test_resource.key_name(chef_env_test_lower_case)
- test_resource.value(env_value1)
- test_resource.run_action(:create)
- expect(ENV[chef_env_test_lower_case]).to eq(env_value1)
- test_resource.value(env_value2)
- test_resource.run_action(:create)
- expect(ENV[chef_env_test_lower_case]).to eq(env_value2)
- end
-
- it "should modify an existing variable's value to a new value if the variable name case differs from the existing variable" do
- test_resource.key_name(chef_env_test_lower_case)
- test_resource.value(env_value1)
- test_resource.run_action(:create)
- expect(ENV[chef_env_test_lower_case]).to eq(env_value1)
- test_resource.key_name(chef_env_test_mixed_case)
- test_resource.value(env_value2)
- test_resource.run_action(:create)
- expect(ENV[chef_env_test_lower_case]).to eq(env_value2)
- end
-
- it "should not expand environment variables if the variable is not PATH" do
- expect(ENV[chef_env_test_lower_case]).to eq(nil)
- test_resource.key_name(chef_env_test_lower_case)
- test_resource.value(env_value_expandable)
- test_resource.run_action(:create)
- expect(ENV[chef_env_test_lower_case]).to eq(env_value_expandable)
- end
- end
-
- context "when the modify action is invoked" do
- it "should raise an exception for modify if the variable doesn't exist" do
- expect(ENV[chef_env_test_lower_case]).to eq(nil)
- test_resource.key_name(chef_env_test_lower_case)
- test_resource.value(env_value1)
- expect { test_resource.run_action(:modify) }.to raise_error(Chef::Exceptions::Env)
- end
-
- it "should modify an existing variable's value to a new value" do
- test_resource.key_name(chef_env_test_lower_case)
- test_resource.value(env_value1)
- test_resource.run_action(:create)
- expect(ENV[chef_env_test_lower_case]).to eq(env_value1)
- test_resource.value(env_value2)
- test_resource.run_action(:modify)
- expect(ENV[chef_env_test_lower_case]).to eq(env_value2)
- end
-
- # This examlpe covers Chef Issue #1754
- it "should modify an existing variable's value to a new value if the variable name case differs from the existing variable" do
- test_resource.key_name(chef_env_test_lower_case)
- test_resource.value(env_value1)
- test_resource.run_action(:create)
- expect(ENV[chef_env_test_lower_case]).to eq(env_value1)
- test_resource.key_name(chef_env_test_mixed_case)
- test_resource.value(env_value2)
- test_resource.run_action(:modify)
- expect(ENV[chef_env_test_lower_case]).to eq(env_value2)
- end
-
- it "should not expand environment variables if the variable is not PATH" do
- test_resource.key_name(chef_env_test_lower_case)
- test_resource.value(env_value1)
- test_resource.run_action(:create)
- expect(ENV[chef_env_test_lower_case]).to eq(env_value1)
- test_resource.value(env_value_expandable)
- test_resource.run_action(:modify)
- expect(ENV[chef_env_test_lower_case]).to eq(env_value_expandable)
- end
-
- context "when using PATH" do
- let(:random_name) { Time.now.to_i }
- let(:env_val) { "#{env_value_expandable}_#{random_name}" }
- let!(:path_before) { test_resource.provider_for_action(test_resource.action).env_value("PATH") || "" }
- let!(:env_path_before) { ENV["PATH"] }
-
- it "should expand PATH" do
- expect(path_before).not_to include(env_val)
- test_resource.key_name("PATH")
- test_resource.value("#{path_before};#{env_val}")
- test_resource.run_action(:create)
- expect(ENV["PATH"]).not_to include(env_val)
- expect(ENV["PATH"]).to include("#{random_name}")
- end
-
- after(:each) do
- # cleanup so we don't flood the path
- test_resource.key_name("PATH")
- test_resource.value(path_before)
- test_resource.run_action(:create)
- ENV["PATH"] = env_path_before
- end
- end
-
- end
-
- context "when the delete action is invoked" do
- it "should delete an environment variable" do
- test_resource.key_name(chef_env_test_lower_case)
- test_resource.value(env_value1)
- test_resource.run_action(:create)
- expect(ENV[chef_env_test_lower_case]).to eq(env_value1)
- test_resource.run_action(:delete)
- expect(ENV[chef_env_test_lower_case]).to eq(nil)
- end
-
- it "should not raise an exception when a non-existent environment variable is deleted" do
- expect(ENV[chef_env_test_lower_case]).to eq(nil)
- test_resource.key_name(chef_env_test_lower_case)
- test_resource.value(env_value1)
- expect { test_resource.run_action(:delete) }.not_to raise_error
- expect(ENV[chef_env_test_lower_case]).to eq(nil)
- end
-
- it "should delete an existing variable's value to a new value if the specified variable name case differs from the existing variable" do
- test_resource.key_name(chef_env_test_lower_case)
- test_resource.value(env_value1)
- test_resource.run_action(:create)
- expect(ENV[chef_env_test_lower_case]).to eq(env_value1)
- test_resource.key_name(chef_env_test_mixed_case)
- test_resource.run_action(:delete)
- expect(ENV[chef_env_test_lower_case]).to eq(nil)
- expect(ENV[chef_env_test_mixed_case]).to eq(nil)
- end
-
- it "should delete a value from the current process even if it is not in the registry" do
- expect(ENV[env_dne_key]).to eq(nil)
- ENV[env_dne_key] = env_value1
- test_resource.key_name(env_dne_key)
- test_resource.run_action(:delete)
- expect(ENV[env_dne_key]).to eq(nil)
- end
- end
- end
-end
diff --git a/spec/functional/resource/windows_env_spec.rb b/spec/functional/resource/windows_env_spec.rb
new file mode 100644
index 0000000000..a6c6b39970
--- /dev/null
+++ b/spec/functional/resource/windows_env_spec.rb
@@ -0,0 +1,285 @@
+#
+# Author:: Adam Edwards (<adamed@chef.io>)
+# Copyright:: Copyright 2014-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 "spec_helper"
+
+describe Chef::Resource::WindowsEnv, :windows_only do
+ context "when running on Windows" do
+ let(:chef_env_test_lower_case) { "chefenvtest" }
+ let(:chef_env_test_mixed_case) { "chefENVtest" }
+ let(:chef_env_with_delim) { "chef_env_with_delim" }
+ let(:chef_env_delim) { ";" }
+ let(:chef_env_test_delim) { "#{value1};#{value2}" }
+ let(:env_dne_key) { "env_dne_key" }
+ let(:env_value1) { "value1" }
+ let(:env_value2) { "value2" }
+ let(:delim_value) { "#{env_value1};#{env_value2}" }
+ let(:env_user) { ENV["USERNAME"].upcase }
+ let(:default_env_user) { "<SYSTEM>" }
+
+ let(:env_obj) do
+ wmi = WmiLite::Wmi.new
+ environment_variables = wmi.query("select * from Win32_Environment where name = '#{test_resource.key_name}'")
+ if environment_variables && environment_variables.length > 0
+ environment_variables.each do |env|
+ env_obj = env.wmi_ole_object
+ return env_obj if env_obj.username.split('\\').last.casecmp(test_resource.user) == 0
+ end
+ end
+ nil
+ end
+
+ let(:env_value_expandable) { "%SystemRoot%" }
+ let(:test_run_context) do
+ node = Chef::Node.new
+ node.default["os"] = "windows"
+ node.default["platform"] = "windows"
+ node.default["platform_version"] = "6.1"
+ empty_events = Chef::EventDispatch::Dispatcher.new
+ Chef::RunContext.new(node, {}, empty_events)
+ end
+ let(:test_resource) do
+ Chef::Resource::WindowsEnv.new("unknown", test_run_context)
+ end
+
+ before(:each) do
+ resource_lower = Chef::Resource::WindowsEnv.new(chef_env_test_lower_case, test_run_context)
+ resource_lower.run_action(:delete)
+ resource_lower = Chef::Resource::WindowsEnv.new(chef_env_test_lower_case, test_run_context)
+ resource_lower.user(env_user)
+ resource_lower.run_action(:delete)
+ resource_mixed = Chef::Resource::WindowsEnv.new(chef_env_test_mixed_case, test_run_context)
+ resource_mixed.run_action(:delete)
+ resource_mixed = Chef::Resource::WindowsEnv.new(chef_env_test_mixed_case, test_run_context)
+ resource_lower.user(env_user)
+ resource_mixed.run_action(:delete)
+ end
+
+ context "when the create action is invoked" do
+ it "should create an environment variable for action create" do
+ expect(ENV[chef_env_test_lower_case]).to eq(nil)
+ test_resource.key_name(chef_env_test_lower_case)
+ test_resource.value(env_value1)
+ test_resource.run_action(:create)
+ expect(ENV[chef_env_test_lower_case]).to eq(env_value1)
+ end
+
+ it "should create an environment variable with default user System for action create" do
+ expect(ENV[chef_env_test_lower_case]).to eq(nil)
+ test_resource.key_name(chef_env_test_lower_case)
+ test_resource.value(env_value1)
+ test_resource.run_action(:create)
+ expect(env_obj.username.upcase).to eq(default_env_user)
+ end
+
+ it "should create an environment variable with user for action create" do
+ expect(ENV[chef_env_test_lower_case]).to eq(nil)
+ test_resource.key_name(chef_env_test_lower_case)
+ test_resource.value(env_value1)
+ test_resource.user(env_user)
+ test_resource.run_action(:create)
+ expect(env_obj.username.split('\\').last.upcase).to eq(env_user)
+ end
+
+ context "when env variable exist with same name" do
+ before(:each) do
+ test_resource.key_name(chef_env_test_lower_case)
+ test_resource.value(env_value1)
+ test_resource.run_action(:create)
+ end
+ it "should modify an existing variable's value to a new value" do
+ expect(ENV[chef_env_test_lower_case]).to eq(env_value1)
+ test_resource.value(env_value2)
+ test_resource.run_action(:create)
+ expect(ENV[chef_env_test_lower_case]).to eq(env_value2)
+ end
+
+ it "should not modify an existing variable's value to a new value if the users are different" do
+ expect(ENV[chef_env_test_lower_case]).to eq(env_value1)
+ test_resource.value(env_value2)
+ test_resource.user(env_user)
+ test_resource.run_action(:create)
+ test_resource.key_name(chef_env_test_lower_case)
+ test_resource.user(default_env_user)
+ expect(env_obj.variablevalue).to eq(env_value1)
+ end
+
+ it "should modify an existing variable's value to a new value if the variable name case differs from the existing variable" do
+ expect(ENV[chef_env_test_lower_case]).to eq(env_value1)
+ test_resource.key_name(chef_env_test_mixed_case)
+ test_resource.value(env_value2)
+ test_resource.run_action(:create)
+ expect(ENV[chef_env_test_lower_case]).to eq(env_value2)
+ end
+ end
+
+ it "should not expand environment variables if the variable is not PATH" do
+ expect(ENV[chef_env_test_lower_case]).to eq(nil)
+ test_resource.key_name(chef_env_test_lower_case)
+ test_resource.value(env_value_expandable)
+ test_resource.run_action(:create)
+ expect(ENV[chef_env_test_lower_case]).to eq(env_value_expandable)
+ end
+ end
+
+ context "when the modify action is invoked" do
+ it "should raise an exception for modify if the variable doesn't exist" do
+ expect(ENV[chef_env_test_lower_case]).to eq(nil)
+ test_resource.key_name(chef_env_test_lower_case)
+ test_resource.value(env_value1)
+ expect { test_resource.run_action(:modify) }.to raise_error(Chef::Exceptions::WindowsEnv)
+ end
+
+ context "when env variable exist with same name" do
+ before(:each) do
+ test_resource.key_name(chef_env_test_lower_case)
+ test_resource.value(env_value1)
+ test_resource.run_action(:create)
+ end
+
+ it "should modify an existing variable's value to a new value" do
+ expect(ENV[chef_env_test_lower_case]).to eq(env_value1)
+ test_resource.value(env_value2)
+ test_resource.run_action(:modify)
+ expect(ENV[chef_env_test_lower_case]).to eq(env_value2)
+ end
+
+ # This examlpe covers Chef Issue #1754
+ it "should modify an existing variable's value to a new value if the variable name case differs from the existing variable" do
+ expect(ENV[chef_env_test_lower_case]).to eq(env_value1)
+ test_resource.key_name(chef_env_test_mixed_case)
+ test_resource.value(env_value2)
+ test_resource.run_action(:modify)
+ expect(ENV[chef_env_test_lower_case]).to eq(env_value2)
+ end
+
+ it "should not expand environment variables if the variable is not PATH" do
+ expect(ENV[chef_env_test_lower_case]).to eq(env_value1)
+ test_resource.value(env_value_expandable)
+ test_resource.run_action(:modify)
+ expect(ENV[chef_env_test_lower_case]).to eq(env_value_expandable)
+ end
+ end
+
+ context "when using PATH" do
+ let(:random_name) { Time.now.to_i }
+ let(:env_val) { "#{env_value_expandable}_#{random_name}" }
+ let!(:path_before) { test_resource.provider_for_action(test_resource.action).env_value("PATH") || "" }
+ let!(:env_path_before) { ENV["PATH"] }
+
+ it "should expand PATH" do
+ expect(path_before).not_to include(env_val)
+ test_resource.key_name("PATH")
+ test_resource.value("#{path_before};#{env_val}")
+ test_resource.run_action(:create)
+ expect(ENV["PATH"]).not_to include(env_val)
+ expect(ENV["PATH"]).to include("#{random_name}")
+ end
+
+ after(:each) do
+ # cleanup so we don't flood the path
+ test_resource.key_name("PATH")
+ test_resource.value(path_before)
+ test_resource.run_action(:create)
+ ENV["PATH"] = env_path_before
+ end
+ end
+
+ end
+
+ context "when the delete action is invoked" do
+ context "when env variable exist with same name" do
+ before(:each) do
+ test_resource.key_name(chef_env_test_lower_case)
+ test_resource.value(env_value1)
+ test_resource.run_action(:create)
+ end
+
+ it "should delete a System environment variable" do
+ expect(ENV[chef_env_test_lower_case]).to eq(env_value1)
+ test_resource.run_action(:delete)
+ expect(ENV[chef_env_test_lower_case]).to eq(nil)
+ end
+
+ it "should not delete an System environment variable if user are passed" do
+ expect(ENV[chef_env_test_lower_case]).to eq(env_value1)
+ test_resource.user(env_user)
+ test_resource.run_action(:delete)
+ test_resource.user(default_env_user)
+ expect(env_obj).not_to be_nil
+ end
+ end
+
+ context "when env variable exist with same name" do
+ before(:each) do
+ test_resource.key_name(chef_env_test_lower_case)
+ test_resource.value(env_value1)
+ test_resource.user(env_user)
+ test_resource.run_action(:create)
+ end
+
+ it "should delete a user environment variable" do
+ expect(ENV[chef_env_test_lower_case]).to eq(env_value1)
+ test_resource.run_action(:delete)
+ expect(env_obj).to eq(nil)
+ end
+
+ it "should not delete an user environment variable if user is not passed" do
+ expect(ENV[chef_env_test_lower_case]).to eq(env_value1)
+ test_resource.user(default_env_user)
+ test_resource.run_action(:delete)
+ test_resource.user(env_user)
+ expect(env_obj).not_to be_nil
+ end
+ end
+
+ context "when env variable exist with same name" do
+ before(:each) do
+ test_resource.key_name(chef_env_with_delim)
+ test_resource.delim(chef_env_delim)
+ test_resource.value(delim_value)
+ test_resource.run_action(:create)
+ end
+
+ it "should not delete variable when a delim present" do
+ expect(ENV[chef_env_with_delim]).to eq(delim_value)
+ test_resource.value(env_value1)
+ test_resource.run_action(:delete)
+ expect(ENV[chef_env_with_delim]).to eq(env_value2)
+ end
+ end
+
+ it "should not raise an exception when a non-existent environment variable is deleted" do
+ expect(ENV[chef_env_test_lower_case]).to eq(nil)
+ test_resource.key_name(chef_env_test_lower_case)
+ test_resource.value(env_value1)
+ expect { test_resource.run_action(:delete) }.not_to raise_error
+ expect(ENV[chef_env_test_lower_case]).to eq(nil)
+ end
+
+ it "should delete a value from the current process even if it is not in the registry" do
+ expect(ENV[env_dne_key]).to eq(nil)
+ ENV[env_dne_key] = env_value1
+ test_resource.key_name(env_dne_key)
+ test_resource.run_action(:delete)
+ expect(ENV[env_dne_key]).to eq(nil)
+ end
+
+ end
+ end
+end
diff --git a/spec/integration/knife/chef_fs_data_store_spec.rb b/spec/integration/knife/chef_fs_data_store_spec.rb
index 02508b799d..ff674082b7 100644
--- a/spec/integration/knife/chef_fs_data_store_spec.rb
+++ b/spec/integration/knife/chef_fs_data_store_spec.rb
@@ -28,6 +28,7 @@ describe "ChefFSDataStore tests", :workstation do
let(:cookbook_x_100_metadata_rb) { cb_metadata("x", "1.0.0") }
let(:cookbook_z_100_metadata_rb) { cb_metadata("z", "1.0.0") }
+ let(:cookbook_y_102_metadata_rb) { cb_metadata("z", "1.0.2") }
describe "with repo mode 'hosted_everything' (default)" do
before do
@@ -39,6 +40,8 @@ describe "ChefFSDataStore tests", :workstation do
file "clients/x.json", {}
file "cookbook_artifacts/x-111/metadata.rb", cookbook_x_100_metadata_rb
file "cookbooks/x/metadata.rb", cookbook_x_100_metadata_rb
+ file "cookbooks/y/metadata.rb", cookbook_y_102_metadata_rb
+ file "cookbooks/z/metadata.rb", cookbook_z_100_metadata_rb
file "data_bags/x/y.json", {}
file "environments/x.json", {}
file "nodes/x.json", {}
@@ -64,6 +67,7 @@ describe "ChefFSDataStore tests", :workstation do
/acls/cookbook_artifacts/x.json
/acls/cookbooks/
/acls/cookbooks/x.json
+/acls/cookbooks/z.json
/acls/data_bags/
/acls/data_bags/x.json
/acls/environments/
@@ -84,11 +88,13 @@ describe "ChefFSDataStore tests", :workstation do
/containers/
/containers/x.json
/cookbook_artifacts/
-/cookbook_artifacts/x-111/
-/cookbook_artifacts/x-111/metadata.rb
+/cookbook_artifacts/x-1.0.0/
+/cookbook_artifacts/x-1.0.0/metadata.rb
/cookbooks/
/cookbooks/x/
/cookbooks/x/metadata.rb
+/cookbooks/z/
+/cookbooks/z/metadata.rb
/data_bags/
/data_bags/x/
/data_bags/x/y.json
@@ -111,6 +117,12 @@ EOM
end
end
+ context "LIST /TYPE/NAME" do
+ it "knife cookbook show -z z" do
+ knife("cookbook show -z z").should_succeed "z 1.0.2 1.0.0\n"
+ end
+ end
+
context "DELETE /TYPE/NAME" do
it "knife delete -z /clients/x.json works" do
knife("delete -z /clients/x.json").should_succeed "Deleted /clients/x.json\n"
@@ -119,7 +131,7 @@ EOM
it "knife delete -z -r /cookbooks/x works" do
knife("delete -z -r /cookbooks/x").should_succeed "Deleted /cookbooks/x\n"
- knife("list -z -Rfp /cookbooks").should_succeed ""
+ knife("list -z -Rfp /cookbooks").should_succeed "/cookbooks/z/\n/cookbooks/z/metadata.rb\n"
end
it "knife delete -z -r /data_bags/x works" do
@@ -194,7 +206,14 @@ EOM
Uploading x [1.0.0]
Uploaded 1 cookbook.
EOM
- knife("list --local -Rfp /cookbooks").should_succeed "/cookbooks/x/\n/cookbooks/x/metadata.rb\n"
+ knife("list --local -Rfp /cookbooks").should_succeed <<EOM
+/cookbooks/x/
+/cookbooks/x/metadata.rb
+/cookbooks/y/
+/cookbooks/y/metadata.rb
+/cookbooks/z/
+/cookbooks/z/metadata.rb
+EOM
end
it "knife raw -z -i empty.json -m PUT /data/x/y" do
diff --git a/spec/unit/exceptions_spec.rb b/spec/unit/exceptions_spec.rb
index e952a5448a..c892b24f28 100644
--- a/spec/unit/exceptions_spec.rb
+++ b/spec/unit/exceptions_spec.rb
@@ -25,7 +25,7 @@ describe Chef::Exceptions do
exception_to_super_class = {
Chef::Exceptions::Application => RuntimeError,
Chef::Exceptions::Cron => RuntimeError,
- Chef::Exceptions::Env => RuntimeError,
+ Chef::Exceptions::WindowsEnv => RuntimeError,
Chef::Exceptions::Exec => RuntimeError,
Chef::Exceptions::FileNotFound => RuntimeError,
Chef::Exceptions::Package => RuntimeError,
diff --git a/spec/unit/knife/configure_spec.rb b/spec/unit/knife/configure_spec.rb
index f1d3bd0745..27bb0d9a3f 100644
--- a/spec/unit/knife/configure_spec.rb
+++ b/spec/unit/knife/configure_spec.rb
@@ -26,8 +26,7 @@ describe Chef::Knife::Configure do
let(:ohai) do
o = {}
- allow(o).to receive(:require_plugin)
- allow(o).to receive(:load_plugins)
+ allow(o).to receive(:all_plugins).with(%w{ os hostname fqdn })
o[:fqdn] = fqdn
o
end
diff --git a/spec/unit/mixin/params_validate_spec.rb b/spec/unit/mixin/params_validate_spec.rb
index 0cafb925c8..7bc8a27398 100644
--- a/spec/unit/mixin/params_validate_spec.rb
+++ b/spec/unit/mixin/params_validate_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Adam Jacob (<adam@chef.io>)
-# Copyright:: Copyright 2008-2016, Chef Software Inc.
+# Copyright:: Copyright 2008-2018, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -342,6 +342,17 @@ describe Chef::Mixin::ParamsValidate do
end.to raise_error(Chef::Exceptions::ValidationFailed)
end
+ it "allows a custom validation message" do
+ expect do
+ @vo.validate({ :not_blank => "should pass" },
+ { :not_blank => { :cannot_be => [ :nil, :empty ], validation_message: "my validation message" } })
+ end.not_to raise_error
+ expect do
+ @vo.validate({ :not_blank => "" },
+ { :not_blank => { :cannot_be => [ :nil, :empty ], validation_message: "my validation message" } })
+ end.to raise_error(Chef::Exceptions::ValidationFailed, "my validation message")
+ end
+
it "should set and return a value, then return the same value" do
value = "meow"
expect(@vo.set_or_return(:test, value, {}).object_id).to eq(value.object_id)
diff --git a/spec/unit/mixin/properties_spec.rb b/spec/unit/mixin/properties_spec.rb
index 1af0bc7abd..ee0c252381 100644
--- a/spec/unit/mixin/properties_spec.rb
+++ b/spec/unit/mixin/properties_spec.rb
@@ -11,6 +11,7 @@ module ChefMixinPropertiesSpec
property :a, "a", default: "a"
property :ab, %w{a b}, default: "a"
property :ac, %w{a c}, default: "a"
+ property :d, "d", description: "The d property", introduced: "14.0"
end
context "and a module B with properties b, ab and bc" do
@@ -30,11 +31,20 @@ module ChefMixinPropertiesSpec
end
it "A.properties has a, ab, and ac with types 'a', ['a', 'b'], and ['b', 'c']" do
- expect(A.properties.keys).to eq [ :a, :ab, :ac ]
+ expect(A.properties.keys).to eq [ :a, :ab, :ac, :d ]
expect(A.properties[:a].validation_options[:is]).to eq "a"
expect(A.properties[:ab].validation_options[:is]).to eq %w{a b}
expect(A.properties[:ac].validation_options[:is]).to eq %w{a c}
end
+
+ it "A.properties can get the description of `d`" do
+ expect(A.properties[:d].description).to eq "The d property"
+ end
+
+ it "A.properties can get the release that introduced `d`" do
+ expect(A.properties[:d].introduced).to eq "14.0"
+ end
+
it "B.properties has b, ab, and bc with types 'b', nil and ['b', 'c']" do
expect(B.properties.keys).to eq [ :b, :ab, :bc ]
expect(B.properties[:b].validation_options[:is]).to eq "b"
@@ -42,7 +52,7 @@ module ChefMixinPropertiesSpec
expect(B.properties[:bc].validation_options[:is]).to eq %w{b c}
end
it "C.properties has a, b, c, ac and bc with merged types" do
- expect(C.properties.keys).to eq [ :a, :ab, :ac, :b, :bc, :c ]
+ expect(C.properties.keys).to eq [ :a, :ab, :ac, :d, :b, :bc, :c ]
expect(C.properties[:a].validation_options[:is]).to eq "a"
expect(C.properties[:b].validation_options[:is]).to eq "b"
expect(C.properties[:c].validation_options[:is]).to eq "c"
diff --git a/spec/unit/node_map_spec.rb b/spec/unit/node_map_spec.rb
index 67bb741ec5..24f3bebe2a 100644
--- a/spec/unit/node_map_spec.rb
+++ b/spec/unit/node_map_spec.rb
@@ -19,6 +19,9 @@
require "spec_helper"
require "chef/node_map"
+class Foo; end
+class Bar; end
+
describe Chef::NodeMap do
let(:node_map) { Chef::NodeMap.new }
@@ -120,8 +123,6 @@ describe Chef::NodeMap do
end
describe "ordering classes" do
- class Foo; end
- class Bar; end
it "last writer wins when its reverse alphabetic order" do
node_map.set(:thing, Foo)
node_map.set(:thing, Bar)
@@ -135,6 +136,30 @@ describe Chef::NodeMap do
end
end
+ describe "deleting classes" do
+ it "deletes a class and removes the mapping completely" do
+ node_map.set(:thing, Bar)
+ expect( node_map.delete_class(Bar) ).to eql({ :thing => [{ :klass => Bar }] })
+ expect( node_map.get(node, :thing) ).to eql(nil)
+ end
+
+ it "deletes a class and leaves the mapping that still has an entry" do
+ node_map.set(:thing, Bar)
+ node_map.set(:thing, Foo)
+ expect( node_map.delete_class(Bar) ).to eql({ :thing => [{ :klass => Bar }] })
+ expect( node_map.get(node, :thing) ).to eql(Foo)
+ end
+
+ it "handles deleting classes from multiple keys" do
+ node_map.set(:thing1, Bar)
+ node_map.set(:thing2, Bar)
+ node_map.set(:thing2, Foo)
+ expect( node_map.delete_class(Bar) ).to eql({ :thing1 => [{ :klass => Bar }], :thing2 => [{ :klass => Bar }] })
+ expect( node_map.get(node, :thing1) ).to eql(nil)
+ expect( node_map.get(node, :thing2) ).to eql(Foo)
+ end
+ end
+
describe "with a block doing platform_version checks" do
before do
node_map.set(:thing, :foo, platform_family: "rhel") do |node|
diff --git a/spec/unit/property/validation_spec.rb b/spec/unit/property/validation_spec.rb
index 13afcdfbc2..882ea3353b 100644
--- a/spec/unit/property/validation_spec.rb
+++ b/spec/unit/property/validation_spec.rb
@@ -699,4 +699,13 @@ describe "Chef::Resource.property validation" do
end
end
end
+
+ context "custom validation messages" do
+ with_property ":x, String, validation_message: 'Must be a string, fool'" do
+ it "raise with the correct error message" do
+ expect { resource.x 1 }.to raise_error Chef::Exceptions::ValidationFailed,
+ "Must be a string, fool"
+ end
+ end
+ end
end
diff --git a/spec/unit/provider/env/windows_spec.rb b/spec/unit/provider/env/windows_spec.rb
deleted file mode 100644
index 5ddc1d6f91..0000000000
--- a/spec/unit/provider/env/windows_spec.rb
+++ /dev/null
@@ -1,103 +0,0 @@
-#
-# Author:: Sander van Harmelen <svanharmelen@schubergphilis.com>
-# Copyright:: Copyright 2014-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 "spec_helper"
-
-describe Chef::Provider::Env::Windows, :windows_only do
- let(:node) { Chef::Node.new }
- let(:events) { Chef::EventDispatch::Dispatcher.new }
- let(:run_context) { Chef::RunContext.new(node, {}, events) }
-
- context "when environment variable is not PATH" do
- let(:new_resource) do
- new_resource = Chef::Resource::Env.new("CHEF_WINDOWS_ENV_TEST")
- new_resource.value("foo")
- new_resource
- end
- let(:provider) do
- provider = Chef::Provider::Env::Windows.new(new_resource, run_context)
- allow(provider).to receive(:env_obj).and_return(double("null object").as_null_object)
- provider
- end
-
- describe "action_create" do
- before do
- ENV.delete("CHEF_WINDOWS_ENV_TEST")
- provider.key_exists = false
- end
-
- it "should update the ruby ENV object when it creates the key" do
- provider.action_create
- expect(ENV["CHEF_WINDOWS_ENV_TEST"]).to eql("foo")
- end
- end
-
- describe "action_modify" do
- before do
- ENV["CHEF_WINDOWS_ENV_TEST"] = "foo"
- end
-
- it "should update the ruby ENV object when it updates the value" do
- expect(provider).to receive(:requires_modify_or_create?).and_return(true)
- new_resource.value("foobar")
- provider.action_modify
- expect(ENV["CHEF_WINDOWS_ENV_TEST"]).to eql("foobar")
- end
-
- describe "action_delete" do
- before do
- ENV["CHEF_WINDOWS_ENV_TEST"] = "foo"
- end
-
- it "should update the ruby ENV object when it deletes the key" do
- provider.action_delete
- expect(ENV["CHEF_WINDOWS_ENV_TEST"]).to eql(nil)
- end
- end
- end
- end
-
- context "when environment is PATH" do
- describe "for PATH" do
- let(:system_root) { "%SystemRoot%" }
- let(:system_root_value) { 'D:\Windows' }
- let(:new_resource) do
- new_resource = Chef::Resource::Env.new("PATH")
- new_resource.value(system_root)
- new_resource
- end
- let(:provider) do
- provider = Chef::Provider::Env::Windows.new(new_resource, run_context)
- allow(provider).to receive(:env_obj).and_return(double("null object").as_null_object)
- provider
- end
-
- before do
- stub_const("ENV", { "PATH" => "" })
- end
-
- it "replaces Windows system variables" do
- expect(provider).to receive(:requires_modify_or_create?).and_return(true)
- expect(provider).to receive(:expand_path).with(system_root).and_return(system_root_value)
- provider.action_modify
- expect(ENV["PATH"]).to eql(system_root_value)
- end
- end
-
- end
-end
diff --git a/spec/unit/provider/remote_file/http_spec.rb b/spec/unit/provider/remote_file/http_spec.rb
index ec9c0cf2e3..e1f74bd35a 100644
--- a/spec/unit/provider/remote_file/http_spec.rb
+++ b/spec/unit/provider/remote_file/http_spec.rb
@@ -185,14 +185,12 @@ describe Chef::Provider::RemoteFile::HTTP do
expect(Chef::HTTP::Simple).to receive(:new).with(*expected_http_args).and_return(rest)
end
- describe "and the request does not return new content" do
-
- it "should return a nil tempfile for a 304 HTTPNotModifed" do
- # Streaming request returns nil for 304 errors
- expect(rest).to receive(:streaming_request).with(uri, {}, tempfile).and_return(nil)
- expect(fetcher.fetch).to be_nil
- end
-
+ it "should clean up the tempfile, and return a nil when streaming_request returns nil" do
+ # Streaming request returns nil for a 304 not modified (etags / last-modified)
+ expect(rest).to receive(:streaming_request).with(uri, {}, tempfile).and_return(nil)
+ expect(tempfile).to receive(:close)
+ expect(tempfile).to receive(:unlink)
+ expect(fetcher.fetch).to be_nil
end
context "with progress reports" do
diff --git a/spec/unit/provider/systemd_unit_spec.rb b/spec/unit/provider/systemd_unit_spec.rb
index 8e19503814..15d5944992 100644
--- a/spec/unit/provider/systemd_unit_spec.rb
+++ b/spec/unit/provider/systemd_unit_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Nathan Williams (<nath.e.will@gmail.com>)
-# Copyright:: Copyright (c), Nathan Williams
+# Copyright:: Copyright 2016-2018, Nathan Williams
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -250,7 +250,7 @@ describe Chef::Provider::SystemdUnit do
.and_return(systemctl_path)
end
- describe "creates/deletes the unit" do
+ describe "creates/deletes/presets/reverts the unit" do
it "creates the unit file when it does not exist" do
allow(provider).to receive(:manage_unit_file)
.with(:create)
@@ -345,6 +345,22 @@ describe Chef::Provider::SystemdUnit do
expect(provider).to_not receive(:manage_unit_file)
provider.action_delete
end
+
+ it "presets the unit" do
+ new_resource.user("joe")
+ expect(provider).to receive(:shell_out_with_systems_locale!)
+ .with("#{systemctl_path} --user preset #{unit_name_escaped}", user_cmd_opts)
+ .and_return(shell_out_success)
+ provider.action_preset
+ end
+
+ it "reverts the unit" do
+ new_resource.user("joe")
+ expect(provider).to receive(:shell_out_with_systems_locale!)
+ .with("#{systemctl_path} --user revert #{unit_name_escaped}", user_cmd_opts)
+ .and_return(shell_out_success)
+ provider.action_revert
+ end
end
context "when no user is specified" do
@@ -368,11 +384,33 @@ describe Chef::Provider::SystemdUnit do
expect(provider).to_not receive(:manage_unit_file)
provider.action_delete
end
+
+ it "presets the unit" do
+ expect(provider).to receive(:shell_out_with_systems_locale!)
+ .with("#{systemctl_path} --system preset #{unit_name_escaped}", {})
+ .and_return(shell_out_success)
+ provider.action_preset
+ end
+
+ it "reverts the unit" do
+ expect(provider).to receive(:shell_out_with_systems_locale!)
+ .with("#{systemctl_path} --system revert #{unit_name_escaped}", {})
+ .and_return(shell_out_success)
+ provider.action_revert
+ end
end
end
- describe "enables/disables the unit" do
+ describe "enables/disables/reenables the unit" do
context "when a user is specified" do
+ it "reenables the unit" do
+ current_resource.user(user_name)
+ expect(provider).to receive(:shell_out_with_systems_locale!)
+ .with("#{systemctl_path} --user reenable #{unit_name_escaped}", user_cmd_opts)
+ .and_return(shell_out_success)
+ provider.action_reenable
+ end
+
it "enables the unit when it is disabled" do
current_resource.user(user_name)
current_resource.enabled(false)
@@ -421,6 +459,13 @@ describe Chef::Provider::SystemdUnit do
end
context "when no user is specified" do
+ it "reenables the unit" do
+ expect(provider).to receive(:shell_out_with_systems_locale!)
+ .with("#{systemctl_path} --system reenable #{unit_name_escaped}", {})
+ .and_return(shell_out_success)
+ provider.action_reenable
+ end
+
it "enables the unit when it is disabled" do
current_resource.enabled(false)
expect(provider).to receive(:shell_out_with_systems_locale!)
diff --git a/spec/unit/provider/env_spec.rb b/spec/unit/provider/windows_env_spec.rb
index fd52c5a8ed..a42a0509c5 100644
--- a/spec/unit/provider/env_spec.rb
+++ b/spec/unit/provider/windows_env_spec.rb
@@ -18,15 +18,16 @@
require "spec_helper"
-describe Chef::Provider::Env do
+describe Chef::Provider::WindowsEnv, :windows_only do
before do
@node = Chef::Node.new
@events = Chef::EventDispatch::Dispatcher.new
@run_context = Chef::RunContext.new(@node, {}, @events)
- @new_resource = Chef::Resource::Env.new("FOO")
+ @new_resource = Chef::Resource::WindowsEnv.new("FOO")
@new_resource.value("bar")
- @provider = Chef::Provider::Env.new(@new_resource, @run_context)
+ @new_resource.user("<System>")
+ @provider = Chef::Provider::WindowsEnv.new(@new_resource, @run_context)
end
it "assumes the key_name exists by default" do
@@ -47,12 +48,17 @@ describe Chef::Provider::Env do
expect(@provider.new_resource.name).to eq("FOO")
end
+ it "should create a current resource with the same user as the new resource" do
+ @provider.load_current_resource
+ expect(@provider.new_resource.user).to eq("<System>")
+ end
+
it "should set the key_name to the key name of the new resource" do
@provider.load_current_resource
expect(@provider.current_resource.key_name).to eq("FOO")
end
- it "should check if the key_name exists" do
+ it "should check if the key_name and user exist" do
expect(@provider).to receive(:env_key_exists).with("FOO").and_return(true)
@provider.load_current_resource
expect(@provider.key_exists).to be_truthy
@@ -65,7 +71,7 @@ describe Chef::Provider::Env do
end
it "should return the current resource" do
- expect(@provider.load_current_resource).to be_a_kind_of(Chef::Resource::Env)
+ expect(@provider.load_current_resource).to be_a_kind_of(Chef::Resource::WindowsEnv)
end
end
@@ -76,7 +82,7 @@ describe Chef::Provider::Env do
allow(@provider).to receive(:modify_env).and_return(true)
end
- it "should call create_env if the key does not exist" do
+ it "should call create_env if the key does not exist with user" do
expect(@provider).to receive(:create_env).and_return(true)
@provider.action_create
end
@@ -92,7 +98,7 @@ describe Chef::Provider::Env do
@provider.action_create
end
- it "should call modify_env if the key exists and values are not equal" do
+ it "should call modify_env if the key exists with provided user and values are not equal" do
@provider.key_exists = true
allow(@provider).to receive(:requires_modify_or_create?).and_return(true)
expect(@provider).to receive(:modify_env).and_return(true)
@@ -152,6 +158,12 @@ describe Chef::Provider::Env do
@provider.action_modify
end
+ it "should call modify_group if the key exists and users are not equal" do
+ expect(@provider).to receive(:requires_modify_or_create?).and_return(true)
+ expect(@provider).to receive(:modify_env).and_return(true)
+ @provider.action_modify
+ end
+
it "should set the new resources updated flag to true if modify_env is called" do
allow(@provider).to receive(:requires_modify_or_create?).and_return(true)
allow(@provider).to receive(:modify_env).and_return(true)
@@ -159,25 +171,26 @@ describe Chef::Provider::Env do
expect(@new_resource).to be_updated
end
- it "should not call modify_env if the key exists but the values are equal" do
+ it "should not call modify_env if the key exists with user but the values are equal" do
expect(@provider).to receive(:requires_modify_or_create?).and_return(false)
expect(@provider).not_to receive(:modify_env)
@provider.action_modify
end
- it "should raise a Chef::Exceptions::Env if the key doesn't exist" do
+ it "should raise a Chef::Exceptions::WindowsEnv if the key doesn't exist" do
@provider.key_exists = false
- expect { @provider.action_modify }.to raise_error(Chef::Exceptions::Env)
+ expect { @provider.action_modify }.to raise_error(Chef::Exceptions::WindowsEnv)
end
end
describe "delete_element" do
before(:each) do
- @current_resource = Chef::Resource::Env.new("FOO")
+ @current_resource = Chef::Resource::WindowsEnv.new("FOO")
@new_resource.delim ";"
@new_resource.value "C:/bar/bin"
+ @current_resource.user "<System>"
@current_resource.value "C:/foo/bin;C:/bar/bin"
@provider.current_resource = @current_resource
end
@@ -280,7 +293,7 @@ describe Chef::Provider::Env do
allow(@provider).to receive(:create_env).and_return(true)
@new_resource.delim ";"
- @current_resource = Chef::Resource::Env.new("FOO")
+ @current_resource = Chef::Resource::WindowsEnv.new("FOO")
@current_resource.value "C:/foo/bin"
@provider.current_resource = @current_resource
end
@@ -307,4 +320,81 @@ describe Chef::Provider::Env do
expect(@new_resource.value).to eq("C:/foo;C:/bar;C:/baz;C:/foo/bar")
end
end
+
+ context "when environment variable is not PATH" do
+ let(:new_resource) do
+ new_resource = Chef::Resource::WindowsEnv.new("CHEF_WINDOWS_ENV_TEST")
+ new_resource.value("foo")
+ new_resource
+ end
+ let(:provider) do
+ provider = Chef::Provider::WindowsEnv.new(new_resource, run_context)
+ allow(provider).to receive(:env_obj).and_return(double("null object").as_null_object)
+ provider
+ end
+
+ describe "action_create" do
+ before do
+ ENV.delete("CHEF_WINDOWS_ENV_TEST")
+ provider.key_exists = false
+ end
+
+ it "should update the ruby ENV object when it creates the key" do
+ provider.action_create
+ expect(ENV["CHEF_WINDOWS_ENV_TEST"]).to eql("foo")
+ end
+ end
+
+ describe "action_modify" do
+ before do
+ ENV["CHEF_WINDOWS_ENV_TEST"] = "foo"
+ end
+
+ it "should update the ruby ENV object when it updates the value" do
+ expect(provider).to receive(:requires_modify_or_create?).and_return(true)
+ new_resource.value("foobar")
+ provider.action_modify
+ expect(ENV["CHEF_WINDOWS_ENV_TEST"]).to eql("foobar")
+ end
+
+ describe "action_delete" do
+ before do
+ ENV["CHEF_WINDOWS_ENV_TEST"] = "foo"
+ end
+
+ it "should update the ruby ENV object when it deletes the key" do
+ provider.action_delete
+ expect(ENV["CHEF_WINDOWS_ENV_TEST"]).to eql(nil)
+ end
+ end
+ end
+ end
+
+ context "when environment is PATH" do
+ describe "for PATH" do
+ let(:system_root) { "%SystemRoot%" }
+ let(:system_root_value) { 'D:\Windows' }
+ let(:new_resource) do
+ new_resource = Chef::Resource::WindowsEnv.new("PATH")
+ new_resource.value(system_root)
+ new_resource
+ end
+ let(:provider) do
+ provider = Chef::Provider::WindowsEnv.new(new_resource, run_context)
+ allow(provider).to receive(:env_obj).and_return(double("null object").as_null_object)
+ provider
+ end
+
+ before do
+ stub_const("ENV", { "PATH" => "" })
+ end
+
+ it "replaces Windows system variables" do
+ expect(provider).to receive(:requires_modify_or_create?).and_return(true)
+ expect(provider).to receive(:expand_path).with(system_root).and_return(system_root_value)
+ provider.action_modify
+ expect(ENV["PATH"]).to eql(system_root_value)
+ end
+ end
+ end
end
diff --git a/spec/unit/provider_resolver_spec.rb b/spec/unit/provider_resolver_spec.rb
index a331093055..ac641de43a 100644
--- a/spec/unit/provider_resolver_spec.rb
+++ b/spec/unit/provider_resolver_spec.rb
@@ -762,7 +762,7 @@ describe Chef::ProviderResolver do
"windows" => {
batch: [ Chef::Resource::Batch, Chef::Provider::Batch ],
dsc_script: [ Chef::Resource::DscScript, Chef::Provider::DscScript ],
- env: [ Chef::Resource::Env, Chef::Provider::Env::Windows ],
+ windows_env: [ Chef::Resource::WindowsEnv, Chef::Provider::WindowsEnv ],
group: [ Chef::Resource::Group, Chef::Provider::Group::Windows ],
mount: [ Chef::Resource::Mount, Chef::Provider::Mount::Windows ],
package: [ Chef::Resource::WindowsPackage, Chef::Provider::Package::Windows ],
diff --git a/spec/unit/resource/hostname_spec.rb b/spec/unit/resource/hostname_spec.rb
new file mode 100644
index 0000000000..33f944dbc9
--- /dev/null
+++ b/spec/unit/resource/hostname_spec.rb
@@ -0,0 +1,43 @@
+#
+# Copyright:: Copyright 2018, 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 "spec_helper"
+
+describe Chef::Resource::Hostname do
+
+ let(:resource) { Chef::Resource::Hostname.new("foo") }
+
+ it "has a resource name of :hostname" do
+ expect(resource.resource_name).to eql(:hostname)
+ end
+
+ it "has a default action of set" do
+ expect(resource.action).to eql([:set])
+ end
+
+ it "runs at compile_time by default" do
+ expect(resource.compile_time).to eql(true)
+ end
+
+ it "reboots windows nodes by default" do
+ expect(resource.windows_reboot).to eql(true)
+ end
+
+ it "the hostname property is the name property" do
+ expect(resource.hostname).to eql("foo")
+ end
+end
diff --git a/spec/unit/resource/rhsm_errata_level_spec.rb b/spec/unit/resource/rhsm_errata_level_spec.rb
new file mode 100644
index 0000000000..3284107e75
--- /dev/null
+++ b/spec/unit/resource/rhsm_errata_level_spec.rb
@@ -0,0 +1,46 @@
+#
+# Copyright:: Copyright 2018, 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 "spec_helper"
+
+describe Chef::Resource::RhsmErrataLevel do
+
+ let(:resource) { Chef::Resource::RhsmErrataLevel.new("moderate") }
+
+ it "has a resource name of :rhsm_errata_level" do
+ expect(resource.resource_name).to eql(:rhsm_errata_level)
+ end
+
+ it "has a default action of install" do
+ expect(resource.action).to eql([:install])
+ end
+
+ it "the errata_level property is the name property" do
+ expect(resource.errata_level).to eql("moderate")
+ end
+
+ it "coerces the errata_level to be lowercase" do
+ resource.errata_level "Important"
+ expect(resource.errata_level).to eql("important")
+ end
+
+ it "raises an exception if invalid errata_level is passed" do
+ expect do
+ resource.errata_level "FOO"
+ end.to raise_error(Chef::Exceptions::ValidationFailed)
+ end
+end
diff --git a/spec/unit/resource/rhsm_errata_spec.rb b/spec/unit/resource/rhsm_errata_spec.rb
new file mode 100644
index 0000000000..8da7269ca8
--- /dev/null
+++ b/spec/unit/resource/rhsm_errata_spec.rb
@@ -0,0 +1,35 @@
+#
+# Copyright:: Copyright 2018, 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 "spec_helper"
+
+describe Chef::Resource::RhsmErrata do
+
+ let(:resource) { Chef::Resource::RhsmErrata.new("foo") }
+
+ it "has a resource name of :rhsm_errata" do
+ expect(resource.resource_name).to eql(:rhsm_errata)
+ end
+
+ it "has a default action of install" do
+ expect(resource.action).to eql([:install])
+ end
+
+ it "the errata_id property is the name property" do
+ expect(resource.errata_id).to eql("foo")
+ end
+end
diff --git a/spec/unit/resource/rhsm_register_spec.rb b/spec/unit/resource/rhsm_register_spec.rb
new file mode 100644
index 0000000000..2e360b5708
--- /dev/null
+++ b/spec/unit/resource/rhsm_register_spec.rb
@@ -0,0 +1,199 @@
+#
+# Copyright:: Copyright 2018, 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 "spec_helper"
+
+describe Chef::Resource::RhsmRegister do
+
+ let(:resource) { Chef::Resource::RhsmRegister.new("foo") }
+ let(:provider) { resource.provider_for_action(:register) }
+
+ it "has a resource name of :rhsm_register" do
+ expect(resource.resource_name).to eql(:rhsm_register)
+ end
+
+ it "has a default action of register" do
+ expect(resource.action).to eql([:register])
+ end
+
+ it "coerces activation_key to an array" do
+ resource.activation_key "foo"
+ expect(resource.activation_key).to eql(["foo"])
+ end
+
+ describe "#katello_cert_rpm_installed?" do
+ let(:cmd) { double("cmd") }
+
+ before do
+ allow(Mixlib::ShellOut).to receive(:new).and_return(cmd)
+ allow(cmd).to receive(:run_command)
+ end
+
+ context "when the output contains katello-ca-consumer" do
+ it "returns true" do
+ allow(cmd).to receive(:stdout).and_return("katello-ca-consumer-somehostname-1.0-1")
+ expect(provider.katello_cert_rpm_installed?).to eq(true)
+ end
+ end
+
+ context "when the output does not contain katello-ca-consumer" do
+ it "returns false" do
+ allow(cmd).to receive(:stdout).and_return("katello-agent-but-not-the-ca")
+ expect(provider.katello_cert_rpm_installed?).to eq(false)
+ end
+ end
+ end
+
+ describe "#register_command" do
+ before do
+ allow(provider).to receive(:activation_key).and_return([])
+ allow(provider).to receive(:auto_attach)
+ end
+
+ context "when activation keys exist" do
+ before do
+ allow(resource).to receive(:activation_key).and_return(%w{key1 key2})
+ end
+
+ context "when no org exists" do
+ it "raises an exception" do
+ allow(resource).to receive(:organization).and_return(nil)
+ expect { provider.register_command }.to raise_error(RuntimeError)
+ end
+ end
+
+ context "when an org exists" do
+ it "returns a command containing the keys and org" do
+ allow(resource).to receive(:organization).and_return("myorg")
+
+ expect(provider.register_command).to match("--activationkey=key1 --activationkey=key2 --org=myorg")
+ end
+ end
+
+ context "when auto_attach is true" do
+ it "does not return a command with --auto-attach since it is not supported with activation keys" do
+ allow(resource).to receive(:organization).and_return("myorg")
+ allow(resource).to receive(:auto_attach).and_return(true)
+
+ expect(provider.register_command).not_to match("--auto-attach")
+ end
+ end
+ end
+
+ context "when username and password exist" do
+ before do
+ allow(resource).to receive(:username).and_return("myuser")
+ allow(resource).to receive(:password).and_return("mypass")
+ allow(resource).to receive(:environment)
+ allow(resource).to receive(:using_satellite_host?)
+ allow(resource).to receive(:activation_key).and_return([])
+ end
+
+ context "when auto_attach is true" do
+ it "returns a command containing --auto-attach" do
+ allow(resource).to receive(:auto_attach).and_return(true)
+
+ expect(provider.register_command).to match("--auto-attach")
+ end
+ end
+
+ context "when auto_attach is false" do
+ it "returns a command that does not contain --auto-attach" do
+ allow(resource).to receive(:auto_attach).and_return(false)
+
+ expect(provider.register_command).not_to match("--auto-attach")
+ end
+ end
+
+ context "when auto_attach is nil" do
+ it "returns a command that does not contain --auto-attach" do
+ allow(resource).to receive(:auto_attach).and_return(nil)
+
+ expect(provider.register_command).not_to match("--auto-attach")
+ end
+ end
+
+ context "when environment does not exist" do
+ context "when registering to a satellite server" do
+ it "raises an exception" do
+ allow(provider).to receive(:using_satellite_host?).and_return(true)
+ allow(resource).to receive(:environment).and_return(nil)
+ expect { provider.register_command }.to raise_error(RuntimeError)
+ end
+ end
+
+ context "when registering to RHSM proper" do
+ before do
+ allow(provider).to receive(:using_satellite_host?).and_return(false)
+ allow(resource).to receive(:environment).and_return(nil)
+ end
+
+ it "does not raise an exception" do
+ expect { provider.register_command }.not_to raise_error
+ end
+
+ it "returns a command containing the username and password and no environment" do
+ allow(resource).to receive(:environment).and_return("myenv")
+ expect(provider.register_command).to match("--username=myuser --password=mypass")
+ expect(provider.register_command).not_to match("--environment")
+ end
+ end
+ end
+
+ context "when an environment exists" do
+ it "returns a command containing the username, password, and environment" do
+ allow(provider).to receive(:using_satellite_host?).and_return(true)
+ allow(resource).to receive(:environment).and_return("myenv")
+ expect(provider.register_command).to match("--username=myuser --password=mypass --environment=myenv")
+ end
+ end
+ end
+
+ context "when no activation keys, username, or password exist" do
+ it "raises an exception" do
+ allow(resource).to receive(:activation_key).and_return([])
+ allow(resource).to receive(:username).and_return(nil)
+ allow(resource).to receive(:password).and_return(nil)
+
+ expect { provider.register_command }.to raise_error(RuntimeError)
+ end
+ end
+ end
+
+ describe "#registered_with_rhsm?" do
+ let(:cmd) { double("cmd") }
+
+ before do
+ allow(Mixlib::ShellOut).to receive(:new).and_return(cmd)
+ allow(cmd).to receive(:run_command)
+ end
+
+ context "when the status is Unknown" do
+ it "returns false" do
+ allow(cmd).to receive(:stdout).and_return("Overall Status: Unknown")
+ expect(provider.registered_with_rhsm?).to eq(false)
+ end
+ end
+
+ context "when the status is anything else" do
+ it "returns true" do
+ allow(cmd).to receive(:stdout).and_return("Overall Status: Insufficient")
+ expect(provider.registered_with_rhsm?).to eq(true)
+ end
+ end
+ end
+end
diff --git a/spec/unit/resource/rhsm_repo_spec.rb b/spec/unit/resource/rhsm_repo_spec.rb
new file mode 100644
index 0000000000..97606a03c8
--- /dev/null
+++ b/spec/unit/resource/rhsm_repo_spec.rb
@@ -0,0 +1,59 @@
+#
+# Copyright:: Copyright 2018, 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 "spec_helper"
+
+describe Chef::Resource::RhsmRepo do
+
+ let(:resource) { Chef::Resource::RhsmRepo.new("foo") }
+ let(:provider) { resource.provider_for_action(:enable) }
+
+ it "has a resource name of :rhsm_repo" do
+ expect(resource.resource_name).to eql(:rhsm_repo)
+ end
+
+ it "has a default action of enable" do
+ expect(resource.action).to eql([:enable])
+ end
+
+ it "the repo_name property is the name property" do
+ expect(resource.repo_name).to eql("foo")
+ end
+
+ describe "#repo_enabled?" do
+ let(:cmd) { double("cmd") }
+ let(:output) { "Repo ID: repo123" }
+
+ before do
+ allow(Mixlib::ShellOut).to receive(:new).and_return(cmd)
+ allow(cmd).to receive(:run_command)
+ allow(cmd).to receive(:stdout).and_return(output)
+ end
+
+ context "when the repo provided matches the output" do
+ it "returns true" do
+ expect(provider.repo_enabled?("repo123")).to eq(true)
+ end
+ end
+
+ context "when the repo provided does not match the output" do
+ it "returns false" do
+ expect(provider.repo_enabled?("differentrepo")).to eq(false)
+ end
+ end
+ end
+end
diff --git a/spec/unit/resource/rhsm_subscription_spec.rb b/spec/unit/resource/rhsm_subscription_spec.rb
new file mode 100644
index 0000000000..0160624f39
--- /dev/null
+++ b/spec/unit/resource/rhsm_subscription_spec.rb
@@ -0,0 +1,93 @@
+#
+# Copyright:: Copyright 2018, 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 "spec_helper"
+
+describe Chef::Resource::RhsmSubscription do
+ let(:resource) { Chef::Resource::RhsmSubscription.new("foo") }
+ let(:provider) { resource.provider_for_action(:attach) }
+
+ it "has a resource name of :rhsm_subscription" do
+ expect(resource.resource_name).to eql(:rhsm_subscription)
+ end
+
+ it "has a default action of attach" do
+ expect(resource.action).to eql([:attach])
+ end
+
+ it "the pool_id property is the name property" do
+ expect(resource.pool_id).to eql("foo")
+ end
+
+ describe "#subscription_attached?" do
+ let(:cmd) { double("cmd") }
+ let(:output) { "Pool ID: pool123" }
+
+ before do
+ allow(Mixlib::ShellOut).to receive(:new).and_return(cmd)
+ allow(cmd).to receive(:run_command)
+ allow(cmd).to receive(:stdout).and_return(output)
+ end
+
+ context "when the pool provided matches the output" do
+ it "returns true" do
+ expect(provider.subscription_attached?("pool123")).to eq(true)
+ end
+ end
+
+ context "when the pool provided does not match the output" do
+ it "returns false" do
+ expect(provider.subscription_attached?("differentpool")).to eq(false)
+ end
+ end
+ end
+
+ describe "#serials_by_pool" do
+ let(:cmd) { double("cmd") }
+ let(:output) do
+ <<~EOL
+ Key1: value1
+ Pool ID: pool1
+ Serial: serial1
+ Key2: value2
+
+ Key1: value1
+ Pool ID: pool2
+ Serial: serial2
+ Key2: value2
+EOL
+ end
+
+ it "parses the output correctly" do
+ allow(Mixlib::ShellOut).to receive(:new).and_return(cmd)
+ allow(cmd).to receive(:run_command)
+ allow(cmd).to receive(:stdout).and_return(output)
+
+ expect(provider.serials_by_pool["pool1"]).to eq("serial1")
+ expect(provider.serials_by_pool["pool2"]).to eq("serial2")
+ end
+ end
+
+ describe "#pool_serial" do
+ let(:serials) { { "pool1" => "serial1", "pool2" => "serial2" } }
+
+ it "returns the serial for a given pool" do
+ allow(provider).to receive(:serials_by_pool).and_return(serials)
+ expect(provider.pool_serial("pool1")).to eq("serial1")
+ end
+ end
+end
diff --git a/spec/unit/resource/systemd_unit_spec.rb b/spec/unit/resource/systemd_unit_spec.rb
index 15b792e6bf..9d156402a1 100644
--- a/spec/unit/resource/systemd_unit_spec.rb
+++ b/spec/unit/resource/systemd_unit_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Nathan Williams (<nath.e.will@gmail.com>)
-# Copyright:: Copyright 2016, Nathan Williams
+# Copyright:: Copyright 2016-2018, Nathan Williams
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -46,8 +46,11 @@ describe Chef::Resource::SystemdUnit do
it "supports appropriate unit actions" do
expect { resource.action :create }.not_to raise_error
expect { resource.action :delete }.not_to raise_error
+ expect { resource.action :preset }.not_to raise_error
+ expect { resource.action :revert }.not_to raise_error
expect { resource.action :enable }.not_to raise_error
expect { resource.action :disable }.not_to raise_error
+ expect { resource.action :reenable }.not_to raise_error
expect { resource.action :mask }.not_to raise_error
expect { resource.action :unmask }.not_to raise_error
expect { resource.action :start }.not_to raise_error
diff --git a/spec/unit/resource/env_spec.rb b/spec/unit/resource/windows_env_spec.rb
index 61c40e33e8..776e4f7cd5 100644
--- a/spec/unit/resource/env_spec.rb
+++ b/spec/unit/resource/windows_env_spec.rb
@@ -19,10 +19,16 @@
require "spec_helper"
-describe Chef::Resource::Env do
- let(:resource) { Chef::Resource::Env.new("FOO") }
+describe Chef::Resource::WindowsEnv do
- it "has a name property" do
+ let(:resource) { Chef::Resource::WindowsEnv.new("FOO") }
+
+ it "creates a new Chef::Resource::WindowsEnv" do
+ expect(resource).to be_a_kind_of(Chef::Resource)
+ expect(resource).to be_a_kind_of(Chef::Resource::WindowsEnv)
+ end
+
+ it "has a name" do
expect(resource.name).to eql("FOO")
end
diff --git a/spec/unit/resource_spec.rb b/spec/unit/resource_spec.rb
index 934a613eee..fe853922a1 100644
--- a/spec/unit/resource_spec.rb
+++ b/spec/unit/resource_spec.rb
@@ -387,6 +387,37 @@ describe Chef::Resource do
end
end
+ context "Documentation of resources" do
+ it "can have a description" do
+ c = Class.new(Chef::Resource) do
+ description "my description"
+ end
+ expect(c.description).to eq "my description"
+ end
+
+ it "can say when it was introduced" do
+ c = Class.new(Chef::Resource) do
+ introduced "14.0"
+ end
+ expect(c.introduced).to eq "14.0"
+ end
+
+ it "can have some examples" do
+ c = Class.new(Chef::Resource) do
+ examples <<-EOH
+resource "foo" do
+ foo foo
+end
+ EOH
+ end
+ expect(c.examples).to eq <<-EOH
+resource "foo" do
+ foo foo
+end
+ EOH
+ end
+ end
+
describe "self.resource_name" do
context "When resource_name is not set" do
it "and there are no provides lines, resource_name is nil" do