summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.expeditor/config.yml14
-rwxr-xr-x.expeditor/update_version.sh1
-rw-r--r--.github/PULL_REQUEST_TEMPLATE.md16
-rw-r--r--.gitignore6
-rw-r--r--CHANGELOG.md10
-rw-r--r--Gemfile1
-rw-r--r--Gemfile.lock67
-rw-r--r--README.md4
-rw-r--r--Rakefile7
-rw-r--r--VERSION2
-rw-r--r--chef-bin/.rspec2
-rw-r--r--chef-bin/Gemfile4
-rw-r--r--chef-bin/LICENSE201
-rw-r--r--chef-bin/Rakefile15
-rwxr-xr-xchef-bin/bin/chef-apply (renamed from bin/chef-apply)0
-rwxr-xr-xchef-bin/bin/chef-client (renamed from bin/chef-client)0
-rwxr-xr-xchef-bin/bin/chef-resource-inspector (renamed from bin/chef-resource-inspector)0
-rwxr-xr-xchef-bin/bin/chef-service-manager (renamed from bin/chef-service-manager)0
-rwxr-xr-xchef-bin/bin/chef-shell (renamed from bin/chef-shell)0
-rwxr-xr-xchef-bin/bin/chef-solo (renamed from bin/chef-solo)0
-rwxr-xr-xchef-bin/bin/chef-windows-service (renamed from bin/chef-windows-service)0
-rw-r--r--chef-bin/chef-bin.gemspec26
-rw-r--r--chef-bin/lib/chef-bin.rb20
-rw-r--r--chef-bin/lib/chef-bin/version.rb34
-rw-r--r--chef-config/lib/chef-config/version.rb2
-rw-r--r--chef.gemspec4
-rw-r--r--kitchen-tests/kitchen.yml2
-rw-r--r--lib/chef.rb12
-rw-r--r--lib/chef/knife/bootstrap.rb104
-rw-r--r--lib/chef/knife/bootstrap/train_connector.rb286
-rw-r--r--lib/chef/knife/core/bootstrap_context.rb2
-rw-r--r--lib/chef/knife/core/windows_bootstrap_context.rb1
-rw-r--r--lib/chef/version.rb2
-rw-r--r--omnibus/Gemfile.lock49
-rw-r--r--spec/functional/shell_spec.rb5
-rw-r--r--spec/functional/version_spec.rb4
-rw-r--r--spec/integration/client/client_spec.rb22
-rw-r--r--spec/integration/client/exit_code_spec.rb2
-rw-r--r--spec/integration/client/ipv6_spec.rb4
-rw-r--r--spec/integration/recipes/accumulator_spec.rb2
-rw-r--r--spec/integration/recipes/lwrp_inline_resources_spec.rb2
-rw-r--r--spec/integration/recipes/lwrp_spec.rb2
-rw-r--r--spec/integration/recipes/notifies_spec.rb2
-rw-r--r--spec/integration/recipes/notifying_block_spec.rb4
-rw-r--r--spec/integration/recipes/remote_directory.rb2
-rw-r--r--spec/integration/solo/solo_spec.rb4
-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/knife/core/bootstrap_context_spec.rb12
-rw-r--r--spec/unit/knife/core/windows_bootstrap_context_spec.rb8
51 files changed, 961 insertions, 247 deletions
diff --git a/.expeditor/config.yml b/.expeditor/config.yml
index 1ce2a6c964..5a6d9a57ac 100644
--- a/.expeditor/config.yml
+++ b/.expeditor/config.yml
@@ -1,5 +1,5 @@
# Documentation available at https://expeditor.chef.io/docs/getting-started/
-
+---
# the name we use for this project when interacting with expeditor chatbot
project:
alias: chef-15
@@ -11,13 +11,14 @@ product_key:
# Slack channel in Chef Software slack to send notifications about build failures, etc
slack:
- notify_channel: chef-notify
+ notify_channel: chef-infra-notify
# Which Ruby Gems, built when the Omnibus package is built, to publish to rubygems.org
# This publish is triggered by the `built_in:publish_rubygems` artifact_action.
rubygems:
- chef
- chef-config
+ - chef-bin
docker_images:
- chef
@@ -33,12 +34,6 @@ pipelines:
- ADHOC: true
github:
- # The file where the MAJOR.MINOR.PATCH version is kept. The version in this file
- # is bumped automatically via the `built_in:bump_version` merge_action.
- version_file: "VERSION"
- # The file where our CHANGELOG is kept. This file is updated automatically with
- # details from the Pull Request via the `built_in:update_changelog` merge_action.
- changelog_file: "CHANGELOG.md"
# This deletes the GitHub PR branch after successfully merged into the release branch
delete_branch_on_merge: true
# The tag format to use (e.g. v1.0.0)
@@ -58,6 +53,9 @@ github:
- chef-14:
version_constraint: 14*
+changelog:
+ rollup_header: Changes not yet released to rubygems.org
+
# These actions are taken, in order they are specified, anytime a Pull Request is merged.
merge_actions:
- built_in:bump_version:
diff --git a/.expeditor/update_version.sh b/.expeditor/update_version.sh
index e058d06f06..85f7340811 100755
--- a/.expeditor/update_version.sh
+++ b/.expeditor/update_version.sh
@@ -12,6 +12,7 @@
set -evx
sed -i -r "s/^(\s*)VERSION = \".+\"/\1VERSION = \"$(cat VERSION)\"/" chef-config/lib/chef-config/version.rb
+sed -i -r "s/^(\s*)VERSION = \".+\"/\1VERSION = \"$(cat VERSION)\"/" chef-bin/lib/chef-bin/version.rb
sed -i -r "s/VersionString\.new\(\".+\"\)/VersionString.new(\"$(cat VERSION)\")/" lib/chef/version.rb
# Update the version inside Gemfile.lock
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
deleted file mode 100644
index ac0fc52309..0000000000
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ /dev/null
@@ -1,16 +0,0 @@
-### Description
-
-[Please describe what this change achieves]
-
-### Issues Resolved
-
-[List any existing issues this PR resolves, or any Discourse or
-StackOverflow discussions that are relevant]
-
-### Check List
-
-- [ ] New functionality includes tests
-- [ ] All tests pass
-- [ ] RELEASE\_NOTES.md has been updated if required (not required for bugfixes, required for API changes)
-- [ ] All commits have been signed-off for the Developer Certificate of Origin. See <https://github.com/chef/chef/blob/master/CONTRIBUTING.md#developer-certification-of-origin-dco>
-- [ ] PR title is a worthy inclusion in the CHANGELOG \ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 200db3afc5..d88442ba7c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -62,3 +62,9 @@ nodes/
# chef-config
chef-config/.bundle
chef-config/Gemfile.lock
+chef-config/pkg
+
+# chef-bin
+chef-bin/.bundle
+chef-bin/Gemfile.lock
+chef-bin/pkg
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 92b1270b55..a60bc5fb85 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.237 -->
-## [v15.0.237](https://github.com/chef/chef/tree/v15.0.237) (2019-04-29)
+<!-- latest_release 15.0.241 -->
+## [v15.0.241](https://github.com/chef/chef/tree/v15.0.241) (2019-04-30)
#### Merged Pull Requests
-- &quot;chef-client&quot; =&gt; #{Chef::Dist::CLIENT} [#8418](https://github.com/chef/chef/pull/8418) ([bobchaos](https://github.com/bobchaos))
+- Update InSpec preview to 4.2.0 [#8426](https://github.com/chef/chef/pull/8426) ([tas50](https://github.com/tas50))
<!-- latest_release -->
<!-- release_rollup -->
### Changes since latest stable release
#### Merged Pull Requests
+- Update InSpec preview to 4.2.0 [#8426](https://github.com/chef/chef/pull/8426) ([tas50](https://github.com/tas50)) <!-- 15.0.241 -->
+- Remove chef-* bin files from chef gem [#8413](https://github.com/chef/chef/pull/8413) ([lamont-granquist](https://github.com/lamont-granquist)) <!-- 15.0.240 -->
+- Enable license acceptance during bootstrap [#8411](https://github.com/chef/chef/pull/8411) ([marcparadise](https://github.com/marcparadise)) <!-- 15.0.239 -->
+- Implement bootstrap directly with train [#8419](https://github.com/chef/chef/pull/8419) ([marcparadise](https://github.com/marcparadise)) <!-- 15.0.238 -->
- &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 -->
diff --git a/Gemfile b/Gemfile
index 6abe88b86e..71a3efd2a8 100644
--- a/Gemfile
+++ b/Gemfile
@@ -11,6 +11,7 @@ gem "chef", path: "."
gem "ohai", git: "https://github.com/chef/ohai.git", branch: "master"
gem "chef-config", path: File.expand_path("../chef-config", __FILE__) if File.exist?(File.expand_path("../chef-config", __FILE__))
+gem "chef-bin", path: File.expand_path("../chef-bin", __FILE__) if File.exist?(File.expand_path("../chef-bin", __FILE__))
gem "cheffish", "~> 14"
group(:omnibus_package) do
diff --git a/Gemfile.lock b/Gemfile.lock
index 82c2fed634..070787e6c4 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.237)
+ chef (15.0.241)
addressable
bcrypt_pbkdf (~> 1.0)
bundler (>= 1.10)
- chef-config (= 15.0.237)
- chef-core (~> 0.0.3)
+ chef-config (= 15.0.241)
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.237-universal-mingw32)
+ chef (15.0.241-universal-mingw32)
addressable
bcrypt_pbkdf (~> 1.0)
bundler (>= 1.10)
- chef-config (= 15.0.237)
- chef-core (~> 0.0.3)
+ chef-config (= 15.0.241)
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)
@@ -99,9 +99,15 @@ PATH
wmi-lite (~> 1.0)
PATH
+ remote: chef-bin
+ specs:
+ chef-bin (15.0.241)
+ chef (= 15.0.241)
+
+PATH
remote: chef-config
specs:
- chef-config (15.0.237)
+ chef-config (15.0.241)
addressable
fuzzyurl
mixlib-config (>= 2.2.12, < 4.0)
@@ -113,7 +119,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 +130,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 +141,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,18 +171,9 @@ 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)
+ inspec-core (4.2.0.preview)
addressable (~> 2.4)
faraday (>= 0.9.0)
faraday_middleware (~> 0.12.2)
@@ -223,7 +203,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 +244,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 +266,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 +352,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 +389,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)
@@ -444,6 +416,7 @@ DEPENDENCIES
appbundler
bcrypt_pbkdf
chef!
+ chef-bin!
chef-config!
chef-vault
cheffish (~> 14)
diff --git a/README.md b/README.md
index 1dabeb23cc..638784f169 100644
--- a/README.md
+++ b/README.md
@@ -9,9 +9,9 @@
**Project State**: [Active](https://github.com/chef/chef-oss-practices/blob/master/repo-management/repo-states.md#active)
-**Issues Response SLA**: 10 business days
+**Issues [Response Time Maximum](https://github.com/chef/chef-oss-practices/blob/master/repo-management/repo-states.md)**: 14 days
-**Pull Request Response SLA**: 10 business days
+**Pull Request [Response Time Maximum](https://github.com/chef/chef-oss-practices/blob/master/repo-management/repo-states.md)**: 14 days
## Getting Started
diff --git a/Rakefile b/Rakefile
index e0aac6170f..d9c3c397da 100644
--- a/Rakefile
+++ b/Rakefile
@@ -34,6 +34,13 @@ task install: :super_install
gemspec = Gem.win_platform? ? "chef-universal-mingw32" : "chef"
Bundler::GemHelper.install_tasks name: gemspec
+# this gets appended to the normal bundler install helper
+task :install do
+ chef_bin_path = ::File.join(::File.dirname(__FILE__), "chef-bin")
+ Dir.chdir(chef_bin_path)
+ sh("rake install:force")
+end
+
task :pedant, :chef_zero_spec
task :build_eventlog do
diff --git a/VERSION b/VERSION
index 7d209f5916..b9143acc25 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-15.0.237 \ No newline at end of file
+15.0.241 \ No newline at end of file
diff --git a/chef-bin/.rspec b/chef-bin/.rspec
new file mode 100644
index 0000000000..eb3ef03653
--- /dev/null
+++ b/chef-bin/.rspec
@@ -0,0 +1,2 @@
+--color
+-fd
diff --git a/chef-bin/Gemfile b/chef-bin/Gemfile
new file mode 100644
index 0000000000..96ab544690
--- /dev/null
+++ b/chef-bin/Gemfile
@@ -0,0 +1,4 @@
+source "https://rubygems.org"
+
+# Specify your gem's dependencies in chef-config.gemspec
+gemspec
diff --git a/chef-bin/LICENSE b/chef-bin/LICENSE
new file mode 100644
index 0000000000..11069edd79
--- /dev/null
+++ b/chef-bin/LICENSE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+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.
diff --git a/chef-bin/Rakefile b/chef-bin/Rakefile
new file mode 100644
index 0000000000..5626d1bc5d
--- /dev/null
+++ b/chef-bin/Rakefile
@@ -0,0 +1,15 @@
+# we need to force the install in order to overwrite the binstubs from
+# old chef gems.
+
+Bundler::GemHelper.install_tasks
+
+# this is necessary to use to overwrite any chef-14 or earlier era gem which has the bin files in
+# the chef gem itself
+desc "force install the chef-bin gem"
+task "install:force" do
+ sh "gem build -V chef-bin.gemspec"
+ built_gem_path = Dir["chef-bin-*.gem"].sort_by { |f| File.mtime(f) }.last
+ FileUtils.mkdir_p("pkg") unless Dir.exist?("pkg")
+ FileUtils.mv(built_gem_path, "pkg")
+ sh "gem install -f pkg/#{built_gem_path}"
+end
diff --git a/bin/chef-apply b/chef-bin/bin/chef-apply
index ddbdc66907..ddbdc66907 100755
--- a/bin/chef-apply
+++ b/chef-bin/bin/chef-apply
diff --git a/bin/chef-client b/chef-bin/bin/chef-client
index af27d7903d..af27d7903d 100755
--- a/bin/chef-client
+++ b/chef-bin/bin/chef-client
diff --git a/bin/chef-resource-inspector b/chef-bin/bin/chef-resource-inspector
index 6a7eac0c32..6a7eac0c32 100755
--- a/bin/chef-resource-inspector
+++ b/chef-bin/bin/chef-resource-inspector
diff --git a/bin/chef-service-manager b/chef-bin/bin/chef-service-manager
index 9021824fed..9021824fed 100755
--- a/bin/chef-service-manager
+++ b/chef-bin/bin/chef-service-manager
diff --git a/bin/chef-shell b/chef-bin/bin/chef-shell
index 666ce1944c..666ce1944c 100755
--- a/bin/chef-shell
+++ b/chef-bin/bin/chef-shell
diff --git a/bin/chef-solo b/chef-bin/bin/chef-solo
index 06c0452d26..06c0452d26 100755
--- a/bin/chef-solo
+++ b/chef-bin/bin/chef-solo
diff --git a/bin/chef-windows-service b/chef-bin/bin/chef-windows-service
index 646e3b4a93..646e3b4a93 100755
--- a/bin/chef-windows-service
+++ b/chef-bin/bin/chef-windows-service
diff --git a/chef-bin/chef-bin.gemspec b/chef-bin/chef-bin.gemspec
new file mode 100644
index 0000000000..66d14f3f52
--- /dev/null
+++ b/chef-bin/chef-bin.gemspec
@@ -0,0 +1,26 @@
+# coding: utf-8
+lib = File.expand_path("../lib", __FILE__)
+$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
+require "chef-bin/version"
+
+Gem::Specification.new do |spec|
+ spec.name = "chef-bin"
+ spec.version = ChefBin::VERSION
+ spec.authors = ["Adam Jacob"]
+ spec.email = ["adam@chef.io"]
+
+ spec.summary = %q{Chef-branded binstubs for chef-client}
+ spec.homepage = "https://github.com/chef/chef"
+ spec.license = "Apache-2.0"
+
+ spec.require_paths = ["lib"]
+
+ spec.add_dependency "chef", "= #{ChefBin::VERSION}"
+ spec.add_development_dependency "rake"
+
+ spec.files = %w{Gemfile Rakefile LICENSE} + Dir.glob("*.gemspec") +
+ Dir.glob("{lib}/**/*", File::FNM_DOTMATCH).reject { |f| File.directory?(f) }
+
+ spec.bindir = "bin"
+ spec.executables = %w{ chef-apply chef-client chef-resource-inspector chef-service-manager chef-shell chef-solo chef-windows-service }
+end
diff --git a/chef-bin/lib/chef-bin.rb b/chef-bin/lib/chef-bin.rb
new file mode 100644
index 0000000000..b40bf9fa11
--- /dev/null
+++ b/chef-bin/lib/chef-bin.rb
@@ -0,0 +1,20 @@
+#
+# Copyright:: Copyright 2015-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.
+#
+
+module ChefBin
+
+end
diff --git a/chef-bin/lib/chef-bin/version.rb b/chef-bin/lib/chef-bin/version.rb
new file mode 100644
index 0000000000..10092ec457
--- /dev/null
+++ b/chef-bin/lib/chef-bin/version.rb
@@ -0,0 +1,34 @@
+# Copyright:: Copyright 2010-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.
+
+# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+# NOTE: This file is generated by running `rake version` in the top level of
+# this repo. Do not edit this manually. Edit the VERSION file and run the rake
+# task instead.
+# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+module ChefBin
+ CHEFBIN_ROOT = File.expand_path("../..", __FILE__)
+ VERSION = "15.0.241".freeze
+end
+
+#
+# NOTE: the Chef::Version class is defined in version_class.rb
+#
+# NOTE: DO NOT Use the Chef::Version class on ChefConfig::VERSIONs. The
+# Chef::Version class is for _cookbooks_ only, and cannot handle
+# pre-release versions like "10.14.0.rc.2". Please use Rubygem's
+# Gem::Version class instead.
+#
diff --git a/chef-config/lib/chef-config/version.rb b/chef-config/lib/chef-config/version.rb
index 1673164441..daa191398d 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.237".freeze
+ VERSION = "15.0.241".freeze
end
#
diff --git a/chef.gemspec b/chef.gemspec
index 32e12bad41..ebd6d192bb 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"
@@ -51,7 +51,7 @@ Gem::Specification.new do |s|
s.add_dependency "bundler", ">= 1.10"
s.bindir = "bin"
- s.executables = %w{ chef-client chef-solo knife chef-shell chef-apply chef-resource-inspector }
+ s.executables = %w{ knife }
s.require_paths = %w{ lib }
s.files = %w{Gemfile Rakefile LICENSE README.md} + Dir.glob("{lib,tasks,spec}/**/*", File::FNM_DOTMATCH).reject { |f| File.directory?(f) } + Dir.glob("*.gemspec")
diff --git a/kitchen-tests/kitchen.yml b/kitchen-tests/kitchen.yml
index 6de7be8ebd..5fe3b8540f 100644
--- a/kitchen-tests/kitchen.yml
+++ b/kitchen-tests/kitchen.yml
@@ -15,7 +15,7 @@ provisioner:
lifecycle:
pre_converge:
- - remote: /opt/chef/embedded/bin/gem install appbundle-updater
+ - remote: /opt/chef/embedded/bin/gem install appbundler appbundle-updater
- remote: /opt/chef/embedded/bin/appbundle-updater chef ohai <%= File.readlines('../Gemfile.lock', File.expand_path(File.dirname(__FILE__))).find { |l| l =~ /^\s+ohai \((\d+\.\d+\.\d+)\)/ }; 'v' + $1 %> --tarball --github chef/ohai
- remote: /opt/chef/embedded/bin/appbundle-updater chef chef <%= ENV['TRAVIS_COMMIT'] || %x(git rev-parse HEAD).chomp %> --tarball --github chef/chef
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/knife/bootstrap.rb b/lib/chef/knife/bootstrap.rb
index daca0957d4..d46bf455e9 100644
--- a/lib/chef/knife/bootstrap.rb
+++ b/lib/chef/knife/bootstrap.rb
@@ -18,11 +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"
-require "chef/dist"
class Chef
class Knife
@@ -387,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)"
@@ -417,7 +414,7 @@ class Chef
#
# @return [String] Default bootstrap template
def default_bootstrap_template
- if target_host.base_os == :windows
+ if connection.windows?
"windows-#{Chef::Dist::CLIENT}-msi"
else
"chef-full"
@@ -482,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
@@ -556,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])))
@@ -589,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}:")
@@ -603,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
@@ -631,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
@@ -640,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
@@ -664,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" &&
@@ -739,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
@@ -768,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 = {}
@@ -788,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,
@@ -807,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 }
@@ -959,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}"
@@ -977,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/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 5e987745e6..dcca7b8a69 100644
--- a/lib/chef/knife/core/bootstrap_context.rb
+++ b/lib/chef/knife/core/bootstrap_context.rb
@@ -171,7 +171,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::Dist::CLIENT}"
- s = "#{client_path} -j /etc/chef/first-boot.json"
+ s = "CHEF_LICENSE=accept #{client_path} -j /etc/chef/first-boot.json"
if @config[:verbosity] && @config[:verbosity] >= 3
s << " -l trace"
elsif @config[:verbosity] && @config[:verbosity] >= 2
diff --git a/lib/chef/knife/core/windows_bootstrap_context.rb b/lib/chef/knife/core/windows_bootstrap_context.rb
index df69399074..7aa4c012aa 100644
--- a/lib/chef/knife/core/windows_bootstrap_context.rb
+++ b/lib/chef/knife/core/windows_bootstrap_context.rb
@@ -154,6 +154,7 @@ class Chef
def start_chef
bootstrap_environment_option = bootstrap_environment.nil? ? "" : " -E #{bootstrap_environment}"
start_chef = "SET \"PATH=%SystemRoot%\\system32;%SystemRoot%;%SystemRoot%\\System32\\Wbem;%SYSTEMROOT%\\System32\\WindowsPowerShell\\v1.0\\;C:\\ruby\\bin;C:\\opscode\\chef\\bin;C:\\opscode\\chef\\embedded\\bin\"\n"
+ start_chef << "SET \"CHEF_LICENSE=accept\"\n"
start_chef << "chef-client -c c:/chef/client.rb -j c:/chef/first-boot.json#{bootstrap_environment_option}\n"
end
diff --git a/lib/chef/version.rb b/lib/chef/version.rb
index 14ae1e880a..4ecb821286 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.237")
+ VERSION = Chef::VersionString.new("15.0.241")
end
#
diff --git a/omnibus/Gemfile.lock b/omnibus/Gemfile.lock
index db2232b90c..490531f84e 100644
--- a/omnibus/Gemfile.lock
+++ b/omnibus/Gemfile.lock
@@ -18,7 +18,7 @@ GIT
GIT
remote: https://github.com/chef/omnibus-software
- revision: 3d4327c0032b8cc7d25eb33290a7aec2fce20a2a
+ revision: e4553dad2f70aae8fee6b19689e8d8596b60bb0e
branch: master
specs:
omnibus-software (4.0.0)
@@ -31,9 +31,9 @@ GEM
addressable (2.5.2)
public_suffix (>= 2.0.2, < 4.0)
awesome_print (1.8.0)
- aws-eventstream (1.0.2)
- aws-partitions (1.151.0)
- aws-sdk-core (3.48.4)
+ aws-eventstream (1.0.3)
+ aws-partitions (1.155.0)
+ aws-sdk-core (3.48.6)
aws-eventstream (~> 1.0, >= 1.0.2)
aws-partitions (~> 1.0)
aws-sigv4 (~> 1.1)
@@ -154,6 +154,7 @@ GEM
concurrent-ruby (1.1.5)
diff-lcs (1.3)
ed25519 (1.2.4)
+ equatable (0.5.0)
erubis (2.7.0)
faraday (0.15.4)
multipart-post (>= 1.2, < 3)
@@ -180,6 +181,11 @@ GEM
kitchen-vagrant (1.5.1)
test-kitchen (>= 1.4, < 3)
libyajl2 (1.2.0)
+ license-acceptance (1.0.0)
+ pastel (~> 0.7)
+ tomlrb (~> 1.2)
+ tty-box (~> 0.3)
+ tty-prompt (~> 0.18)
license_scout (1.0.24)
ffi-yajl (~> 2.2)
mixlib-shellout (~> 2.2)
@@ -210,6 +216,7 @@ GEM
molinillo (0.6.6)
multi_json (1.13.1)
multipart-post (2.0.0)
+ necromancer (0.4.0)
net-scp (2.0.0)
net-ssh (>= 2.6.5, < 6.0.0)
net-sftp (2.1.2)
@@ -236,6 +243,9 @@ GEM
plist (~> 3.1)
systemu (~> 2.6.4)
wmi-lite (~> 1.0)
+ pastel (0.7.2)
+ equatable (~> 0.5.0)
+ tty-color (~> 0.4.0)
pedump (0.5.2)
awesome_print
iostruct (>= 0.0.4)
@@ -288,12 +298,18 @@ GEM
net-ssh (>= 2.7)
net-telnet (= 0.1.1)
sfl
+ strings (0.1.5)
+ strings-ansi (~> 0.1)
+ unicode-display_width (~> 1.5)
+ unicode_utils (~> 1.4)
+ strings-ansi (0.1.0)
structured_warnings (0.3.0)
syslog-logger (1.6.8)
systemu (2.6.5)
- test-kitchen (2.1.0)
+ test-kitchen (2.2.0)
bcrypt_pbkdf (~> 1.0)
ed25519 (~> 1.2)
+ license-acceptance (>= 0.2.16, < 2.0)
mixlib-install (~> 3.6)
mixlib-shellout (>= 1.2, < 3.0)
net-scp (>= 1.1, < 3.0)
@@ -304,9 +320,29 @@ GEM
winrm-elevated (~> 1.0)
winrm-fs (~> 1.1)
thor (0.20.3)
+ timers (4.3.0)
toml-rb (1.1.2)
citrus (~> 3.0, > 3.0)
tomlrb (1.2.8)
+ tty-box (0.3.0)
+ pastel (~> 0.7.2)
+ strings (~> 0.1.4)
+ tty-cursor (~> 0.6.0)
+ tty-color (0.4.3)
+ tty-cursor (0.6.1)
+ tty-prompt (0.18.1)
+ necromancer (~> 0.4.0)
+ pastel (~> 0.7.0)
+ timers (~> 4.0)
+ tty-cursor (~> 0.6.0)
+ tty-reader (~> 0.5.0)
+ tty-reader (0.5.0)
+ tty-cursor (~> 0.6.0)
+ tty-screen (~> 0.6.4)
+ wisper (~> 2.0.0)
+ tty-screen (0.6.5)
+ unicode-display_width (1.5.0)
+ unicode_utils (1.4.0)
uuidtools (2.1.5)
win32-api (1.5.3-universal-mingw32)
win32-certstore (0.3.0)
@@ -332,7 +368,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)
@@ -349,6 +385,7 @@ GEM
logging (>= 1.6.1, < 3.0)
rubyzip (~> 1.1)
winrm (~> 2.0)
+ wisper (2.0.0)
wmi-lite (1.0.2)
zhexdump (0.0.2)
diff --git a/spec/functional/shell_spec.rb b/spec/functional/shell_spec.rb
index 3990f1afe0..dd0455fc9e 100644
--- a/spec/functional/shell_spec.rb
+++ b/spec/functional/shell_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Daniel DeLeo (<dan@chef.io>)
-# Copyright:: Copyright 2012-2017, Chef Software Inc.
+# Copyright:: Copyright 2012-2019, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -82,8 +82,7 @@ describe Shell do
require "pty"
config = File.expand_path("shef-config.rb", CHEF_SPEC_DATA)
- path_to_chef_shell = File.expand_path("../../../bin/chef-shell", __FILE__)
- reader, writer, pid = PTY.spawn("#{path_to_chef_shell} -c #{config} #{options}")
+ reader, writer, pid = PTY.spawn("bundle exec chef-shell -c #{config} #{options}")
read_until(reader, "chef (#{Chef::VERSION})>")
yield reader, writer if block_given?
writer.puts('"done"')
diff --git a/spec/functional/version_spec.rb b/spec/functional/version_spec.rb
index d968c36e8c..b12d235405 100644
--- a/spec/functional/version_spec.rb
+++ b/spec/functional/version_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Serdar Sutay (<dan@chef.io>)
-# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# Copyright:: Copyright 2013-2019, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -28,7 +28,7 @@ describe "Chef Versions" do
binaries.each do |binary|
it "#{binary} version should be sane" do
- expect(shell_out!("ruby #{File.join("bin", binary)} -v", cwd: chef_dir).stdout.chomp).to match(/.*: #{Chef::VERSION}/)
+ expect(shell_out!("bundle exec #{binary} -v", cwd: chef_dir).stdout.chomp).to match(/.*: #{Chef::VERSION}/)
end
end
diff --git a/spec/integration/client/client_spec.rb b/spec/integration/client/client_spec.rb
index 006839be3f..cde25662c1 100644
--- a/spec/integration/client/client_spec.rb
+++ b/spec/integration/client/client_spec.rb
@@ -45,10 +45,8 @@ describe "chef-client" do
# machine that has omnibus chef installed. In that case we need to ensure
# we're running `chef-client` from the source tree and not the external one.
# cf. CHEF-4914
- let(:chef_client) { "ruby '#{chef_dir}/chef-client' --minimal-ohai" }
- let(:chef_solo) { "ruby '#{chef_dir}/chef-solo' --legacy-mode --minimal-ohai" }
-
- let(:critical_env_vars) { %w{_ORIGINAL_GEM_PATH GEM_PATH GEM_HOME GEM_ROOT BUNDLE_BIN_PATH BUNDLE_GEMFILE RUBYLIB RUBYOPT RUBY_ENGINE RUBY_ROOT RUBY_VERSION PATH}.map { |o| "#{o}=#{ENV[o]}" } .join(" ") }
+ let(:chef_client) { "bundle exec chef-client --minimal-ohai" }
+ let(:chef_solo) { "bundle exec chef-solo --legacy-mode --minimal-ohai" }
when_the_repository "has a cookbook with a no-op recipe" do
before { file "cookbooks/x/recipes/default.rb", "" }
@@ -62,22 +60,6 @@ describe "chef-client" do
shell_out!("#{chef_client} -c \"#{path_to('config/client.rb')}\" -o 'x::default'", cwd: chef_dir)
end
- it "should complete successfully with no other environment variables", skip: (Chef::Platform.windows?) do
- file "config/client.rb", <<~EOM
- local_mode true
- cookbook_path "#{path_to('cookbooks')}"
- EOM
-
- begin
- result = shell_out("env -i #{critical_env_vars} #{chef_client} -c \"#{path_to('config/client.rb')}\" -o 'x::default'", cwd: chef_dir)
- result.error!
- rescue
- Chef::Log.info "Bare invocation will have the following load-path."
- Chef::Log.info shell_out!("env -i #{critical_env_vars} ruby -e 'puts $:'").stdout
- raise
- end
- end
-
it "should complete successfully with --no-listen" do
file "config/client.rb", <<~EOM
local_mode true
diff --git a/spec/integration/client/exit_code_spec.rb b/spec/integration/client/exit_code_spec.rb
index 2e29502070..6600a65c9f 100644
--- a/spec/integration/client/exit_code_spec.rb
+++ b/spec/integration/client/exit_code_spec.rb
@@ -21,7 +21,7 @@ describe "chef-client" do
# machine that has omnibus chef installed. In that case we need to ensure
# we're running `chef-client` from the source tree and not the external one.
# cf. CHEF-4914
- let(:chef_client) { "ruby '#{chef_dir}/chef-client' --no-fork --minimal-ohai" }
+ let(:chef_client) { "bundle exec chef-client --no-fork --minimal-ohai" }
let(:critical_env_vars) { %w{PATH RUBYOPT BUNDLE_GEMFILE GEM_PATH}.map { |o| "#{o}=#{ENV[o]}" } .join(" ") }
diff --git a/spec/integration/client/ipv6_spec.rb b/spec/integration/client/ipv6_spec.rb
index 04154c296f..b97eb4e8b4 100644
--- a/spec/integration/client/ipv6_spec.rb
+++ b/spec/integration/client/ipv6_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: Daniel DeLeo (<dan@chef.io>)
-# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# Copyright:: Copyright 2013-2019, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -75,7 +75,7 @@ describe "chef-client" do
let(:chef_dir) { File.join(File.dirname(__FILE__), "..", "..", "..", "bin") }
- let(:chef_client_cmd) { %Q{ruby '#{chef_dir}/chef-client' --minimal-ohai -c "#{path_to('config/client.rb')}" -lwarn} }
+ let(:chef_client_cmd) { %Q{bundle exec chef-client --minimal-ohai -c "#{path_to('config/client.rb')}" -lwarn} }
after do
FileUtils.rm_rf(cache_path)
diff --git a/spec/integration/recipes/accumulator_spec.rb b/spec/integration/recipes/accumulator_spec.rb
index 65a05fcdc5..d19d8637bb 100644
--- a/spec/integration/recipes/accumulator_spec.rb
+++ b/spec/integration/recipes/accumulator_spec.rb
@@ -16,7 +16,7 @@ describe "Accumulators" do
# machine that has omnibus chef installed. In that case we need to ensure
# we're running `chef-client` from the source tree and not the external one.
# cf. CHEF-4914
- let(:chef_client) { "ruby '#{chef_dir}/chef-client' --minimal-ohai" }
+ let(:chef_client) { "bundle exec chef-client --minimal-ohai" }
let(:aliases_temppath) do
t = Tempfile.new("chef_accumulator_test")
diff --git a/spec/integration/recipes/lwrp_inline_resources_spec.rb b/spec/integration/recipes/lwrp_inline_resources_spec.rb
index 2f4ef92f31..6bc857df48 100644
--- a/spec/integration/recipes/lwrp_inline_resources_spec.rb
+++ b/spec/integration/recipes/lwrp_inline_resources_spec.rb
@@ -16,7 +16,7 @@ describe "LWRPs with inline resources" do
# machine that has omnibus chef installed. In that case we need to ensure
# we're running `chef-client` from the source tree and not the external one.
# cf. CHEF-4914
- let(:chef_client) { "ruby '#{chef_dir}/chef-client' --minimal-ohai" }
+ let(:chef_client) { "bundle exec chef-client --minimal-ohai" }
context "with a use_inline_resources provider with 'def action_a' instead of action :a" do
class LwrpInlineResourcesTest < Chef::Resource
diff --git a/spec/integration/recipes/lwrp_spec.rb b/spec/integration/recipes/lwrp_spec.rb
index b5af6978ac..ce2861d43b 100644
--- a/spec/integration/recipes/lwrp_spec.rb
+++ b/spec/integration/recipes/lwrp_spec.rb
@@ -16,7 +16,7 @@ describe "LWRPs" do
# machine that has omnibus chef installed. In that case we need to ensure
# we're running `chef-client` from the source tree and not the external one.
# cf. CHEF-4914
- let(:chef_client) { "ruby '#{chef_dir}/chef-client' --minimal-ohai" }
+ let(:chef_client) { "bundle exec chef-client --minimal-ohai" }
when_the_repository "has a cookbook named l-w-r-p" do
before do
diff --git a/spec/integration/recipes/notifies_spec.rb b/spec/integration/recipes/notifies_spec.rb
index 0df7aa311f..860a109e4d 100644
--- a/spec/integration/recipes/notifies_spec.rb
+++ b/spec/integration/recipes/notifies_spec.rb
@@ -6,7 +6,7 @@ describe "notifications" do
include Chef::Mixin::ShellOut
let(:chef_dir) { File.expand_path("../../../../bin", __FILE__) }
- let(:chef_client) { "ruby '#{chef_dir}/chef-client' --minimal-ohai" }
+ let(:chef_client) { "bundle exec chef-client --minimal-ohai" }
when_the_repository "notifies a nameless resource" do
before do
diff --git a/spec/integration/recipes/notifying_block_spec.rb b/spec/integration/recipes/notifying_block_spec.rb
index 6c50854038..753e81dadb 100644
--- a/spec/integration/recipes/notifying_block_spec.rb
+++ b/spec/integration/recipes/notifying_block_spec.rb
@@ -1,6 +1,6 @@
#
# Author:: John Keiser (<jkeiser@chef.io>)
-# Copyright:: Copyright 2013-2016, Chef Software Inc.
+# Copyright:: Copyright 2013-2019, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -23,7 +23,7 @@ describe "notifying_block" do
include Chef::Mixin::ShellOut
let(:chef_dir) { File.expand_path("../../../../bin", __FILE__) }
- let(:chef_client) { "ruby '#{chef_dir}/chef-client' --minimal-ohai" }
+ let(:chef_client) { "bundle exec chef-client --minimal-ohai" }
when_the_repository "notifying_block test one" do
before do
diff --git a/spec/integration/recipes/remote_directory.rb b/spec/integration/recipes/remote_directory.rb
index a0e3e23ef3..6f67a38fc8 100644
--- a/spec/integration/recipes/remote_directory.rb
+++ b/spec/integration/recipes/remote_directory.rb
@@ -16,7 +16,7 @@ describe Chef::Resource::RemoteDirectory do
# machine that has omnibus chef installed. In that case we need to ensure
# we're running `chef-client` from the source tree and not the external one.
# cf. CHEF-4914
- let(:chef_client) { "ruby '#{chef_dir}/chef-client' --minimal-ohai" }
+ let(:chef_client) { "bundle exec chef-client --minimal-ohai" }
when_the_repository "has a cookbook with a source_dir with two subdirectories, each with one file and subdir in a different alphabetical order" do
before do
diff --git a/spec/integration/solo/solo_spec.rb b/spec/integration/solo/solo_spec.rb
index efd889c5d0..a098256d36 100644
--- a/spec/integration/solo/solo_spec.rb
+++ b/spec/integration/solo/solo_spec.rb
@@ -16,7 +16,7 @@ describe "chef-solo" do
let(:cookbook_ancient_100_metadata_rb) { cb_metadata("ancient", "1.0.0") }
- let(:chef_solo) { "ruby bin/chef-solo --legacy-mode --minimal-ohai" }
+ let(:chef_solo) { "bundle exec chef-solo --legacy-mode --minimal-ohai" }
when_the_repository "creates nodes" do
let(:nodes_dir) { File.join(@repository_dir, "nodes") }
@@ -26,7 +26,7 @@ describe "chef-solo" do
file "config/solo.rb", <<~EOM
chef_repo_path "#{@repository_dir}"
EOM
- result = shell_out("ruby bin/chef-solo -c \"#{path_to('config/solo.rb')}\" -l debug", cwd: chef_dir)
+ result = shell_out("bundle exec chef-solo -c \"#{path_to('config/solo.rb')}\" -l debug", cwd: chef_dir)
result.error!
end
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/knife/core/bootstrap_context_spec.rb b/spec/unit/knife/core/bootstrap_context_spec.rb
index 7b12177ab9..2ed8b6bc51 100644
--- a/spec/unit/knife/core/bootstrap_context_spec.rb
+++ b/spec/unit/knife/core/bootstrap_context_spec.rb
@@ -46,21 +46,21 @@ describe Chef::Knife::Core::BootstrapContext do
expect { described_class.new(config, run_list, chef_config) }.not_to raise_error
end
- it "runs chef with the first-boot.json with no environment specified" do
- expect(bootstrap_context.start_chef).to eq "chef-client -j /etc/chef/first-boot.json"
+ it "runs chef with the first-boot.json with no environment other than chef-license acceptance specified" do
+ expect(bootstrap_context.start_chef).to eq "CHEF_LICENSE=accept chef-client -j /etc/chef/first-boot.json"
end
describe "when in verbosity mode" do
let(:config) { { verbosity: 2, color: true } }
it "adds '-l debug' when verbosity is >= 2" do
- expect(bootstrap_context.start_chef).to eq "chef-client -j /etc/chef/first-boot.json -l debug"
+ expect(bootstrap_context.start_chef).to eq "CHEF_LICENSE=accept chef-client -j /etc/chef/first-boot.json -l debug"
end
end
describe "when no color value has been set in config" do
let(:config) { { color: false } }
it "adds '--no-color' when color is false" do
- expect(bootstrap_context.start_chef).to eq "chef-client -j /etc/chef/first-boot.json --no-color"
+ expect(bootstrap_context.start_chef).to eq "CHEF_LICENSE=accept chef-client -j /etc/chef/first-boot.json --no-color"
end
end
@@ -82,7 +82,7 @@ describe Chef::Knife::Core::BootstrapContext do
describe "alternate chef-client path" do
let(:chef_config) { { chef_client_path: "/usr/local/bin/chef-client" } }
it "runs chef-client from another path when specified" do
- expect(bootstrap_context.start_chef).to eq "/usr/local/bin/chef-client -j /etc/chef/first-boot.json"
+ expect(bootstrap_context.start_chef).to eq "CHEF_LICENSE=accept /usr/local/bin/chef-client -j /etc/chef/first-boot.json"
end
end
@@ -105,7 +105,7 @@ describe Chef::Knife::Core::BootstrapContext do
describe "when bootstrapping into a specific environment" do
let(:config) { { environment: "prodtastic", color: true } }
it "starts chef in the configured environment" do
- expect(bootstrap_context.start_chef).to eq("chef-client -j /etc/chef/first-boot.json -E prodtastic")
+ expect(bootstrap_context.start_chef).to eq("CHEF_LICENSE=accept chef-client -j /etc/chef/first-boot.json -E prodtastic")
end
end
diff --git a/spec/unit/knife/core/windows_bootstrap_context_spec.rb b/spec/unit/knife/core/windows_bootstrap_context_spec.rb
index 3ab173f316..a19ad11247 100644
--- a/spec/unit/knife/core/windows_bootstrap_context_spec.rb
+++ b/spec/unit/knife/core/windows_bootstrap_context_spec.rb
@@ -264,4 +264,12 @@ describe Chef::Knife::Core::WindowsBootstrapContext do
end
end
end
+
+ describe "#start_chef" do
+ it "the command includes the license acceptance environment variable" do
+ expect(bootstrap_context.start_chef).to match(/SET "CHEF_LICENSE=accept"\n/m)
+ end
+
+ end
+
end