summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md10
-rw-r--r--Gemfile.lock58
-rw-r--r--RELEASE_NOTES.md44
-rw-r--r--VERSION2
-rw-r--r--chef-config/lib/chef-config/version.rb2
-rw-r--r--chef.gemspec2
-rw-r--r--lib/chef.rb12
-rw-r--r--lib/chef/application.rb3
-rw-r--r--lib/chef/application/solo.rb2
-rw-r--r--lib/chef/application/windows_service.rb2
-rw-r--r--lib/chef/cookbook/synchronizer.rb3
-rw-r--r--lib/chef/exceptions.rb3
-rw-r--r--lib/chef/file_access_control/windows.rb8
-rw-r--r--lib/chef/formatters/error_inspectors/api_error_formatting.rb3
-rw-r--r--lib/chef/formatters/error_inspectors/node_load_error_inspector.rb3
-rw-r--r--lib/chef/formatters/error_inspectors/registration_error_inspector.rb5
-rw-r--r--lib/chef/formatters/error_inspectors/resource_failure_inspector.rb3
-rw-r--r--lib/chef/knife/bootstrap.rb117
-rw-r--r--lib/chef/knife/bootstrap/templates/chef-full.erb2
-rw-r--r--lib/chef/knife/bootstrap/templates/windows-chef-client-msi.erb10
-rw-r--r--lib/chef/knife/bootstrap/train_connector.rb286
-rw-r--r--lib/chef/knife/core/bootstrap_context.rb3
-rw-r--r--lib/chef/knife/core/windows_bootstrap_context.rb3
-rw-r--r--lib/chef/log/syslog.rb3
-rw-r--r--lib/chef/policy_builder/policyfile.rb3
-rw-r--r--lib/chef/provider/file.rb3
-rw-r--r--lib/chef/provider/windows_task.rb9
-rw-r--r--lib/chef/resource/breakpoint.rb3
-rw-r--r--lib/chef/resource/chef_gem.rb5
-rw-r--r--lib/chef/resource/cookbook_file.rb3
-rw-r--r--lib/chef/resource/dnf_package.rb3
-rw-r--r--lib/chef/resource/execute.rb5
-rw-r--r--lib/chef/resource/file.rb5
-rw-r--r--lib/chef/resource/gem_package.rb3
-rw-r--r--lib/chef/resource/homebrew_package.rb3
-rw-r--r--lib/chef/resource/ohai.rb5
-rw-r--r--lib/chef/resource/ruby_block.rb3
-rw-r--r--lib/chef/resource/service.rb5
-rw-r--r--lib/chef/resource/snap_package.rb1
-rw-r--r--lib/chef/resource/subversion.rb3
-rw-r--r--lib/chef/resource/template.rb3
-rw-r--r--lib/chef/resource/windows_certificate.rb3
-rw-r--r--lib/chef/resource/windows_task.rb4
-rw-r--r--lib/chef/resource/yum_package.rb3
-rw-r--r--lib/chef/version.rb2
-rw-r--r--lib/chef/win32/api/security.rb2
-rw-r--r--spec/functional/resource/link_spec.rb4
-rw-r--r--spec/functional/resource/windows_task_spec.rb76
-rw-r--r--spec/support/shared/functional/directory_resource.rb22
-rw-r--r--spec/support/shared/functional/file_resource.rb4
-rw-r--r--spec/support/shared/functional/securable_resource.rb173
-rw-r--r--spec/support/shared/integration/integration_helper.rb1
-rw-r--r--spec/unit/knife/bootstrap/train_connector_spec.rb155
-rw-r--r--spec/unit/knife/bootstrap_spec.rb83
-rw-r--r--spec/unit/resource/windows_task_spec.rb4
55 files changed, 867 insertions, 323 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e53ac8661c..92b1270b55 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,15 +1,19 @@
<!-- usage documentation: http://expeditor-docs.es.chef.io/configuration/changelog/ -->
-<!-- latest_release 15.0.233 -->
-## [v15.0.233](https://github.com/chef/chef/tree/v15.0.233) (2019-04-24)
+<!-- latest_release 15.0.237 -->
+## [v15.0.237](https://github.com/chef/chef/tree/v15.0.237) (2019-04-29)
#### Merged Pull Requests
-- Refactor bootstrapping to use train as the transport with full Windows bootstrap support [#8253](https://github.com/chef/chef/pull/8253) ([marcparadise](https://github.com/marcparadise))
+- &quot;chef-client&quot; =&gt; #{Chef::Dist::CLIENT} [#8418](https://github.com/chef/chef/pull/8418) ([bobchaos](https://github.com/bobchaos))
<!-- latest_release -->
<!-- release_rollup -->
### Changes since latest stable release
#### Merged Pull Requests
+- &quot;chef-client&quot; =&gt; #{Chef::Dist::CLIENT} [#8418](https://github.com/chef/chef/pull/8418) ([bobchaos](https://github.com/bobchaos)) <!-- 15.0.237 -->
+- Add the introduced field to snap_package [#8412](https://github.com/chef/chef/pull/8412) ([tas50](https://github.com/tas50)) <!-- 15.0.236 -->
+- windows_task: Add start_when_available support [#8420](https://github.com/chef/chef/pull/8420) ([vsingh-msys](https://github.com/vsingh-msys)) <!-- 15.0.235 -->
+- Fix for write permissions were not working properly on windows [#8168](https://github.com/chef/chef/pull/8168) ([vijaymmali1990](https://github.com/vijaymmali1990)) <!-- 15.0.234 -->
- Refactor bootstrapping to use train as the transport with full Windows bootstrap support [#8253](https://github.com/chef/chef/pull/8253) ([marcparadise](https://github.com/marcparadise)) <!-- 15.0.233 -->
- Move ed25519 gems into omnibus [#8410](https://github.com/chef/chef/pull/8410) ([tas50](https://github.com/tas50)) <!-- 15.0.232 -->
- Implement new owner/review structure + expand dev docs [#8350](https://github.com/chef/chef/pull/8350) ([tas50](https://github.com/tas50)) <!-- 15.0.231 -->
diff --git a/Gemfile.lock b/Gemfile.lock
index a4f7a2845a..43b7e06845 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -8,7 +8,7 @@ GIT
GIT
remote: https://github.com/chef/ohai.git
- revision: 5c70e89388ebc8ddf7d2d7bfd489024b11c0aece
+ revision: a1ec73298d623d18cbe05c2b53ac57c8cc9beae0
branch: master
specs:
ohai (15.0.34)
@@ -27,12 +27,11 @@ GIT
PATH
remote: .
specs:
- chef (15.0.233)
+ chef (15.0.237)
addressable
bcrypt_pbkdf (~> 1.0)
bundler (>= 1.10)
- chef-config (= 15.0.233)
- chef-core (~> 0.0.3)
+ chef-config (= 15.0.237)
chef-zero (>= 14.0.11)
diff-lcs (~> 1.2, >= 1.2.4)
ed25519 (~> 1.2)
@@ -54,14 +53,14 @@ PATH
plist (~> 3.2)
proxifier (~> 1.0)
syslog-logger (~> 1.6)
+ train-core (~> 2.0, >= 2.0.12)
tty-screen (~> 0.6)
uuidtools (~> 2.1.5)
- chef (15.0.233-universal-mingw32)
+ chef (15.0.237-universal-mingw32)
addressable
bcrypt_pbkdf (~> 1.0)
bundler (>= 1.10)
- chef-config (= 15.0.233)
- chef-core (~> 0.0.3)
+ chef-config (= 15.0.237)
chef-zero (>= 14.0.11)
diff-lcs (~> 1.2, >= 1.2.4)
ed25519 (~> 1.2)
@@ -84,6 +83,7 @@ PATH
plist (~> 3.2)
proxifier (~> 1.0)
syslog-logger (~> 1.6)
+ train-core (~> 2.0, >= 2.0.12)
tty-screen (~> 0.6)
uuidtools (~> 2.1.5)
win32-api (~> 1.5.3)
@@ -101,7 +101,7 @@ PATH
PATH
remote: chef-config
specs:
- chef-config (15.0.233)
+ chef-config (15.0.237)
addressable
fuzzyurl
mixlib-config (>= 2.2.12, < 4.0)
@@ -113,7 +113,7 @@ GEM
specs:
addressable (2.5.2)
public_suffix (>= 2.0.2, < 4.0)
- appbundler (0.12.4)
+ appbundler (0.12.5)
mixlib-cli (>= 1.4, < 3.0)
mixlib-shellout (>= 2.0, < 4.0)
ast (2.4.0)
@@ -124,20 +124,6 @@ GEM
debug_inspector (>= 0.0.1)
builder (3.2.3)
byebug (11.0.1)
- chef-core (0.0.3)
- chef-telemetry
- mixlib-log
- pastel
- r18n-desktop
- train-core (~> 2.0, >= 2.0.12)
- tty-color
- tty-cursor
- tty-spinner
- chef-telemetry (0.1.8)
- chef-config
- concurrent-ruby (~> 1.0)
- ffi-yajl (~> 2.2)
- http (~> 2.2)
chef-vault (3.4.3)
chef-zero (14.0.12)
ffi-yajl (~> 2.2)
@@ -149,14 +135,11 @@ GEM
chef-zero (~> 14.0)
net-ssh
coderay (1.1.2)
- concurrent-ruby (1.1.5)
crack (0.4.3)
safe_yaml (~> 1.0.0)
debug_inspector (0.0.3)
diff-lcs (1.3)
docile (1.3.1)
- domain_name (0.5.20180417)
- unf (>= 0.0.5, < 1.0.0)
ed25519 (1.2.4)
equatable (0.5.0)
erubis (2.7.0)
@@ -182,15 +165,6 @@ GEM
hashie (3.6.0)
highline (1.7.10)
htmlentities (4.3.4)
- http (2.2.2)
- addressable (~> 2.3)
- http-cookie (~> 1.0)
- http-form_data (~> 1.0.1)
- http_parser.rb (~> 0.6.0)
- http-cookie (1.0.3)
- domain_name (~> 0.5)
- http-form_data (1.0.3)
- http_parser.rb (0.6.0)
httpclient (2.8.3)
iniparse (1.4.4)
inspec-core (4.1.4.preview)
@@ -223,7 +197,7 @@ GEM
jaro_winkler (1.5.2)
json (2.2.0)
libyajl2 (1.2.0)
- license-acceptance (0.2.13)
+ license-acceptance (0.2.16)
pastel (~> 0.7)
tomlrb (~> 1.2)
tty-box (~> 0.3)
@@ -264,7 +238,7 @@ GEM
octokit (4.14.0)
sawyer (~> 0.8.0, >= 0.5.3)
parallel (1.17.0)
- parser (2.6.2.1)
+ parser (2.6.3.0)
ast (~> 2.4.0)
parslet (1.8.2)
pastel (0.7.2)
@@ -286,9 +260,6 @@ GEM
binding_of_caller (>= 0.7)
pry (>= 0.9.11)
public_suffix (3.0.3)
- r18n-core (3.2.0)
- r18n-desktop (3.2.0)
- r18n-core (= 3.2.0)
rack (2.0.7)
rainbow (3.0.0)
rake (12.3.2)
@@ -375,17 +346,12 @@ GEM
tty-screen (~> 0.6.4)
wisper (~> 2.0.0)
tty-screen (0.6.5)
- tty-spinner (0.9.0)
- tty-cursor (~> 0.6.0)
tty-table (0.10.0)
equatable (~> 0.5.0)
necromancer (~> 0.4.0)
pastel (~> 0.7.2)
strings (~> 0.1.0)
tty-screen (~> 0.6.4)
- unf (0.1.4)
- unf_ext
- unf_ext (0.0.7.6)
unicode-display_width (1.4.1)
unicode_utils (1.4.0)
uuidtools (2.1.5)
@@ -417,7 +383,7 @@ GEM
win32-taskscheduler (2.0.4)
ffi
structured_warnings
- winrm (2.3.1)
+ winrm (2.3.2)
builder (>= 2.1.2)
erubis (~> 2.7)
gssapi (~> 1.2)
diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
index ef2e843bd5..b0913a2a2f 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -12,9 +12,7 @@ Chef 15 release notes will be added here as development progresses.
### copy_properties_from in Custom Resources
-### locale resource
-
-The locale resource now allows setting all possible LC_* environmental variables.
+### ed25519 SSH key support
## New Resources
@@ -28,9 +26,45 @@ The locale resource now allows setting all possible LC_* environmental variables
### snap_package resource
-### Ruby 2.6.2
+## Resource Improvements
+
+### windows_task
+
+windows_task now supports the Start When Available option with a new ``start_when_available`` property.
+
+### locale
+
+The locale resource now allows setting all possible LC_* environmental variables.
+
+### directory
+
+The directory resource now property supports passing ``deny_rights :write`` on Windows nodes.
+
+### windows_service
+
+The windows_service resource has been improved to prevent accidently reverting a service back to default settings in a subsequent definition.
+
+This example will no longer result in the MyApp service reverting to default RunAsUser:
+```ruby
+windows_service 'MyApp' do
+ run_as_user 'MyAppsUser'
+ run_as_password 'MyAppsUserPassword'
+ startup_type :automatic
+ delayed_start true
+ action [:configure, :start]
+end
+
+...
+
+windows_service 'MyApp' do
+ startup_type :automatic
+ action [:configure, :start]
+end
+```
+
+### Ruby 2.6.3
-Chef now ships with Ruby 2.6.2. This new version of Ruby improves performance and includes many new features to make more advanced Chef usage easier. See https://www.rubyguides.com/2018/11/ruby-2-6-new-features/ for a list of some of the new functionality.
+Chef now ships with Ruby 2.6.3. This new version of Ruby improves performance and includes many new features to make more advanced Chef usage easier. See https://www.rubyguides.com/2018/11/ruby-2-6-new-features/ for a list of some of the new functionality.
## New Deprecations
diff --git a/VERSION b/VERSION
index b26b43468c..7d209f5916 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-15.0.233 \ No newline at end of file
+15.0.237 \ 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 824de26477..1673164441 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.0.233".freeze
+ VERSION = "15.0.237".freeze
end
#
diff --git a/chef.gemspec b/chef.gemspec
index 32e12bad41..a9d9ded1cd 100644
--- a/chef.gemspec
+++ b/chef.gemspec
@@ -16,7 +16,7 @@ Gem::Specification.new do |s|
s.required_ruby_version = ">= 2.5.0"
s.add_dependency "chef-config", "= #{Chef::VERSION}"
- s.add_dependency "chef-core", "~> 0.0.3"
+ s.add_dependency "train-core", "~> 2.0", ">= 2.0.12"
s.add_dependency "mixlib-cli", ">= 1.7", "< 3.0"
s.add_dependency "mixlib-log", ">= 2.0.3", "< 4.0"
diff --git a/lib/chef.rb b/lib/chef.rb
index c58f46debd..8869a5a890 100644
--- a/lib/chef.rb
+++ b/lib/chef.rb
@@ -18,18 +18,6 @@
require "chef/version"
-# Ensure that this loads ahead of anything that
-# might cause rubygems to hit Gem.load_yaml, including
-# evaluating gemspecs. When load_yaml is invoked,
-# it stubs out the YAML::Syck namespace. This causes
-# r18n to break, which expects either YAML::Syck to be there
-# and fully defined (particularly, the Syck::PrivateType class),
-# or for it to not be there at all.
-#
-# When it's not - because it's a stub - r18n explodes on loading.
-# Ensuring chef_core/text and r18n are loaded first prevents this.
-require "chef_core/text"
-
require "chef/nil_argument"
require "chef/mash"
require "chef/exceptions"
diff --git a/lib/chef/application.rb b/lib/chef/application.rb
index 0eaf9721d9..549d8b4482 100644
--- a/lib/chef/application.rb
+++ b/lib/chef/application.rb
@@ -28,6 +28,7 @@ require "mixlib/cli"
require "tmpdir"
require "rbconfig"
require "chef/application/exit_code"
+require "chef/dist"
class Chef
class Application
@@ -313,7 +314,7 @@ class Chef
" finishing converge to exit normally (send SIGINT to terminate immediately)")
end
- client_solo = chef_config[:solo] ? "chef-solo" : "chef-client"
+ client_solo = chef_config[:solo] ? "chef-solo" : "#{Chef::Dist::CLIENT}"
$0 = "#{client_solo} worker: ppid=#{Process.ppid};start=#{Time.new.strftime("%R:%S")};"
begin
logger.trace "Forked instance now converging"
diff --git a/lib/chef/application/solo.rb b/lib/chef/application/solo.rb
index 457cb1578c..5655b8cdfd 100644
--- a/lib/chef/application/solo.rb
+++ b/lib/chef/application/solo.rb
@@ -324,7 +324,7 @@ class Chef::Application::Solo < Chef::Application
def interval_run_chef_client
if Chef::Config[:daemonize]
- Chef::Daemon.daemonize("chef-client")
+ Chef::Daemon.daemonize("#{Chef::Dist::CLIENT}")
end
loop do
diff --git a/lib/chef/application/windows_service.rb b/lib/chef/application/windows_service.rb
index 6fbb1a36a2..3eb4f63129 100644
--- a/lib/chef/application/windows_service.rb
+++ b/lib/chef/application/windows_service.rb
@@ -57,7 +57,7 @@ class Chef
option :interval,
short: "-i SECONDS",
long: "--interval SECONDS",
- description: "Set the number of seconds to wait between chef-client runs",
+ description: "Set the number of seconds to wait between #{Chef::Dist::CLIENT} runs",
proc: lambda { |s| s.to_i }
DEFAULT_LOG_LOCATION ||= "#{ENV['SYSTEMDRIVE']}/chef/client.log".freeze
diff --git a/lib/chef/cookbook/synchronizer.rb b/lib/chef/cookbook/synchronizer.rb
index a1d02bac65..5f098a0538 100644
--- a/lib/chef/cookbook/synchronizer.rb
+++ b/lib/chef/cookbook/synchronizer.rb
@@ -17,6 +17,7 @@ require "chef/client"
require "chef/util/threaded_job_queue"
require "chef/server_api"
require "singleton"
+require "chef/dist"
class Chef
@@ -63,7 +64,7 @@ class Chef
# manifest.
cache.find(File.join(%w{cookbooks ** {*,.*}})).each do |cache_filename|
unless @valid_cache_entries[cache_filename]
- Chef::Log.info("Removing #{cache_filename} from the cache; it is no longer needed by chef-client.")
+ Chef::Log.info("Removing #{cache_filename} from the cache; it is no longer needed by #{Chef::Dist::CLIENT}.")
cache.delete(cache_filename)
end
end
diff --git a/lib/chef/exceptions.rb b/lib/chef/exceptions.rb
index 0a6c7dc635..4ab9434906 100644
--- a/lib/chef/exceptions.rb
+++ b/lib/chef/exceptions.rb
@@ -18,6 +18,7 @@
# limitations under the License.
require "chef-config/exceptions"
+require "chef/dist"
class Chef
# == Chef::Exceptions
@@ -401,7 +402,7 @@ class Chef
def initialize(response_length, content_length)
super <<~EOF
Response body length #{response_length} does not match HTTP Content-Length header #{content_length}.
- This error is most often caused by network issues (proxies, etc) outside of chef-client.
+ This error is most often caused by network issues (proxies, etc) outside of #{Chef::Dist::CLIENT}.
EOF
end
end
diff --git a/lib/chef/file_access_control/windows.rb b/lib/chef/file_access_control/windows.rb
index 2c6b69c257..a7cefdc6d7 100644
--- a/lib/chef/file_access_control/windows.rb
+++ b/lib/chef/file_access_control/windows.rb
@@ -90,11 +90,13 @@ class Chef
target_acl.each do |target_ace|
if target_ace.flags & INHERIT_ONLY_ACE == 0
self_ace = target_ace.dup
- self_ace.flags = 0
+ # We need flag value which is already being set in case of WRITE permissions as 3, so we will not be overwriting it with the hard coded value.
+ self_ace.flags = 0 unless target_ace.mask == Chef::ReservedNames::Win32::API::Security::WRITE
self_ace.mask = securable_object.predict_rights_mask(target_ace.mask)
new_target_acl << self_ace
end
- if target_ace.flags & (CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE) != 0
+ # As there is no inheritence needed in case of WRITE permissions.
+ if target_ace.mask != Chef::ReservedNames::Win32::API::Security::WRITE && target_ace.flags & (CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE) != 0
children_ace = target_ace.dup
children_ace.flags |= INHERIT_ONLY_ACE
new_target_acl << children_ace
@@ -220,7 +222,7 @@ class Chef
when :read_execute
mask |= GENERIC_READ | GENERIC_EXECUTE
when :write
- mask |= GENERIC_WRITE
+ mask |= WRITE
else
# Otherwise, assume it's an integer specifying the actual flags
mask |= permission
diff --git a/lib/chef/formatters/error_inspectors/api_error_formatting.rb b/lib/chef/formatters/error_inspectors/api_error_formatting.rb
index 4ecdec7105..e74c353ba9 100644
--- a/lib/chef/formatters/error_inspectors/api_error_formatting.rb
+++ b/lib/chef/formatters/error_inspectors/api_error_formatting.rb
@@ -17,6 +17,7 @@
#
require "chef/http/authenticator"
+require "chef/dist"
class Chef
module Formatters
@@ -39,7 +40,7 @@ class Chef
def describe_eof_error(error_description)
error_description.section("Authentication Error:", <<~E)
Received an EOF on transport socket. This almost always indicates a network
- error external to chef-client. Some causes include:
+ error external to #{Chef::Dist::CLIENT}. Some causes include:
- Blocking ICMP Dest Unreachable (breaking Path MTU Discovery)
- IPsec or VPN tunnelling / TCP Encapsulation MTU issues
diff --git a/lib/chef/formatters/error_inspectors/node_load_error_inspector.rb b/lib/chef/formatters/error_inspectors/node_load_error_inspector.rb
index 9617f729c1..8a94529237 100644
--- a/lib/chef/formatters/error_inspectors/node_load_error_inspector.rb
+++ b/lib/chef/formatters/error_inspectors/node_load_error_inspector.rb
@@ -17,6 +17,7 @@
#
require "chef/formatters/error_inspectors/api_error_formatting"
+require "chef/dist"
class Chef
module Formatters
@@ -45,7 +46,7 @@ class Chef
when Chef::Exceptions::PrivateKeyMissing
error_description.section("Private Key Not Found:", <<~E)
Your private key could not be loaded. If the key file exists, ensure that it is
- readable by chef-client.
+ readable by #{Chef::Dist::CLIENT}.
E
error_description.section("Relevant Config Settings:", <<~E)
client_key "#{api_key}"
diff --git a/lib/chef/formatters/error_inspectors/registration_error_inspector.rb b/lib/chef/formatters/error_inspectors/registration_error_inspector.rb
index 002870abeb..5ba5eba39d 100644
--- a/lib/chef/formatters/error_inspectors/registration_error_inspector.rb
+++ b/lib/chef/formatters/error_inspectors/registration_error_inspector.rb
@@ -1,7 +1,8 @@
+require "chef/dist"
+
class Chef
module Formatters
module ErrorInspectors
-
# == RegistrationErrorInspector
# Wraps exceptions that occur during the client registration process and
# suggests possible causes.
@@ -38,7 +39,7 @@ class Chef
when Chef::Exceptions::PrivateKeyMissing
error_description.section("Private Key Not Found:", <<~E)
Your private key could not be loaded. If the key file exists, ensure that it is
- readable by chef-client.
+ readable by #{Chef::Dist::CLIENT}.
E
error_description.section("Relevant Config Settings:", <<~E)
validation_key "#{api_key}"
diff --git a/lib/chef/formatters/error_inspectors/resource_failure_inspector.rb b/lib/chef/formatters/error_inspectors/resource_failure_inspector.rb
index 1cc147db7a..367bba321e 100644
--- a/lib/chef/formatters/error_inspectors/resource_failure_inspector.rb
+++ b/lib/chef/formatters/error_inspectors/resource_failure_inspector.rb
@@ -16,6 +16,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+require "chef/dist"
class Chef
module Formatters
@@ -55,7 +56,7 @@ class Chef
require "chef/win32/security"
if !Chef::ReservedNames::Win32::Security.has_admin_privileges?
- error_description.section("Missing Windows Admin Privileges", "chef-client doesn't have administrator privileges. This can be a possible reason for the resource failure.")
+ error_description.section("Missing Windows Admin Privileges", "#{Chef::Dist::CLIENT} doesn't have administrator privileges. This can be a possible reason for the resource failure.")
end
end
end
diff --git a/lib/chef/knife/bootstrap.rb b/lib/chef/knife/bootstrap.rb
index b68fb1aa1e..d46bf455e9 100644
--- a/lib/chef/knife/bootstrap.rb
+++ b/lib/chef/knife/bootstrap.rb
@@ -18,10 +18,6 @@
require "chef/knife"
require "chef/knife/data_bag_secret_options"
-require "erubis"
-require "chef/knife/bootstrap/chef_vault_handler"
-require "chef/knife/bootstrap/client_builder"
-require "chef/util/path_helper"
class Chef
class Knife
@@ -251,14 +247,14 @@ class Chef
option :first_boot_attributes,
short: "-j JSON_ATTRIBS",
long: "--json-attributes",
- description: "A JSON string to be added to the first run of chef-client",
+ description: "A JSON string to be added to the first run of #{Chef::Dist::CLIENT}",
proc: lambda { |o| Chef::JSONCompat.parse(o) },
default: nil
# bootstrap template
option :first_boot_attributes_from_file,
long: "--json-attribute-file FILE",
- description: "A JSON file to be used to the first run of chef-client",
+ description: "A JSON file to be used to the first run of #{Chef::Dist::CLIENT}",
proc: lambda { |o| Chef::JSONCompat.parse(File.read(o)) },
default: nil
@@ -296,25 +292,25 @@ class Chef
# bootstrap override: Do this instead of our own setup.sh from omnitruck. Causes bootstrap_url to be ignored.
option :bootstrap_install_command,
long: "--bootstrap-install-command COMMANDS",
- description: "Custom command to install chef-client",
+ description: "Custom command to install #{Chef::Dist::CLIENT}",
proc: Proc.new { |ic| Chef::Config[:knife][:bootstrap_install_command] = ic }
# bootstrap template: Run this command first in the bootstrap script
option :bootstrap_preinstall_command,
long: "--bootstrap-preinstall-command COMMANDS",
- description: "Custom commands to run before installing chef-client",
+ description: "Custom commands to run before installing #{Chef::Dist::CLIENT}",
proc: Proc.new { |preic| Chef::Config[:knife][:bootstrap_preinstall_command] = preic }
# bootstrap template
option :bootstrap_wget_options,
long: "--bootstrap-wget-options OPTIONS",
- description: "Add options to wget when installing chef-client",
+ description: "Add options to wget when installing #{Chef::Dist::CLIENT}",
proc: Proc.new { |wo| Chef::Config[:knife][:bootstrap_wget_options] = wo }
# bootstrap template
option :bootstrap_curl_options,
long: "--bootstrap-curl-options OPTIONS",
- description: "Add options to curl when install chef-client",
+ description: "Add options to curl when install #{Chef::Dist::CLIENT}",
proc: Proc.new { |co| Chef::Config[:knife][:bootstrap_curl_options] = co }
# chef_vault_handler
@@ -386,14 +382,16 @@ class Chef
attr_accessor :client_builder
attr_accessor :chef_vault_handler
- attr_reader :target_host
+ attr_reader :connection
deps do
+ require "erubis"
+
require "chef/json_compat"
- require "tempfile"
- require "chef_core/text" # i18n and standardized error structures
- require "chef_core/target_host"
- require "chef_core/target_resolver"
+ require "chef/util/path_helper"
+ require "chef/knife/bootstrap/chef_vault_handler"
+ require "chef/knife/bootstrap/client_builder"
+ require "chef/knife/bootstrap/train_connector"
end
banner "knife bootstrap [PROTOCOL://][USER@]FQDN (options)"
@@ -416,8 +414,8 @@ class Chef
#
# @return [String] Default bootstrap template
def default_bootstrap_template
- if target_host.base_os == :windows
- "windows-chef-client-msi"
+ if connection.windows?
+ "windows-#{Chef::Dist::CLIENT}-msi"
else
"chef-full"
end
@@ -481,11 +479,11 @@ class Chef
end
# Establish bootstrap context for template rendering.
- # Requires target_host to be a live connection in order to determine
+ # Requires connection to be a live connection in order to determine
# the correct platform.
def bootstrap_context
@bootstrap_context ||=
- if target_host.base_os == :windows
+ if connection.windows?
require "chef/knife/core/windows_bootstrap_context"
Knife::Core::WindowsBootstrapContext.new(config, config[:run_list], Chef::Config, secret)
else
@@ -555,17 +553,12 @@ class Chef
bootstrap_path = upload_bootstrap(content)
perform_bootstrap(bootstrap_path)
ensure
- target_host.del_file(bootstrap_path) if target_host && bootstrap_path
+ connection.del_file!(bootstrap_path) if connection && bootstrap_path
end
def register_client
# chef-vault integration must use the new client-side hawtness, otherwise to use the
# new client-side hawtness, just delete your validation key.
- # 2019-04-01 TODO
- # TODO - should this raise if config says to use vault because json/file/item exists
- # but we still have a validation key? That means we can't use the new client hawtness,
- # but we also don't tell the operator that their requested vault operations
- # won't be performed
if chef_vault_handler.doing_chef_vault? ||
(Chef::Config[:validation_key] &&
!File.exist?(File.expand_path(Chef::Config[:validation_key])))
@@ -588,8 +581,8 @@ class Chef
def perform_bootstrap(remote_bootstrap_script_path)
ui.info("Bootstrapping #{ui.color(server_name, :bold)}")
cmd = bootstrap_command(remote_bootstrap_script_path)
- r = target_host.run_command(cmd) do |data|
- ui.msg("#{ui.color(" [#{target_host.hostname}]", :cyan)} #{data}")
+ r = connection.run_command(cmd) do |data|
+ ui.msg("#{ui.color(" [#{connection.hostname}]", :cyan)} #{data}")
end
if r.exit_status != 0
ui.error("The following error occurred on #{server_name}:")
@@ -602,24 +595,13 @@ class Chef
ui.info("Connecting to #{ui.color(server_name, :bold)}")
opts = connection_opts.dup
do_connect(opts)
- rescue => e
- # Ugh. TODO: Train raises a Train::Transports::SSHFailed for a number of different errors. chef_core makes that
- # a more general ConnectionFailed, with an error code based on the specific error text/reason provided from trainm.
- # This means we have to look three layers into the exception to find out what actually happened instead of just
- # looking at the exception type
- #
- # It doesn't help to provide our own error if it does't let the caller know what they need to identify the problem.
- # Let's update chef_core to be a bit smarter about resolving the errors to an appropriate exception type
- # (eg ChefCore::ConnectionFailed::AuthError or similar) that will work across protocols, instead of just a single
- # ConnectionFailure type
- #
-
- if e.cause && e.cause.cause && e.cause.cause.class == Net::SSH::AuthenticationFailed
- if opts[:password]
+ rescue Train::Error => e
+ if e.cause && e.cause.class == Net::SSH::AuthenticationFailed
+ if connection.password_auth?
raise
else
ui.warn("Failed to authenticate #{opts[:user]} to #{server_name} - trying password auth")
- password = ui.ask("Enter password for #{opts[:user]}@#{server_name} - trying password auth") do |q|
+ password = ui.ask("Enter password for #{opts[:user]}@#{server_name}.") do |q|
q.echo = false
end
end
@@ -630,6 +612,9 @@ class Chef
end
end
+ # TODO - maybe remove the footgun detection this was built on.
+ # url values override CLI flags, if you provide both
+ # we'll use the one that you gave in the URL.
def connection_protocol
return @connection_protocol if @connection_protocol
from_url = host_descriptor =~ /^(.*):\/\// ? $1 : nil
@@ -639,14 +624,8 @@ class Chef
end
def do_connect(conn_options)
- # Resolve the given host name to a TargetHost instance. We will limit
- # the number of hosts to 1 (effectivly eliminating wildcard support) since
- # we only support running bootstrap against one host at a time.
- resolver = ChefCore::TargetResolver.new(host_descriptor, connection_protocol,
- conn_options, max_expanded_targets: 1)
- @target_host = resolver.targets.first
- target_host.connect!
- target_host
+ @connection = TrainConnector.new(host_descriptor, connection_protocol, conn_options)
+ connection.connect!
end
# Fail if both first_boot_attributes and first_boot_attributes_from_file
@@ -663,7 +642,7 @@ class Chef
# TODO test for this method
# TODO check that the protoocol is valid.
def validate_winrm_transport_opts!
- return true if connection_protocol != "winrm"
+ return true unless winrm?
if Chef::Config[:validation_key] && !File.exist?(File.expand_path(Chef::Config[:validation_key]))
if config_value(:winrm_auth_method) == "plaintext" &&
@@ -738,7 +717,7 @@ class Chef
end
def winrm_warn_no_ssl_verification
- return if connection_protocol != "winrm"
+ return unless winrm?
# REVIEWER NOTE
# The original check from knife plugin did not include winrm_ssl_peer_fingerprint
@@ -767,13 +746,8 @@ class Chef
end
end
- #
-
- # Create a configuration hash for TargetHost to connect
- # to the remote host via Train.
- #
# @return a configuration hash suitable for connecting to the remote
- # host via TargetHost.
+ # host via train
def connection_opts
return @connection_opts unless @connection_opts.nil?
@connection_opts = {}
@@ -787,9 +761,16 @@ class Chef
@connection_opts
end
+ def winrm?
+ connection_protocol == "winrm"
+ end
+
+ def ssh?
+ connection_protocol == "ssh"
+ end
+
# Common configuration for all protocols
def base_opts
- #
port = config_value(:connection_port,
knife_key_for_protocol(connection_protocol, :port))
user = config_value(:connection_user,
@@ -806,10 +787,9 @@ class Chef
end
def host_verify_opts
- case connection_protocol
- when "winrm"
+ if winrm?
{ self_signed: config_value(:winrm_no_verify_cert) === true }
- when "ssh"
+ elsif ssh?
# Fall back to the old knife config key name for back compat.
{ verify_host_key: config_value(:ssh_verify_host_key,
:host_key_verify, true) === true }
@@ -958,16 +938,16 @@ class Chef
end
def upload_bootstrap(content)
- script_name = target_host.base_os == :windows ? "bootstrap.bat" : "bootstrap.sh"
- remote_path = target_host.normalize_path(File.join(target_host.temp_dir, script_name))
- target_host.save_as_remote_file(content, remote_path)
+ script_name = connection.windows? ? "bootstrap.bat" : "bootstrap.sh"
+ remote_path = connection.normalize_path(File.join(connection.temp_dir, script_name))
+ connection.upload_file_content!(content, remote_path)
remote_path
end
# build the command string for bootrapping
# @return String
def bootstrap_command(remote_path)
- if target_host.base_os == :windows
+ if connection.windows?
"cmd.exe /C #{remote_path}"
else
"sh #{remote_path}"
@@ -976,8 +956,9 @@ class Chef
# To avoid cluttering the CLI options, some flags (such as port and user)
# are shared between protocols. However, there is still a need to allow the operator
- # to specify defaults separately, since they may not be the same values for different protocols.
- #
+ # to specify defaults separately, since they may not be the same values for different
+ # protocols.
+
# These keys are available in Chef::Config, and are prefixed with the protocol name.
# For example, :user CLI option will map to :winrm_user and :ssh_user Chef::Config keys,
# based on the connection protocol in use.
diff --git a/lib/chef/knife/bootstrap/templates/chef-full.erb b/lib/chef/knife/bootstrap/templates/chef-full.erb
index ec1f7e72c9..58a64a23b8 100644
--- a/lib/chef/knife/bootstrap/templates/chef-full.erb
+++ b/lib/chef/knife/bootstrap/templates/chef-full.erb
@@ -172,7 +172,7 @@ do_download() {
<%= knife_config[:bootstrap_install_command] %>
<% else %>
install_sh="<%= knife_config[:bootstrap_url] ? knife_config[:bootstrap_url] : "https://omnitruck.chef.io/chef/install.sh" %>"
- if test -f /usr/bin/chef-client; then
+ if test -f /usr/bin/<%= Chef::Dist::CLIENT %>}; then
echo "-----> Existing <%= Chef::Dist::PRODUCT %> installation detected"
else
echo "-----> Installing Chef Omnibus (<%= latest_current_chef_version_string %>)"
diff --git a/lib/chef/knife/bootstrap/templates/windows-chef-client-msi.erb b/lib/chef/knife/bootstrap/templates/windows-chef-client-msi.erb
index 37fcf15682..fd7b48f28d 100644
--- a/lib/chef/knife/bootstrap/templates/windows-chef-client-msi.erb
+++ b/lib/chef/knife/bootstrap/templates/windows-chef-client-msi.erb
@@ -110,7 +110,7 @@ goto chef_installed
:chef_installed
@echo Checking for existing chef installation
-WHERE chef-client >nul 2>nul
+WHERE <%= Chef::Dist::CLIENT %> >nul 2>nul
If !ERRORLEVEL!==0 (
@echo Existing Chef installation detected, skipping download
goto key_create
@@ -120,14 +120,14 @@ If !ERRORLEVEL!==0 (
)
:install
-@rem If user has provided the custom installation command for chef-client then execute it
+@rem If user has provided the custom installation command for <%= Chef::Dist::CLIENT %> then execute it
<% if @chef_config[:knife][:bootstrap_install_command] %>
<%= @chef_config[:knife][:bootstrap_install_command] %>
<% else %>
- @rem Install Chef using chef-client MSI installer
+ @rem Install Chef using <%= Chef::Dist::CLIENT %> MSI installer
@set "LOCAL_DESTINATION_MSI_PATH=<%= local_download_path %>"
- @set "CHEF_CLIENT_MSI_LOG_PATH=%TEMP%\chef-client-msi%RANDOM%.log"
+ @set "CHEF_CLIENT_MSI_LOG_PATH=%TEMP%\<%= Chef::Dist::CLIENT %>-msi%RANDOM%.log"
@rem Clear any pre-existing downloads
@echo Checking for existing downloaded package at "%LOCAL_DESTINATION_MSI_PATH%"
@@ -197,7 +197,7 @@ If !ERRORLEVEL!==0 (
<%= install_chef %>
@if ERRORLEVEL 1 (
- echo Chef-client package failed to install with status code !ERRORLEVEL!. > "&2"
+ echo <%= Chef::Dist::CLIENT %> package failed to install with status code !ERRORLEVEL!. > "&2"
echo See installation log for additional detail: %CHEF_CLIENT_MSI_LOG_PATH%. > "&2"
) else (
@echo Installation completed successfully
diff --git a/lib/chef/knife/bootstrap/train_connector.rb b/lib/chef/knife/bootstrap/train_connector.rb
new file mode 100644
index 0000000000..5230d6638c
--- /dev/null
+++ b/lib/chef/knife/bootstrap/train_connector.rb
@@ -0,0 +1,286 @@
+# Copyright:: Copyright (c) 2019 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 "train"
+require "tempfile"
+require "uri"
+
+class Chef
+ class Knife
+ class Bootstrap < Knife
+ class TrainConnector
+ SSH_CONFIG_OVERRIDE_KEYS = [:user, :port, :proxy].freeze
+
+ MKTEMP_WIN_COMMAND = <<~EOM.freeze
+ $parent = [System.IO.Path]::GetTempPath();
+ [string] $name = [System.Guid]::NewGuid();
+ $tmp = New-Item -ItemType Directory -Path;
+ (Join-Path $parent $name);
+ $tmp.FullName
+ EOM
+
+ MKTEMP_NIX_COMMAND = "bash -c 'd=$(mktemp -d ${TMPDIR:-/tmp}/chef_XXXXXX); echo $d'".freeze
+
+ def initialize(host_url, default_transport, opts)
+ uri_opts = opts_from_uri(host_url)
+ uri_opts[:backend] ||= @default_transport
+ @transport_type = uri_opts[:backend]
+
+ # opts in the URI will override user-provided options
+ @config = transport_config(host_url, opts.merge(uri_opts))
+ end
+
+ # Because creating a valid train connection for testing is a two-step process in which
+ # we need to connect before mocking config,
+ # we expose test_instance as a way for tests to create actual instances
+ # but ensure that they don't connect to any back end.
+ def self.test_instance(url, protocol: "ssh",
+ family: "unknown", name: "unknown",
+ release: "unknown", arch: "x86_64",
+ opts: {})
+ # Specifying sudo: false ensures that attempted operations
+ # don't fail because the mock platform doesn't support sudo
+ tc = TrainConnector.new(url, protocol, { sudo: false }.merge(opts))
+ tc.connect!
+ tc.connection.mock_os(
+ family: family,
+ name: name,
+ release: release,
+ arch: arch
+ )
+ tc
+ end
+
+ def connect!
+ # Force connection to establish
+ connection.wait_until_ready
+ true
+ end
+
+ def hostname
+ @config[:host]
+ end
+
+ def password_auth?
+ @config.key? :password
+ end
+
+ # True if we're connected to a linux host
+ def linux?
+ connection.platform.linux?
+ end
+
+ # True if we're connected to a unix host.
+ # NOTE: this is always true
+ # for a linux host because train classifies
+ # linux as a unix
+ def unix?
+ connection.platform.unix?
+ end
+
+ # True if we're connected to a windows host
+ def windows?
+ connection.platform.windows?
+ end
+
+ def winrm?
+ @transport_type == "winrm"
+ end
+
+ def ssh?
+ @transport_type == "ssh"
+ end
+
+ # Creates a temporary directory on the remote host if it
+ # hasn't already. Caches directory location.
+ #
+ # Returns the path on the remote host.
+ def temp_dir
+ cmd = windows? ? MKTEMP_WIN_COMMAND : MKTEMP_NIX_COMMAND
+ @tmpdir ||= begin
+ res = run_command!(cmd)
+ dir = res.stdout.chomp.strip
+ unless windows?
+ # Ensure that dir has the correct owner. We are possibly
+ # running with sudo right now - so this directory would be owned by root.
+ # File upload is performed over SCP as the current logged-in user,
+ # so we'll set ownership to ensure that works.
+ run_command!("chown #{@config[:user]} '#{dir}'")
+ end
+ dir
+ end
+ end
+
+ def upload_file!(local_path, remote_path)
+ connection.upload(local_path, remote_path)
+ end
+
+ def upload_file_content!(content, remote_path)
+ t = Tempfile.new("chef-content")
+ t << content
+ t.close
+ upload_file!(t.path, remote_path)
+ ensure
+ t.close
+ t.unlink
+ end
+
+ def del_file!(path)
+ if windows?
+ run_command!("If (Test-Path \"#{path}\") { Remove-Item -Force -Path \"#{path}\" }")
+ else
+ run_command!("rm -f \"#{path}\"")
+ end
+ end
+
+ # normalizes path across OS's
+ def normalize_path(path)
+ path.tr("\\", "/")
+ end
+
+ def run_command(command, &data_handler)
+ connection.run_command(command, &data_handler)
+ end
+
+ def run_command!(command, &data_handler)
+ result = run_command(command, &data_handler)
+ if result.exit_status != 0
+ raise RemoteExecutionFailed.new(hostname, command, result)
+ end
+ result
+ end
+
+ def connection
+ @connection ||= begin
+ Train.validate_backend(@config)
+ train = Train.create(@transport_type, @config)
+ train.connection
+ end
+ end
+
+ private
+
+ # For a given url and set of options, create a config
+ # hash suitable for passing into train.
+ def transport_config(host_url, opts_in)
+ opts = { target: host_url,
+ sudo: opts_in[:sudo] === false ? false : true,
+ www_form_encoded_password: true,
+ key_files: opts_in[:key_files],
+ non_interactive: true, # Prevent password prompts
+ transport_retries: 2,
+ transport_retry_sleep: 1,
+ logger: opts_in[:logger],
+ backend: @transport_type }
+
+ # Base opts are those provided by the caller directly
+ opts.merge!(opts_from_caller(opts, opts_in))
+
+ # WinRM has some additional computed options
+ opts.merge!(opts_inferred_from_winrm(opts, opts_in))
+
+ # Now that everything is populated, fill in anything left
+ # from user ssh config that may be present
+ opts.merge!(missing_opts_from_ssh_config(opts, opts_in))
+
+ Train.target_config(opts)
+ end
+
+ # Some winrm options are inferred based on other options.
+ # Return a hash of winrm options based on configuration already built.
+ def opts_inferred_from_winrm(config, opts_in)
+ return {} unless winrm?
+ opts_out = {}
+
+ if opts_in[:ssl]
+ opts_out[:ssl] = true
+ opts_out[:self_signed] = opts_in[:self_signed] || false
+ end
+
+ # See note here: https://github.com/mwrock/WinRM#example
+ if %w{ssl plaintext}.include?(opts_in[:winrm_auth_method])
+ opts_out[:winrm_disable_sspi] = true
+ end
+ opts_out
+ end
+
+ # Returns a hash containing valid options for the current
+ # transport protocol that are not already present in config
+ def opts_from_caller(config, opts_in)
+ # Train.options gives us the supported config options for the
+ # backend provider (ssh, winrm). We'll use that
+ # to filter out options that don't belong
+ # to the transport type we're using.
+ valid_opts = Train.options(config[:backend])
+ opts_in.select do |key, _v|
+ valid_opts.key?(key) && !config.key?(key)
+ end
+ end
+
+ # Extract any of username/password/host/port/transport
+ # that are in the URI and return them as a config has
+ def opts_from_uri(uri)
+ # Train.unpack_target_from_uri only works for complete URIs in
+ # form of proto://[user[:pass]@]host[:port]/
+ # So we'll add the protocol prefix if it's not supplied.
+ uri_to_check = if URI.regexp.match(uri)
+ uri
+ else
+ "#{@transport_type}://#{uri}"
+ end
+
+ Train.unpack_target_from_uri(uri_to_check)
+ end
+
+ # This returns a hash that consists of settings
+ # populated from SSH configuration that are not already present
+ # in the configuration passed in.
+ # This is necessary because train will default these values
+ # itself - causing SSH config data to be ignored
+ def missing_opts_from_ssh_config(config, opts_in)
+ return {} unless ssh?
+ host_cfg = ssh_config_for_host(config[:host])
+ opts_out = {}
+ opts_in.each do |key, _value|
+ if SSH_CONFIG_OVERRIDE_KEYS.include?(key) && !config.key?(key)
+ opts_out[key] = host_cfg[key]
+ end
+ end
+ opts_out
+ end
+
+ # Having this as a method makes it easier to mock
+ # SSH Config for testing.
+ def ssh_config_for_host(host)
+ require "net/ssh"
+ Net::SSH::Config.for(host)
+ end
+ end
+
+ class RemoteExecutionFailed < StandardError
+ attr_reader :exit_status, :command, :hostname, :stdout, :stderr
+ def initialize(hostname, command, result)
+ @hostname = hostname
+ @exit_status = result.exit_status
+ @stderr = result.stderr
+ @stdout = result.stdout
+ end
+ end
+
+ end
+ end
+end
diff --git a/lib/chef/knife/core/bootstrap_context.rb b/lib/chef/knife/core/bootstrap_context.rb
index 355978c79d..5e987745e6 100644
--- a/lib/chef/knife/core/bootstrap_context.rb
+++ b/lib/chef/knife/core/bootstrap_context.rb
@@ -19,6 +19,7 @@
require "chef/run_list"
require "chef/util/path_helper"
require "pathname"
+require "chef/dist"
class Chef
class Knife
@@ -169,7 +170,7 @@ class Chef
def start_chef
# If the user doesn't have a client path configure, let bash use the PATH for what it was designed for
- client_path = @chef_config[:chef_client_path] || "chef-client"
+ client_path = @chef_config[:chef_client_path] || "#{Chef::Dist::CLIENT}"
s = "#{client_path} -j /etc/chef/first-boot.json"
if @config[:verbosity] && @config[:verbosity] >= 3
s << " -l trace"
diff --git a/lib/chef/knife/core/windows_bootstrap_context.rb b/lib/chef/knife/core/windows_bootstrap_context.rb
index c7b8666ed0..df69399074 100644
--- a/lib/chef/knife/core/windows_bootstrap_context.rb
+++ b/lib/chef/knife/core/windows_bootstrap_context.rb
@@ -18,6 +18,7 @@
require "chef/knife/core/bootstrap_context"
require "chef/util/path_helper"
+require "chef/dist"
class Chef
class Knife
@@ -268,7 +269,7 @@ class Chef
end
def local_download_path
- "%TEMP%\\chef-client-latest.msi"
+ "%TEMP%\\#{Chef::Dist::CLIENT}-latest.msi"
end
def msi_url(machine_os = nil, machine_arch = nil, download_context = nil)
diff --git a/lib/chef/log/syslog.rb b/lib/chef/log/syslog.rb
index 58d6671095..d4179d465c 100644
--- a/lib/chef/log/syslog.rb
+++ b/lib/chef/log/syslog.rb
@@ -19,6 +19,7 @@
require "logger"
require "syslog-logger"
require "chef/mixin/unformatter"
+require "chef/dist"
class Chef
class Log
@@ -32,7 +33,7 @@ class Chef
attr_accessor :sync, :formatter
- def initialize(program_name = "chef-client", facility = ::Syslog::LOG_DAEMON, logopts = nil)
+ def initialize(program_name = "#{Chef::Dist::CLIENT}", facility = ::Syslog::LOG_DAEMON, logopts = nil)
super
return if defined? ::Logger::Syslog::SYSLOG
::Logger::Syslog.const_set :SYSLOG, SYSLOG
diff --git a/lib/chef/policy_builder/policyfile.rb b/lib/chef/policy_builder/policyfile.rb
index a4134c02bd..421d2ca8ec 100644
--- a/lib/chef/policy_builder/policyfile.rb
+++ b/lib/chef/policy_builder/policyfile.rb
@@ -24,6 +24,7 @@ require "chef/run_context"
require "chef/config"
require "chef/node"
require "chef/server_api"
+require "chef/dist"
class Chef
module PolicyBuilder
@@ -90,7 +91,7 @@ class Chef
@node = nil
if Chef::Config[:solo_legacy_mode]
- raise UnsupportedFeature, "Policyfile does not support chef-solo. Use chef-client local mode instead."
+ raise UnsupportedFeature, "Policyfile does not support chef-solo. Use #{Chef::Dist::CLIENT} local mode instead."
end
if override_runlist
diff --git a/lib/chef/provider/file.rb b/lib/chef/provider/file.rb
index 05522f1eb8..589a70de09 100644
--- a/lib/chef/provider/file.rb
+++ b/lib/chef/provider/file.rb
@@ -31,6 +31,7 @@ require "chef/util/backup"
require "chef/util/diff"
require "chef/util/selinux"
require "chef/file_content_management/deploy"
+require "chef/dist"
# The Tao of File Providers:
# - the content provider must always return a tempfile that we can delete/mv
@@ -389,7 +390,7 @@ class Chef
return if tempfile.nil?
# but a tempfile that has no path or doesn't exist should not happen
if tempfile.path.nil? || !::File.exists?(tempfile.path)
- raise "chef-client is confused, trying to deploy a file that has no path or does not exist..."
+ raise "#{Chef::Dist::CLIENT} is confused, trying to deploy a file that has no path or does not exist..."
end
# the file? on the next line suppresses the case in why-run when we have a not-file here that would have otherwise been removed
diff --git a/lib/chef/provider/windows_task.rb b/lib/chef/provider/windows_task.rb
index ab88575510..34c64199bf 100644
--- a/lib/chef/provider/windows_task.rb
+++ b/lib/chef/provider/windows_task.rb
@@ -334,7 +334,8 @@ class Chef
task.parameters != new_resource.command_arguments.to_s ||
task.principals[:run_level] != run_level ||
task.settings[:disallow_start_if_on_batteries] != new_resource.disallow_start_if_on_batteries ||
- task.settings[:stop_if_going_on_batteries] != new_resource.stop_if_going_on_batteries)
+ task.settings[:stop_if_going_on_batteries] != new_resource.stop_if_going_on_batteries ||
+ task.settings[:start_when_available] != new_resource.start_when_available)
else
current_task_trigger = task.trigger(0)
new_task_trigger = trigger
@@ -360,7 +361,8 @@ class Chef
task.principals[:run_level] != run_level ||
PRIORITY[task.priority] != new_resource.priority ||
task.settings[:disallow_start_if_on_batteries] != new_resource.disallow_start_if_on_batteries ||
- task.settings[:stop_if_going_on_batteries] != new_resource.stop_if_going_on_batteries
+ task.settings[:stop_if_going_on_batteries] != new_resource.stop_if_going_on_batteries ||
+ task.settings[:start_when_available] != new_resource.start_when_available
if trigger_type == TaskScheduler::MONTHLYDATE
flag = true if current_task_trigger[:run_on_last_day_of_month] != new_task_trigger[:run_on_last_day_of_month]
end
@@ -560,12 +562,13 @@ class Chef
settings[:priority] = new_resource.priority
settings[:disallow_start_if_on_batteries] = new_resource.disallow_start_if_on_batteries
settings[:stop_if_going_on_batteries] = new_resource.stop_if_going_on_batteries
+ settings[:start_when_available] = new_resource.start_when_available
settings
end
def principal_settings
settings = {}
- settings [:run_level] = run_level
+ settings[:run_level] = run_level
settings[:logon_type] = logon_type
settings
end
diff --git a/lib/chef/resource/breakpoint.rb b/lib/chef/resource/breakpoint.rb
index 8af3edbe22..820ac70c09 100644
--- a/lib/chef/resource/breakpoint.rb
+++ b/lib/chef/resource/breakpoint.rb
@@ -17,6 +17,7 @@
#
require "chef/resource"
+require "chef/dist"
class Chef
class Resource
@@ -24,7 +25,7 @@ class Chef
provides :breakpoint
resource_name :breakpoint
- description "Use the breakpoint resource to add breakpoints to recipes. Run the chef-shell in chef-client mode, and then use those breakpoints to debug recipes. Breakpoints are ignored by the chef-client during an actual chef-client run. That said, breakpoints are typically used to debug recipes only when running them in a non-production environment, after which they are removed from those recipes before the parent cookbook is uploaded to the Chef server."
+ description "Use the breakpoint resource to add breakpoints to recipes. Run the chef-shell in #{Chef::Dist::CLIENT} mode, and then use those breakpoints to debug recipes. Breakpoints are ignored by the #{Chef::Dist::CLIENT} during an actual #{Chef::Dist::CLIENT} run. That said, breakpoints are typically used to debug recipes only when running them in a non-production environment, after which they are removed from those recipes before the parent cookbook is uploaded to the Chef server."
introduced "12.0"
default_action :break
diff --git a/lib/chef/resource/chef_gem.rb b/lib/chef/resource/chef_gem.rb
index 2079e5d796..7655d6651c 100644
--- a/lib/chef/resource/chef_gem.rb
+++ b/lib/chef/resource/chef_gem.rb
@@ -18,6 +18,7 @@
require "chef/resource/package"
require "chef/resource/gem_package"
+require "chef/dist"
class Chef
class Resource
@@ -37,12 +38,12 @@ class Chef
resource_name :chef_gem
property :gem_binary, default: "#{RbConfig::CONFIG['bindir']}/gem", default_description: "Chef's built-in gem binary.",
- description: "The path of a gem binary to use for the installation. By default, the same version of Ruby that is used by the chef-client will be installed.",
+ description: "The path of a gem binary to use for the installation. By default, the same version of Ruby that is used by the #{Chef::Dist::CLIENT} will be installed.",
callbacks: {
"The chef_gem resource is restricted to the current gem environment, use gem_package to install to other environments." => proc { |v| v == "#{RbConfig::CONFIG['bindir']}/gem" },
}
property :compile_time, [TrueClass, FalseClass],
- description: "Controls the phase during which a gem is installed on a node. Set to 'true' to install a gem while the resource collection is being built (the 'compile phase'). Set to 'false' to install a gem while the chef-client is configuring the node (the 'converge phase').",
+ description: "Controls the phase during which a gem is installed on a node. Set to 'true' to install a gem while the resource collection is being built (the 'compile phase'). Set to 'false' to install a gem while the #{Chef::Dist::CLIENT} is configuring the node (the 'converge phase').",
default: false, desired_state: false
# force the resource to compile time if the compile time property has been set
diff --git a/lib/chef/resource/cookbook_file.rb b/lib/chef/resource/cookbook_file.rb
index c96e794469..bee4a5f3f4 100644
--- a/lib/chef/resource/cookbook_file.rb
+++ b/lib/chef/resource/cookbook_file.rb
@@ -21,6 +21,7 @@
require "chef/resource/file"
require "chef/provider/cookbook_file"
require "chef/mixin/securable"
+require "chef/dist"
class Chef
class Resource
@@ -29,7 +30,7 @@ class Chef
resource_name :cookbook_file
- description "Use the cookbook_file resource to transfer files from a sub-directory of COOKBOOK_NAME/files/ to a specified path located on a host that is running the chef-client. The file is selected according to file specificity, which allows different source files to be used based on the hostname, host platform (operating system, distro, or as appropriate), or platform version. Files that are located in the COOKBOOK_NAME/files/default sub-directory may be used on any platform.\n\nDuring a chef-client run, the checksum for each local file is calculated and then compared against the checksum for the same file as it currently exists in the cookbook on the Chef server. A file is not transferred when the checksums match. Only files that require an update are transferred from the Chef server to a node."
+ description "Use the cookbook_file resource to transfer files from a sub-directory of COOKBOOK_NAME/files/ to a specified path located on a host that is running the #{Chef::Dist::CLIENT}. The file is selected according to file specificity, which allows different source files to be used based on the hostname, host platform (operating system, distro, or as appropriate), or platform version. Files that are located in the COOKBOOK_NAME/files/default sub-directory may be used on any platform.\n\nDuring a #{Chef::Dist::CLIENT} run, the checksum for each local file is calculated and then compared against the checksum for the same file as it currently exists in the cookbook on the Chef server. A file is not transferred when the checksums match. Only files that require an update are transferred from the Chef server to a node."
property :source, [ String, Array ],
description: "The name of the file in COOKBOOK_NAME/files/default or the path to a file located in COOKBOOK_NAME/files. The path must include the file name and its extension. This can be used to distribute specific files depending upon the platform used.",
diff --git a/lib/chef/resource/dnf_package.rb b/lib/chef/resource/dnf_package.rb
index 3b40a6dffb..6590c6c003 100644
--- a/lib/chef/resource/dnf_package.rb
+++ b/lib/chef/resource/dnf_package.rb
@@ -18,6 +18,7 @@
require "chef/resource/package"
require "chef/mixin/which"
require "chef/mixin/shell_out"
+require "chef/dist"
class Chef
class Resource
@@ -52,7 +53,7 @@ class Chef
# Flush the in-memory available/installed cache, this does not flush the dnf caches on disk
property :flush_cache, Hash,
- description: "Flush the in-memory cache before or after a DNF operation that installs, upgrades, or removes a package. DNF automatically synchronizes remote metadata to a local cache. The chef-client creates a copy of the local cache, and then stores it in-memory during the chef-client run. The in-memory cache allows packages to be installed during the chef-client run without the need to continue synchronizing the remote metadata to the local cache while the chef-client run is in-progress.",
+ description: "Flush the in-memory cache before or after a DNF operation that installs, upgrades, or removes a package. DNF automatically synchronizes remote metadata to a local cache. The #{Chef::Dist::CLIENT} creates a copy of the local cache, and then stores it in-memory during the #{Chef::Dist::CLIENT} run. The in-memory cache allows packages to be installed during the #{Chef::Dist::CLIENT} run without the need to continue synchronizing the remote metadata to the local cache while the #{Chef::Dist::CLIENT} run is in-progress.",
default: { before: false, after: false },
coerce: proc { |v|
if v.is_a?(Hash)
diff --git a/lib/chef/resource/execute.rb b/lib/chef/resource/execute.rb
index afab9a7b27..de3b7e044a 100644
--- a/lib/chef/resource/execute.rb
+++ b/lib/chef/resource/execute.rb
@@ -18,6 +18,7 @@
#
require "chef/resource"
+require "chef/dist"
class Chef
class Resource
@@ -65,7 +66,7 @@ class Chef
description: "The group name or group ID that must be changed before running a command."
property :live_stream, [ TrueClass, FalseClass ], default: false,
- description: "Send the output of the command run by this execute resource block to the chef-client event stream."
+ description: "Send the output of the command run by this execute resource block to the #{Chef::Dist::CLIENT} event stream."
# default_env defaults to `false` so that the command execution more exactly matches what the user gets on the command line without magic
property :default_env, [ TrueClass, FalseClass ], desired_state: false, default: false,
@@ -91,7 +92,7 @@ class Chef
# lazy used to set default value of sensitive to true if password is set
property :sensitive, [ TrueClass, FalseClass ],
- description: "Ensure that sensitive resource data is not logged by the chef-client.",
+ description: "Ensure that sensitive resource data is not logged by the #{Chef::Dist::CLIENT}.",
default: lazy { |r| r.password ? true : false }, default_description: "True if the password property is set. False otherwise."
property :elevated, [ TrueClass, FalseClass ], default: false,
diff --git a/lib/chef/resource/file.rb b/lib/chef/resource/file.rb
index 8db15fc661..1875846d79 100644
--- a/lib/chef/resource/file.rb
+++ b/lib/chef/resource/file.rb
@@ -22,6 +22,7 @@ require "chef/platform/query_helpers"
require "chef/mixin/securable"
require "chef/resource/file/verification"
require "pathname"
+require "chef/dist"
class Chef
class Resource
@@ -52,7 +53,7 @@ class Chef
allowed_actions :create, :delete, :touch, :create_if_missing
property :path, String, name_property: true, identity: true,
- description: "The full path to the file, including the file name and its extension. For example: /files/file.txt. Default value: the name of the resource block. Microsoft Windows: A path that begins with a forward slash (/) will point to the root of the current working directory of the chef-client process. This path can vary from system to system. Therefore, using a path that begins with a forward slash (/) is not recommended."
+ description: "The full path to the file, including the file name and its extension. For example: /files/file.txt. Default value: the name of the resource block. Microsoft Windows: A path that begins with a forward slash (/) will point to the root of the current working directory of the #{Chef::Dist::CLIENT} process. This path can vary from system to system. Therefore, using a path that begins with a forward slash (/) is not recommended."
property :atomic_update, [ TrueClass, FalseClass ], desired_state: false, default: lazy { |r| r.docker? && r.special_docker_files?(r.path) ? false : Chef::Config[:file_atomic_update] },
description: "Perform atomic file updates on a per-resource basis. Set to true for atomic file updates. Set to false for non-atomic file updates. This setting overrides file_atomic_update, which is a global setting found in the client.rb file."
@@ -69,7 +70,7 @@ class Chef
property :diff, [ String, nil ], desired_state: false, skip_docs: true
property :force_unlink, [ TrueClass, FalseClass ], desired_state: false, default: false,
- description: "How the chef-client handles certain situations when the target file turns out not to be a file. For example, when a target file is actually a symlink. Set to true for the chef-client delete the non-file target and replace it with the specified file. Set to false for the chef-client to raise an error."
+ description: "How the #{Chef::Dist::CLIENT} handles certain situations when the target file turns out not to be a file. For example, when a target file is actually a symlink. Set to true for the #{Chef::Dist::CLIENT} delete the non-file target and replace it with the specified file. Set to false for the #{Chef::Dist::CLIENT} to raise an error."
property :manage_symlink_source, [ TrueClass, FalseClass ], desired_state: false,
description: "Change the behavior of the file resource if it is pointed at a symlink. When this value is set to true, the Chef client will manage the symlink's permissions or will replace the symlink with a normal file if the resource has content. When this value is set to false, Chef will follow the symlink and will manage the permissions and content of symlink's target file. The default behavior is true but emits a warning that the default value will be changed to false in a future version; setting this explicitly to true or false suppresses this warning."
diff --git a/lib/chef/resource/gem_package.rb b/lib/chef/resource/gem_package.rb
index 0f6fd413ca..e057cbd485 100644
--- a/lib/chef/resource/gem_package.rb
+++ b/lib/chef/resource/gem_package.rb
@@ -17,6 +17,7 @@
#
require "chef/resource/package"
+require "chef/dist"
class Chef
class Resource
@@ -44,7 +45,7 @@ class Chef
default: lazy { Chef::Config[:clear_gem_sources] }, desired_state: false
property :gem_binary, String, desired_state: false,
- description: "The path of a gem binary to use for the installation. By default, the same version of Ruby that is used by the chef-client will be installed."
+ description: "The path of a gem binary to use for the installation. By default, the same version of Ruby that is used by the #{Chef::Dist::CLIENT} will be installed."
property :include_default_source, [ TrueClass, FalseClass ],
description: "Set to 'false' to not include 'Chef::Config[:rubygems_url]'' in the sources.",
diff --git a/lib/chef/resource/homebrew_package.rb b/lib/chef/resource/homebrew_package.rb
index 9d8c7b2596..930e25d820 100644
--- a/lib/chef/resource/homebrew_package.rb
+++ b/lib/chef/resource/homebrew_package.rb
@@ -20,6 +20,7 @@
require "chef/provider/package"
require "chef/resource/package"
+require "chef/dist"
class Chef
class Resource
@@ -31,7 +32,7 @@ class Chef
introduced "12.0"
property :homebrew_user, [ String, Integer ],
- description: "The name of the Homebrew owner to be used by the chef-client when executing a command."
+ description: "The name of the Homebrew owner to be used by the #{Chef::Dist::CLIENT} when executing a command."
end
end
diff --git a/lib/chef/resource/ohai.rb b/lib/chef/resource/ohai.rb
index b5cd97cae0..59f2967a2f 100644
--- a/lib/chef/resource/ohai.rb
+++ b/lib/chef/resource/ohai.rb
@@ -18,6 +18,7 @@
#
require "chef/resource"
+require "chef/dist"
class Chef
class Resource
@@ -25,10 +26,10 @@ class Chef
resource_name :ohai
provides :ohai
- description "Use the ohai resource to reload the Ohai configuration on a node. This allows recipes that change system attributes (like a recipe that adds a user) to refer to those attributes later on during the chef-client run."
+ description "Use the ohai resource to reload the Ohai configuration on a node. This allows recipes that change system attributes (like a recipe that adds a user) to refer to those attributes later on during the #{Chef::Dist::CLIENT} run."
property :plugin, String,
- description: "The name of an Ohai plugin to be reloaded. If this property is not specified, the chef-client will reload all plugins."
+ description: "The name of an Ohai plugin to be reloaded. If this property is not specified, the #{Chef::Dist::CLIENT} will reload all plugins."
default_action :reload
allowed_actions :reload
diff --git a/lib/chef/resource/ruby_block.rb b/lib/chef/resource/ruby_block.rb
index 911e6203d8..0ec6647fd8 100644
--- a/lib/chef/resource/ruby_block.rb
+++ b/lib/chef/resource/ruby_block.rb
@@ -19,11 +19,12 @@
require "chef/resource"
require "chef/provider/ruby_block"
+require "chef/dist"
class Chef
class Resource
class RubyBlock < Chef::Resource
- description "Use the ruby_block resource to execute Ruby code during a chef-client run."\
+ description "Use the ruby_block resource to execute Ruby code during a #{Chef::Dist::CLIENT} run."\
" Ruby code in the ruby_block resource is evaluated with other resources during"\
" convergence, whereas Ruby code outside of a ruby_block resource is evaluated"\
" before other resources, as the recipe is compiled."
diff --git a/lib/chef/resource/service.rb b/lib/chef/resource/service.rb
index 4e808d6035..20bf9ecc65 100644
--- a/lib/chef/resource/service.rb
+++ b/lib/chef/resource/service.rb
@@ -19,6 +19,7 @@
require "chef/resource"
require "shellwords"
+require "chef/dist"
class Chef
class Resource
@@ -33,7 +34,7 @@ class Chef
# this is a poor API please do not re-use this pattern
property :supports, Hash, default: { restart: nil, reload: nil, status: nil },
- description: "A list of properties that controls how the chef-client is to attempt to manage a service: :restart, :reload, :status. For :restart, the init script or other service provider can use a restart command; if :restart is not specified, the chef-client attempts to stop and then start a service. For :reload, the init script or other service provider can use a reload command. For :status, the init script or other service provider can use a status command to determine if the service is running; if :status is not specified, the chef-client attempts to match the service_name against the process table as a regular expression, unless a pattern is specified as a parameter property. Default value: { restart: false, reload: false, status: false } for all platforms (except for the Red Hat platform family, which defaults to { restart: false, reload: false, status: true }.)",
+ description: "A list of properties that controls how the #{Chef::Dist::CLIENT} is to attempt to manage a service: :restart, :reload, :status. For :restart, the init script or other service provider can use a restart command; if :restart is not specified, the #{Chef::Dist::CLIENT} attempts to stop and then start a service. For :reload, the init script or other service provider can use a reload command. For :status, the init script or other service provider can use a status command to determine if the service is running; if :status is not specified, the #{Chef::Dist::CLIENT} attempts to match the service_name against the process table as a regular expression, unless a pattern is specified as a parameter property. Default value: { restart: false, reload: false, status: false } for all platforms (except for the Red Hat platform family, which defaults to { restart: false, reload: false, status: true }.)",
coerce: proc { |x| x.is_a?(Array) ? x.each_with_object({}) { |i, m| m[i] = true } : x }
property :service_name, String,
@@ -76,7 +77,7 @@ class Chef
# specify overrides for the start_command, stop_command and
# restart_command properties.
property :init_command, String,
- description: "The path to the init script that is associated with the service. Use init_command to prevent the need to specify overrides for the start_command, stop_command, and restart_command properties. When this property is not specified, the chef-client will use the default init command for the service provider being used.",
+ description: "The path to the init script that is associated with the service. Use init_command to prevent the need to specify overrides for the start_command, stop_command, and restart_command properties. When this property is not specified, the #{Chef::Dist::CLIENT} will use the default init command for the service provider being used.",
desired_state: false
# if the service is enabled or not
diff --git a/lib/chef/resource/snap_package.rb b/lib/chef/resource/snap_package.rb
index 81904f8405..080b604d28 100644
--- a/lib/chef/resource/snap_package.rb
+++ b/lib/chef/resource/snap_package.rb
@@ -24,6 +24,7 @@ class Chef
resource_name :snap_package
description "Use the snap_package resource to manage snap packages on Debian and Ubuntu platforms."
+ introduced "15.0"
property :channel, String,
description: "The default channel. For example: stable.",
diff --git a/lib/chef/resource/subversion.rb b/lib/chef/resource/subversion.rb
index adf8244668..4febb9353c 100644
--- a/lib/chef/resource/subversion.rb
+++ b/lib/chef/resource/subversion.rb
@@ -18,6 +18,7 @@
#
require "chef/resource/scm"
+require "chef/dist"
class Chef
class Resource
@@ -32,7 +33,7 @@ class Chef
default: "--no-auth-cache"
property :svn_info_args, [String, nil, FalseClass],
- description: "Use when the svn info command is used by the chef-client and arguments need to be passed. The svn_arguments command does not work when the svn info command is used.",
+ description: "Use when the svn info command is used by the #{Chef::Dist::CLIENT} and arguments need to be passed. The svn_arguments command does not work when the svn info command is used.",
coerce: proc { |v| v == false ? nil : v }, # coerce false to nil
default: "--no-auth-cache"
diff --git a/lib/chef/resource/template.rb b/lib/chef/resource/template.rb
index bd8325f2c1..b08bf0b8fb 100644
--- a/lib/chef/resource/template.rb
+++ b/lib/chef/resource/template.rb
@@ -20,6 +20,7 @@
require "chef/resource/file"
require "chef/mixin/securable"
+require "chef/dist"
class Chef
class Resource
@@ -67,7 +68,7 @@ class Chef
property :local, [ TrueClass, FalseClass ],
default: false, desired_state: false,
- description: "Load a template from a local path. By default, the chef-client loads templates from a cookbook’s /templates directory. When this property is set to true, use the source property to specify the path to a template on the local node."
+ description: "Load a template from a local path. By default, the #{Chef::Dist::CLIENT} loads templates from a cookbook’s /templates directory. When this property is set to true, use the source property to specify the path to a template on the local node."
# Declares a helper method to be defined in the template context when
# rendering.
diff --git a/lib/chef/resource/windows_certificate.rb b/lib/chef/resource/windows_certificate.rb
index e7261adfba..c530d3b67d 100644
--- a/lib/chef/resource/windows_certificate.rb
+++ b/lib/chef/resource/windows_certificate.rb
@@ -21,6 +21,7 @@ require "chef/util/path_helper"
require "chef/resource"
require "win32-certstore" if Chef::Platform.windows?
require "openssl"
+require "chef/dist"
class Chef
class Resource
@@ -53,7 +54,7 @@ class Chef
# lazy used to set default value of sensitive to true if password is set
property :sensitive, [TrueClass, FalseClass],
- description: "Ensure that sensitive resource data is not logged by the chef-client.",
+ description: "Ensure that sensitive resource data is not logged by the #{Chef::Dist::CLIENT}.",
default: lazy { |r| r.pfx_password ? true : false }, skip_docs: true
action :create do
diff --git a/lib/chef/resource/windows_task.rb b/lib/chef/resource/windows_task.rb
index 54920f2bac..c60515a0ee 100644
--- a/lib/chef/resource/windows_task.rb
+++ b/lib/chef/resource/windows_task.rb
@@ -120,6 +120,10 @@ class Chef
introduced: "14.7",
description: "The task description."
+ property :start_when_available, [TrueClass, FalseClass],
+ introduced: "15.0", default: false,
+ description: "To start the task at any time after its scheduled time has passed."
+
attr_accessor :exists, :task, :command_arguments
VALID_WEEK_DAYS = %w{ mon tue wed thu fri sat sun * }.freeze
diff --git a/lib/chef/resource/yum_package.rb b/lib/chef/resource/yum_package.rb
index 602fe489fb..8f088371ed 100644
--- a/lib/chef/resource/yum_package.rb
+++ b/lib/chef/resource/yum_package.rb
@@ -17,6 +17,7 @@
#
require "chef/resource/package"
+require "chef/dist"
class Chef
class Resource
@@ -51,7 +52,7 @@ class Chef
coerce: proc { |x| x.is_a?(Array) ? x.to_a : x }
property :flush_cache, Hash,
- description: "Flush the in-memory cache before or after a Yum operation that installs, upgrades, or removes a package. Accepts a Hash in the form: { :before => true/false, :after => true/false } or an Array in the form [ :before, :after ].\nYum automatically synchronizes remote metadata to a local cache. The chef-client creates a copy of the local cache, and then stores it in-memory during the chef-client run. The in-memory cache allows packages to be installed during the chef-client run without the need to continue synchronizing the remote metadata to the local cache while the chef-client run is in-progress.",
+ description: "Flush the in-memory cache before or after a Yum operation that installs, upgrades, or removes a package. Accepts a Hash in the form: { :before => true/false, :after => true/false } or an Array in the form [ :before, :after ].\nYum automatically synchronizes remote metadata to a local cache. The #{Chef::Dist::CLIENT} creates a copy of the local cache, and then stores it in-memory during the #{Chef::Dist::CLIENT} run. The in-memory cache allows packages to be installed during the #{Chef::Dist::CLIENT} run without the need to continue synchronizing the remote metadata to the local cache while the #{Chef::Dist::CLIENT} run is in-progress.",
default: { before: false, after: false },
coerce: proc { |v|
if v.is_a?(Hash)
diff --git a/lib/chef/version.rb b/lib/chef/version.rb
index 23584f4be2..14ae1e880a 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("15.0.233")
+ VERSION = Chef::VersionString.new("15.0.237")
end
#
diff --git a/lib/chef/win32/api/security.rb b/lib/chef/win32/api/security.rb
index 277e85a26b..5c3dd69c3e 100644
--- a/lib/chef/win32/api/security.rb
+++ b/lib/chef/win32/api/security.rb
@@ -140,6 +140,8 @@ class Chef
FILE_READ_EA | SYNCHRONIZE
FILE_GENERIC_WRITE = STANDARD_RIGHTS_WRITE | FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | FILE_APPEND_DATA | SYNCHRONIZE
FILE_GENERIC_EXECUTE = STANDARD_RIGHTS_EXECUTE | FILE_READ_ATTRIBUTES | FILE_EXECUTE | SYNCHRONIZE
+ WRITE = FILE_WRITE_DATA | FILE_APPEND_DATA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA
+ SUBFOLDERS_AND_FILES_ONLY = INHERIT_ONLY_ACE | CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE
# Access Token Rights (for OpenProcessToken)
# Access Rights for Access-Token Objects (used in OpenProcessToken)
TOKEN_ASSIGN_PRIMARY = 0x0001
diff --git a/spec/functional/resource/link_spec.rb b/spec/functional/resource/link_spec.rb
index 4464b6ed69..d86a904098 100644
--- a/spec/functional/resource/link_spec.rb
+++ b/spec/functional/resource/link_spec.rb
@@ -417,11 +417,11 @@ describe Chef::Resource::Link do
it_behaves_like "a securable resource without existing target" do
let(:path) { target_file }
- def allowed_acl(sid, expected_perms)
+ def allowed_acl(sid, expected_perms, _flags = 0)
[ ACE.access_allowed(sid, expected_perms[:specific]) ]
end
- def denied_acl(sid, expected_perms)
+ def denied_acl(sid, expected_perms, _flags = 0)
[ ACE.access_denied(sid, expected_perms[:specific]) ]
end
diff --git a/spec/functional/resource/windows_task_spec.rb b/spec/functional/resource/windows_task_spec.rb
index b0c6998d77..fa51ad3f8a 100644
--- a/spec/functional/resource/windows_task_spec.rb
+++ b/spec/functional/resource/windows_task_spec.rb
@@ -18,6 +18,7 @@
require "spec_helper"
require "chef/provider/windows_task"
+require "chef/dist"
describe Chef::Resource::WindowsTask, :windows_only do
# resource.task.application_name will default to task_name unless resource.command is set
@@ -45,37 +46,37 @@ describe Chef::Resource::WindowsTask, :windows_only do
context "With Arguments" do
it "creates scheduled task and sets command arguments" do
- subject.command "chef-client -W"
+ subject.command "#{Chef::Dist::CLIENT} -W"
call_for_create_action
# loading current resource again to check new task is creted and it matches task parameters
current_resource = call_for_load_current_resource
expect(current_resource.exists).to eq(true)
- expect(current_resource.task.application_name).to eq("chef-client")
+ expect(current_resource.task.application_name).to eq(Chef::Dist::CLIENT)
expect(current_resource.task.parameters).to eq("-W")
end
it "does not converge the resource if it is already converged" do
- subject.command "chef-client -W"
+ subject.command "#{Chef::Dist::CLIENT} -W"
subject.run_action(:create)
- subject.command "chef-client -W"
+ subject.command "#{Chef::Dist::CLIENT} -W"
subject.run_action(:create)
expect(subject).not_to be_updated_by_last_action
end
it "creates scheduled task and sets command arguments when arguments inclusive single quotes" do
- subject.command "chef-client -W -L 'C:\\chef\\chef-ad-join.log'"
+ subject.command "#{Chef::Dist::CLIENT} -W -L 'C:\\chef\\chef-ad-join.log'"
call_for_create_action
# loading current resource again to check new task is creted and it matches task parameters
current_resource = call_for_load_current_resource
expect(current_resource.exists).to eq(true)
- expect(current_resource.task.application_name).to eq("chef-client")
+ expect(current_resource.task.application_name).to eq(Chef::Dist::CLIENT)
expect(current_resource.task.parameters).to eq("-W -L 'C:\\chef\\chef-ad-join.log'")
end
it "does not converge the resource if it is already converged" do
- subject.command "chef-client -W -L 'C:\\chef\\chef-ad-join.log'"
+ subject.command "#{Chef::Dist::CLIENT} -W -L 'C:\\chef\\chef-ad-join.log'"
subject.run_action(:create)
- subject.command "chef-client -W -L 'C:\\chef\\chef-ad-join.log'"
+ subject.command "#{Chef::Dist::CLIENT} -W -L 'C:\\chef\\chef-ad-join.log'"
subject.run_action(:create)
expect(subject).not_to be_updated_by_last_action
end
@@ -135,19 +136,19 @@ describe Chef::Resource::WindowsTask, :windows_only do
context "Without Arguments" do
it "creates scheduled task and sets command arguments" do
- subject.command "chef-client"
+ subject.command Chef::Dist::CLIENT
call_for_create_action
# loading current resource again to check new task is creted and it matches task parameters
current_resource = call_for_load_current_resource
expect(current_resource.exists).to eq(true)
- expect(current_resource.task.application_name).to eq("chef-client")
+ expect(current_resource.task.application_name).to eq(Chef::Dist::CLIENT)
expect(current_resource.task.parameters).to be_empty
end
it "does not converge the resource if it is already converged" do
- subject.command "chef-client"
+ subject.command Chef::Dist::CLIENT
subject.run_action(:create)
- subject.command "chef-client"
+ subject.command Chef::Dist::CLIENT
subject.run_action(:create)
expect(subject).not_to be_updated_by_last_action
end
@@ -1283,6 +1284,57 @@ describe Chef::Resource::WindowsTask, :windows_only do
expect(subject).not_to be_updated_by_last_action
end
end
+
+ context "when start_when_available is passed" do
+ subject do
+ new_resource = Chef::Resource::WindowsTask.new(task_name, run_context)
+ new_resource.command task_name
+ new_resource.run_level :highest
+ new_resource.execution_time_limit = 259200 / 60 # converting "PT72H" into minutes and passing here since win32-taskscheduler accespts this
+ new_resource
+ end
+
+ it "sets start_when_available to true" do
+ subject.frequency :minute
+ subject.start_when_available true
+ call_for_create_action
+ # loading current resource again to check new task is creted and it matches task parameters
+ current_resource = call_for_load_current_resource
+ expect(current_resource.exists).to eq(true)
+ expect(current_resource.task.settings[:start_when_available]).to eql(true)
+ end
+
+ it "sets start_when_available to false" do
+ subject.frequency :minute
+ subject.start_when_available false
+ call_for_create_action
+ # loading current resource again to check new task is created and it matches task parameters
+ current_resource = call_for_load_current_resource
+ expect(current_resource.exists).to eq(true)
+ expect(current_resource.task.settings[:start_when_available]).to eql(false)
+ end
+
+ it "sets the default if start_when_available is nil" do
+ subject.frequency :minute
+ subject.start_when_available nil
+ call_for_create_action
+ # loading current resource again to check new task is created and it matches task parameters
+ current_resource = call_for_load_current_resource
+ expect(current_resource.exists).to eq(true)
+ expect(current_resource.task.settings[:start_when_available]).to eql(false)
+ end
+
+ it "does not converge the resource if it is already converged" do
+ subject.frequency :minute
+ subject.start_when_available true
+ subject.run_action(:create)
+ subject.frequency :minute
+ subject.start_when_available true
+ subject.disallow_start_if_on_batteries false
+ subject.run_action(:create)
+ expect(subject).not_to be_updated_by_last_action
+ end
+ end
end
context "task_name with parent folder" do
diff --git a/spec/support/shared/functional/directory_resource.rb b/spec/support/shared/functional/directory_resource.rb
index 5e5e2bb360..4fb08479e6 100644
--- a/spec/support/shared/functional/directory_resource.rb
+++ b/spec/support/shared/functional/directory_resource.rb
@@ -65,18 +65,20 @@ shared_examples_for "a directory resource" do
end
# Set up the context for security tests
- def allowed_acl(sid, expected_perms)
- [
- ACE.access_allowed(sid, expected_perms[:specific]),
- ACE.access_allowed(sid, expected_perms[:generic], (Chef::ReservedNames::Win32::API::Security::INHERIT_ONLY_ACE | Chef::ReservedNames::Win32::API::Security::CONTAINER_INHERIT_ACE | Chef::ReservedNames::Win32::API::Security::OBJECT_INHERIT_ACE)),
- ]
+ def allowed_acl(sid, expected_perms, flags = 0)
+ acl = [ ACE.access_allowed(sid, expected_perms[:specific], flags) ]
+ if expected_perms[:generic]
+ acl << ACE.access_allowed(sid, expected_perms[:generic], (Chef::ReservedNames::Win32::API::Security::SUBFOLDERS_AND_FILES_ONLY))
+ end
+ acl
end
- def denied_acl(sid, expected_perms)
- [
- ACE.access_denied(sid, expected_perms[:specific]),
- ACE.access_denied(sid, expected_perms[:generic], (Chef::ReservedNames::Win32::API::Security::INHERIT_ONLY_ACE | Chef::ReservedNames::Win32::API::Security::CONTAINER_INHERIT_ACE | Chef::ReservedNames::Win32::API::Security::OBJECT_INHERIT_ACE)),
- ]
+ def denied_acl(sid, expected_perms, flags = 0)
+ acl = [ ACE.access_denied(sid, expected_perms[:specific], flags) ]
+ if expected_perms[:generic]
+ acl << ACE.access_denied(sid, expected_perms[:generic], (Chef::ReservedNames::Win32::API::Security::SUBFOLDERS_AND_FILES_ONLY))
+ end
+ acl
end
def parent_inheritable_acls
diff --git a/spec/support/shared/functional/file_resource.rb b/spec/support/shared/functional/file_resource.rb
index 8ae5db6a57..db947614b3 100644
--- a/spec/support/shared/functional/file_resource.rb
+++ b/spec/support/shared/functional/file_resource.rb
@@ -899,11 +899,11 @@ shared_examples_for "a configured file resource" do
end
# Set up the context for security tests
- def allowed_acl(sid, expected_perms)
+ def allowed_acl(sid, expected_perms, _flags = 0)
[ ACE.access_allowed(sid, expected_perms[:specific]) ]
end
- def denied_acl(sid, expected_perms)
+ def denied_acl(sid, expected_perms, _flags = 0)
[ ACE.access_denied(sid, expected_perms[:specific]) ]
end
diff --git a/spec/support/shared/functional/securable_resource.rb b/spec/support/shared/functional/securable_resource.rb
index 2abae030c2..18e7243453 100644
--- a/spec/support/shared/functional/securable_resource.rb
+++ b/spec/support/shared/functional/securable_resource.rb
@@ -117,8 +117,7 @@ shared_context "use Windows permissions", :windows_only do
let(:expected_write_perms) do
{
- generic: Chef::ReservedNames::Win32::API::Security::GENERIC_WRITE,
- specific: Chef::ReservedNames::Win32::API::Security::FILE_GENERIC_WRITE,
+ specific: Chef::ReservedNames::Win32::API::Security::WRITE,
}
end
@@ -136,6 +135,8 @@ shared_context "use Windows permissions", :windows_only do
}
end
+ let (:write_flag) { 3 }
+
RSpec::Matchers.define :have_expected_properties do |mask, type, flags|
match do |ace|
ace.mask == mask &&
@@ -363,78 +364,108 @@ shared_examples_for "a securable resource without existing target" do
expect(descriptor.group).to eq(arbitrary_non_default_group)
end
- describe "with rights and deny_rights attributes" do
-
- it "correctly sets :read rights" do
- resource.rights(:read, "Guest")
- resource.run_action(:create)
- expect(explicit_aces).to eq(allowed_acl(SID.Guest, expected_read_perms))
+ describe "#allowed_acl" do
+ context "correctly sets" do
+
+ it ":read rights" do
+ resource.rights(:read, "Guest")
+ resource.run_action(:create)
+ expect(explicit_aces).to eq(allowed_acl(SID.Guest, expected_read_perms))
+ end
+
+ it ":read_execute rights" do
+ resource.rights(:read_execute, "Guest")
+ resource.run_action(:create)
+ expect(explicit_aces).to eq(allowed_acl(SID.Guest, expected_read_execute_perms))
+ end
+
+ it ":write rights" do
+ resource.rights(:write, "Guest")
+ resource.run_action(:create)
+ expect(explicit_aces).to eq(allowed_acl(SID.Guest, expected_write_perms, write_flag))
+ end
+
+ it ":modify rights" do
+ resource.rights(:modify, "Guest")
+ resource.run_action(:create)
+ expect(explicit_aces).to eq(allowed_acl(SID.Guest, expected_modify_perms))
+ end
+
+ it ":full_control rights" do
+ resource.rights(:full_control, "Guest")
+ resource.run_action(:create)
+ expect(explicit_aces).to eq(allowed_acl(SID.Guest, expected_full_control_perms))
+ end
+
+ it "multiple rights" do
+ resource.rights(:read, "Everyone")
+ resource.rights(:modify, "Guest")
+ resource.run_action(:create)
+
+ expect(explicit_aces).to eq(
+ allowed_acl(SID.Everyone, expected_read_perms) +
+ allowed_acl(SID.Guest, expected_modify_perms)
+ )
+ end
end
+ end
- it "correctly sets :read_execute rights" do
- resource.rights(:read_execute, "Guest")
- resource.run_action(:create)
- expect(explicit_aces).to eq(allowed_acl(SID.Guest, expected_read_execute_perms))
- end
-
- it "correctly sets :write rights" do
- resource.rights(:write, "Guest")
- resource.run_action(:create)
- expect(explicit_aces).to eq(allowed_acl(SID.Guest, expected_write_perms))
- end
-
- it "correctly sets :modify rights" do
- resource.rights(:modify, "Guest")
- resource.run_action(:create)
- expect(explicit_aces).to eq(allowed_acl(SID.Guest, expected_modify_perms))
- end
-
- it "correctly sets :full_control rights" do
- resource.rights(:full_control, "Guest")
- resource.run_action(:create)
- expect(explicit_aces).to eq(allowed_acl(SID.Guest, expected_full_control_perms))
- end
-
- it "correctly sets deny_rights" do
- # deny is an ACE with full rights, but is a deny type ace, not an allow type
- resource.deny_rights(:full_control, "Guest")
- resource.run_action(:create)
- expect(explicit_aces).to eq(denied_acl(SID.Guest, expected_full_control_perms))
- end
-
- it "Sets multiple rights" do
- resource.rights(:read, "Everyone")
- resource.rights(:modify, "Guest")
- resource.run_action(:create)
-
- expect(explicit_aces).to eq(
- allowed_acl(SID.Everyone, expected_read_perms) +
- allowed_acl(SID.Guest, expected_modify_perms)
- )
- end
-
- it "Sets deny_rights ahead of rights" do
- resource.rights(:read, "Everyone")
- resource.deny_rights(:modify, "Guest")
- resource.run_action(:create)
-
- expect(explicit_aces).to eq(
- denied_acl(SID.Guest, expected_modify_perms) +
- allowed_acl(SID.Everyone, expected_read_perms)
- )
- end
-
- it "Sets deny_rights ahead of rights when specified in reverse order" do
- resource.deny_rights(:modify, "Guest")
- resource.rights(:read, "Everyone")
- resource.run_action(:create)
-
- expect(explicit_aces).to eq(
- denied_acl(SID.Guest, expected_modify_perms) +
- allowed_acl(SID.Everyone, expected_read_perms)
- )
+ describe "#denied_acl" do
+ context "correctly sets" do
+
+ it ":read rights" do
+ resource.deny_rights(:read, "Guest")
+ resource.run_action(:create)
+ expect(explicit_aces).to eq(denied_acl(SID.Guest, expected_read_perms))
+ end
+
+ it ":read_execute rights" do
+ resource.deny_rights(:read_execute, "Guest")
+ resource.run_action(:create)
+ expect(explicit_aces).to eq(denied_acl(SID.Guest, expected_read_execute_perms))
+ end
+
+ it ":write rights" do
+ resource.deny_rights(:write, "Guest")
+ resource.run_action(:create)
+ expect(explicit_aces).to eq(denied_acl(SID.Guest, expected_write_perms, write_flag))
+ end
+
+ it ":modify rights" do
+ resource.deny_rights(:modify, "Guest")
+ resource.run_action(:create)
+ expect(explicit_aces).to eq(denied_acl(SID.Guest, expected_modify_perms))
+ end
+
+ it ":full_control rights" do
+ # deny is an ACE with full rights, but is a deny type ace, not an allow type
+ resource.deny_rights(:full_control, "Guest")
+ resource.run_action(:create)
+ expect(explicit_aces).to eq(denied_acl(SID.Guest, expected_full_control_perms))
+ end
+
+ it "deny_rights ahead of rights" do
+ resource.rights(:read, "Everyone")
+ resource.deny_rights(:modify, "Guest")
+ resource.run_action(:create)
+
+ expect(explicit_aces).to eq(
+ denied_acl(SID.Guest, expected_modify_perms) +
+ allowed_acl(SID.Everyone, expected_read_perms)
+ )
+ end
+
+ it "deny_rights ahead of rights when specified in reverse order" do
+ resource.deny_rights(:modify, "Guest")
+ resource.rights(:read, "Everyone")
+ resource.run_action(:create)
+
+ expect(explicit_aces).to eq(
+ denied_acl(SID.Guest, expected_modify_perms) +
+ allowed_acl(SID.Everyone, expected_read_perms)
+ )
+ end
end
-
end
context "with a mode attribute" do
diff --git a/spec/support/shared/integration/integration_helper.rb b/spec/support/shared/integration/integration_helper.rb
index b6851f2d0e..5fc9de4de7 100644
--- a/spec/support/shared/integration/integration_helper.rb
+++ b/spec/support/shared/integration/integration_helper.rb
@@ -19,7 +19,6 @@
require "tmpdir"
require "fileutils"
-require "chef_core/text"
require "chef/config"
require "chef/json_compat"
require "chef/server_api"
diff --git a/spec/unit/knife/bootstrap/train_connector_spec.rb b/spec/unit/knife/bootstrap/train_connector_spec.rb
new file mode 100644
index 0000000000..08bf21dd42
--- /dev/null
+++ b/spec/unit/knife/bootstrap/train_connector_spec.rb
@@ -0,0 +1,155 @@
+#
+# Copyright:: Copyright (c) 2019 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"
+require "ostruct"
+require "chef/knife/bootstrap/train_connector"
+
+describe Chef::Knife::Bootstrap::TrainConnector do
+ let(:protocol) { "mock" }
+ let(:family) { "unknown" }
+ let(:release) { "unknown" } # version
+ let(:name) { "unknown" }
+ let(:arch) { "x86_64" }
+ let(:host_url) { "mock://user1@example.com" }
+ let(:opts) { {} }
+ subject do
+ # Create a valid TargetHost with the backend stubbed out.
+ Chef::Knife::Bootstrap::TrainConnector.test_instance(host_url,
+ protocol: protocol,
+ family: family,
+ name: name,
+ release: release,
+ arch: arch,
+ opts: opts)
+ end
+
+ context "connect!" do
+ end
+
+ describe "platform helpers" do
+ context "on linux" do
+ let(:family) { "debian" }
+ let(:name) { "ubuntu" }
+ it "reports that it is linux and unix, because that is how train classifies it" do
+ expect(subject.unix?).to eq true
+ expect(subject.linux?).to eq true
+ expect(subject.windows?).to eq false
+ end
+ end
+ context "on unix" do
+ let(:family) { "os" }
+ let(:name) { "mac_os_x" }
+ it "reports only a unix OS" do
+ expect(subject.unix?).to eq true
+ expect(subject.linux?).to eq false
+ expect(subject.windows?).to eq false
+ end
+ end
+ context "on windows" do
+ let(:family) { "windows" }
+ let(:name) { "windows" }
+ it "reports only a windows OS" do
+ expect(subject.unix?).to eq false
+ expect(subject.linux?).to eq false
+ expect(subject.windows?).to eq true
+ end
+ end
+ end
+
+ describe "#connect!" do
+ it "establishes the connection to the remote host by waiting for it" do
+ expect(subject.connection).to receive(:wait_until_ready)
+ subject.connect!
+ end
+ end
+
+ describe "#temp_dir" do
+ context "under windows" do
+ let(:family) { "windows" }
+ let(:name) { "windows" }
+
+ it "uses the windows command to create the temp dir" do
+ expected_command = Chef::Knife::Bootstrap::TrainConnector::MKTEMP_WIN_COMMAND
+ expect(subject).to receive(:run_command!).with(expected_command)
+ .and_return double("result", stdout: "C:/a/path")
+ expect(subject.temp_dir).to eq "C:/a/path"
+ end
+
+ end
+ context "under linux and unix-like" do
+ let(:family) { "debian" }
+ let(:name) { "ubuntu" }
+ it "uses the *nix command to create the temp dir and sets ownership to logged-in user" do
+ expected_command = Chef::Knife::Bootstrap::TrainConnector::MKTEMP_NIX_COMMAND
+ expect(subject).to receive(:run_command!).with(expected_command)
+ .and_return double("result", stdout: "/a/path")
+ expect(subject).to receive(:run_command!).with("chown user1 '/a/path'")
+ expect(subject.temp_dir).to eq "/a/path"
+ end
+
+ end
+ end
+ context "#upload_file_content!" do
+ it "creates a local file with expected content and uploads it" do
+ expect(subject).to receive(:upload_file!) do |local_path, remote_path|
+ expect(File.read(local_path)).to eq "test data"
+ expect(remote_path).to eq "/target/path"
+ end
+ subject.upload_file_content!("test data", "/target/path")
+ end
+ end
+
+ context "del_file" do
+ context "on windows" do
+ let(:family) { "windows" }
+ let(:name) { "windows" }
+ it "deletes the file with a windows command" do
+ expect(subject).to receive(:run_command!) do |cmd, &_handler|
+ expect(cmd).to match(/Test-Path "deleteme\.txt".*/)
+ end
+ subject.del_file!("deleteme.txt")
+ end
+ end
+ context "on unix-like" do
+ let(:family) { "debian" }
+ let(:name) { "ubuntu" }
+ it "deletes the file with a windows command" do
+ expect(subject).to receive(:run_command!) do |cmd, &_handler|
+ expect(cmd).to match(/rm -f "deleteme\.txt".*/)
+ end
+ subject.del_file!("deleteme.txt")
+ end
+ end
+ end
+
+ context "#run_command!" do
+ it "raises a RemoteExecutionFailed when the remote execution failed" do
+ command_result = double("results", stdout: "", stderr: "failed", exit_status: 1)
+ expect(subject).to receive(:run_command).and_return command_result
+
+ expect { subject.run_command!("test") }.to raise_error do |e|
+ expect(e.hostname).to eq subject.hostname
+ expect(e.class).to eq Chef::Knife::Bootstrap::RemoteExecutionFailed
+ expect(e.stderr).to eq "failed"
+ expect(e.stdout).to eq ""
+ expect(e.exit_status).to eq 1
+ end
+ end
+ end
+
+end
diff --git a/spec/unit/knife/bootstrap_spec.rb b/spec/unit/knife/bootstrap_spec.rb
index f54c8ac1d6..ce590fc9ee 100644
--- a/spec/unit/knife/bootstrap_spec.rb
+++ b/spec/unit/knife/bootstrap_spec.rb
@@ -25,8 +25,17 @@ describe Chef::Knife::Bootstrap do
let(:bootstrap_template) { nil }
let(:stderr) { StringIO.new }
let(:bootstrap_cli_options) { [ ] }
- let(:base_os) { :linux }
- let(:target_host) { double("TargetHost") }
+ let(:linux_test) { true }
+ let(:windows_test) { false }
+ let(:linux_test) { false }
+ let(:unix_test) { false }
+ let(:ssh_test) { false }
+
+ let(:connection) do
+ double("TrainConnector",
+ windows?: windows_test,
+ linux?: linux_test,
+ unix?: unix_test) end
let(:knife) do
Chef::Log.logger = Logger.new(StringIO.new)
@@ -35,15 +44,11 @@ describe Chef::Knife::Bootstrap do
k = Chef::Knife::Bootstrap.new(bootstrap_cli_options)
allow(k.ui).to receive(:stderr).and_return(stderr)
allow(k).to receive(:encryption_secret_provided_ignore_encrypt_flag?).and_return(false)
- allow(k).to receive(:target_host).and_return target_host
+ allow(k).to receive(:connection).and_return connection
k.merge_configs
k
end
- before do
- allow(target_host).to receive(:base_os).and_return base_os
- end
-
context "#bootstrap_template" do
it "should default to chef-full" do
expect(knife.bootstrap_template).to be_a_kind_of(String)
@@ -320,7 +325,7 @@ describe Chef::Knife::Bootstrap do
subject(:knife) do
k = described_class.new
Chef::Config[:knife][:bootstrap_template] = template_file
- allow(k).to receive(:target_host).and_return target_host
+ allow(k).to receive(:connection).and_return connection
k.parse_options(options)
k.merge_configs
k
@@ -1578,7 +1583,7 @@ describe Chef::Knife::Bootstrap do
expect(knife).to receive(:render_template).and_return "content"
expect(knife).to receive(:upload_bootstrap).with("content").and_return "/remote/path.sh"
expect(knife).to receive(:perform_bootstrap).with("/remote/path.sh")
- expect(target_host).to receive(:del_file) # Make sure cleanup happens
+ expect(connection).to receive(:del_file!) # Make sure cleanup happens
knife.run
@@ -1687,14 +1692,14 @@ describe Chef::Knife::Bootstrap do
let(:result_mock) { double("result", exit_status: exit_status, stderr: "A message") }
before do
- allow(target_host).to receive(:hostname).and_return "testhost"
+ allow(connection).to receive(:hostname).and_return "testhost"
end
it "runs the remote script and logs the output" do
expect(knife.ui).to receive(:info).with(/Bootstrapping.*/)
expect(knife).to receive(:bootstrap_command)
.with("/path.sh")
.and_return("sh /path.sh")
- expect(target_host)
+ expect(connection)
.to receive(:run_command)
.with("sh /path.sh")
.and_yield("output here")
@@ -1710,7 +1715,7 @@ describe Chef::Knife::Bootstrap do
expect(knife).to receive(:bootstrap_command)
.with("/path.sh")
.and_return("sh /path.sh")
- expect(target_host).to receive(:run_command).with("sh /path.sh").and_return result_mock
+ expect(connection).to receive(:run_command).with("sh /path.sh").and_return result_mock
expect { knife.perform_bootstrap("/path.sh") }.to raise_error(SystemExit)
end
end
@@ -1738,13 +1743,11 @@ describe Chef::Knife::Bootstrap do
context "when an auth failure occurs" do
let(:expected_error) do
- # TODO This is awkward and ugly. Requires some refactor of chef_core/error
- # to make it not so. See comment in rescue block of connect! for details.
- e = RuntimeError.new
- interim = RuntimeError.new
+ e = Train::Error.new
actual = Net::SSH::AuthenticationFailed.new
- allow(interim).to receive(:cause).and_return(actual)
- allow(e).to receive(:cause).and_return(interim)
+ # Simulate train's nested error - they wrap
+ # ssh/network errors in a TrainError.
+ allow(e).to receive(:cause).and_return(actual)
e
end
@@ -1754,7 +1757,7 @@ describe Chef::Knife::Bootstrap do
context "and password auth was used" do
before do
- knife.config[:connection_password] = "tryme"
+ allow(connection).to receive(:password_auth?).and_return true
end
it "re-raises the error so as not to resubmit the same failing password" do
@@ -1765,8 +1768,8 @@ describe Chef::Knife::Bootstrap do
context "and password auth was not used" do
before do
- knife.config.delete :connection_password
- allow(target_host).to receive(:user).and_return "testuser"
+ allow(connection).to receive(:password_auth?).and_return false
+ allow(connection).to receive(:user).and_return "testuser"
end
it "warns, prompts for password, then reconnects with a password-enabled configuration using the new password" do
@@ -1793,7 +1796,7 @@ describe Chef::Knife::Bootstrap do
describe "#bootstrap_context" do
context "under Windows" do
- let(:base_os) { :windows }
+ let(:windows_test) { true }
it "creates a WindowsBootstrapContext" do
require "chef/knife/core/windows_bootstrap_context"
expect(knife.bootstrap_context.class).to eq Chef::Knife::Core::WindowsBootstrapContext
@@ -1801,7 +1804,7 @@ describe Chef::Knife::Bootstrap do
end
context "under linux" do
- let(:base_os) { :linux }
+ let(:linux_test) { true }
it "creates a BootstrapContext" do
require "chef/knife/core/bootstrap_context"
expect(knife.bootstrap_context.class).to eq Chef::Knife::Core::BootstrapContext
@@ -1841,25 +1844,25 @@ describe Chef::Knife::Bootstrap do
describe "#upload_bootstrap" do
before do
- allow(target_host).to receive(:temp_dir).and_return(temp_dir)
- allow(target_host).to receive(:normalize_path) { |a| a }
+ allow(connection).to receive(:temp_dir).and_return(temp_dir)
+ allow(connection).to receive(:normalize_path) { |a| a }
end
let(:content) { "bootstrap script content" }
context "under Windows" do
- let(:base_os) { :windows }
+ let(:windows_test) { true }
let(:temp_dir) { "C:/Temp/bootstrap" }
- it "creates a bat file in the temp dir provided by target_host, using given content" do
- expect(target_host).to receive(:save_as_remote_file).with(content, "C:/Temp/bootstrap/bootstrap.bat")
+ it "creates a bat file in the temp dir provided by connection, using given content" do
+ expect(connection).to receive(:upload_file_content!).with(content, "C:/Temp/bootstrap/bootstrap.bat")
expect(knife.upload_bootstrap(content)).to eq "C:/Temp/bootstrap/bootstrap.bat"
end
end
context "under Linux" do
- let(:base_os) { :linux }
+ let(:linux_test) { true }
let(:temp_dir) { "/tmp/bootstrap" }
- it "creates a 'sh file in the temp dir provided by target_host, using given content" do
- expect(target_host).to receive(:save_as_remote_file).with(content, "/tmp/bootstrap/bootstrap.sh")
+ it "creates a 'sh file in the temp dir provided by connection, using given content" do
+ expect(connection).to receive(:upload_file_content!).with(content, "/tmp/bootstrap/bootstrap.sh")
expect(knife.upload_bootstrap(content)).to eq "/tmp/bootstrap/bootstrap.sh"
end
end
@@ -1867,14 +1870,14 @@ describe Chef::Knife::Bootstrap do
describe "#bootstrap_command" do
context "under Windows" do
- let(:base_os) { :windows }
+ let(:windows_test) { true }
it "prefixes the command to run under cmd.exe" do
expect(knife.bootstrap_command("autoexec.bat")).to eq "cmd.exe /C autoexec.bat"
end
end
context "under Linux" do
- let(:base_os) { :linux }
+ let(:linux_test) { true }
it "prefixes the command to run under sh" do
expect(knife.bootstrap_command("bootstrap")).to eq "sh bootstrap"
end
@@ -1883,14 +1886,14 @@ describe Chef::Knife::Bootstrap do
describe "#default_bootstrap_template" do
context "under Windows" do
- let(:base_os) { :windows }
+ let(:windows_test) { true }
it "is windows-chef-client-msi" do
expect(knife.default_bootstrap_template).to eq "windows-chef-client-msi"
end
end
context "under Linux" do
- let(:base_os) { :linux }
+ let(:linux_test) { true }
it "is chef-full" do
expect(knife.default_bootstrap_template).to eq "chef-full"
end
@@ -1899,15 +1902,15 @@ describe Chef::Knife::Bootstrap do
describe "#do_connect" do
let(:host_descriptor) { "example.com" }
- let(:target_host) { double("TargetHost") }
- let(:resolver_mock) { double("TargetResolver", targets: [ target_host ]) }
+ let(:connection) { double("TrainConnector") }
+ let(:connector_mock) { double("TargetResolver", targets: [ connection ]) }
before do
allow(knife).to receive(:host_descriptor).and_return host_descriptor
end
- it "resolves the target and connects it" do
- expect(ChefCore::TargetResolver).to receive(:new).and_return resolver_mock
- expect(target_host).to receive(:connect!)
+ it "creates a TrainConnector and connects it" do
+ expect(Chef::Knife::Bootstrap::TrainConnector).to receive(:new).and_return connection
+ expect(connection).to receive(:connect!)
knife.do_connect({})
end
end
diff --git a/spec/unit/resource/windows_task_spec.rb b/spec/unit/resource/windows_task_spec.rb
index 96482d3d56..b152d879f6 100644
--- a/spec/unit/resource/windows_task_spec.rb
+++ b/spec/unit/resource/windows_task_spec.rb
@@ -61,6 +61,10 @@ describe Chef::Resource::WindowsTask, :windows_only do
expect(resource.stop_if_going_on_batteries).to eql(false)
end
+ it "sets the default value for start_when_available as false" do
+ expect(resource.start_when_available).to eql(false)
+ end
+
context "when frequency is not provided" do
it "raises ArgumentError to provide frequency" do
expect { resource.after_created }.to raise_error(ArgumentError, "Frequency needs to be provided. Valid frequencies are :minute, :hourly, :daily, :weekly, :monthly, :once, :on_logon, :onstart, :on_idle, :none." )