summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLamont Granquist <lamont@scriptkiddie.org>2019-09-09 19:43:15 -0700
committerLamont Granquist <lamont@scriptkiddie.org>2019-09-10 12:47:38 -0700
commit5ad3d87a29e6986c1026ec44f64e64bcdb7a2bcd (patch)
treefe8783dcf60c6f39352f7176dc959ecca6f55d19
parentb1a5a4f7e3eb30d30ebd1c5b9e22b299441350a1 (diff)
downloadchef-5ad3d87a29e6986c1026ec44f64e64bcdb7a2bcd.tar.gz
savegame
Signed-off-by: Lamont Granquist <lamont@scriptkiddie.org>
-rwxr-xr-xchef-bin/bin/chef-solo2
-rw-r--r--lib/chef/application/base.rb107
-rw-r--r--lib/chef/application/client.rb104
-rw-r--r--lib/chef/application/solo.rb85
-rw-r--r--lib/chef/daemon.rb2
-rw-r--r--lib/chef/deprecated.rb6
-rw-r--r--spec/support/shared/unit/application_dot_d.rb2
-rw-r--r--spec/unit/application/solo_spec.rb246
8 files changed, 243 insertions, 311 deletions
diff --git a/chef-bin/bin/chef-solo b/chef-bin/bin/chef-solo
index 7a2168230d..0847473100 100755
--- a/chef-bin/bin/chef-solo
+++ b/chef-bin/bin/chef-solo
@@ -21,4 +21,4 @@
$:.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
require "chef/application/solo"
-Chef::Application::Solo.new.run(enforce_license: true)
+Chef::Application::Client.new(solo: true).run
diff --git a/lib/chef/application/base.rb b/lib/chef/application/base.rb
index c5bff9874e..bef048287c 100644
--- a/lib/chef/application/base.rb
+++ b/lib/chef/application/base.rb
@@ -45,6 +45,9 @@ class Chef::Application::Base < Chef::Application
# Mimic self_pipe sleep from Unicorn to capture signals safely
SELF_PIPE = [] # rubocop:disable Style/MutableConstant
+ # @return <Boolean> If we have been called from chef-solo
+ attr_reader :solo_flag
+
option :config_option,
long: "--config-option OPTION=VALUE",
description: "Override a single configuration option.",
@@ -295,6 +298,110 @@ class Chef::Application::Base < Chef::Application
attr_reader :chef_client_json
+ def reconfigure
+ super
+
+ if Chef::Config[:local_mode] || solo_flag || Chef::Config[:solo_legacy_mode]
+ Chef::Config[:solo] = true
+ unless Chef::Config[:solo_legacy_mode]
+ Chef::Config.local_mode = true
+ end
+ end
+
+ # Load all config files in client.d
+ if Chef::Config[:solo]
+ load_dot_d(Chef::Config[:solo_d_dir]) if Chef::Config[:solo_d_dir]
+ else
+ load_dot_d(Chef::Config[:client_d_dir]) if Chef::Config[:client_d_dir]
+ end
+
+ set_specific_recipes
+
+ Chef::Config[:fips] = config[:fips] if config.key? :fips
+
+ raise Chef::Exceptions::PIDFileLockfileMatch if Chef::Util::PathHelper.paths_eql? (Chef::Config[:pid_file] || "" ), (Chef::Config[:lockfile] || "")
+
+ Chef::Config[:chef_server_url] = config[:chef_server_url] if config.key?(:chef_server_url)
+
+ if Chef::Config.local_mode
+ if Chef::Config.key?(:chef_repo_path) && Chef::Config.chef_repo_path.nil?
+ Chef::Config.delete(:chef_repo_path)
+ Chef::Log.warn "chef_repo_path was set in a config file but was empty. Assuming #{Chef::Config.chef_repo_path}"
+ end
+
+ if Chef::Config.local_mode && !Chef::Config.key?(:cookbook_path) && !Chef::Config.key?(:chef_repo_path)
+ Chef::Config.chef_repo_path = Chef::Config.find_chef_repo_path(Dir.pwd)
+ end
+ end
+
+ if Chef::Config[:recipe_url]
+ if !Chef::Config.solo
+ Chef::Application.fatal!("recipe-url can be used only in local-mode")
+ else
+ if Chef::Config[:delete_entire_chef_repo]
+ Chef::Log.trace "Cleanup path #{Chef::Config.chef_repo_path} before extract recipes into it"
+ FileUtils.rm_rf(Chef::Config.chef_repo_path, secure: true)
+ end
+ Chef::Log.trace "Creating path #{Chef::Config.chef_repo_path} to extract recipes into"
+ FileUtils.mkdir_p(Chef::Config.chef_repo_path)
+ tarball_path = File.join(Chef::Config.chef_repo_path, "recipes.tgz")
+ fetch_recipe_tarball(Chef::Config[:recipe_url], tarball_path)
+ Mixlib::Archive.new(tarball_path).extract(Chef::Config.chef_repo_path, perms: false, ignore: /^\.$/)
+ config_path = File.join(Chef::Config.chef_repo_path, "#{Chef::Dist::USER_CONF_DIR}/config.rb")
+ Chef::Config.from_string(IO.read(config_path), config_path) if File.file?(config_path)
+ end
+ end
+
+ Chef::Config.chef_zero.host = config[:chef_zero_host] if config[:chef_zero_host]
+ Chef::Config.chef_zero.port = config[:chef_zero_port] if config[:chef_zero_port]
+
+ if config[:target] || Chef::Config.target
+ Chef::Config.target_mode.enabled = true
+ Chef::Config.target_mode.host = config[:target] || Chef::Config.target
+ Chef::Config.node_name = Chef::Config.target_mode.host unless Chef::Config.node_name
+ end
+
+ if Chef::Config[:daemonize]
+ Chef::Config[:interval] ||= 1800
+ end
+
+ if Chef::Config[:once]
+ Chef::Config[:interval] = nil
+ Chef::Config[:splay] = nil
+ end
+
+ # supervisor processes are enabled by default for interval-running processes but not for one-shot runs
+ if Chef::Config[:client_fork].nil?
+ Chef::Config[:client_fork] = !!Chef::Config[:interval]
+ end
+
+ if Chef::Config[:interval]
+ if Chef::Platform.windows?
+ Chef::Application.fatal!(windows_interval_error_message)
+ elsif !Chef::Config[:client_fork]
+ Chef::Application.fatal!(unforked_interval_error_message)
+ end
+ end
+
+ if Chef::Config[:json_attribs]
+ config_fetcher = Chef::ConfigFetcher.new(Chef::Config[:json_attribs])
+ @chef_client_json = config_fetcher.fetch_json
+ end
+ end
+
+ def load_config_file
+ if !config.key?(:config_file) && !config[:disable_config]
+ if config[:local_mode]
+ config[:config_file] = Chef::WorkstationConfigLoader.new(nil, Chef::Log).config_location
+ else
+ config[:config_file] = Chef::Config.platform_specific_path("#{Chef::Dist::CONF_DIR}/client.rb")
+ end
+ end
+
+ # Load the client.rb configuration
+ super
+ end
+
def setup_application
Chef::Daemon.change_privilege
end
diff --git a/lib/chef/application/client.rb b/lib/chef/application/client.rb
index 890ecbd385..2ea3df9f7b 100644
--- a/lib/chef/application/client.rb
+++ b/lib/chef/application/client.rb
@@ -63,99 +63,23 @@ class Chef::Application::Client < Chef::Application::Base
long: "--recipe-url=RECIPE_URL",
description: "Pull down a remote archive of recipes and unpack it to the cookbook cache. Only used in local mode."
- # Reconfigure the chef client
- # Re-open the JSON attributes and load them into the node
- def reconfigure
- super
-
- raise Chef::Exceptions::PIDFileLockfileMatch if Chef::Util::PathHelper.paths_eql? (Chef::Config[:pid_file] || "" ), (Chef::Config[:lockfile] || "")
-
- set_specific_recipes
-
- Chef::Config[:fips] = config[:fips] if config.key? :fips
-
- Chef::Config[:chef_server_url] = config[:chef_server_url] if config.key? :chef_server_url
-
- Chef::Config.local_mode = config[:local_mode] if config.key?(:local_mode)
-
- if Chef::Config.key?(:chef_repo_path) && Chef::Config.chef_repo_path.nil?
- Chef::Config.delete(:chef_repo_path)
- Chef::Log.warn "chef_repo_path was set in a config file but was empty. Assuming #{Chef::Config.chef_repo_path}"
- end
-
- if Chef::Config.local_mode && !Chef::Config.key?(:cookbook_path) && !Chef::Config.key?(:chef_repo_path)
- Chef::Config.chef_repo_path = Chef::Config.find_chef_repo_path(Dir.pwd)
- end
-
- if Chef::Config[:recipe_url]
- if !Chef::Config.local_mode
- Chef::Application.fatal!("recipe-url can be used only in local-mode")
- else
- if Chef::Config[:delete_entire_chef_repo]
- Chef::Log.trace "Cleanup path #{Chef::Config.chef_repo_path} before extract recipes into it"
- FileUtils.rm_rf(Chef::Config.chef_repo_path, secure: true)
- end
- Chef::Log.trace "Creating path #{Chef::Config.chef_repo_path} to extract recipes into"
- FileUtils.mkdir_p(Chef::Config.chef_repo_path)
- tarball_path = File.join(Chef::Config.chef_repo_path, "recipes.tgz")
- fetch_recipe_tarball(Chef::Config[:recipe_url], tarball_path)
- Mixlib::Archive.new(tarball_path).extract(Chef::Config.chef_repo_path, perms: false, ignore: /^\.$/)
- config_path = File.join(Chef::Config.chef_repo_path, "#{Chef::Dist::USER_CONF_DIR}/config.rb")
- Chef::Config.from_string(IO.read(config_path), config_path) if File.file?(config_path)
- end
- end
-
- Chef::Config.chef_zero.host = config[:chef_zero_host] if config[:chef_zero_host]
- Chef::Config.chef_zero.port = config[:chef_zero_port] if config[:chef_zero_port]
-
- if config[:target] || Chef::Config.target
- Chef::Config.target_mode.enabled = true
- Chef::Config.target_mode.host = config[:target] || Chef::Config.target
- Chef::Config.node_name = Chef::Config.target_mode.host unless Chef::Config.node_name
- end
-
- if Chef::Config[:daemonize]
- Chef::Config[:interval] ||= 1800
- end
-
- if Chef::Config[:once]
- Chef::Config[:interval] = nil
- Chef::Config[:splay] = nil
- end
-
- # supervisor processes are enabled by default for interval-running processes but not for one-shot runs
- if Chef::Config[:client_fork].nil?
- Chef::Config[:client_fork] = !!Chef::Config[:interval]
- end
-
- if Chef::Config[:interval]
- if Chef::Platform.windows?
- Chef::Application.fatal!(windows_interval_error_message)
- elsif !Chef::Config[:client_fork]
- Chef::Application.fatal!(unforked_interval_error_message)
- end
- end
-
- if Chef::Config[:json_attribs]
- config_fetcher = Chef::ConfigFetcher.new(Chef::Config[:json_attribs])
- @chef_client_json = config_fetcher.fetch_json
- end
+ def initialize(solo: false)
+ @solo_flag = solo
+ super()
end
- def load_config_file
- if !config.key?(:config_file) && !config[:disable_config]
- if config[:local_mode]
- config[:config_file] = Chef::WorkstationConfigLoader.new(nil, Chef::Log).config_location
- else
- config[:config_file] = Chef::Config.platform_specific_path("#{Chef::Dist::CONF_DIR}/client.rb")
- end
+ def run(enforce_license: false)
+ setup_signal_handlers
+ reconfigure
+ # setup_application does a Dir.chdir("/") and cannot come before reconfigure or many things break
+ setup_application
+ check_license_acceptance if enforce_license
+ for_ezra if Chef::Config[:ez]
+ if Chef::Config[:solo_legacy_mode]
+ Chef::Application::Solo.new.run # FIXME: minimally we just need to reparse the cli and then run_application
+ else
+ run_application
end
-
- # Load the client.rb configuration
- super
-
- # Load all config files in client.d
- load_dot_d(Chef::Config[:client_d_dir]) if Chef::Config[:client_d_dir]
end
def configure_logging
diff --git a/lib/chef/application/solo.rb b/lib/chef/application/solo.rb
index da9ec7f566..0d0b6dd216 100644
--- a/lib/chef/application/solo.rb
+++ b/lib/chef/application/solo.rb
@@ -49,88 +49,13 @@ class Chef::Application::Solo < Chef::Application::Base
long: "--recipe-url RECIPE_URL",
description: "Pull down a remote gzipped tarball of recipes and untar it to the cookbook cache."
- # Get this party started
- def run(enforce_license: false)
- setup_signal_handlers
- setup_application
- reconfigure
- check_license_acceptance if enforce_license
- for_ezra if Chef::Config[:ez]
- if !Chef::Config[:solo_legacy_mode]
- Chef::Application::Client.new.run
- else
- run_application
- end
+ def initialize(solo: true)
+ @solo_flag = solo
+ super()
end
- def reconfigure
+ def run
super
-
- load_dot_d(Chef::Config[:solo_d_dir]) if Chef::Config[:solo_d_dir]
-
- set_specific_recipes
-
- Chef::Config[:fips] = config[:fips] if config.key? :fips
-
- Chef::Config[:solo] = true
-
- if !Chef::Config[:solo_legacy_mode]
- # Because we re-parse ARGV when we move to chef-client, we need to tidy up some options first.
- ARGV.delete("--ez")
-
- # For back compat reasons, we need to ensure that we try and use the cache_path as a repo first
- Chef::Log.trace "Current chef_repo_path is #{Chef::Config.chef_repo_path}"
-
- if !Chef::Config.key?(:cookbook_path) && !Chef::Config.key?(:chef_repo_path)
- Chef::Config.chef_repo_path = Chef::Config.find_chef_repo_path(Chef::Config[:cache_path])
- end
-
- Chef::Config[:local_mode] = true
- Chef::Config[:listen] = false
- else
- configure_legacy_mode!
- end
+ # Chef.deprecated(:solo_legacy_mode, "Solo legacy mode is deprecated FIXME WORDS");
end
-
- def configure_legacy_mode!
- if Chef::Config[:daemonize]
- Chef::Config[:interval] ||= 1800
- end
-
- # supervisor processes are enabled by default for interval-running processes but not for one-shot runs
- if Chef::Config[:client_fork].nil?
- Chef::Config[:client_fork] = !!Chef::Config[:interval]
- end
-
- if Chef::Config[:interval]
- if Chef::Platform.windows?
- Chef::Application.fatal!(windows_interval_error_message)
- elsif !Chef::Config[:client_fork]
- Chef::Application.fatal!(unforked_interval_error_message)
- end
- end
-
- if Chef::Config[:recipe_url]
- cookbooks_path = Array(Chef::Config[:cookbook_path]).detect { |e| Pathname.new(e).cleanpath.to_s =~ %r{/cookbooks/*$} }
- recipes_path = File.expand_path(File.join(cookbooks_path, ".."))
-
- if Chef::Config[:delete_entire_chef_repo]
- Chef::Log.trace "Cleanup path #{recipes_path} before extract recipes into it"
- FileUtils.rm_rf(recipes_path, secure: true)
- end
- Chef::Log.trace "Creating path #{recipes_path} to extract recipes into"
- FileUtils.mkdir_p(recipes_path)
- tarball_path = File.join(recipes_path, "recipes.tgz")
- fetch_recipe_tarball(Chef::Config[:recipe_url], tarball_path)
- Mixlib::Archive.new(tarball_path).extract(Chef::Config.chef_repo_path, perms: false, ignore: /^\.$/)
- end
-
- # json_attribs shuld be fetched after recipe_url tarball is unpacked.
- # Otherwise it may fail if points to local file from tarball.
- if Chef::Config[:json_attribs]
- config_fetcher = Chef::ConfigFetcher.new(Chef::Config[:json_attribs])
- @chef_client_json = config_fetcher.fetch_json
- end
- end
-
end
diff --git a/lib/chef/daemon.rb b/lib/chef/daemon.rb
index 64c451a26c..d778e5a17d 100644
--- a/lib/chef/daemon.rb
+++ b/lib/chef/daemon.rb
@@ -1,6 +1,6 @@
#
# Author:: AJ Christensen (<aj@junglist.gen.nz>)
-# Copyright:: Copyright 2008-2016, Chef Software Inc.
+# Copyright:: Copyright 2008-2019, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/lib/chef/deprecated.rb b/lib/chef/deprecated.rb
index cda8e197d3..0349a73664 100644
--- a/lib/chef/deprecated.rb
+++ b/lib/chef/deprecated.rb
@@ -1,5 +1,5 @@
#--
-# Copyright:: Copyright 2016-2018, Chef Software Inc.
+# Copyright:: Copyright 2016-2019, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -229,6 +229,10 @@ class Chef
target 27
end
+ class SoloLegacyMode < Base
+ target 28
+ end
+
class Generic < Base
def url
"https://docs.chef.io/chef_deprecations_client.html"
diff --git a/spec/support/shared/unit/application_dot_d.rb b/spec/support/shared/unit/application_dot_d.rb
index 0f2f06eff8..e8ff7c2291 100644
--- a/spec/support/shared/unit/application_dot_d.rb
+++ b/spec/support/shared/unit/application_dot_d.rb
@@ -1,5 +1,5 @@
#
-# Copyright:: Copyright 2016, Chef Software, Inc.
+# Copyright:: Copyright 2016-2019, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/spec/unit/application/solo_spec.rb b/spec/unit/application/solo_spec.rb
index b70f959ab5..1199482bb7 100644
--- a/spec/unit/application/solo_spec.rb
+++ b/spec/unit/application/solo_spec.rb
@@ -19,7 +19,7 @@ require "spec_helper"
describe Chef::Application::Solo do
- let(:app) { Chef::Application::Solo.new }
+ let(:app) { Chef::Application::Client.new(solo: true) }
before do
allow(Kernel).to receive(:trap).and_return(:ok)
@@ -30,187 +30,159 @@ describe Chef::Application::Solo do
allow(app).to receive(:cli_arguments).and_return([])
Chef::Config[:json_attribs] = false
- Chef::Config[:solo] = true
- Chef::Config[:solo_legacy_mode] = true
# protect the unit tests against accidental --delete-entire-chef-repo from firing
# for real during tests. DO NOT delete this line.
expect(FileUtils).not_to receive(:rm_rf)
end
- context "in legacy mode" do
- describe "configuring the application" do
- it "should call set_specific_recipes" do
- expect(app).to receive(:set_specific_recipes)
- app.reconfigure
- end
-
- it "should set solo mode to true" do
- app.reconfigure
- expect(Chef::Config[:solo]).to be_truthy
- end
-
- describe "when configured to not fork the client process" do
- before do
- Chef::Config[:client_fork] = false
- Chef::Config[:daemonize] = false
- Chef::Config[:interval] = nil
- Chef::Config[:splay] = nil
- end
+ describe "configuring the application" do
+ it "should call set_specific_recipes" do
+ expect(app).to receive(:set_specific_recipes)
+ app.reconfigure
+ end
- context "when interval is given" do
- before do
- Chef::Config[:interval] = 600
- end
+ it "should set solo mode to true" do
+ app.reconfigure
+ expect(Chef::Config[:solo]).to be_truthy
+ end
- it "should terminate with message" do
- expect(Chef::Application).to receive(:fatal!).with(/interval runs are (disabled|not supported)/)
- app.reconfigure
- end
- end
+ describe "when configured to not fork the client process" do
+ before do
+ Chef::Config[:client_fork] = false
+ Chef::Config[:daemonize] = false
+ Chef::Config[:interval] = nil
+ Chef::Config[:splay] = nil
end
- describe "when in daemonized mode and no interval has been set", :unix_only do
+ context "when interval is given" do
before do
- Chef::Config[:daemonize] = true
+ Chef::Config[:interval] = 600
end
- it "should set the interval to 1800" do
- Chef::Config[:interval] = nil
+ it "should terminate with message" do
+ expect(Chef::Application).to receive(:fatal!).with(/interval runs are (disabled|not supported)/)
app.reconfigure
- expect(Chef::Config[:interval]).to eq(1800)
end
end
+ end
- describe "when the json_attribs configuration option is specified" do
- let(:json_attribs) { { "a" => "b" } }
- let(:config_fetcher) { double(Chef::ConfigFetcher, fetch_json: json_attribs) }
- let(:json_source) { "https://foo.com/foo.json" }
-
- before do
- Chef::Config[:json_attribs] = json_source
- expect(Chef::ConfigFetcher).to receive(:new).with(json_source)
- .and_return(config_fetcher)
- end
-
- it "reads the JSON attributes from the specified source" do
- app.reconfigure
- expect(app.chef_client_json).to eq(json_attribs)
- end
+ describe "when in daemonized mode and no interval has been set", :unix_only do
+ before do
+ Chef::Config[:daemonize] = true
end
- it "downloads a tarball when the recipe_url configuration option is specified" do
- Chef::Config[:cookbook_path] = "#{Dir.tmpdir}/chef-solo/cookbooks"
- Chef::Config[:recipe_url] = "http://junglist.gen.nz/recipes.tgz"
-
- expect(FileUtils).to receive(:mkdir_p).with("#{Dir.tmpdir}/chef-solo").and_return(true)
-
- tarfile = StringIO.new("remote_tarball_content")
- target_file = StringIO.new
-
- expect(app).to receive(:open).with("http://junglist.gen.nz/recipes.tgz").and_yield(tarfile)
- expect(File).to receive(:open).with("#{Dir.tmpdir}/chef-solo/recipes.tgz", "wb").and_yield(target_file)
-
- archive = double(Mixlib::Archive)
-
- expect(Mixlib::Archive).to receive(:new).with("#{Dir.tmpdir}/chef-solo/recipes.tgz").and_return(archive)
- expect(archive).to receive(:extract).with("#{Dir.tmpdir}/chef-solo", { perms: false, ignore: /^\.$/ })
+ it "should set the interval to 1800" do
+ Chef::Config[:interval] = nil
app.reconfigure
- expect(target_file.string).to eq("remote_tarball_content")
+ expect(Chef::Config[:interval]).to eq(1800)
end
+ end
- it "fetches the recipe_url first when both json_attribs and recipe_url are specified" do
- json_attribs = { "a" => "b" }
- config_fetcher = instance_double("Chef::ConfigFetcher", fetch_json: json_attribs)
-
- Chef::Config[:json_attribs] = "https://foo.com/foo.json"
- Chef::Config[:recipe_url] = "http://icanhas.cheezburger.com/lolcats"
- Chef::Config[:cookbook_path] = "#{Dir.tmpdir}/chef-solo/cookbooks"
- expect(FileUtils).to receive(:mkdir_p).with("#{Dir.tmpdir}/chef-solo").and_return(true)
+ describe "when the json_attribs configuration option is specified" do
+ let(:json_attribs) { { "a" => "b" } }
+ let(:config_fetcher) { double(Chef::ConfigFetcher, fetch_json: json_attribs) }
+ let(:json_source) { "https://foo.com/foo.json" }
- archive = double(Mixlib::Archive)
+ before do
+ Chef::Config[:json_attribs] = json_source
+ expect(Chef::ConfigFetcher).to receive(:new).with(json_source)
+ .and_return(config_fetcher)
+ end
- expect(Mixlib::Archive).to receive(:new).with("#{Dir.tmpdir}/chef-solo/recipes.tgz").and_return(archive)
- expect(archive).to receive(:extract).with("#{Dir.tmpdir}/chef-solo", { perms: false, ignore: /^\.$/ })
- expect(app).to receive(:fetch_recipe_tarball).ordered
- expect(Chef::ConfigFetcher).to receive(:new).ordered.and_return(config_fetcher)
+ it "reads the JSON attributes from the specified source" do
app.reconfigure
+ expect(app.chef_client_json).to eq(json_attribs)
end
end
- describe "after the application has been configured" do
- before do
- Chef::Config[:solo] = true
- Chef::Config[:solo_legacy_mode] = true
-
- allow(Chef::Daemon).to receive(:change_privilege)
- chef_client = double("Chef::Client")
- allow(Chef::Client).to receive(:new).and_return(chef_client)
- # this is all stuff the reconfigure method needs
- allow(app).to receive(:configure_opt_parser).and_return(true)
- allow(app).to receive(:configure_chef).and_return(true)
- allow(app).to receive(:configure_logging).and_return(true)
- end
+ it "downloads a tarball when the recipe_url configuration option is specified" do
+ Chef::Config[:cookbook_path] = "#{Dir.tmpdir}/chef-solo/cookbooks"
+ Chef::Config[:recipe_url] = "http://junglist.gen.nz/recipes.tgz"
- it "should change privileges" do
- expect(Chef::Daemon).to receive(:change_privilege).and_return(true)
- app.setup_application
- end
- end
+ expect(FileUtils).to receive(:mkdir_p).with("#{Dir.tmpdir}/chef-solo").and_return(true)
- it_behaves_like "an application that loads a dot d" do
- let(:dot_d_config_name) { :solo_d_dir }
- end
- end
+ tarfile = StringIO.new("remote_tarball_content")
+ target_file = StringIO.new
- context "in local mode" do
- before do
- Chef::Config[:solo_legacy_mode] = false
- end
+ expect(app).to receive(:open).with("http://junglist.gen.nz/recipes.tgz").and_yield(tarfile)
+ expect(File).to receive(:open).with("#{Dir.tmpdir}/chef-solo/recipes.tgz", "wb").and_yield(target_file)
- it "sets solo mode to true" do
- app.reconfigure
- expect(Chef::Config[:solo]).to be_truthy
- end
+ archive = double(Mixlib::Archive)
- it "sets local mode to true" do
+ expect(Mixlib::Archive).to receive(:new).with("#{Dir.tmpdir}/chef-solo/recipes.tgz").and_return(archive)
+ expect(archive).to receive(:extract).with("#{Dir.tmpdir}/chef-solo", { perms: false, ignore: /^\.$/ })
app.reconfigure
- expect(Chef::Config[:local_mode]).to be_truthy
+ expect(target_file.string).to eq("remote_tarball_content")
end
- context "argv gets tidied up" do
- before do
- @original_argv = ARGV.dup
- ARGV.clear
- Chef::Config[:treat_deprecation_warnings_as_errors] = false
- end
+ it "fetches the recipe_url first when both json_attribs and recipe_url are specified" do
+ json_attribs = { "a" => "b" }
+ config_fetcher = instance_double("Chef::ConfigFetcher", fetch_json: json_attribs)
- after do
- ARGV.replace(@original_argv)
- end
+ Chef::Config[:json_attribs] = "https://foo.com/foo.json"
+ Chef::Config[:recipe_url] = "http://icanhas.cheezburger.com/lolcats"
+ Chef::Config[:cookbook_path] = "#{Dir.tmpdir}/chef-solo/cookbooks"
+ expect(FileUtils).to receive(:mkdir_p).with("#{Dir.tmpdir}/chef-solo").and_return(true)
- it "deletes --ez" do
- ARGV << "--ez"
- app.reconfigure
- expect(ARGV.include?("--ez")).to be_falsey
- end
- end
+ archive = double(Mixlib::Archive)
- it "sets the repo path" do
- expect(Chef::Config).to receive(:find_chef_repo_path).and_return("/var/chef")
+ expect(Mixlib::Archive).to receive(:new).with("#{Dir.tmpdir}/chef-solo/recipes.tgz").and_return(archive)
+ expect(archive).to receive(:extract).with("#{Dir.tmpdir}/chef-solo", { perms: false, ignore: /^\.$/ })
+ expect(app).to receive(:fetch_recipe_tarball).ordered
+ expect(Chef::ConfigFetcher).to receive(:new).ordered.and_return(config_fetcher)
app.reconfigure
- expect(Chef::Config.key?(:chef_repo_path)).to be_truthy
- expect(Chef::Config[:chef_repo_path]).to eq ("/var/chef")
end
+ end
- it "runs chef-client in local mode" do
- allow(app).to receive(:setup_application).and_return(true)
- allow(app).to receive(:run_application).and_return(true)
+ describe "after the application has been configured" do
+ before do
+ allow(Chef::Daemon).to receive(:change_privilege)
+ chef_client = double("Chef::Client")
+ allow(Chef::Client).to receive(:new).and_return(chef_client)
+ # this is all stuff the reconfigure method needs
+ allow(app).to receive(:configure_opt_parser).and_return(true)
allow(app).to receive(:configure_chef).and_return(true)
allow(app).to receive(:configure_logging).and_return(true)
- expect(Chef::Application::Client).to receive_message_chain(:new, :run)
- app.run
end
+ it "should change privileges" do
+ expect(Chef::Daemon).to receive(:change_privilege).and_return(true)
+ app.setup_application
+ end
+ end
+
+ describe "testing configure_chef" do
+ before do
+ expect(app).to receive(:configure_chef).and_call_original
+ end
+ it_behaves_like "an application that loads a dot d" do
+ let(:dot_d_config_name) { :solo_d_dir }
+ end
+ end
+
+ it "sets solo mode to true" do
+ app.reconfigure
+ expect(Chef::Config[:solo]).to be_truthy
+ end
+
+ it "sets local mode to true" do
+ app.reconfigure
+ expect(Chef::Config[:local_mode]).to be_truthy
+ end
+
+ it "sets the repo path" do
+ expect(Chef::Config).to receive(:find_chef_repo_path).and_return("/var/chef")
+ app.reconfigure
+ expect(Chef::Config.key?(:chef_repo_path)).to be_truthy
+ expect(Chef::Config[:chef_repo_path]).to eq ("/var/chef")
+ end
+
+ it "runs chef-client in local mode" do
+ allow(app).to receive(:setup_application).and_return(true)
+ allow(app).to receive(:run_application).and_return(true)
+ allow(app).to receive(:configure_chef).and_return(true)
+ allow(app).to receive(:configure_logging).and_return(true)
+ app.run
end
end