summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.expeditor/release.omnibus.yml1
-rw-r--r--CHANGELOG.md15
-rw-r--r--Dockerfile8
-rw-r--r--Gemfile.lock43
-rw-r--r--VERSION2
-rw-r--r--chef-bin/lib/chef-bin/version.rb2
-rw-r--r--chef-config/lib/chef-config/config.rb16
-rw-r--r--chef-config/lib/chef-config/mixin/credentials.rb2
-rw-r--r--chef-config/lib/chef-config/version.rb2
-rw-r--r--chef.gemspec3
-rw-r--r--lib/chef/application/base.rb7
-rw-r--r--lib/chef/application/client.rb8
-rw-r--r--lib/chef/application/solo.rb8
-rw-r--r--lib/chef/exceptions.rb12
-rw-r--r--lib/chef/node.rb2
-rw-r--r--lib/chef/policy_builder/expand_node_object.rb2
-rw-r--r--lib/chef/policy_builder/policyfile.rb7
-rw-r--r--lib/chef/provider.rb6
-rw-r--r--lib/chef/provider/ifconfig.rb8
-rw-r--r--lib/chef/resource.rb48
-rw-r--r--lib/chef/resource/resource_notification.rb30
-rw-r--r--lib/chef/resource_collection.rb6
-rw-r--r--lib/chef/run_context.rb88
-rw-r--r--lib/chef/runner.rb62
-rw-r--r--lib/chef/version.rb2
-rw-r--r--omnibus/Gemfile.lock34
-rw-r--r--spec/integration/client/client_spec.rb22
-rw-r--r--spec/integration/knife/raw_spec.rb58
-rw-r--r--spec/integration/knife/redirection_spec.rb35
-rw-r--r--spec/integration/knife/serve_spec.rb3
-rw-r--r--spec/integration/recipes/unified_mode_spec.rb876
-rw-r--r--spec/support/shared/integration/app_server_support.rb39
-rw-r--r--spec/support/shared/integration/integration_helper.rb3
-rw-r--r--spec/unit/application/client_spec.rb11
-rw-r--r--spec/unit/application/solo_spec.rb11
-rw-r--r--spec/unit/application_spec.rb2
-rw-r--r--spec/unit/provider/ifconfig_spec.rb11
37 files changed, 1269 insertions, 226 deletions
diff --git a/.expeditor/release.omnibus.yml b/.expeditor/release.omnibus.yml
index 440ce1ce34..1819c0d207 100644
--- a/.expeditor/release.omnibus.yml
+++ b/.expeditor/release.omnibus.yml
@@ -9,6 +9,7 @@ fips-platforms:
builder-to-testers-map:
aix-7.1-powerpc:
- aix-7.1-powerpc
+ - aix-7.2-powerpc
debian-8-x86_64:
- debian-8-x86_64
- debian-9-x86_64
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2c4e357704..9b06039592 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,15 +1,24 @@
<!-- usage documentation: http://expeditor-docs.es.chef.io/configuration/changelog/ -->
-<!-- latest_release 15.2.24 -->
-## [v15.2.24](https://github.com/chef/chef/tree/v15.2.24) (2019-08-13)
+<!-- latest_release 15.2.33 -->
+## [v15.2.33](https://github.com/chef/chef/tree/v15.2.33) (2019-08-29)
#### Merged Pull Requests
-- Begin signing MSI&#39;s with renewed Windows Signing Cert [#8813](https://github.com/chef/chef/pull/8813) ([schisamo](https://github.com/schisamo))
+- Update InSpec to 4.12 and Train to 3.0 [#8854](https://github.com/chef/chef/pull/8854) ([tas50](https://github.com/tas50))
<!-- latest_release -->
<!-- release_rollup since=15.2.20 -->
### Changes not yet released to stable
#### Merged Pull Requests
+- Update InSpec to 4.12 and Train to 3.0 [#8854](https://github.com/chef/chef/pull/8854) ([tas50](https://github.com/tas50)) <!-- 15.2.33 -->
+- remove app_server_support spec file [#8852](https://github.com/chef/chef/pull/8852) ([lamont-granquist](https://github.com/lamont-granquist)) <!-- 15.2.32 -->
+- Fix node[:cookbooks] attribute [#8846](https://github.com/chef/chef/pull/8846) ([lamont-granquist](https://github.com/lamont-granquist)) <!-- 15.2.31 -->
+- Fail on interval runs on windows as interval runs on Windows don&#39;t entirely work [#6777](https://github.com/chef/chef/pull/6777) ([lamont-granquist](https://github.com/lamont-granquist)) <!-- 15.2.30 -->
+- ifconfig: fix regex matching interface name with hyphen [#8756](https://github.com/chef/chef/pull/8756) ([dheerajd-msys](https://github.com/dheerajd-msys)) <!-- 15.2.29 -->
+- Add AIX 7.2 platform [#8832](https://github.com/chef/chef/pull/8832) ([jaymalasinha](https://github.com/jaymalasinha)) <!-- 15.2.28 -->
+- Fix crash when showing error about missing profile [#8828](https://github.com/chef/chef/pull/8828) ([andrewdotn](https://github.com/andrewdotn)) <!-- 15.2.27 -->
+- Add unified_mode for resources [#8668](https://github.com/chef/chef/pull/8668) ([lamont-granquist](https://github.com/lamont-granquist)) <!-- 15.2.26 -->
+- Update omnibus build deps to the latest [#8823](https://github.com/chef/chef/pull/8823) ([tas50](https://github.com/tas50)) <!-- 15.2.25 -->
- Begin signing MSI&#39;s with renewed Windows Signing Cert [#8813](https://github.com/chef/chef/pull/8813) ([schisamo](https://github.com/schisamo)) <!-- 15.2.24 -->
- Updated knife cookbook metadata from file command banner [#8812](https://github.com/chef/chef/pull/8812) ([samshinde](https://github.com/samshinde)) <!-- 15.2.23 -->
- Update the link to our release cadence information [#8807](https://github.com/chef/chef/pull/8807) ([tas50](https://github.com/tas50)) <!-- 15.2.22 -->
diff --git a/Dockerfile b/Dockerfile
index cd3fdbce8e..437511e9cf 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -15,11 +15,17 @@
# applied so 15.0.260 would be tagged as "latest", "15" and "15.0", as well as "15.0.260".
FROM busybox
-MAINTAINER Chef Software, Inc. <docker@chef.io>
+LABEL maintainer="Chef Software, Inc. <docker@chef.io>"
+ARG EXPEDITOR_CHANNEL
ARG CHANNEL=stable
+ARG EXPEDITOR_VERSION
ARG VERSION=15.2.20
+# Allow the build arg below to be controlled by either build arguments
+ENV VERSION ${EXPEDITOR_VERSION:-${VERSION}}
+ENV CHANNEL ${EXPEDITOR_CHANNEL:-${CHANNEL}}
+
RUN wget "http://packages.chef.io/files/${CHANNEL}/chef/${VERSION}/el/6/chef-${VERSION}-1.el6.x86_64.rpm" -O /tmp/chef-client.rpm && \
rpm2cpio /tmp/chef-client.rpm | cpio -idmv && \
rm -rf /tmp/chef-client.rpm
diff --git a/Gemfile.lock b/Gemfile.lock
index 4ffd3f8348..197cbdb6a3 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -8,10 +8,10 @@ GIT
GIT
remote: https://github.com/chef/ohai.git
- revision: f76c5f583736a5731e2fb6e92c21dc8419655d95
+ revision: 15315e3e36f07062111faede26f2667ead8c723f
branch: master
specs:
- ohai (15.2.5)
+ ohai (15.2.7)
chef-config (>= 12.8, < 16)
ffi (~> 1.9)
ffi-yajl (~> 2.2)
@@ -27,11 +27,11 @@ GIT
PATH
remote: .
specs:
- chef (15.2.24)
+ chef (15.2.33)
addressable
bcrypt_pbkdf (~> 1.0)
bundler (>= 1.10)
- chef-config (= 15.2.24)
+ chef-config (= 15.2.33)
chef-zero (>= 14.0.11)
diff-lcs (~> 1.2, >= 1.2.4)
ed25519 (~> 1.2)
@@ -54,14 +54,15 @@ PATH
plist (~> 3.2)
proxifier (~> 1.0)
syslog-logger (~> 1.6)
- train-core (~> 2.0, >= 2.0.12)
+ train-core (~> 3.0)
+ train-winrm
tty-screen (~> 0.6)
uuidtools (~> 2.1.5)
- chef (15.2.24-universal-mingw32)
+ chef (15.2.33-universal-mingw32)
addressable
bcrypt_pbkdf (~> 1.0)
bundler (>= 1.10)
- chef-config (= 15.2.24)
+ chef-config (= 15.2.33)
chef-zero (>= 14.0.11)
diff-lcs (~> 1.2, >= 1.2.4)
ed25519 (~> 1.2)
@@ -85,7 +86,8 @@ PATH
plist (~> 3.2)
proxifier (~> 1.0)
syslog-logger (~> 1.6)
- train-core (~> 2.0, >= 2.0.12)
+ train-core (~> 3.0)
+ train-winrm
tty-screen (~> 0.6)
uuidtools (~> 2.1.5)
win32-api (~> 1.5.3)
@@ -103,13 +105,13 @@ PATH
PATH
remote: chef-bin
specs:
- chef-bin (15.2.24)
- chef (= 15.2.24)
+ chef-bin (15.2.33)
+ chef (= 15.2.33)
PATH
remote: chef-config
specs:
- chef-config (15.2.24)
+ chef-config (15.2.33)
addressable
fuzzyurl
mixlib-config (>= 2.2.12, < 4.0)
@@ -175,7 +177,7 @@ GEM
htmlentities (4.3.4)
httpclient (2.8.3)
iniparse (1.4.4)
- inspec-core (4.10.4)
+ inspec-core (4.12.0)
addressable (~> 2.4)
faraday (>= 0.9.0)
faraday_middleware (~> 0.12.2)
@@ -197,11 +199,11 @@ GEM
term-ansicolor
thor (~> 0.20)
tomlrb (~> 1.2)
- train-core (~> 2.0)
+ train-core (~> 3.0)
tty-prompt (~> 0.17)
tty-table (~> 0.10)
- inspec-core-bin (4.10.4)
- inspec-core (= 4.10.4)
+ inspec-core-bin (4.12.0)
+ inspec-core (= 4.12.0)
ipaddress (0.8.3)
iso8601 (0.12.1)
jaro_winkler (1.5.3)
@@ -312,7 +314,7 @@ GEM
simplecov-html (0.10.2)
slop (3.6.0)
sslshake (1.3.0)
- strings (0.1.5)
+ strings (0.1.6)
strings-ansi (~> 0.1)
unicode-display_width (~> 1.5)
unicode_utils (~> 1.4)
@@ -325,16 +327,17 @@ GEM
thor (0.20.3)
tins (1.21.1)
tomlrb (1.2.8)
- train-core (2.1.19)
+ train-core (3.0.3)
json (>= 1.8, < 3.0)
mixlib-shellout (>= 2.0, < 4.0)
net-scp (>= 1.2, < 3.0)
net-ssh (>= 2.9, < 6.0)
+ train-winrm (0.2.3)
winrm (~> 2.0)
winrm-fs (~> 1.0)
- tty-box (0.4.0)
+ tty-box (0.4.1)
pastel (~> 0.7.2)
- strings (~> 0.1.5)
+ strings (~> 0.1.6)
tty-cursor (~> 0.7)
tty-color (0.5.0)
tty-cursor (0.7.0)
@@ -356,7 +359,7 @@ GEM
unicode-display_width (1.6.0)
unicode_utils (1.4.0)
uuidtools (2.1.5)
- webmock (3.6.2)
+ webmock (3.7.0)
addressable (>= 2.3.6)
crack (>= 0.3.2)
hashdiff (>= 0.4.0, < 2.0.0)
diff --git a/VERSION b/VERSION
index e296b72707..75a79e8cee 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-15.2.24 \ No newline at end of file
+15.2.33 \ No newline at end of file
diff --git a/chef-bin/lib/chef-bin/version.rb b/chef-bin/lib/chef-bin/version.rb
index d4d90d38e2..d27bbc5507 100644
--- a/chef-bin/lib/chef-bin/version.rb
+++ b/chef-bin/lib/chef-bin/version.rb
@@ -21,7 +21,7 @@
module ChefBin
CHEFBIN_ROOT = File.expand_path("../..", __FILE__)
- VERSION = "15.2.24".freeze
+ VERSION = "15.2.33".freeze
end
#
diff --git a/chef-config/lib/chef-config/config.rb b/chef-config/lib/chef-config/config.rb
index d136a8f79c..b0583b7a06 100644
--- a/chef-config/lib/chef-config/config.rb
+++ b/chef-config/lib/chef-config/config.rb
@@ -875,6 +875,7 @@ module ChefConfig
#
# NOTE: CHANGING THIS SETTING MAY CAUSE CORRUPTION, DATA LOSS AND
# INSTABILITY.
+ #
default :file_atomic_update, true
# There are 3 possible values for this configuration setting.
@@ -882,19 +883,28 @@ module ChefConfig
# false => file staging is done via tempfiles under ENV['TMP']
# :auto => file staging will try using destination directory if possible and
# will fall back to ENV['TMP'] if destination directory is not usable.
+ #
default :file_staging_uses_destdir, :auto
# Exit if another run is in progress and the chef-client is unable to
# get the lock before time expires. If nil, no timeout is enforced. (Exits
# immediately if 0.)
+ #
default :run_lock_timeout, nil
# Number of worker threads for syncing cookbooks in parallel. Increasing
# this number can result in gateway errors from the server (namely 503 and 504).
# If you are seeing this behavior while using the default setting, reducing
# the number of threads will help.
+ #
default :cookbook_sync_threads, 10
+ # True if all resources by default default to unified mode, with all resources
+ # applying in "compile" mode, with no "converge" mode. False is backwards compatible
+ # setting for Chef 11-15 behavior. This will break forward notifications.
+ #
+ default :resource_unified_mode_default, false
+
# At the beginning of the Chef Client run, the cookbook manifests are downloaded which
# contain URLs for every file in every relevant cookbook. Most of the files
# (recipes, resources, providers, libraries, etc) are immediately synchronized
@@ -920,9 +930,9 @@ module ChefConfig
default :no_lazy_load, true
# A whitelisted array of attributes you want sent over the wire when node
- # data is saved.
- # The default setting is nil, which collects all data. Setting to [] will not
- # collect any data for save.
+ # data is saved. The default setting is nil, which collects all data. Setting
+ # to [] will not collect any data for save.
+ #
default :automatic_attribute_whitelist, nil
default :default_attribute_whitelist, nil
default :normal_attribute_whitelist, nil
diff --git a/chef-config/lib/chef-config/mixin/credentials.rb b/chef-config/lib/chef-config/mixin/credentials.rb
index 3882924d1a..bb4d55f4bc 100644
--- a/chef-config/lib/chef-config/mixin/credentials.rb
+++ b/chef-config/lib/chef-config/mixin/credentials.rb
@@ -92,7 +92,7 @@ module ChefConfig
# raise an error.
return if profile == "default"
- raise ChefConfig::ConfigurationError, "Profile #{profile} doesn't exist. Please add it to #{credentials_file}."
+ raise ChefConfig::ConfigurationError, "Profile #{profile} doesn't exist. Please add it to #{credentials_file_path}."
end
apply_credentials(config[profile], profile)
end
diff --git a/chef-config/lib/chef-config/version.rb b/chef-config/lib/chef-config/version.rb
index 1363c33edc..ef7014daf3 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 = "15.2.24".freeze
+ VERSION = "15.2.33".freeze
end
#
diff --git a/chef.gemspec b/chef.gemspec
index a89cf4ceb2..e78237b31d 100644
--- a/chef.gemspec
+++ b/chef.gemspec
@@ -16,7 +16,8 @@ Gem::Specification.new do |s|
s.required_ruby_version = ">= 2.5.0"
s.add_dependency "chef-config", "= #{Chef::VERSION}"
- s.add_dependency "train-core", "~> 2.0", ">= 2.0.12"
+ s.add_dependency "train-core", "~> 3.0"
+ s.add_dependency "train-winrm"
s.add_dependency "license-acceptance", "~> 1.0", ">= 1.0.5"
s.add_dependency "mixlib-cli", ">= 2.1.1", "< 3.0"
diff --git a/lib/chef/application/base.rb b/lib/chef/application/base.rb
index fea3d844ce..c5bff9874e 100644
--- a/lib/chef/application/base.rb
+++ b/lib/chef/application/base.rb
@@ -340,6 +340,13 @@ class Chef::Application::Base < Chef::Application
private
+ def windows_interval_error_message
+ "Windows #{Chef::Dist::PRODUCT} interval runs are not supported in #{Chef::Dist::PRODUCT} 15 and later." +
+ "\nConfiguration settings:" +
+ ("\n interval = #{Chef::Config[:interval]} seconds" if Chef::Config[:interval]).to_s +
+ "\nPlease manage #{Chef::Dist::PRODUCT} as a scheduled task instead."
+ end
+
def unforked_interval_error_message
"Unforked #{Chef::Dist::PRODUCT} interval runs are disabled by default." +
"\nConfiguration settings:" +
diff --git a/lib/chef/application/client.rb b/lib/chef/application/client.rb
index 0fc5ca7711..890ecbd385 100644
--- a/lib/chef/application/client.rb
+++ b/lib/chef/application/client.rb
@@ -128,8 +128,12 @@ class Chef::Application::Client < Chef::Application::Base
Chef::Config[:client_fork] = !!Chef::Config[:interval]
end
- if !Chef::Config[:client_fork] && Chef::Config[:interval] && !Chef::Platform.windows?
- Chef::Application.fatal!(unforked_interval_error_message)
+ if Chef::Config[:interval]
+ if Chef::Platform.windows?
+ Chef::Application.fatal!(windows_interval_error_message)
+ elsif !Chef::Config[:client_fork]
+ Chef::Application.fatal!(unforked_interval_error_message)
+ end
end
if Chef::Config[:json_attribs]
diff --git a/lib/chef/application/solo.rb b/lib/chef/application/solo.rb
index bce95c2841..da9ec7f566 100644
--- a/lib/chef/application/solo.rb
+++ b/lib/chef/application/solo.rb
@@ -102,7 +102,13 @@ class Chef::Application::Solo < Chef::Application::Base
Chef::Config[:client_fork] = !!Chef::Config[:interval]
end
- Chef::Application.fatal!(unforked_interval_error_message) if !Chef::Config[:client_fork] && Chef::Config[:interval]
+ if Chef::Config[:interval]
+ if Chef::Platform.windows?
+ Chef::Application.fatal!(windows_interval_error_message)
+ elsif !Chef::Config[:client_fork]
+ Chef::Application.fatal!(unforked_interval_error_message)
+ end
+ end
if Chef::Config[:recipe_url]
cookbooks_path = Array(Chef::Config[:cookbook_path]).detect { |e| Pathname.new(e).cleanpath.to_s =~ %r{/cookbooks/*$} }
diff --git a/lib/chef/exceptions.rb b/lib/chef/exceptions.rb
index 7687e7d89c..40d20cc3ac 100644
--- a/lib/chef/exceptions.rb
+++ b/lib/chef/exceptions.rb
@@ -509,5 +509,17 @@ class Chef
super "Conflicting requirements for gem '#{gem_name}': Both #{value1.inspect} and #{value2.inspect} given for option #{option.inspect}"
end
end
+
+ class UnifiedModeImmediateSubscriptionEarlierResource < RuntimeError
+ def initialize(notification)
+ super "immediate subscription from #{notification.resource} resource cannot be setup to #{notification.notifying_resource} resource, which has already fired while in unified mode"
+ end
+ end
+
+ class UnifiedModeBeforeSubscriptionEarlierResource < RuntimeError
+ def initialize(notification)
+ super "before subscription from #{notification.resource} resource cannot be setup to #{notification.notifying_resource} resource, which has already fired while in unified mode"
+ end
+ end
end
end
diff --git a/lib/chef/node.rb b/lib/chef/node.rb
index ec20fbee86..1e5d3a8d59 100644
--- a/lib/chef/node.rb
+++ b/lib/chef/node.rb
@@ -87,8 +87,6 @@ class Chef
# after the run_context has been set on the node, go through the cookbook_collection
# and setup the node[:cookbooks] attribute so that it is published in the node object
def set_cookbook_attribute
- return unless run_context.cookbook_collection
-
run_context.cookbook_collection.each do |cookbook_name, cookbook|
automatic_attrs[:cookbooks][cookbook_name][:version] = cookbook.version
end
diff --git a/lib/chef/policy_builder/expand_node_object.rb b/lib/chef/policy_builder/expand_node_object.rb
index 4afb4d7d60..bb5e2e199b 100644
--- a/lib/chef/policy_builder/expand_node_object.rb
+++ b/lib/chef/policy_builder/expand_node_object.rb
@@ -75,7 +75,6 @@ class Chef
#
def setup_run_context(specific_recipes = nil, run_context = nil)
run_context ||= Chef::RunContext.new
-
run_context.events = events
run_context.node = node
@@ -93,6 +92,7 @@ class Chef
cookbook_collection.validate!
cookbook_collection.install_gems(events)
+
run_context.cookbook_collection = cookbook_collection
# TODO: move this into the cookbook_compilation_start hook
diff --git a/lib/chef/policy_builder/policyfile.rb b/lib/chef/policy_builder/policyfile.rb
index 70a2e44635..7eb9de042e 100644
--- a/lib/chef/policy_builder/policyfile.rb
+++ b/lib/chef/policy_builder/policyfile.rb
@@ -177,16 +177,17 @@ class Chef
#
# @return [Chef::RunContext]
def setup_run_context(specific_recipes = nil, run_context = nil)
+ run_context ||= Chef::RunContext.new
+ run_context.node = node
+ run_context.events = events
+
Chef::Cookbook::FileVendor.fetch_from_remote(api_service)
sync_cookbooks
cookbook_collection = Chef::CookbookCollection.new(cookbooks_to_sync)
cookbook_collection.validate!
cookbook_collection.install_gems(events)
- run_context ||= Chef::RunContext.new
- run_context.node = node
run_context.cookbook_collection = cookbook_collection
- run_context.events = events
setup_chef_class(run_context)
diff --git a/lib/chef/provider.rb b/lib/chef/provider.rb
index 6d1985bbbb..fb5697fd0c 100644
--- a/lib/chef/provider.rb
+++ b/lib/chef/provider.rb
@@ -1,7 +1,7 @@
#
# Author:: Adam Jacob (<adam@chef.io>)
# Author:: Christopher Walters (<cw@chef.io>)
-# Copyright:: Copyright 2008-2016, 2009-2018, Chef Software Inc.
+# Copyright:: Copyright 2008-2016, 2009-2019, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -238,8 +238,10 @@ class Chef
def compile_and_converge_action(&block)
old_run_context = run_context
@run_context = run_context.create_child
+ @run_context.resource_collection.unified_mode = new_resource.class.unified_mode
+ runner = Chef::Runner.new(@run_context)
return_value = instance_eval(&block)
- Chef::Runner.new(run_context).converge
+ runner.converge
return_value
ensure
if run_context.resource_collection.any?(&:updated?)
diff --git a/lib/chef/provider/ifconfig.rb b/lib/chef/provider/ifconfig.rb
index 93db827e97..71b64169c2 100644
--- a/lib/chef/provider/ifconfig.rb
+++ b/lib/chef/provider/ifconfig.rb
@@ -109,18 +109,20 @@ class Chef
# RX errors 0 dropped 0 overruns 0 frame 0
# TX packets 1244218 bytes 977339327 (932.0 MiB)
# TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
+ #
+ # Permalink for addr_regex : https://rubular.com/r/JrykUpfjRnYeQD
@status = shell_out("ifconfig")
@status.stdout.each_line do |line|
- addr_regex = /^(\w+):?(\d*):?\ .+$/
+ addr_regex = /^((\w|-)+):?(\d*):?\ .+$/
if line =~ addr_regex
if line.match(addr_regex).nil?
@int_name = "nil"
- elsif line.match(addr_regex)[2] == ""
+ elsif line.match(addr_regex)[3] == ""
@int_name = line.match(addr_regex)[1]
@interfaces[@int_name] = {}
@interfaces[@int_name]["mtu"] = (line =~ /mtu (\S+)/ ? Regexp.last_match(1) : "nil") if line =~ /mtu/ && @interfaces[@int_name]["mtu"].nil?
else
- @int_name = "#{line.match(addr_regex)[1]}:#{line.match(addr_regex)[2]}"
+ @int_name = "#{line.match(addr_regex)[1]}:#{line.match(addr_regex)[3]}"
@interfaces[@int_name] = {}
@interfaces[@int_name]["mtu"] = (line =~ /mtu (\S+)/ ? Regexp.last_match(1) : "nil") if line =~ /mtu/ && @interfaces[@int_name]["mtu"].nil?
end
diff --git a/lib/chef/resource.rb b/lib/chef/resource.rb
index 7f0895d6c9..a413e3e8d4 100644
--- a/lib/chef/resource.rb
+++ b/lib/chef/resource.rb
@@ -182,7 +182,7 @@ class Chef
{ action: { kind_of: Symbol, equal_to: allowed_actions } }
)
# the resource effectively sends a delayed notification to itself
- run_context.add_delayed_action(Notification.new(self, action, self))
+ run_context.add_delayed_action(Notification.new(self, action, self, run_context.unified_mode))
end
end
@@ -453,7 +453,6 @@ class Chef
#
attr_reader :elapsed_time
- #
# @return [Boolean] If the resource was executed by the runner
#
attr_accessor :executed_by_runner
@@ -985,6 +984,16 @@ class Chef
resource_name automatic_name
end
+ # If the resource's action should run in separated compile/converge mode.
+ #
+ # @param flag [Boolean] value to set unified_mode to
+ # @return [Boolean] unified_mode value
+ def self.unified_mode(flag = nil)
+ @unified_mode = Chef::Config[:resource_unified_mode_default] if @unified_mode.nil?
+ @unified_mode = flag unless flag.nil?
+ !!@unified_mode
+ end
+
#
# The list of allowed actions for the resource.
#
@@ -1038,7 +1047,6 @@ class Chef
default_action action_name
end
- #
# Define an action on this resource.
#
# The action is defined as a *recipe* block that will be compiled and then
@@ -1076,7 +1084,6 @@ class Chef
default_action action if Array(default_action) == [:nothing]
end
- #
# Define a method to load up this resource's properties with the current
# actual values.
#
@@ -1087,7 +1094,6 @@ class Chef
define_method(:load_current_value!, &load_block)
end
- #
# Call this in `load_current_value` to indicate that the value does not
# exist and that `current_resource` should therefore be `nil`.
#
@@ -1097,7 +1103,6 @@ class Chef
raise Chef::Exceptions::CurrentValueDoesNotExist
end
- #
# Get the current actual value of this resource.
#
# This does not cache--a new value will be returned each time.
@@ -1154,7 +1159,6 @@ class Chef
end
end
- #
# Ensure the action class actually gets created. This is called
# when the user does `action :x do ... end`.
#
@@ -1211,22 +1215,27 @@ class Chef
# @return [Chef::RunContext] The run context for this Resource. This is
# where the context for the current Chef run is stored, including the node
# and the resource collection.
+ #
attr_accessor :run_context
# @return [Mixlib::Log::Child] The logger for this resources. This is a child
# of the run context's logger, if one exists.
+ #
attr_reader :logger
# @return [String] The cookbook this resource was declared in.
+ #
attr_accessor :cookbook_name
# @return [String] The recipe this resource was declared in.
+ #
attr_accessor :recipe_name
# @return [Chef::Provider] The provider this resource was declared in (if
# it was declared in an LWRP). When you call methods that do not exist
# on this Resource, Chef will try to call the method on the provider
# as well before giving up.
+ #
attr_accessor :enclosing_provider
# @return [String] The source line where this resource was declared.
@@ -1234,6 +1243,7 @@ class Chef
# of these formats:
# /some/path/to/file.rb:80:in `wombat_tears'
# C:/some/path/to/file.rb:80 in 1`wombat_tears'
+ #
attr_accessor :source_line
# @return [String] The actual name that was used to create this resource.
@@ -1242,37 +1252,40 @@ class Chef
# user will expect to see the thing they wrote, not the type that was
# returned. May be `nil`, in which case callers should read #resource_name.
# See #declared_key.
+ #
attr_accessor :declared_type
- #
# Iterates over all immediate and delayed notifications, calling
# resolve_resource_reference on each in turn, causing them to
# resolve lazy/forward references.
- def resolve_notification_references
+ #
+ def resolve_notification_references(always_raise = false)
run_context.before_notifications(self).each do |n|
- n.resolve_resource_reference(run_context.resource_collection)
+ n.resolve_resource_reference(run_context.resource_collection, true)
end
+
run_context.immediate_notifications(self).each do |n|
- n.resolve_resource_reference(run_context.resource_collection)
+ n.resolve_resource_reference(run_context.resource_collection, always_raise)
end
+
run_context.delayed_notifications(self).each do |n|
- n.resolve_resource_reference(run_context.resource_collection)
+ n.resolve_resource_reference(run_context.resource_collection, always_raise)
end
end
# Helper for #notifies
def notifies_before(action, resource_spec)
- run_context.notifies_before(Notification.new(resource_spec, action, self))
+ run_context.notifies_before(Notification.new(resource_spec, action, self, run_context.unified_mode))
end
# Helper for #notifies
def notifies_immediately(action, resource_spec)
- run_context.notifies_immediately(Notification.new(resource_spec, action, self))
+ run_context.notifies_immediately(Notification.new(resource_spec, action, self, run_context.unified_mode))
end
# Helper for #notifies
def notifies_delayed(action, resource_spec)
- run_context.notifies_delayed(Notification.new(resource_spec, action, self))
+ run_context.notifies_delayed(Notification.new(resource_spec, action, self, run_context.unified_mode))
end
class << self
@@ -1321,7 +1334,6 @@ class Chef
end
end
- #
# This API can be used for backcompat to do:
#
# chef_version_for_provides "< 14.0" if defined?(:chef_version_for_provides)
@@ -1343,7 +1355,6 @@ class Chef
@chef_version_for_provides = constraint
end
- #
# Mark this resource as providing particular DSL.
#
# Resources have an automatic DSL based on their resource_name, equivalent to
@@ -1472,7 +1483,6 @@ class Chef
@default_description
end
- #
# The cookbook in which this Resource was defined (if any).
#
# @return Chef::CookbookVersion The cookbook in which this Resource was defined.
@@ -1498,7 +1508,6 @@ class Chef
provider
end
- #
# Preface an exception message with generic Resource information.
#
# @param e [StandardError] An exception with `e.message`
@@ -1554,7 +1563,6 @@ class Chef
klass
end
- #
# Returns the class with the given resource_name.
#
# NOTE: Chef::Resource.resource_matching_short_name(:package) returns
diff --git a/lib/chef/resource/resource_notification.rb b/lib/chef/resource/resource_notification.rb
index 7e93fff433..d3b9856332 100644
--- a/lib/chef/resource/resource_notification.rb
+++ b/lib/chef/resource/resource_notification.rb
@@ -1,6 +1,6 @@
#
# Author:: Tyler Ball (<tball@chef.io>)
-# Copyright:: Copyright 2014-2016, Chef Software, Inc.
+# Copyright:: Copyright 2014-2019, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -26,12 +26,13 @@ class Chef
# @attr [Resource] notifying_resource the Chef resource performing the notification
class Notification
- attr_accessor :resource, :action, :notifying_resource
+ attr_accessor :resource, :action, :notifying_resource, :unified_mode
- def initialize(resource, action, notifying_resource)
+ def initialize(resource, action, notifying_resource, unified_mode = false)
@resource = resource
@action = action&.to_sym
@notifying_resource = notifying_resource
+ @unified_mode = unified_mode
end
# Is the current notification a duplicate of another notification
@@ -52,11 +53,11 @@ class Chef
# @param [ResourceCollection] resource_collection
#
# @return [void]
- def resolve_resource_reference(resource_collection)
+ def resolve_resource_reference(resource_collection, always_raise = false)
return resource if resource.is_a?(Chef::Resource) && notifying_resource.is_a?(Chef::Resource)
unless resource.is_a?(Chef::Resource)
- fix_resource_reference(resource_collection)
+ fix_resource_reference(resource_collection, always_raise)
end
unless notifying_resource.is_a?(Chef::Resource)
@@ -69,7 +70,7 @@ class Chef
# @param [ResourceCollection] resource_collection
#
# @return [void]
- def fix_resource_reference(resource_collection)
+ def fix_resource_reference(resource_collection, always_raise = false)
matching_resource = resource_collection.find(resource)
if Array(matching_resource).size > 1
msg = "Notification #{self} from #{notifying_resource} was created with a reference to multiple resources, "\
@@ -79,13 +80,16 @@ class Chef
self.resource = matching_resource
rescue Chef::Exceptions::ResourceNotFound => e
- err = Chef::Exceptions::ResourceNotFound.new(<<~FAIL)
- resource #{notifying_resource} is configured to notify resource #{resource} with action #{action}, \
- but #{resource} cannot be found in the resource collection. #{notifying_resource} is defined in \
- #{notifying_resource.source_line}
- FAIL
- err.set_backtrace(e.backtrace)
- raise err
+ # in unified mode we allow lazy notifications to resources not yet declared
+ if !unified_mode || always_raise
+ err = Chef::Exceptions::ResourceNotFound.new(<<~FAIL)
+ resource #{notifying_resource} is configured to notify resource #{resource} with action #{action}, \
+ but #{resource} cannot be found in the resource collection. #{notifying_resource} is defined in \
+ #{notifying_resource.source_line}
+ FAIL
+ err.set_backtrace(e.backtrace)
+ raise err
+ end
rescue Chef::Exceptions::InvalidResourceSpecification => e
err = Chef::Exceptions::InvalidResourceSpecification.new(<<~F)
Resource #{notifying_resource} is configured to notify resource #{resource} with action #{action}, \
diff --git a/lib/chef/resource_collection.rb b/lib/chef/resource_collection.rb
index 3b6ff4297e..da675fc4de 100644
--- a/lib/chef/resource_collection.rb
+++ b/lib/chef/resource_collection.rb
@@ -32,6 +32,8 @@ class Chef
include ResourceCollectionSerialization
extend Forwardable
+ attr_accessor :unified_mode
+
attr_reader :resource_set, :resource_list
attr_accessor :run_context
@@ -41,6 +43,7 @@ class Chef
@run_context = run_context
@resource_set = ResourceSet.new
@resource_list = ResourceList.new
+ @unified_mode = false
end
# @param resource [Chef::Resource] The resource to insert
@@ -57,6 +60,9 @@ class Chef
else
resource_set.insert_as(resource)
end
+ if unified_mode
+ run_context.runner.run_all_actions(resource)
+ end
end
def delete(key)
diff --git a/lib/chef/run_context.rb b/lib/chef/run_context.rb
index eb211dc5a5..d849679680 100644
--- a/lib/chef/run_context.rb
+++ b/lib/chef/run_context.rb
@@ -26,12 +26,16 @@ require_relative "recipe"
require_relative "run_context/cookbook_compiler"
require_relative "event_dispatch/events_output_stream"
require_relative "train_transport"
+require_relative "exceptions"
require "forwardable" unless defined?(Forwardable)
+require "set" unless defined?(Set)
class Chef
# Value object that loads and tracks the context of a Chef run
class RunContext
+ extend Forwardable
+
#
# Global state
#
@@ -62,7 +66,7 @@ class Chef
#
# @return [Chef::CookbookCollection]
#
- attr_accessor :cookbook_collection
+ attr_reader :cookbook_collection
#
# Resource Definitions for this run. Populated when the files in
@@ -72,14 +76,12 @@ class Chef
#
attr_reader :definitions
- #
# Event dispatcher for this run.
#
# @return [Chef::EventDispatch::Dispatcher]
#
attr_accessor :events
- #
# Hash of factoids for a reboot request.
#
# @return [Hash]
@@ -90,7 +92,6 @@ class Chef
# Scoped state
#
- #
# The parent run context.
#
# @return [Chef::RunContext] The parent run context, or `nil` if this is the
@@ -98,7 +99,6 @@ class Chef
#
attr_reader :parent_run_context
- #
# The root run context.
#
# @return [Chef::RunContext] The root run context.
@@ -109,7 +109,6 @@ class Chef
rc
end
- #
# The collection of resources intended to be converged (and able to be
# notified).
#
@@ -119,8 +118,12 @@ class Chef
#
attr_reader :resource_collection
- attr_accessor :action_collection
+ # Handle to the global action_collection of executed actions for reporting / data_collector /etc
+ #
+ # @return [Chef::ActionCollection
#
+ attr_accessor :action_collection
+
# Pointer back to the Chef::Runner that created this
#
attr_accessor :runner
@@ -129,7 +132,6 @@ class Chef
# Notification handling
#
- #
# A Hash containing the before notifications triggered by resources
# during the converge phase of the chef run.
#
@@ -138,7 +140,6 @@ class Chef
#
attr_reader :before_notification_collection
- #
# A Hash containing the immediate notifications triggered by resources
# during the converge phase of the chef run.
#
@@ -147,7 +148,6 @@ class Chef
#
attr_reader :immediate_notification_collection
- #
# A Hash containing the delayed (end of run) notifications triggered by
# resources during the converge phase of the chef run.
#
@@ -156,7 +156,6 @@ class Chef
#
attr_reader :delayed_notification_collection
- #
# An Array containing the delayed (end of run) notifications triggered by
# resources during the converge phase of the chef run.
#
@@ -164,7 +163,16 @@ class Chef
#
attr_reader :delayed_actions
+ # A Set keyed by the string name, of all the resources that are updated. We do not
+ # track actions or individual resource objects, since this matches the behavior of
+ # the notification collections which are keyed by Strings.
+ #
+ attr_reader :updated_resources
+
+ # @return [Boolean] If the resource_collection is in unified_mode (no separate converge phase)
#
+ def_delegator :resource_collection, :unified_mode
+
# A child of the root Chef::Log logging object.
#
# @return Mixlib::Log::Child A child logger
@@ -180,17 +188,16 @@ class Chef
# @param events [EventDispatch::Dispatcher] The event dispatcher for this
# run.
#
- def initialize(node = nil, cookbook_collection = {}, events = nil, logger = nil)
+ def initialize(node = nil, cookbook_collection = nil, events = nil, logger = nil)
@events = events
@logger = logger || Chef::Log.with_child
- @cookbook_collection = cookbook_collection
self.node = node if node
+ self.cookbook_collection = cookbook_collection if cookbook_collection
@definitions = {}
@loaded_recipes_hash = {}
@loaded_attributes_hash = {}
@reboot_info = {}
@cookbook_compiler = nil
- @delayed_actions = []
initialize_child_state
end
@@ -198,6 +205,10 @@ class Chef
def node=(node)
@node = node
node.run_context = self
+ end
+
+ def cookbook_collection=(cookbook_collection)
+ @cookbook_collection = cookbook_collection
node.set_cookbook_attribute
end
@@ -221,6 +232,7 @@ class Chef
@immediate_notification_collection = Hash.new { |h, k| h[k] = [] }
@delayed_notification_collection = Hash.new { |h, k| h[k] = [] }
@delayed_actions = []
+ @updated_resources = Set.new
end
#
@@ -232,6 +244,10 @@ class Chef
# Note for the future, notification.notifying_resource may be an instance
# of Chef::Resource::UnresolvedSubscribes when calling {Resource#subscribes}
# with a string value.
+ if unified_mode && updated_resources.include?(notification.notifying_resource.declared_key)
+ raise Chef::Exceptions::UnifiedModeBeforeSubscriptionEarlierResource.new(notification)
+ end
+
before_notification_collection[notification.notifying_resource.declared_key] << notification
end
@@ -256,11 +272,13 @@ class Chef
# Note for the future, notification.notifying_resource may be an instance
# of Chef::Resource::UnresolvedSubscribes when calling {Resource#subscribes}
# with a string value.
+ if unified_mode && updated_resources.include?(notification.notifying_resource.declared_key)
+ add_delayed_action(notification)
+ end
delayed_notification_collection[notification.notifying_resource.declared_key] << notification
end
- #
- # Adds a delayed action to the +delayed_actions+.
+ # Adds a delayed action to the delayed_actions collection
#
def add_delayed_action(notification)
if delayed_actions.any? { |existing_notification| existing_notification.duplicates?(notification) }
@@ -271,32 +289,45 @@ class Chef
end
end
- #
# Get the list of before notifications sent by the given resource.
#
# @return [Array[Notification]]
#
def before_notifications(resource)
- before_notification_collection[resource.declared_key]
+ key = resource.is_a?(String) ? resource : resource.declared_key
+ before_notification_collection[key]
end
- #
# Get the list of immediate notifications sent by the given resource.
#
# @return [Array[Notification]]
#
def immediate_notifications(resource)
- immediate_notification_collection[resource.declared_key]
+ key = resource.is_a?(String) ? resource : resource.declared_key
+ immediate_notification_collection[key]
end
+ # Get the list of immeidate notifications pending to the given resource
#
+ # @return [Array[Notification]]
+ #
+ def reverse_immediate_notifications(resource)
+ immediate_notification_collection.map do |k, v|
+ v.select do |n|
+ (n.resource.is_a?(String) && n.resource == resource.declared_key) ||
+ n.resource == resource
+ end
+ end.flatten
+ end
+
# Get the list of delayed (end of run) notifications sent by the given
# resource.
#
# @return [Array[Notification]]
#
def delayed_notifications(resource)
- delayed_notification_collection[resource.declared_key]
+ key = resource.is_a?(String) ? resource : resource.declared_key
+ delayed_notification_collection[key]
end
#
@@ -666,9 +697,9 @@ class Chef
rest=
rest_clean
rest_clean=
- unreachable_cookbook?
transport
transport_connection
+ unreachable_cookbook?
}
def initialize(parent_run_context)
@@ -681,8 +712,10 @@ class Chef
end
CHILD_STATE = %w{
- create_child
add_delayed_action
+ before_notification_collection
+ before_notifications
+ create_child
delayed_actions
delayed_notification_collection
delayed_notification_collection=
@@ -690,21 +723,22 @@ class Chef
immediate_notification_collection
immediate_notification_collection=
immediate_notifications
- before_notification_collection
- before_notifications
include_recipe
initialize_child_state
load_recipe
load_recipe_file
notifies_before
- notifies_immediately
notifies_delayed
+ notifies_immediately
parent_run_context
- root_run_context
resource_collection
resource_collection=
+ reverse_immediate_notifications
+ root_run_context
runner
runner=
+ unified_mode
+ updated_resources
}.map(&:to_sym)
# Verify that we didn't miss any methods
diff --git a/lib/chef/runner.rb b/lib/chef/runner.rb
index a0ae61fe4c..8c68554af5 100644
--- a/lib/chef/runner.rb
+++ b/lib/chef/runner.rb
@@ -34,7 +34,7 @@ class Chef
def initialize(run_context)
@run_context = run_context
- run_context.runner = self
+ @run_context.runner = self
end
def delayed_actions
@@ -45,6 +45,10 @@ class Chef
@run_context.events
end
+ def updated_resources
+ @run_context.updated_resources
+ end
+
# Determine the appropriate provider for the given resource, then
# execute it.
def run_action(resource, action, notification_type = nil, notifying_resource = nil)
@@ -73,33 +77,66 @@ class Chef
# associated with the resource, but only if it was updated *this time*
# we ran an action on it.
if resource.updated_by_last_action?
+ updated_resources.add(resource.declared_key) # track updated resources for unified_mode
run_context.immediate_notifications(resource).each do |notification|
- Chef::Log.info("#{resource} sending #{notification.action} action to #{notification.resource} (immediate)")
- run_action(notification.resource, notification.action, :immediate, resource)
+ if notification.resource.is_a?(String) && run_context.unified_mode
+ Chef::Log.debug("immediate notification from #{resource} to #{notification.resource} is delayed until declaration due to unified_mode")
+ else
+ Chef::Log.info("#{resource} sending #{notification.action} action to #{notification.resource} (immediate)")
+ run_action(notification.resource, notification.action, :immediate, resource)
+ end
end
run_context.delayed_notifications(resource).each do |notification|
- # send the notification to the run_context of the receiving resource
- notification.resource.run_context.add_delayed_action(notification)
+ if notification.resource.is_a?(String)
+ # for string resources that have not be declared yet in unified mode we only support notifying the current run_context
+ run_context.add_delayed_action(notification)
+ else
+ # send the notification to the run_context of the receiving resource
+ notification.resource.run_context.add_delayed_action(notification)
+ end
+ end
+ end
+ end
+
+ # Runs all of the actions on a given resource. This fires notifications and marks
+ # the resource as having been executed by the runner.
+ #
+ # @param resource [Chef::Resource] the resource to run
+ #
+ def run_all_actions(resource)
+ Array(resource.action).each { |action| run_action(resource, action) }
+ if run_context.unified_mode
+ run_context.reverse_immediate_notifications(resource).each do |n|
+ if updated_resources.include?(n.notifying_resource.declared_key)
+ n.resolve_resource_reference(run_context.resource_collection)
+ Chef::Log.info("#{resource} sent #{n.action} action to #{n.resource} (immediate at declaration time)")
+ run_action(n.resource, n.action, :immediate, n.notifying_resource)
+ end
end
end
+ ensure
+ resource.executed_by_runner = true
end
- # Iterates over the +resource_collection+ in the +run_context+ calling
- # +run_action+ for each resource in turn.
+ # Iterates over the resource_collection in the run_context calling
+ # run_action for each resource in turn.
+ #
def converge
# Resolve all lazy/forward references in notifications
run_context.resource_collection.each(&:resolve_notification_references)
# Execute each resource.
run_context.resource_collection.execute_each_resource do |resource|
- begin
- Array(resource.action).each { |action| run_action(resource, action) }
- ensure
- resource.executed_by_runner = true
+ unless run_context.resource_collection.unified_mode
+ run_all_actions(resource)
end
end
+ if run_context.resource_collection.unified_mode
+ run_context.resource_collection.each { |r| r.resolve_notification_references(true) }
+ end
+
rescue Exception => e
Chef::Log.info "Running queued delayed notifications before re-raising exception"
run_delayed_notifications(e)
@@ -126,7 +163,8 @@ class Chef
def run_delayed_notification(notification)
Chef::Log.info( "#{notification.notifying_resource} sending #{notification.action}"\
" action to #{notification.resource} (delayed)")
- # Struct of resource/action to call
+ # notifications may have lazy strings in them to resolve
+ notification.resolve_resource_reference(run_context.resource_collection)
run_action(notification.resource, notification.action, :delayed)
true
rescue Exception => e
diff --git a/lib/chef/version.rb b/lib/chef/version.rb
index 7d20e4886f..238143495b 100644
--- a/lib/chef/version.rb
+++ b/lib/chef/version.rb
@@ -23,7 +23,7 @@ require_relative "version_string"
class Chef
CHEF_ROOT = File.expand_path("../..", __FILE__)
- VERSION = Chef::VersionString.new("15.2.24")
+ VERSION = Chef::VersionString.new("15.2.33")
end
#
diff --git a/omnibus/Gemfile.lock b/omnibus/Gemfile.lock
index e8460b670f..74bd1ddd09 100644
--- a/omnibus/Gemfile.lock
+++ b/omnibus/Gemfile.lock
@@ -1,9 +1,9 @@
GIT
remote: https://github.com/chef/omnibus
- revision: 33bddeefb10afe23a57ea72807625881ab01990f
+ revision: c872e61c30d2b3f88ead03bd1254ff96d37059a3
branch: master
specs:
- omnibus (6.1.0)
+ omnibus (6.1.3)
aws-sdk-s3 (~> 1)
chef-sugar (>= 3.3)
cleanroom (~> 1.0)
@@ -18,7 +18,7 @@ GIT
GIT
remote: https://github.com/chef/omnibus-software
- revision: 501b5e51a26f4fc8a31c458252c361fdd0767efd
+ revision: 75f8868a794508d6b567162f13924c9d21ce5dfa
branch: master
specs:
omnibus-software (4.0.0)
@@ -33,8 +33,8 @@ GEM
artifactory (3.0.5)
awesome_print (1.8.0)
aws-eventstream (1.0.3)
- aws-partitions (1.196.0)
- aws-sdk-core (3.62.0)
+ aws-partitions (1.207.0)
+ aws-sdk-core (3.65.1)
aws-eventstream (~> 1.0, >= 1.0.2)
aws-partitions (~> 1.0)
aws-sigv4 (~> 1.1)
@@ -42,7 +42,7 @@ GEM
aws-sdk-kms (1.24.0)
aws-sdk-core (~> 3, >= 3.61.1)
aws-sigv4 (~> 1.1)
- aws-sdk-s3 (1.46.0)
+ aws-sdk-s3 (1.47.0)
aws-sdk-core (~> 3, >= 3.61.1)
aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.1)
@@ -65,11 +65,11 @@ GEM
solve (~> 4.0)
thor (>= 0.20)
builder (3.2.3)
- chef (15.1.36)
+ chef (15.2.20)
addressable
bcrypt_pbkdf (~> 1.0)
bundler (>= 1.10)
- chef-config (= 15.1.36)
+ chef-config (= 15.2.20)
chef-zero (>= 14.0.11)
diff-lcs (~> 1.2, >= 1.2.4)
ed25519 (~> 1.2)
@@ -95,11 +95,11 @@ GEM
train-core (~> 2.0, >= 2.0.12)
tty-screen (~> 0.6)
uuidtools (~> 2.1.5)
- chef (15.1.36-universal-mingw32)
+ chef (15.2.20-universal-mingw32)
addressable
bcrypt_pbkdf (~> 1.0)
bundler (>= 1.10)
- chef-config (= 15.1.36)
+ chef-config (= 15.2.20)
chef-zero (>= 14.0.11)
diff-lcs (~> 1.2, >= 1.2.4)
ed25519 (~> 1.2)
@@ -137,7 +137,7 @@ GEM
win32-service (>= 2.1.2, < 3.0)
win32-taskscheduler (~> 2.0)
wmi-lite (~> 1.0)
- chef-config (15.1.36)
+ chef-config (15.2.20)
addressable
fuzzyurl
mixlib-config (>= 2.2.12, < 4.0)
@@ -182,7 +182,7 @@ GEM
iso8601 (0.12.1)
jmespath (1.4.0)
json (2.2.0)
- kitchen-vagrant (1.5.2)
+ kitchen-vagrant (1.6.0)
test-kitchen (>= 1.4, < 3)
libyajl2 (1.2.0)
license-acceptance (1.0.13)
@@ -234,7 +234,7 @@ GEM
nori (2.6.0)
octokit (4.14.0)
sawyer (~> 0.8.0, >= 0.5.3)
- ohai (15.1.5)
+ ohai (15.2.5)
chef-config (>= 12.8, < 16)
ffi (~> 1.9)
ffi-yajl (~> 2.2)
@@ -271,7 +271,7 @@ GEM
solve (4.0.2)
molinillo (~> 0.6)
semverse (>= 1.1, < 4.0)
- strings (0.1.5)
+ strings (0.1.6)
strings-ansi (~> 0.1)
unicode-display_width (~> 1.5)
unicode_utils (~> 1.4)
@@ -279,7 +279,7 @@ GEM
structured_warnings (0.3.0)
syslog-logger (1.6.8)
systemu (2.6.5)
- test-kitchen (2.2.5)
+ test-kitchen (2.3.1)
bcrypt_pbkdf (~> 1.0)
ed25519 (~> 1.2)
license-acceptance (~> 1.0, >= 1.0.11)
@@ -303,9 +303,9 @@ GEM
net-ssh (>= 2.9, < 6.0)
winrm (~> 2.0)
winrm-fs (~> 1.0)
- tty-box (0.4.0)
+ tty-box (0.4.1)
pastel (~> 0.7.2)
- strings (~> 0.1.5)
+ strings (~> 0.1.6)
tty-cursor (~> 0.7)
tty-color (0.5.0)
tty-cursor (0.7.0)
diff --git a/spec/integration/client/client_spec.rb b/spec/integration/client/client_spec.rb
index 68cfd015ab..b1763da1f0 100644
--- a/spec/integration/client/client_spec.rb
+++ b/spec/integration/client/client_spec.rb
@@ -369,6 +369,28 @@ describe "chef-client" do
end
end
+ when_the_repository "has a cookbook that outputs some node attributes" do
+ before do
+ file "cookbooks/x/recipes/default.rb", <<~'EOM'
+ puts "COOKBOOKS: #{node[:cookbooks]}"
+ EOM
+ file "cookbooks/x/metadata.rb", <<~EOM
+ name 'x'
+ version '0.0.1'
+ EOM
+ file "config/client.rb", <<~EOM
+ local_mode true
+ cookbook_path "#{path_to("cookbooks")}"
+ EOM
+ end
+
+ it "should have a cookbook attribute" do
+ result = shell_out("#{chef_client} -c \"#{path_to("config/client.rb")}\" -o 'x::default' --no-fork", cwd: chef_dir)
+ result.error!
+ expect(result.stdout).to include('COOKBOOKS: {"x"=>{"version"=>"0.0.1"}}')
+ end
+ end
+
when_the_repository "has a cookbook that should fail chef_version checks" do
before do
file "cookbooks/x/recipes/default.rb", ""
diff --git a/spec/integration/knife/raw_spec.rb b/spec/integration/knife/raw_spec.rb
index 9fd7664ddd..99fb7b5787 100644
--- a/spec/integration/knife/raw_spec.rb
+++ b/spec/integration/knife/raw_spec.rb
@@ -19,11 +19,11 @@ require "support/shared/integration/integration_helper"
require "support/shared/context/config"
require "chef/knife/raw"
require "chef/knife/show"
+require "tiny_server"
describe "knife raw", :workstation do
include IntegrationSupport
include KnifeSupport
- include AppServerSupport
include_context "default config options"
@@ -185,19 +185,29 @@ describe "knife raw", :workstation do
end
context "When a server returns raw json" do
- before :each do
- Chef::Config.chef_server_url = "http://localhost:9018"
- app = lambda do |env|
- [200, { "Content-Type" => "application/json" }, ['{ "x": "y", "a": "b" }'] ]
+ def start_tiny_server(server_opts = {})
+ @server = TinyServer::Manager.new(server_opts)
+ @server.start
+ @api = TinyServer::API.instance
+ @api.clear
+
+ @api.get("/blah", 200, nil, { "Content-Type" => "application/json" }) do
+ '{ "x": "y", "a": "b" }'
end
- @raw_server_thread = start_app_server(app, 9018)
+ end
+
+ def stop_tiny_server
+ @server.stop
+ @server = @api = nil
+ end
+
+ before :each do
+ Chef::Config.chef_server_url = "http://localhost:9000"
+ start_tiny_server
end
after :each do
- if @raw_server_thread
- @raw_server_thread.kill
- @raw_server_thread.join(30)
- end
+ stop_tiny_server
end
it "knife raw /blah returns the prettified json" do
@@ -217,19 +227,29 @@ describe "knife raw", :workstation do
end
context "When a server returns text" do
- before :each do
- Chef::Config.chef_server_url = "http://localhost:9018"
- app = lambda do |env|
- [200, { "Content-Type" => "text" }, ['{ "x": "y", "a": "b" }'] ]
+ def start_tiny_server(server_opts = {})
+ @server = TinyServer::Manager.new(server_opts)
+ @server.start
+ @api = TinyServer::API.instance
+ @api.clear
+
+ @api.get("/blah", 200, nil, { "Content-Type" => "text" }) do
+ '{ "x": "y", "a": "b" }'
end
- @raw_server_thread = start_app_server(app, 9018)
+ end
+
+ def stop_tiny_server
+ @server.stop
+ @server = @api = nil
+ end
+
+ before :each do
+ Chef::Config.chef_server_url = "http://localhost:9000"
+ start_tiny_server
end
after :each do
- if @raw_server_thread
- @raw_server_thread.kill
- @raw_server_thread.join(30)
- end
+ stop_tiny_server
end
it "knife raw /blah returns the raw text" do
diff --git a/spec/integration/knife/redirection_spec.rb b/spec/integration/knife/redirection_spec.rb
index 5e5ef27b9a..fe39315fe4 100644
--- a/spec/integration/knife/redirection_spec.rb
+++ b/spec/integration/knife/redirection_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: John Keiser (<jkeiser@chef.io>)
-# Copyright:: Copyright 2013-2018, Chef Software Inc.
+# Copyright:: Copyright 2013-2019, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,6 +15,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+require "tiny_server"
require "support/shared/integration/integration_helper"
require "support/shared/context/config"
require "chef/knife/list"
@@ -22,7 +23,21 @@ require "chef/knife/list"
describe "redirection", :workstation do
include IntegrationSupport
include KnifeSupport
- include AppServerSupport
+
+ def start_tiny_server(real_chef_server_url, server_opts = {})
+ @server = TinyServer::Manager.new(server_opts)
+ @server.start
+ @api = TinyServer::API.instance
+ @api.clear
+
+ @api.get("/roles", 302, nil, { "Content-Type" => "text", "Location" => "#{real_chef_server_url}/roles" }) do
+ end
+ end
+
+ def stop_tiny_server
+ @server.stop
+ @server = @api = nil
+ end
include_context "default config options"
@@ -30,20 +45,14 @@ describe "redirection", :workstation do
before { role "x", {} }
context "and another server redirects to it with 302" do
- before :each do
+ before(:each) do
real_chef_server_url = Chef::Config.chef_server_url
- Chef::Config.chef_server_url = "http://localhost:9018"
- app = lambda do |env|
- [302, { "Content-Type" => "text", "Location" => "#{real_chef_server_url}#{env["PATH_INFO"]}" }, ["302 found"] ]
- end
- @redirector_server_thread = start_app_server(app, 9018)
+ Chef::Config.chef_server_url = "http://localhost:9000"
+ start_tiny_server(real_chef_server_url)
end
- after :each do
- if @redirector_thread
- @redirector_thread.kill
- @redirector_thread.join(30)
- end
+ after(:each) do
+ stop_tiny_server
end
it "knife list /roles returns the role" do
diff --git a/spec/integration/knife/serve_spec.rb b/spec/integration/knife/serve_spec.rb
index b0cdd8c070..ab293174d4 100644
--- a/spec/integration/knife/serve_spec.rb
+++ b/spec/integration/knife/serve_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: John Keiser (<jkeiser@chef.io>)
-# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# Copyright:: Copyright 2013-2019, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -22,7 +22,6 @@ require "chef/server_api"
describe "knife serve", :workstation do
include IntegrationSupport
include KnifeSupport
- include AppServerSupport
def with_knife_serve
exception = nil
diff --git a/spec/integration/recipes/unified_mode_spec.rb b/spec/integration/recipes/unified_mode_spec.rb
new file mode 100644
index 0000000000..944319f7bf
--- /dev/null
+++ b/spec/integration/recipes/unified_mode_spec.rb
@@ -0,0 +1,876 @@
+require "support/shared/integration/integration_helper"
+require "chef/mixin/shell_out"
+
+describe "Unified Mode" do
+ include IntegrationSupport
+ include Chef::Mixin::ShellOut
+
+ let(:chef_dir) { File.expand_path("../../../../bin", __FILE__) }
+
+ let(:chef_client) { "bundle exec chef-client --minimal-ohai" }
+
+ when_the_repository "has a cookbook with a unified_mode resource with a delayed notification from the second block to the first block" do
+ before do
+ directory "cookbooks/x" do
+
+ file "resources/unified_mode.rb", <<-EOM
+ unified_mode true
+ resource_name :unified_mode
+ provides :unified_mode
+
+ action :doit do
+ klass = new_resource.class
+ var = "foo"
+ ruby_block "first block" do
+ block do
+ puts "\nfirst: \#\{var\}"
+ end
+ action :nothing
+ end
+ var = "bar"
+ ruby_block "second block" do
+ block do
+ puts "\nsecond: \#\{var\}"
+ end
+ notifies :run, "ruby_block[first block]", :delayed
+ end
+ var = "baz"
+ end
+ EOM
+
+ file "recipes/default.rb", <<-EOM
+ unified_mode "whatever"
+ EOM
+
+ end # directory 'cookbooks/x'
+ end
+
+ it "should complete with success" do
+ file "config/client.rb", <<~EOM
+ local_mode true
+ cookbook_path "#{path_to("cookbooks")}"
+ log_level :warn
+ EOM
+
+ result = shell_out("#{chef_client} -c \"#{path_to("config/client.rb")}\" --no-color -F doc -o 'x::default'", cwd: chef_dir)
+ # the "second block" runs first after "bar" is set
+ expect(result.stdout).to include("second: bar")
+ # then the "first block" runs after "baz" in the delayed phase
+ expect(result.stdout).to include("first: baz")
+ # nothing else should fire
+ expect(result.stdout).not_to include("first: foo")
+ expect(result.stdout).not_to include("first: bar")
+ expect(result.stdout).not_to include("second: foo")
+ expect(result.stdout).not_to include("second: baz")
+ result.error!
+ end
+ end
+
+ when_the_repository "has a cookbook with a unified_mode resource with a delayed notification from the first block to the second block" do
+ before do
+ directory "cookbooks/x" do
+
+ file "resources/unified_mode.rb", <<-EOM
+ unified_mode true
+ resource_name :unified_mode
+ provides :unified_mode
+
+ action :doit do
+ klass = new_resource.class
+ var = "foo"
+ ruby_block "first block" do
+ block do
+ puts "\nfirst: \#\{var\}"
+ end
+ notifies :run, "ruby_block[second block]", :delayed
+ end
+ var = "bar"
+ ruby_block "second block" do
+ block do
+ puts "\nsecond: \#\{var\}"
+ end
+ action :nothing
+ end
+ var = "baz"
+ end
+ EOM
+
+ file "recipes/default.rb", <<-EOM
+ unified_mode "whatever"
+ EOM
+
+ end # directory 'cookbooks/x'
+ end
+
+ it "should complete with success" do
+ file "config/client.rb", <<~EOM
+ local_mode true
+ cookbook_path "#{path_to("cookbooks")}"
+ log_level :warn
+ EOM
+
+ result = shell_out("#{chef_client} -c \"#{path_to("config/client.rb")}\" --no-color -F doc -o 'x::default' -l debug", cwd: chef_dir)
+ # the first block should fire first
+ expect(result.stdout).to include("first: foo")
+ # the second block should fire in delayed phase
+ expect(result.stdout).to include("second: baz")
+ # nothing else should fire
+ expect(result.stdout).not_to include("first: bar")
+ expect(result.stdout).not_to include("first: baz")
+ expect(result.stdout).not_to include("second: foo")
+ expect(result.stdout).not_to include("second: bar")
+ result.error!
+ end
+ end
+
+ when_the_repository "has a cookbook with a unified_mode resource with an immediate notification from the second block to the first block" do
+ before do
+ directory "cookbooks/x" do
+
+ file "resources/unified_mode.rb", <<-EOM
+ unified_mode true
+ resource_name :unified_mode
+ provides :unified_mode
+ action :doit do
+ klass = new_resource.class
+ var = "foo"
+ ruby_block "first block" do
+ block do
+ puts "\nfirst: \#\{var\}"
+ end
+ action :nothing
+ end
+ var = "bar"
+ ruby_block "second block" do
+ block do
+ puts "\nsecond: \#\{var\}"
+ end
+ notifies :run, "ruby_block[first block]", :immediate
+ end
+ var = "baz"
+ end
+ EOM
+
+ file "recipes/default.rb", <<-EOM
+ unified_mode "whatever"
+ EOM
+
+ end # directory 'cookbooks/x'
+ end
+
+ it "should complete with success" do
+ file "config/client.rb", <<~EOM
+ local_mode true
+ cookbook_path "#{path_to("cookbooks")}"
+ log_level :warn
+ EOM
+
+ result = shell_out("#{chef_client} -c \"#{path_to("config/client.rb")}\" --no-color -F doc -o 'x::default'", cwd: chef_dir)
+ # the second resource should fire first when it is parsed
+ expect(result.stdout).to include("second: bar")
+ # the first resource should then immediately fire
+ expect(result.stdout).to include("first: bar")
+ # no other resources should fire
+ expect(result.stdout).not_to include("second: baz")
+ expect(result.stdout).not_to include("second: foo")
+ expect(result.stdout).not_to include("first: foo")
+ expect(result.stdout).not_to include("first: baz")
+ result.error!
+ end
+ end
+
+ when_the_repository "has a cookbook with a unified_mode resource with an immediate notification from the first block to the second block" do
+ before do
+ directory "cookbooks/x" do
+
+ file "resources/unified_mode.rb", <<-EOM
+ unified_mode true
+ resource_name :unified_mode
+ provides :unified_mode
+ action :doit do
+ klass = new_resource.class
+ var = "foo"
+ ruby_block "first block" do
+ block do
+ puts "\nfirst: \#\{var\}"
+ end
+ notifies :run, "ruby_block[second block]", :immediate
+ end
+ var = "bar"
+ ruby_block "second block" do
+ block do
+ puts "\nsecond: \#\{var\}"
+ end
+ action :nothing
+ end
+ var = "baz"
+ end
+ EOM
+
+ file "recipes/default.rb", <<-EOM
+ unified_mode "whatever"
+ EOM
+
+ end # directory 'cookbooks/x'
+ end
+
+ it "should complete with success" do
+ file "config/client.rb", <<~EOM
+ local_mode true
+ cookbook_path "#{path_to("cookbooks")}"
+ log_level :warn
+ EOM
+
+ result = shell_out("#{chef_client} -c \"#{path_to("config/client.rb")}\" --no-color -F doc -o 'x::default' -l debug", cwd: chef_dir)
+ # both blocks should run when they're declared
+ expect(result.stdout).to include("first: foo")
+ expect(result.stdout).to include("second: bar")
+ # nothing else should run
+ expect(result.stdout).not_to include("first: bar")
+ expect(result.stdout).not_to include("first: baz")
+ expect(result.stdout).not_to include("second: foo")
+ expect(result.stdout).not_to include("second: baz")
+ result.error!
+ end
+ end
+
+ when_the_repository "has a cookbook with a unified_mode resource with an immediate notification from the first block to a block that does not exist" do
+ before do
+ directory "cookbooks/x" do
+
+ file "resources/unified_mode.rb", <<-EOM
+ unified_mode true
+ resource_name :unified_mode
+ provides :unified_mode
+ action :doit do
+ klass = new_resource.class
+ var = "foo"
+ ruby_block "first block" do
+ block do
+ puts "\nfirst: \#\{var\}"
+ end
+ notifies :run, "ruby_block[second block]", :immediate
+ end
+ var = "bar"
+ var = "baz"
+ end
+ EOM
+
+ file "recipes/default.rb", <<-EOM
+ unified_mode "whatever"
+ EOM
+
+ end # directory 'cookbooks/x'
+ end
+
+ it "should fail the run" do
+ file "config/client.rb", <<~EOM
+ local_mode true
+ cookbook_path "#{path_to("cookbooks")}"
+ log_level :warn
+ EOM
+
+ result = shell_out("#{chef_client} -c \"#{path_to("config/client.rb")}\" --no-color -F doc -o 'x::default'", cwd: chef_dir)
+ # both blocks should run when they're declared
+ expect(result.stdout).to include("first: foo")
+ # nothing else should run
+ expect(result.stdout).not_to include("second: bar")
+ expect(result.stdout).not_to include("first: bar")
+ expect(result.stdout).not_to include("first: baz")
+ expect(result.stdout).not_to include("second: foo")
+ expect(result.stdout).not_to include("second: baz")
+ expect(result.stdout).to include("Chef::Exceptions::ResourceNotFound")
+ expect(result.error?).to be true
+ end
+ end
+
+ when_the_repository "has a cookbook with a normal resource with an delayed notification with global resource unified mode on" do
+ before do
+ directory "cookbooks/x" do
+
+ file "resources/unified_mode.rb", <<-EOM
+ resource_name :unified_mode
+ provides :unified_mode
+
+ action :doit do
+ klass = new_resource.class
+ var = "foo"
+ ruby_block "second block" do
+ block do
+ puts "\nsecond: \#\{var\}"
+ end
+ action :nothing
+ end
+ var = "bar"
+ ruby_block "first block" do
+ block do
+ puts "\nfirst: \#\{var\}"
+ end
+ notifies :run, "ruby_block[second block]", :delayed
+ end
+ var = "baz"
+ end
+ EOM
+
+ file "recipes/default.rb", <<-EOM
+ unified_mode "whatever"
+ EOM
+
+ end # directory 'cookbooks/x'
+ end
+
+ it "should complete with success" do
+ file "config/client.rb", <<~EOM
+ resource_unified_mode_default true
+ local_mode true
+ cookbook_path "#{path_to("cookbooks")}"
+ log_level :warn
+ EOM
+
+ result = shell_out("#{chef_client} -c \"#{path_to("config/client.rb")}\" --no-color -F doc -o 'x::default'", cwd: chef_dir)
+ # the "first block" resource runs before the assignment to baz in compile time
+ expect(result.stdout).to include("first: bar")
+ # we should not run the "first block" at compile time
+ expect(result.stdout).not_to include("first: baz")
+ # (and certainly should run it this early)
+ expect(result.stdout).not_to include("first: foo")
+ # the delayed notification should still fire and run after everything else
+ expect(result.stdout).to include("second: baz")
+ # the action :nothing should suppress any other running of the second block
+ expect(result.stdout).not_to include("second: foo")
+ expect(result.stdout).not_to include("second: bar")
+ result.error!
+ end
+ end
+
+ when_the_repository "has a cookbook with a normal resource with an immediate notification with global resource unified mode on" do
+ before do
+ directory "cookbooks/x" do
+
+ file "resources/unified_mode.rb", <<-EOM
+ resource_name :unified_mode
+ provides :unified_mode
+ action :doit do
+ klass = new_resource.class
+ var = "foo"
+ ruby_block "second block" do
+ block do
+ puts "\nsecond: \#\{var\}"
+ end
+ action :nothing
+ end
+ var = "bar"
+ ruby_block "first block" do
+ block do
+ puts "\nfirst: \#\{var\}"
+ end
+ notifies :run, "ruby_block[second block]", :immediate
+ end
+ var = "baz"
+ end
+ EOM
+
+ file "recipes/default.rb", <<-EOM
+ unified_mode "whatever"
+ EOM
+
+ end # directory 'cookbooks/x'
+ end
+
+ it "should complete with success" do
+ file "config/client.rb", <<~EOM
+ resource_unified_mode_default true
+ local_mode true
+ cookbook_path "#{path_to("cookbooks")}"
+ log_level :warn
+ EOM
+
+ result = shell_out("#{chef_client} -c \"#{path_to("config/client.rb")}\" --no-color -F doc -o 'x::default'", cwd: chef_dir)
+ # the "first block" resource runs before the assignment to baz in compile time
+ expect(result.stdout).to include("first: bar")
+ # we should not run the "first block" at compile time
+ expect(result.stdout).not_to include("first: baz")
+ # (and certainly should run it this early)
+ expect(result.stdout).not_to include("first: foo")
+ # the immediate notifiation fires immediately
+ expect(result.stdout).to include("second: bar")
+ # the action :nothing should suppress any other running of the second block
+ expect(result.stdout).not_to include("second: foo")
+ expect(result.stdout).not_to include("second: baz")
+ result.error!
+ end
+ end
+
+ when_the_repository "has a cookbook with a unified resource with an immediate subscribes from the second resource to the first" do
+ before do
+ directory "cookbooks/x" do
+
+ file "resources/unified_mode.rb", <<-EOM
+ unified_mode true
+ resource_name :unified_mode
+ provides :unified_mode
+ action :doit do
+ klass = new_resource.class
+ var = "foo"
+ ruby_block "first block" do
+ block do
+ puts "\nfirst: \#\{var\}"
+ end
+ end
+ var = "bar"
+ ruby_block "second block" do
+ block do
+ puts "\nsecond: \#\{var\}"
+ end
+ subscribes :run, "ruby_block[first block]", :immediate
+ action :nothing
+ end
+ var = "baz"
+ end
+ EOM
+
+ file "recipes/default.rb", <<-EOM
+ unified_mode "whatever"
+ EOM
+
+ end # directory 'cookbooks/x'
+ end
+
+ it "should complete with success" do
+ file "config/client.rb", <<~EOM
+ local_mode true
+ cookbook_path "#{path_to("cookbooks")}"
+ log_level :warn
+ EOM
+
+ result = shell_out("#{chef_client} -c \"#{path_to("config/client.rb")}\" --no-color -F doc -o 'x::default'", cwd: chef_dir)
+ # the first resource fires
+ expect(result.stdout).to include("first: foo")
+ # the second resource fires when it is parsed
+ expect(result.stdout).to include("second: bar")
+ # no other actions should run
+ expect(result.stdout).not_to include("first: bar")
+ expect(result.stdout).not_to include("first: baz")
+ expect(result.stdout).not_to include("second: foo")
+ expect(result.stdout).not_to include("second: baz")
+ result.error!
+ end
+ end
+
+ when_the_repository "has a cookbook with a unified resource with an immediate subscribes from the first resource to the second" do
+ before do
+ directory "cookbooks/x" do
+
+ file "resources/unified_mode.rb", <<-EOM
+ unified_mode true
+ resource_name :unified_mode
+ provides :unified_mode
+ action :doit do
+ klass = new_resource.class
+ var = "foo"
+ ruby_block "first block" do
+ block do
+ puts "\nfirst: \#\{var\}"
+ end
+ subscribes :run, "ruby_block[second block]", :immediate
+ action :nothing
+ end
+ var = "bar"
+ ruby_block "second block" do
+ block do
+ puts "\nsecond: \#\{var\}"
+ end
+ end
+ var = "baz"
+ end
+ EOM
+
+ file "recipes/default.rb", <<-EOM
+ unified_mode "whatever"
+ EOM
+
+ end # directory 'cookbooks/x'
+ end
+
+ it "should complete with success" do
+ file "config/client.rb", <<~EOM
+ local_mode true
+ cookbook_path "#{path_to("cookbooks")}"
+ log_level :warn
+ EOM
+
+ result = shell_out("#{chef_client} -c \"#{path_to("config/client.rb")}\" --no-color -F doc -o 'x::default'", cwd: chef_dir)
+ # the second resource fires first after bar is set
+ expect(result.stdout).to include("second: bar")
+ # the first resource then has its immediate subscribes fire at that location
+ expect(result.stdout).to include("first: bar")
+ # no other actions should run
+ expect(result.stdout).not_to include("first: baz")
+ expect(result.stdout).not_to include("first: foo")
+ expect(result.stdout).not_to include("second: foo")
+ expect(result.stdout).not_to include("second: baz")
+ result.error!
+ end
+ end
+
+ when_the_repository "has a cookbook with a unified resource with an delayed subscribes from the second resource to the first" do
+ before do
+ directory "cookbooks/x" do
+
+ file "resources/unified_mode.rb", <<-EOM
+ unified_mode true
+ resource_name :unified_mode
+ provides :unified_mode
+ action :doit do
+ klass = new_resource.class
+ var = "foo"
+ ruby_block "first block" do
+ block do
+ puts "\nfirst: \#\{var\}"
+ end
+ end
+ var = "bar"
+ ruby_block "second block" do
+ block do
+ puts "\nsecond: \#\{var\}"
+ end
+ subscribes :run, "ruby_block[first block]", :delayed
+ action :nothing
+ end
+ var = "baz"
+ end
+ EOM
+
+ file "recipes/default.rb", <<-EOM
+ unified_mode "whatever"
+ EOM
+
+ end # directory 'cookbooks/x'
+ end
+
+ it "should complete with success" do
+ file "config/client.rb", <<~EOM
+ local_mode true
+ cookbook_path "#{path_to("cookbooks")}"
+ log_level :warn
+ EOM
+
+ result = shell_out("#{chef_client} -c \"#{path_to("config/client.rb")}\" --no-color -F doc -o 'x::default'", cwd: chef_dir)
+ # the first resource fires as it is parsed
+ expect(result.stdout).to include("first: foo")
+ # the second resource then fires in the delayed notifications phase
+ expect(result.stdout).to include("second: baz")
+ # no other actions should run
+ expect(result.stdout).not_to include("first: bar")
+ expect(result.stdout).not_to include("first: baz")
+ expect(result.stdout).not_to include("second: foo")
+ expect(result.stdout).not_to include("second: bar")
+ result.error!
+ end
+ end
+
+ when_the_repository "has a cookbook with a unified resource with an delayed subscribes from the first resource to the second" do
+ before do
+ directory "cookbooks/x" do
+
+ file "resources/unified_mode.rb", <<-EOM
+ unified_mode true
+ resource_name :unified_mode
+ provides :unified_mode
+ action :doit do
+ klass = new_resource.class
+ var = "foo"
+ ruby_block "first block" do
+ block do
+ puts "\nfirst: \#\{var\}"
+ end
+ subscribes :run, "ruby_block[second block]", :delayed
+ action :nothing
+ end
+ var = "bar"
+ ruby_block "second block" do
+ block do
+ puts "\nsecond: \#\{var\}"
+ end
+ end
+ var = "baz"
+ end
+ EOM
+
+ file "recipes/default.rb", <<-EOM
+ unified_mode "whatever"
+ EOM
+
+ end # directory 'cookbooks/x'
+ end
+
+ it "should complete with success" do
+ file "config/client.rb", <<~EOM
+ local_mode true
+ cookbook_path "#{path_to("cookbooks")}"
+ log_level :warn
+ EOM
+
+ result = shell_out("#{chef_client} -c \"#{path_to("config/client.rb")}\" --no-color -F doc -o 'x::default'", cwd: chef_dir)
+ # the second resource fires first after bar is set
+ expect(result.stdout).to include("second: bar")
+ # the first resource then fires in the delayed notifications phase
+ expect(result.stdout).to include("first: baz")
+ # no other actions should run
+ expect(result.stdout).not_to include("first: foo")
+ expect(result.stdout).not_to include("first: bar")
+ expect(result.stdout).not_to include("second: foo")
+ expect(result.stdout).not_to include("second: baz")
+ result.error!
+ end
+ end
+
+ when_the_repository "has a cookbook with a unified resource with a correct before notification" do
+ before do
+ directory "cookbooks/x" do
+
+ file "resources/unified_mode.rb", <<-EOM
+ unified_mode true
+ resource_name :unified_mode
+ provides :unified_mode
+ action :doit do
+ klass = new_resource.class
+ var = "foo"
+ ruby_block "notified block" do
+ block do
+ puts "\nnotified: \#\{var\}"
+ end
+ action :nothing
+ end
+ var = "bar"
+ whyrun_safe_ruby_block "notifying block" do
+ block do
+ puts "\nnotifying: \#\{var\}"
+ end
+ notifies :run, "ruby_block[notified block]", :before
+ end
+ var = "baz"
+ end
+ EOM
+
+ file "recipes/default.rb", <<-EOM
+ unified_mode "whatever"
+ EOM
+
+ end # directory 'cookbooks/x'
+ end
+
+ it "should complete with success" do
+ file "config/client.rb", <<~EOM
+ local_mode true
+ cookbook_path "#{path_to("cookbooks")}"
+ log_level :warn
+ EOM
+
+ result = shell_out("#{chef_client} -c \"#{path_to("config/client.rb")}\" --no-color -F doc -o 'x::default'", cwd: chef_dir)
+ expect(result.stdout.scan(/notifying: bar/).length).to eql(2)
+ expect(result.stdout).to include("Would execute the whyrun_safe_ruby_block notifying block")
+ expect(result.stdout).to include("notified: bar")
+ # no other actions should run
+ expect(result.stdout).not_to include("notified: foo")
+ expect(result.stdout).not_to include("notified: baz")
+ expect(result.stdout).not_to include("notifying: foo")
+ expect(result.stdout).not_to include("notifying: baz")
+ result.error!
+ end
+ end
+
+ when_the_repository "has a cookbook with a unified resource with a correct before subscribes" do
+ before do
+ directory "cookbooks/x" do
+
+ file "resources/unified_mode.rb", <<-EOM
+ unified_mode true
+ resource_name :unified_mode
+ provides :unified_mode
+ action :doit do
+ klass = new_resource.class
+ var = "foo"
+ ruby_block "notified block" do
+ block do
+ puts "\nnotified: \#\{var\}"
+ end
+ subscribes :run, "whyrun_safe_ruby_block[notifying block]", :before
+ action :nothing
+ end
+ var = "bar"
+ whyrun_safe_ruby_block "notifying block" do
+ block do
+ puts "\nnotifying: \#\{var\}"
+ end
+ end
+ var = "baz"
+ end
+ EOM
+
+ file "recipes/default.rb", <<-EOM
+ unified_mode "whatever"
+ EOM
+
+ end # directory 'cookbooks/x'
+ end
+
+ it "should complete with success" do
+ file "config/client.rb", <<~EOM
+ local_mode true
+ cookbook_path "#{path_to("cookbooks")}"
+ log_level :warn
+ EOM
+
+ result = shell_out("#{chef_client} -c \"#{path_to("config/client.rb")}\" --no-color -F doc -o 'x::default'", cwd: chef_dir)
+ expect(result.stdout.scan(/notifying: bar/).length).to eql(2)
+ expect(result.stdout).to include("Would execute the whyrun_safe_ruby_block notifying block")
+ expect(result.stdout).to include("notified: bar")
+ # no other actions should run
+ expect(result.stdout).not_to include("notified: foo")
+ expect(result.stdout).not_to include("notified: baz")
+ expect(result.stdout).not_to include("notifying: foo")
+ expect(result.stdout).not_to include("notifying: baz")
+ result.error!
+ end
+ end
+
+ when_the_repository "has a cookbook with a unified resource with a broken/reversed before notification" do
+ before do
+ directory "cookbooks/x" do
+
+ file "resources/unified_mode.rb", <<-EOM
+ unified_mode true
+ resource_name :unified_mode
+ provides :unified_mode
+ action :doit do
+ klass = new_resource.class
+ var = "foo"
+ whyrun_safe_ruby_block "notifying block" do
+ block do
+ puts "\nnotifying: \#\{var\}"
+ end
+ notifies :run, "ruby_block[notified block]", :before
+ end
+ var = "bar"
+ ruby_block "notified block" do
+ block do
+ puts "\nnotified: \#\{var\}"
+ end
+ action :nothing
+ end
+ var = "baz"
+ end
+ EOM
+
+ file "recipes/default.rb", <<-EOM
+ unified_mode "whatever"
+ EOM
+
+ end # directory 'cookbooks/x'
+ end
+
+ it "should fail the run" do
+ file "config/client.rb", <<~EOM
+ local_mode true
+ cookbook_path "#{path_to("cookbooks")}"
+ log_level :warn
+ EOM
+
+ result = shell_out("#{chef_client} -c \"#{path_to("config/client.rb")}\" --no-color -F doc -o 'x::default' -l debug", cwd: chef_dir)
+ # this doesn't work and we can't tell the difference between it and if we were trying to do a correct :before notification but typo'd the name
+ # so Chef::Exceptions::ResourceNotFound is the best we can do
+ expect(result.stdout).to include("Chef::Exceptions::ResourceNotFound")
+ expect(result.error?).to be true
+ end
+ end
+
+ when_the_repository "has a cookbook with a unified resource with a broken/reversed before subscribes" do
+ before do
+ directory "cookbooks/x" do
+
+ file "resources/unified_mode.rb", <<-EOM
+ unified_mode true
+ resource_name :unified_mode
+ provides :unified_mode
+ action :doit do
+ klass = new_resource.class
+ var = "foo"
+ whyrun_safe_ruby_block "notifying block" do
+ block do
+ puts "\nnotifying: \#\{var\}"
+ end
+ end
+ var = "bar"
+ ruby_block "notified block" do
+ block do
+ puts "\nnotified: \#\{var\}"
+ end
+ subscribes :run, "whyrun_safe_ruby_block[notifying block]", :before
+ action :nothing
+ end
+ var = "baz"
+ end
+ EOM
+
+ file "recipes/default.rb", <<-EOM
+ unified_mode "whatever"
+ EOM
+
+ end # directory 'cookbooks/x'
+ end
+
+ it "should fail the run" do
+ file "config/client.rb", <<~EOM
+ local_mode true
+ cookbook_path "#{path_to("cookbooks")}"
+ log_level :warn
+ EOM
+
+ result = shell_out("#{chef_client} -c \"#{path_to("config/client.rb")}\" --no-color -F doc -o 'x::default'", cwd: chef_dir)
+ # this fires first normally before the error
+ expect(result.stdout).to include("notifying: foo")
+ # everything else does not run
+ expect(result.stdout).not_to include("notified: foo")
+ expect(result.stdout).not_to include("notified: bar")
+ expect(result.stdout).not_to include("notified: baz")
+ expect(result.stdout).not_to include("notifying: bar")
+ expect(result.stdout).not_to include("notifying: baz")
+ expect(result.stdout).to include("Chef::Exceptions::UnifiedModeBeforeSubscriptionEarlierResource")
+ expect(result.error?).to be true
+ end
+ end
+
+ when_the_repository "has global resource unified mode on" do
+ before do
+ directory "cookbooks/x" do
+
+ file "recipes/default.rb", <<-EOM
+ var = "foo"
+ ruby_block "first block" do
+ block do
+ puts "\nfirst: \#\{var\}"
+ end
+ end
+ var = "bar"
+ EOM
+
+ end # directory 'cookbooks/x'
+ end
+
+ it "recipes should still have a compile/converge mode" do
+ file "config/client.rb", <<~EOM
+ resource_unified_mode_default true
+ local_mode true
+ cookbook_path "#{path_to("cookbooks")}"
+ log_level :warn
+ EOM
+
+ result = shell_out("#{chef_client} -c \"#{path_to("config/client.rb")}\" --no-color -F doc -o 'x::default'", cwd: chef_dir)
+ # in recipe mode we should still run normally with a compile/converge mode
+ expect(result.stdout).to include("first: bar")
+ expect(result.stdout).not_to include("first: foo")
+ result.error!
+ end
+ end
+end
diff --git a/spec/support/shared/integration/app_server_support.rb b/spec/support/shared/integration/app_server_support.rb
deleted file mode 100644
index 317a5a2679..0000000000
--- a/spec/support/shared/integration/app_server_support.rb
+++ /dev/null
@@ -1,39 +0,0 @@
-#
-# Author:: John Keiser (<jkeiser@chef.io>)
-# Author:: Ho-Sheng Hsiao (<hosh@chef.io>)
-# Copyright:: Copyright 2012-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 "rack"
-require "stringio"
-
-module AppServerSupport
- def start_app_server(app, port)
- server = nil
- thread = Thread.new do
- Rack::Handler::WEBrick.run(app,
- Port: 9018,
- AccessLog: [],
- Logger: WEBrick::Log.new(StringIO.new, 7)) do |found_server|
- server = found_server
- end
- end
- Timeout.timeout(30) do
- sleep(0.01) until server && server.status == :Running
- end
- thread
- end
-end
diff --git a/spec/support/shared/integration/integration_helper.rb b/spec/support/shared/integration/integration_helper.rb
index 6c0eca98be..f0dfd1dc43 100644
--- a/spec/support/shared/integration/integration_helper.rb
+++ b/spec/support/shared/integration/integration_helper.rb
@@ -1,7 +1,7 @@
#
# Author:: John Keiser (<jkeiser@chef.io>)
# Author:: Ho-Sheng Hsiao (<hosh@chef.io>)
-# Copyright:: Copyright 2012-2016, Chef Software Inc.
+# Copyright:: Copyright 2012-2019, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -23,7 +23,6 @@ require "chef/config"
require "chef/json_compat"
require "chef/server_api"
require "support/shared/integration/knife_support"
-require "support/shared/integration/app_server_support"
require "cheffish/rspec/chef_run_support"
require "spec_helper"
diff --git a/spec/unit/application/client_spec.rb b/spec/unit/application/client_spec.rb
index 0773fc70fd..d4ed403197 100644
--- a/spec/unit/application/client_spec.rb
+++ b/spec/unit/application/client_spec.rb
@@ -1,6 +1,6 @@
# Author:: AJ Christensen (<aj@junglist.gen.nz>)
-# Copyright:: Copyright 2008-2018, Chef Software Inc.
+# Copyright:: Copyright 2008-2019, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -85,7 +85,6 @@ describe Chef::Application::Client, "reconfigure" do
allow(app).to receive(:trap)
allow(app).to receive(:configure_logging).and_return(true)
- Chef::Config[:interval] = 10
Chef::Config[:once] = false
@@ -162,7 +161,7 @@ describe Chef::Application::Client, "reconfigure" do
it_behaves_like "sets the configuration", "--no-fork", client_fork: false
end
- context "with an interval" do
+ context "with an interval", :unix_only do
it_behaves_like "sets the configuration", "--interval 1800", client_fork: true
end
@@ -322,7 +321,7 @@ describe Chef::Application::Client, "reconfigure" do
Chef::Config[:splay] = nil
end
- it "should terminal with message when interval is given" do
+ it "should terminate with message when interval is given" do
Chef::Config[:interval] = 600
allow(ChefConfig).to receive(:windows?).and_return(false)
expect(Chef::Application).to receive(:fatal!).with(
@@ -340,8 +339,8 @@ Enable .* interval runs by setting `:client_fork = true` in your config file or
allow(ChefConfig).to receive(:windows?).and_return(true)
end
- it "should not terminate" do
- expect(Chef::Application).not_to receive(:fatal!)
+ it "should terminate" do
+ expect(Chef::Application).to receive(:fatal!)
app.reconfigure
end
end
diff --git a/spec/unit/application/solo_spec.rb b/spec/unit/application/solo_spec.rb
index 3f540d24e2..b70f959ab5 100644
--- a/spec/unit/application/solo_spec.rb
+++ b/spec/unit/application/solo_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: AJ Christensen (<aj@junglist.gen.nz>)
-# Copyright:: Copyright 2008-2018, Chef Software Inc.
+# Copyright:: Copyright 2008-2019, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -64,18 +64,13 @@ describe Chef::Application::Solo do
end
it "should terminate with message" do
- expect(Chef::Application).to receive(:fatal!).with(
- /Unforked .* interval runs are disabled by default\.
-Configuration settings:
- interval = 600 seconds
-Enable .* interval runs by setting `:client_fork = true` in your config file or adding `--fork` to your command line options\./
- )
+ expect(Chef::Application).to receive(:fatal!).with(/interval runs are (disabled|not supported)/)
app.reconfigure
end
end
end
- describe "when in daemonized mode and no interval has been set" do
+ describe "when in daemonized mode and no interval has been set", :unix_only do
before do
Chef::Config[:daemonize] = true
end
diff --git a/spec/unit/application_spec.rb b/spec/unit/application_spec.rb
index e94f9b74ae..7a787d1f3f 100644
--- a/spec/unit/application_spec.rb
+++ b/spec/unit/application_spec.rb
@@ -1,7 +1,7 @@
#
# Author:: AJ Christensen (<aj@junglist.gen.nz>)
# Author:: Mark Mzyk (mmzyk@chef.io)
-# Copyright:: Copyright 2008-2018, Chef Software Inc.
+# Copyright:: Copyright 2008-2019, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/spec/unit/provider/ifconfig_spec.rb b/spec/unit/provider/ifconfig_spec.rb
index 5b1256300e..38561d6e49 100644
--- a/spec/unit/provider/ifconfig_spec.rb
+++ b/spec/unit/provider/ifconfig_spec.rb
@@ -94,6 +94,17 @@ describe Chef::Provider::Ifconfig do
expect(@new_resource).not_to be_updated
end
+ it "should add a bridge interface" do
+ allow(@provider).to receive(:load_current_resource)
+ @new_resource.device "br-1234"
+ command = "ifconfig br-1234 10.0.0.1 netmask 255.255.254.0 metric 1 mtu 1500"
+ expect(@provider).to receive(:shell_out_compacted!).with(*command.split(" "))
+ expect(@provider).to receive(:generate_config)
+
+ @provider.run_action(:add)
+ expect(@new_resource).to be_updated
+ end
+
# We are not testing this case with the assumption that anyone writing the cookbook would not make a typo == lo
# it "should add a blank command if the #{@new_resource.device} == lo" do
# end