summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSerdar Sutay <serdar@opscode.com>2014-11-08 22:45:28 -0800
committerSerdar Sutay <serdar@opscode.com>2014-11-08 22:49:36 -0800
commit0fb0ef6a1c367d64e8d6b52e823038d75a025e3c (patch)
tree95e05e79b84dee5939f4afd820c8fac3eb134e30
parent708e2896e76aa79f1630b15b4a08bfcb9f044474 (diff)
downloadchef-sersut/serv-prov-port.tar.gz
Merge pull request #2336 from opscode/lcg/12-systemd-fixessersut/serv-prov-port
fix systemd for Ubuntu 14.10 Conflicts: CHANGELOG.md spec/unit/provider/service/systemd_service_spec.rb
-rw-r--r--CHANGELOG.md1
-rw-r--r--lib/chef/mixin/which.rb37
-rw-r--r--lib/chef/platform/provider_priority_map.rb5
-rw-r--r--lib/chef/platform/service_helpers.rb45
-rw-r--r--lib/chef/provider/service/aixinit.rb2
-rw-r--r--lib/chef/provider/service/arch.rb2
-rw-r--r--lib/chef/provider/service/debian.rb6
-rw-r--r--lib/chef/provider/service/init.rb4
-rw-r--r--lib/chef/provider/service/insserv.rb6
-rw-r--r--lib/chef/provider/service/invokercd.rb6
-rw-r--r--lib/chef/provider/service/redhat.rb6
-rw-r--r--lib/chef/provider/service/systemd.rb82
-rw-r--r--lib/chef/provider/service/upstart.rb7
-rw-r--r--lib/chef/provider_resolver.rb46
-rw-r--r--lib/chef/resource.rb3
-rw-r--r--lib/chef/run_context.rb5
-rw-r--r--lib/chef/util/selinux.rb12
-rw-r--r--spec/support/shared/unit/resource/static_provider_resolution.rb7
-rw-r--r--spec/unit/provider/service/systemd_service_spec.rb331
-rw-r--r--spec/unit/provider_resolver_spec.rb185
-rw-r--r--spec/unit/resource/timestamped_deploy_spec.rb37
-rw-r--r--spec/unit/runner_spec.rb4
22 files changed, 553 insertions, 286 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index aed9f16163..0e99ff425b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -237,6 +237,7 @@
* The Windows env provider will delete elements even if they are only in ENV (and not in the registry)
* Allow events to be logged to Windows Event Log
* Fixed bug in env resource where a value containing the delimiter could never correctly match the existing values
+* More intelligent service check for systemd on Ubuntu 14.10.
## 11.16.4
diff --git a/lib/chef/mixin/which.rb b/lib/chef/mixin/which.rb
new file mode 100644
index 0000000000..4179c97b62
--- /dev/null
+++ b/lib/chef/mixin/which.rb
@@ -0,0 +1,37 @@
+#--
+# Author:: Lamont Granquist <lamont@getchef.io>
+# Copyright:: Copyright (c) 2010 Opscode, 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.
+
+class Chef
+ module Mixin
+ module Which
+ def which(cmd, opts = {})
+ extra_path =
+ if opts[:extra_path].nil?
+ [ '/bin', '/usr/bin', '/sbin', '/usr/sbin' ]
+ else
+ [ opts[:extra_path] ].flatten
+ end
+ paths = ENV['PATH'].split(File::PATH_SEPARATOR) + extra_path
+ paths.each do |path|
+ filename = File.join(path, cmd)
+ return filename if File.executable?(filename)
+ end
+ false
+ end
+ end
+ end
+end
diff --git a/lib/chef/platform/provider_priority_map.rb b/lib/chef/platform/provider_priority_map.rb
index ccf6ef0bbe..765dd74859 100644
--- a/lib/chef/platform/provider_priority_map.rb
+++ b/lib/chef/platform/provider_priority_map.rb
@@ -34,9 +34,10 @@ class Chef
], platform_family: "gentoo"
priority :service, [
- # on debian-ish system if an upstart script exists that always wins
- Chef::Provider::Service::Upstart,
+ # we can determine what systemd supports accurately
Chef::Provider::Service::Systemd,
+ # on debian-ish system if an upstart script exists that must win over sysv types
+ Chef::Provider::Service::Upstart,
Chef::Provider::Service::Insserv,
Chef::Provider::Service::Debian,
Chef::Provider::Service::Invokercd,
diff --git a/lib/chef/platform/service_helpers.rb b/lib/chef/platform/service_helpers.rb
index 440391843e..dc0a808c06 100644
--- a/lib/chef/platform/service_helpers.rb
+++ b/lib/chef/platform/service_helpers.rb
@@ -18,6 +18,7 @@
# XXX: mixing shellout into a mixin into classes has to be code smell
require 'chef/mixin/shell_out'
+require 'chef/mixin/which'
class Chef
class Platform
@@ -25,12 +26,21 @@ class Chef
class << self
include Chef::Mixin::ShellOut
+ include Chef::Mixin::Which
# This helper is mostly used to sort out the mess of different
# linux mechanisms that can be used to start services. It does
# not necessarily need to linux-specific, but currently all our
# other service providers are narrowly platform-specific with no
# alternatives.
+ #
+ # NOTE: if a system has (for example) chkconfig installed then we
+ # should report that chkconfig is installed. The fact that a system
+ # may also have systemd installed does not mean that we do not
+ # report that systemd is also installed. This module is purely for
+ # discovery of all the alternatives, handling the priority of the
+ # different services is NOT a design concern of this module.
+ #
def service_resource_providers
service_resource_providers = []
@@ -55,8 +65,7 @@ class Chef
service_resource_providers << :redhat
end
- if ::File.exist?("/bin/systemctl")
- # FIXME: look for systemd as init provider
+ if systemd_sanity_check?
service_resource_providers << :systemd
end
@@ -86,7 +95,7 @@ class Chef
configs << :usr_local_etc_rcd
end
- if ::File.exist?("/bin/systemctl") && platform_has_systemd_unit?(service_name)
+ if systemd_sanity_check? && platform_has_systemd_unit?(service_name)
configs << :systemd
end
@@ -95,17 +104,37 @@ class Chef
private
- def extract_systemd_services(output)
+ def systemctl_path
+ if @systemctl_path.nil?
+ @systemctl_path = which("systemctl")
+ end
+ @systemctl_path
+ end
+
+ def systemd_sanity_check?
+ systemctl_path && File.exist?("/proc/1/comm") && File.open("/proc/1/comm").gets.chomp == "systemd"
+ end
+
+ def extract_systemd_services(command)
+ output = shell_out!(command).stdout
# first line finds e.g. "sshd.service"
- services = output.lines.split.map { |l| l.split[0] }
+ services = []
+ output.each_line do |line|
+ fields = line.split
+ services << fields[0] if fields[1] == "loaded" || fields[1] == "not-found"
+ end
# this splits off the suffix after the last dot to return "sshd"
- services += services.map { |s| s.sub(/(.*)\..*/, '\1') }
+ services += services.select {|s| s.match(/\.service$/) }.map { |s| s.sub(/(.*)\.service$/, '\1') }
+ rescue Mixlib::ShellOut::ShellCommandFailed
+ false
end
def platform_has_systemd_unit?(service_name)
- services = extract_systemd_services(shell_out!("systemctl --all").stdout) +
- extract_systemd_services(shell_out!("systemctl --list-unit-files").stdout)
+ services = extract_systemd_services("#{systemctl_path} --all") +
+ extract_systemd_services("#{systemctl_path} list-unit-files")
services.include?(service_name)
+ rescue Mixlib::ShellOut::ShellCommandFailed
+ false
end
end
end
diff --git a/lib/chef/provider/service/aixinit.rb b/lib/chef/provider/service/aixinit.rb
index ab4b8e5406..19beac79f0 100644
--- a/lib/chef/provider/service/aixinit.rb
+++ b/lib/chef/provider/service/aixinit.rb
@@ -114,4 +114,4 @@ class Chef
end
end
end
-end \ No newline at end of file
+end
diff --git a/lib/chef/provider/service/arch.rb b/lib/chef/provider/service/arch.rb
index 888fb3fdf5..e7fbcc820c 100644
--- a/lib/chef/provider/service/arch.rb
+++ b/lib/chef/provider/service/arch.rb
@@ -23,7 +23,7 @@ class Chef::Provider::Service::Arch < Chef::Provider::Service::Init
provides :service, platform_family: "arch"
def self.supports?(resource, action)
- ::File.exist?("/etc/rc.d/#{resource.service_name}")
+ Chef::Platform::ServiceHelpers.config_for_service(resource.service_name).include?(:etc_rcd)
end
def initialize(new_resource, run_context)
diff --git a/lib/chef/provider/service/debian.rb b/lib/chef/provider/service/debian.rb
index 25b1960b26..01505924cb 100644
--- a/lib/chef/provider/service/debian.rb
+++ b/lib/chef/provider/service/debian.rb
@@ -27,8 +27,12 @@ class Chef
provides :service, platform_family: "debian"
+ def self.provides?(node, resource)
+ super && Chef::Platform::ServiceHelpers.service_resource_providers.include?(:debian)
+ end
+
def self.supports?(resource, action)
- Chef::Platform::ServiceHelpers.service_resource_providers.include?(:debian)
+ Chef::Platform::ServiceHelpers.config_for_service(resource.service_name).include?(:initd)
end
def load_current_resource
diff --git a/lib/chef/provider/service/init.rb b/lib/chef/provider/service/init.rb
index ab40a720f6..0a219a69e1 100644
--- a/lib/chef/provider/service/init.rb
+++ b/lib/chef/provider/service/init.rb
@@ -28,6 +28,10 @@ class Chef
provides :service, os: "!windows"
+ def self.supports?(resource, action)
+ Chef::Platform::ServiceHelpers.config_for_service(resource.service_name).include?(:initd)
+ end
+
def initialize(new_resource, run_context)
super
@init_command = "/etc/init.d/#{@new_resource.service_name}"
diff --git a/lib/chef/provider/service/insserv.rb b/lib/chef/provider/service/insserv.rb
index df5a162a45..31965a4bc6 100644
--- a/lib/chef/provider/service/insserv.rb
+++ b/lib/chef/provider/service/insserv.rb
@@ -26,8 +26,12 @@ class Chef
provides :service, os: "linux"
+ def self.provides?(node, resource)
+ super && Chef::Platform::ServiceHelpers.service_resource_providers.include?(:insserv)
+ end
+
def self.supports?(resource, action)
- Chef::Platform::ServiceHelpers.service_resource_providers.include?(:insserv)
+ Chef::Platform::ServiceHelpers.config_for_service(resource.service_name).include?(:initd)
end
def load_current_resource
diff --git a/lib/chef/provider/service/invokercd.rb b/lib/chef/provider/service/invokercd.rb
index c7472211bc..5ff24e0dbb 100644
--- a/lib/chef/provider/service/invokercd.rb
+++ b/lib/chef/provider/service/invokercd.rb
@@ -25,8 +25,12 @@ class Chef
provides :service, platform_family: "debian"
+ def self.provides?(node, resource)
+ super && Chef::Platform::ServiceHelpers.service_resource_providers.include?(:invokercd)
+ end
+
def self.supports?(resource, action)
- Chef::Platform::ServiceHelpers.service_resource_providers.include?(:invokerc)
+ Chef::Platform::ServiceHelpers.config_for_service(resource.service_name).include?(:initd)
end
def initialize(new_resource, run_context)
diff --git a/lib/chef/provider/service/redhat.rb b/lib/chef/provider/service/redhat.rb
index 90744ae268..850953125e 100644
--- a/lib/chef/provider/service/redhat.rb
+++ b/lib/chef/provider/service/redhat.rb
@@ -28,8 +28,12 @@ class Chef
provides :service, platform_family: [ "rhel", "fedora", "suse" ]
+ def self.provides?(node, resource)
+ super && Chef::Platform::ServiceHelpers.service_resource_providers.include?(:redhat)
+ end
+
def self.supports?(resource, action)
- Chef::Platform::ServiceHelpers.service_resource_providers.include?(:redhat)
+ Chef::Platform::ServiceHelpers.config_for_service(resource.service_name).include?(:initd)
end
def initialize(new_resource, run_context)
diff --git a/lib/chef/provider/service/systemd.rb b/lib/chef/provider/service/systemd.rb
index 311751ab9a..9085ffde2e 100644
--- a/lib/chef/provider/service/systemd.rb
+++ b/lib/chef/provider/service/systemd.rb
@@ -18,87 +18,95 @@
require 'chef/resource/service'
require 'chef/provider/service/simple'
+require 'chef/mixin/which'
class Chef::Provider::Service::Systemd < Chef::Provider::Service::Simple
+ include Chef::Mixin::Which
+
provides :service, os: "linux"
+ attr_accessor :status_check_success
+
+ def self.provides?(node, resource)
+ super && Chef::Platform::ServiceHelpers.service_resource_providers.include?(:systemd)
+ end
+
def self.supports?(resource, action)
- Chef::Platform::ServiceHelpers.service_resource_providers.include?(:systemd)
+ Chef::Platform::ServiceHelpers.config_for_service(resource.service_name).include?(:systemd)
end
def load_current_resource
- @current_resource = Chef::Resource::Service.new(@new_resource.name)
- @current_resource.service_name(@new_resource.service_name)
+ @current_resource = Chef::Resource::Service.new(new_resource.name)
+ current_resource.service_name(new_resource.service_name)
@status_check_success = true
- if @new_resource.status_command
- Chef::Log.debug("#{@new_resource} you have specified a status command, running..")
+ if new_resource.status_command
+ Chef::Log.debug("#{new_resource} you have specified a status command, running..")
- unless shell_out(@new_resource.status_command).error?
- @current_resource.running(true)
+ unless shell_out(new_resource.status_command).error?
+ current_resource.running(true)
else
@status_check_success = false
- @current_resource.running(false)
- @current_resource.enabled(false)
- nil
+ current_resource.running(false)
+ current_resource.enabled(false)
end
else
- @current_resource.running(is_active?)
+ current_resource.running(is_active?)
end
- @current_resource.enabled(is_enabled?)
- @current_resource
+ current_resource.enabled(is_enabled?)
+ current_resource
end
def define_resource_requirements
shared_resource_requirements
requirements.assert(:all_actions) do |a|
- a.assertion { @status_check_success }
+ a.assertion { status_check_success }
# We won't stop in any case, but in whyrun warn and tell what we're doing.
- a.whyrun ["Failed to determine status of #{@new_resource}, using command #{@new_resource.status_command}.",
+ a.whyrun ["Failed to determine status of #{new_resource}, using command #{new_resource.status_command}.",
"Assuming service would have been installed and is disabled"]
end
end
def start_service
- if @current_resource.running
- Chef::Log.debug("#{@new_resource} already running, not starting")
+ if current_resource.running
+ Chef::Log.debug("#{new_resource} already running, not starting")
else
- if @new_resource.start_command
+ if new_resource.start_command
super
else
- shell_out_with_systems_locale!("/bin/systemctl start #{@new_resource.service_name}")
+ shell_out_with_systems_locale!("#{systemctl_path} start #{new_resource.service_name}")
end
end
end
def stop_service
- unless @current_resource.running
- Chef::Log.debug("#{@new_resource} not running, not stopping")
+ unless current_resource.running
+ Chef::Log.debug("#{new_resource} not running, not stopping")
else
- if @new_resource.stop_command
+ if new_resource.stop_command
super
else
- shell_out_with_systems_locale!("/bin/systemctl stop #{@new_resource.service_name}")
+ shell_out_with_systems_locale!("#{systemctl_path} stop #{new_resource.service_name}")
end
end
end
def restart_service
- if @new_resource.restart_command
+ if new_resource.restart_command
super
else
- shell_out_with_systems_locale!("/bin/systemctl restart #{@new_resource.service_name}")
+ shell_out_with_systems_locale!("#{systemctl_path} restart #{new_resource.service_name}")
end
end
def reload_service
- if @new_resource.reload_command
+ if new_resource.reload_command
super
else
- if @current_resource.running
- shell_out_with_systems_locale!("/bin/systemctl reload #{@new_resource.service_name}")
+ if current_resource.running
+ shell_out_with_systems_locale!("#{systemctl_path} reload #{new_resource.service_name}")
else
start_service
end
@@ -106,18 +114,28 @@ class Chef::Provider::Service::Systemd < Chef::Provider::Service::Simple
end
def enable_service
- shell_out!("/bin/systemctl enable #{@new_resource.service_name}")
+ shell_out!("#{systemctl_path} enable #{new_resource.service_name}")
end
def disable_service
- shell_out!("/bin/systemctl disable #{@new_resource.service_name}")
+ shell_out!("#{systemctl_path} disable #{new_resource.service_name}")
end
def is_active?
- shell_out("/bin/systemctl is-active #{@new_resource.service_name} --quiet").exitstatus == 0
+ shell_out("#{systemctl_path} is-active #{new_resource.service_name} --quiet").exitstatus == 0
end
def is_enabled?
- shell_out("/bin/systemctl is-enabled #{@new_resource.service_name} --quiet").exitstatus == 0
+ shell_out("#{systemctl_path} is-enabled #{new_resource.service_name} --quiet").exitstatus == 0
end
+
+ private
+
+ def systemctl_path
+ if @systemctl_path.nil?
+ @systemctl_path = which("systemctl")
+ end
+ @systemctl_path
+ end
+
end
diff --git a/lib/chef/provider/service/upstart.rb b/lib/chef/provider/service/upstart.rb
index 41bd850d6a..3a3ddb2385 100644
--- a/lib/chef/provider/service/upstart.rb
+++ b/lib/chef/provider/service/upstart.rb
@@ -29,9 +29,12 @@ class Chef
provides :service, os: "linux"
+ def self.provides?(node, resource)
+ super && Chef::Platform::ServiceHelpers.service_resource_providers.include?(:upstart)
+ end
+
def self.supports?(resource, action)
- Chef::Platform::ServiceHelpers.service_resource_providers.include?(:upstart) &&
- Chef::Platform::ServiceHelpers.config_for_service(resource.service_name).include?(:upstart)
+ Chef::Platform::ServiceHelpers.config_for_service(resource.service_name).include?(:upstart)
end
# Upstart does more than start or stop a service, creating multiple 'states' [1] that a service can be in.
diff --git a/lib/chef/provider_resolver.rb b/lib/chef/provider_resolver.rb
index c819b0c87f..247102f191 100644
--- a/lib/chef/provider_resolver.rb
+++ b/lib/chef/provider_resolver.rb
@@ -23,22 +23,42 @@ class Chef
class ProviderResolver
attr_reader :node
+ attr_reader :resource
+ attr_reader :action
- def initialize(node)
+ def initialize(node, resource, action)
@node = node
+ @resource = resource
+ @action = action
end
# return a deterministically sorted list of Chef::Provider subclasses
def providers
- Chef::Provider.descendants.sort {|a,b| a.to_s <=> b.to_s }
+ @providers ||= Chef::Provider.descendants.sort {|a,b| a.to_s <=> b.to_s }
end
- def resolve(resource, action)
+ def resolve
maybe_explicit_provider(resource) ||
maybe_dynamic_provider_resolution(resource, action) ||
maybe_chef_platform_lookup(resource)
end
+ # this cut looks at if the provider can handle the resource type on the node
+ def enabled_handlers
+ @enabled_handlers ||=
+ providers.select do |klass|
+ klass.provides?(node, resource)
+ end
+ end
+
+ # this cut looks at if the provider can handle the specific resource and action
+ def supported_handlers
+ @supported_handlers ||=
+ enabled_handlers.select do |klass|
+ klass.supports?(resource, action)
+ end
+ end
+
private
# if resource.provider is set, just return one of those objects
@@ -49,31 +69,23 @@ class Chef
# try dynamically finding a provider based on querying the providers to see what they support
def maybe_dynamic_provider_resolution(resource, action)
- # this cut only depends on the node value and is going to be static for all nodes
- # will contain all providers that could possibly support a resource on a node
- enabled_handlers = providers.select do |klass|
- klass.provides?(node, resource)
- end
-
# log this so we know what providers will work for the generic resource on the node (early cut)
Chef::Log.debug "providers for generic #{resource.resource_name} resource enabled on node include: #{enabled_handlers}"
- # ask all the enabled providers if they can actually support the resource
- supported_handlers = enabled_handlers.select do |klass|
- klass.supports?(resource, action)
- end
-
# what providers were excluded by machine state (late cut)
Chef::Log.debug "providers that refused resource #{resource} were: #{enabled_handlers - supported_handlers}"
Chef::Log.debug "providers that support resource #{resource} include: #{supported_handlers}"
+ # if none of the providers specifically support the resource, we still need to pick one of the providers that are
+ # enabled on the node to handle the why-run use case.
handlers = supported_handlers.empty? ? enabled_handlers : supported_handlers
+ Chef::Log.debug "no providers supported the resource, falling back to enabled handlers" if supported_handlers.empty?
if handlers.count >= 2
+ # this magic stack ranks the providers by where they appear in the provider_priority_map, it is mostly used
+ # to pick amongst N different ways to start init scripts on different debian/ubuntu systems.
priority_list = [ get_provider_priority_map(resource.resource_name, node) ].flatten.compact
-
handlers = handlers.sort_by { |x| i = priority_list.index x; i.nil? ? Float::INFINITY : i }
-
handlers = [ handlers.first ]
end
@@ -81,6 +93,8 @@ class Chef
raise Chef::Exceptions::AmbiguousProviderResolution.new(resource, handlers) if handlers.count >= 2
+ Chef::Log.debug "dynamic provider resolver FAILED to resolve a provider" if handlers.empty?
+
return nil if handlers.empty?
handlers[0]
diff --git a/lib/chef/resource.rb b/lib/chef/resource.rb
index c38f36aa72..8d964da66d 100644
--- a/lib/chef/resource.rb
+++ b/lib/chef/resource.rb
@@ -29,6 +29,7 @@ require 'chef/resource/conditional_action_not_nothing'
require 'chef/resource_collection'
require 'chef/node_map'
require 'chef/node'
+require 'chef/provider_resolver'
require 'chef/platform'
require 'chef/mixin/deprecation'
@@ -679,7 +680,7 @@ F
end
def provider_for_action(action)
- provider = run_context.provider_resolver.resolve(self, action).new(self, run_context)
+ provider = Chef::ProviderResolver.new(node, self, action).resolve.new(self, run_context)
provider.action = action
provider
end
diff --git a/lib/chef/run_context.rb b/lib/chef/run_context.rb
index 18d353ac61..1a2d7ba3a3 100644
--- a/lib/chef/run_context.rb
+++ b/lib/chef/run_context.rb
@@ -18,7 +18,6 @@
# limitations under the License.
require 'chef/resource_collection'
-require 'chef/provider_resolver'
require 'chef/cookbook_version'
require 'chef/node'
require 'chef/role'
@@ -51,9 +50,6 @@ class Chef
# recipes, which is triggered by #load. (See also: CookbookCompiler)
attr_accessor :resource_collection
- # Chef::ProviderResolver for this run
- attr_accessor :provider_resolver
-
# A Hash containing the immediate notifications triggered by resources
# during the converge phase of the chef run.
attr_accessor :immediate_notification_collection
@@ -87,7 +83,6 @@ class Chef
@node.run_context = self
@cookbook_compiler = nil
- @provider_resolver = Chef::ProviderResolver.new(@node)
end
# Triggers the compile phase of the chef run. Implemented by
diff --git a/lib/chef/util/selinux.rb b/lib/chef/util/selinux.rb
index 92d5756552..778da042e3 100644
--- a/lib/chef/util/selinux.rb
+++ b/lib/chef/util/selinux.rb
@@ -21,6 +21,7 @@
# limitations under the License.
require 'chef/mixin/shell_out'
+require 'chef/mixin/which'
class Chef
class Util
@@ -32,6 +33,7 @@ class Chef
module Selinux
include Chef::Mixin::ShellOut
+ include Chef::Mixin::Which
# We want to initialize below variables once during a
# chef-client run therefore they are class variables.
@@ -67,15 +69,6 @@ class Chef
@@selinuxenabled_path
end
- def which(cmd)
- paths = ENV['PATH'].split(File::PATH_SEPARATOR) + [ '/bin', '/usr/bin', '/sbin', '/usr/sbin' ]
- paths.each do |path|
- filename = File.join(path, cmd)
- return filename if File.executable?(filename)
- end
- false
- end
-
def check_selinux_enabled?
if selinuxenabled_path
cmd = shell_out!(selinuxenabled_path, :returns => [0,1])
@@ -97,4 +90,3 @@ class Chef
end
end
end
-
diff --git a/spec/support/shared/unit/resource/static_provider_resolution.rb b/spec/support/shared/unit/resource/static_provider_resolution.rb
index 147852598a..2bc4c70d95 100644
--- a/spec/support/shared/unit/resource/static_provider_resolution.rb
+++ b/spec/support/shared/unit/resource/static_provider_resolution.rb
@@ -43,12 +43,7 @@ def static_provider_resolution(opts={})
node
}
let(:events) { Chef::EventDispatch::Dispatcher.new }
- let(:provider_resolver) { Chef::ProviderResolver.new(node) }
- let(:run_context) {
- run_context = Chef::RunContext.new(node, {}, events)
- run_context.provider_resolver = provider_resolver
- run_context
- }
+ let(:run_context) { Chef::RunContext.new(node, {}, events) }
let(:resource) { resource_class.new("foo", run_context) }
it "should return a #{resource_class}" do
diff --git a/spec/unit/provider/service/systemd_service_spec.rb b/spec/unit/provider/service/systemd_service_spec.rb
index 2fed6bfd11..5ba3bed184 100644
--- a/spec/unit/provider/service/systemd_service_spec.rb
+++ b/spec/unit/provider/service/systemd_service_spec.rb
@@ -19,238 +19,253 @@
require 'spec_helper'
describe Chef::Provider::Service::Systemd do
+
+ let(:node) { Chef::Node.new }
+
+ let(:events) { Chef::EventDispatch::Dispatcher.new }
+
+ let(:run_context) { Chef::RunContext.new(node, {}, events) }
+
+ let(:service_name) { "rsyslog.service" }
+
+ let(:new_resource) { Chef::Resource::Service.new(service_name) }
+
+ let(:provider) { Chef::Provider::Service::Systemd.new(new_resource, run_context) }
+
+ let(:shell_out_success) do
+ double('shell_out_with_systems_locale', :exitstatus => 0, :error? => false)
+ end
+
+ let(:shell_out_failure) do
+ double('shell_out_with_systems_locale', :exitstatus => 1, :error? => true)
+ end
+
+ let(:current_resource) { Chef::Resource::Service.new(service_name) }
+
before(:each) do
- @node = Chef::Node.new
- @events = Chef::EventDispatch::Dispatcher.new
- @run_context = Chef::RunContext.new(@node, {}, @events)
- @new_resource = Chef::Resource::Service.new('rsyslog.service')
- @provider = Chef::Provider::Service::Systemd.new(@new_resource, @run_context)
-
- @shell_out_success = double('shell_out_with_systems_locale',
- :exitstatus => 0, :error? => false)
- @shell_out_failure = double('shell_out_with_systems_locale',
- :exitstatus => 1, :error? => true)
+ allow(Chef::Resource::Service).to receive(:new).with(service_name).and_return(current_resource)
end
describe "load_current_resource" do
- before(:each) do
- @current_resource = Chef::Resource::Service.new('rsyslog.service')
- allow(Chef::Resource::Service).to receive(:new).and_return(@current_resource)
- allow(@provider).to receive(:is_active?).and_return(false)
- allow(@provider).to receive(:is_enabled?).and_return(false)
+ before(:each) do
+ allow(provider).to receive(:is_active?).and_return(false)
+ allow(provider).to receive(:is_enabled?).and_return(false)
end
it "should create a current resource with the name of the new resource" do
- expect(Chef::Resource::Service).to receive(:new).and_return(@current_resource)
- @provider.load_current_resource
+ expect(Chef::Resource::Service).to receive(:new).with(new_resource.name).and_return(current_resource)
+ provider.load_current_resource
end
it "should set the current resources service name to the new resources service name" do
- expect(@current_resource).to receive(:service_name).with(@new_resource.service_name)
- @provider.load_current_resource
+ provider.load_current_resource
+ expect(current_resource.service_name).to eql(service_name)
end
it "should check if the service is running" do
- expect(@provider).to receive(:is_active?)
- @provider.load_current_resource
+ expect(provider).to receive(:is_active?)
+ provider.load_current_resource
end
it "should set running to true if the service is running" do
- allow(@provider).to receive(:is_active?).and_return(true)
- expect(@current_resource).to receive(:running).with(true)
- @provider.load_current_resource
+ allow(provider).to receive(:is_active?).and_return(true)
+ provider.load_current_resource
+ expect(current_resource.running).to be true
end
it "should set running to false if the service is not running" do
- allow(@provider).to receive(:is_active?).and_return(false)
- expect(@current_resource).to receive(:running).with(false)
- @provider.load_current_resource
+ allow(provider).to receive(:is_active?).and_return(false)
+ provider.load_current_resource
+ expect(current_resource.running).to be false
end
describe "when a status command has been specified" do
before do
- allow(@new_resource).to receive(:status_command).and_return("/bin/chefhasmonkeypants status")
+ allow(new_resource).to receive(:status_command).and_return("/bin/chefhasmonkeypants status")
end
it "should run the services status command if one has been specified" do
- allow(@provider).to receive(:shell_out).and_return(@shell_out_success)
- expect(@current_resource).to receive(:running).with(true)
- @provider.load_current_resource
+ allow(provider).to receive(:shell_out).and_return(shell_out_success)
+ provider.load_current_resource
+ expect(current_resource.running).to be true
end
it "should run the services status command if one has been specified and properly set status check state" do
- allow(@provider).to receive(:shell_out).with("/bin/chefhasmonkeypants status").and_return(@shell_out_success)
- @provider.load_current_resource
- expect(@provider.instance_variable_get("@status_check_success")).to be_true
+ allow(provider).to receive(:shell_out).with("/bin/chefhasmonkeypants status").and_return(shell_out_success)
+ provider.load_current_resource
+ expect(provider.status_check_success).to be true
end
it "should set running to false if a status command fails" do
- allow(@provider).to receive(:shell_out).and_return(@shell_out_failure)
- expect(@current_resource).to receive(:running).with(false)
- @provider.load_current_resource
+ allow(provider).to receive(:shell_out).and_return(shell_out_failure)
+ provider.load_current_resource
+ expect(current_resource.running).to be false
end
it "should update state to indicate status check failed when a status command fails" do
- allow(@provider).to receive(:shell_out).and_return(@shell_out_failure)
- @provider.load_current_resource
- expect(@provider.instance_variable_get("@status_check_success")).to be_false
+ allow(provider).to receive(:shell_out).and_return(shell_out_failure)
+ provider.load_current_resource
+ expect(provider.status_check_success).to be false
end
end
it "should check if the service is enabled" do
- expect(@provider).to receive(:is_enabled?)
- @provider.load_current_resource
+ expect(provider).to receive(:is_enabled?)
+ provider.load_current_resource
end
it "should set enabled to true if the service is enabled" do
- allow(@provider).to receive(:is_enabled?).and_return(true)
- expect(@current_resource).to receive(:enabled).with(true)
- @provider.load_current_resource
+ allow(provider).to receive(:is_enabled?).and_return(true)
+ provider.load_current_resource
+ expect(current_resource.enabled).to be true
end
it "should set enabled to false if the service is not enabled" do
- allow(@provider).to receive(:is_enabled?).and_return(false)
- expect(@current_resource).to receive(:enabled).with(false)
- @provider.load_current_resource
+ allow(provider).to receive(:is_enabled?).and_return(false)
+ provider.load_current_resource
+ expect(current_resource.enabled).to be false
end
it "should return the current resource" do
- expect(@provider.load_current_resource).to eql(@current_resource)
+ expect(provider.load_current_resource).to eql(current_resource)
end
end
- describe "start and stop service" do
- before(:each) do
- @current_resource = Chef::Resource::Service.new('rsyslog.service')
- allow(Chef::Resource::Service).to receive(:new).and_return(@current_resource)
- @provider.current_resource = @current_resource
- end
-
- it "should call the start command if one is specified" do
- allow(@new_resource).to receive(:start_command).and_return("/sbin/rsyslog startyousillysally")
- expect(@provider).to receive(:shell_out_with_systems_locale!).with("/sbin/rsyslog startyousillysally")
- @provider.start_service
- end
+ def setup_current_resource
+ provider.current_resource = current_resource
+ current_resource.service_name(service_name)
+ end
- it "should call '/bin/systemctl start service_name' if no start command is specified" do
- expect(@provider).to receive(:shell_out_with_systems_locale!).with("/bin/systemctl start #{@new_resource.service_name}").and_return(@shell_out_success)
- @provider.start_service
- end
+ %w{/usr/bin/systemctl /bin/systemctl}.each do |systemctl_path|
+ describe "when systemctl path is #{systemctl_path}" do
+ before(:each) do
+ setup_current_resource
+ allow(provider).to receive(:which).with("systemctl").and_return(systemctl_path)
+ end
- it "should not call '/bin/systemctl start service_name' if it is already running" do
- allow(@current_resource).to receive(:running).and_return(true)
- expect(@provider).not_to receive(:shell_out_with_systems_locale!).with("/bin/systemctl start #{@new_resource.service_name}")
- @provider.start_service
- end
+ describe "start and stop service" do
- it "should call the restart command if one is specified" do
- allow(@current_resource).to receive(:running).and_return(true)
- allow(@new_resource).to receive(:restart_command).and_return("/sbin/rsyslog restartyousillysally")
- expect(@provider).to receive(:shell_out_with_systems_locale!).with("/sbin/rsyslog restartyousillysally")
- @provider.restart_service
- end
+ it "should call the start command if one is specified" do
+ allow(new_resource).to receive(:start_command).and_return("/sbin/rsyslog startyousillysally")
+ expect(provider).to receive(:shell_out_with_systems_locale!).with("/sbin/rsyslog startyousillysally")
+ provider.start_service
+ end
- it "should call '/bin/systemctl restart service_name' if no restart command is specified" do
- allow(@current_resource).to receive(:running).and_return(true)
- expect(@provider).to receive(:shell_out_with_systems_locale!).with("/bin/systemctl restart #{@new_resource.service_name}").and_return(@shell_out_success)
- @provider.restart_service
- end
+ it "should call '#{systemctl_path} start service_name' if no start command is specified" do
+ expect(provider).to receive(:shell_out_with_systems_locale!).with("#{systemctl_path} start #{service_name}").and_return(shell_out_success)
+ provider.start_service
+ end
- describe "reload service" do
- context "when a reload command is specified" do
- it "should call the reload command" do
- allow(@current_resource).to receive(:running).and_return(true)
- allow(@new_resource).to receive(:reload_command).and_return("/sbin/rsyslog reloadyousillysally")
- expect(@provider).to receive(:shell_out_with_systems_locale!).with("/sbin/rsyslog reloadyousillysally")
- @provider.reload_service
+ it "should not call '#{systemctl_path} start service_name' if it is already running" do
+ current_resource.running(true)
+ expect(provider).not_to receive(:shell_out_with_systems_locale!).with("#{systemctl_path} start #{service_name}")
+ provider.start_service
end
- end
- context "when a reload command is not specified" do
- it "should call '/bin/systemctl reload service_name' if the service is running" do
- allow(@current_resource).to receive(:running).and_return(true)
- expect(@provider).to receive(:shell_out_with_systems_locale!).with("/bin/systemctl reload #{@new_resource.service_name}").and_return(@shell_out_success)
- @provider.reload_service
+ it "should call the restart command if one is specified" do
+ current_resource.running(true)
+ allow(new_resource).to receive(:restart_command).and_return("/sbin/rsyslog restartyousillysally")
+ expect(provider).to receive(:shell_out_with_systems_locale!).with("/sbin/rsyslog restartyousillysally")
+ provider.restart_service
end
- it "should start the service if the service is not running" do
- allow(@current_resource).to receive(:running).and_return(false)
- expect(@provider).to receive(:start_service).and_return(true)
- @provider.reload_service
+ it "should call '#{systemctl_path} restart service_name' if no restart command is specified" do
+ current_resource.running(true)
+ expect(provider).to receive(:shell_out_with_systems_locale!).with("#{systemctl_path} restart #{service_name}").and_return(shell_out_success)
+ provider.restart_service
end
- end
- end
- it "should call the stop command if one is specified" do
- allow(@current_resource).to receive(:running).and_return(true)
- allow(@new_resource).to receive(:stop_command).and_return("/sbin/rsyslog stopyousillysally")
- expect(@provider).to receive(:shell_out_with_systems_locale!).with("/sbin/rsyslog stopyousillysally")
- @provider.stop_service
- end
+ describe "reload service" do
+ context "when a reload command is specified" do
+ it "should call the reload command" do
+ current_resource.running(true)
+ allow(new_resource).to receive(:reload_command).and_return("/sbin/rsyslog reloadyousillysally")
+ expect(provider).to receive(:shell_out_with_systems_locale!).with("/sbin/rsyslog reloadyousillysally")
+ provider.reload_service
+ end
+ end
+
+ context "when a reload command is not specified" do
+ it "should call '#{systemctl_path} reload service_name' if the service is running" do
+ current_resource.running(true)
+ expect(provider).to receive(:shell_out_with_systems_locale!).with("#{systemctl_path} reload #{service_name}").and_return(shell_out_success)
+ provider.reload_service
+ end
+
+ it "should start the service if the service is not running" do
+ current_resource.running(false)
+ expect(provider).to receive(:start_service).and_return(true)
+ provider.reload_service
+ end
+ end
+ end
- it "should call '/bin/systemctl stop service_name' if no stop command is specified" do
- allow(@current_resource).to receive(:running).and_return(true)
- expect(@provider).to receive(:shell_out_with_systems_locale!).with("/bin/systemctl stop #{@new_resource.service_name}").and_return(@shell_out_success)
- @provider.stop_service
- end
+ it "should call the stop command if one is specified" do
+ current_resource.running(true)
+ allow(new_resource).to receive(:stop_command).and_return("/sbin/rsyslog stopyousillysally")
+ expect(provider).to receive(:shell_out_with_systems_locale!).with("/sbin/rsyslog stopyousillysally")
+ provider.stop_service
+ end
- it "should not call '/bin/systemctl stop service_name' if it is already stopped" do
- allow(@current_resource).to receive(:running).and_return(false)
- expect(@provider).not_to receive(:shell_out_with_systems_locale!).with("/bin/systemctl stop #{@new_resource.service_name}")
- @provider.stop_service
- end
- end
+ it "should call '#{systemctl_path} stop service_name' if no stop command is specified" do
+ current_resource.running(true)
+ expect(provider).to receive(:shell_out_with_systems_locale!).with("#{systemctl_path} stop #{service_name}").and_return(shell_out_success)
+ provider.stop_service
+ end
- describe "enable and disable service" do
- before(:each) do
- @current_resource = Chef::Resource::Service.new('rsyslog.service')
- allow(Chef::Resource::Service).to receive(:new).and_return(@current_resource)
- @provider.current_resource = @current_resource
- end
+ it "should not call '#{systemctl_path} stop service_name' if it is already stopped" do
+ current_resource.running(false)
+ expect(provider).not_to receive(:shell_out_with_systems_locale!).with("#{systemctl_path} stop #{service_name}")
+ provider.stop_service
+ end
+ end
- it "should call '/bin/systemctl enable service_name' to enable the service" do
- expect(@provider).to receive(:shell_out!).with("/bin/systemctl enable #{@new_resource.service_name}").and_return(@shell_out_success)
- @provider.enable_service
- end
+ describe "enable and disable service" do
+ before(:each) do
+ provider.current_resource = current_resource
+ current_resource.service_name(service_name)
+ allow(provider).to receive(:which).with("systemctl").and_return("#{systemctl_path}")
+ end
- it "should call '/bin/systemctl disable service_name' to disable the service" do
- expect(@provider).to receive(:shell_out!).with("/bin/systemctl disable #{@new_resource.service_name}").and_return(@shell_out_success)
- @provider.disable_service
- end
- end
+ it "should call '#{systemctl_path} enable service_name' to enable the service" do
+ expect(provider).to receive(:shell_out!).with("#{systemctl_path} enable #{service_name}").and_return(shell_out_success)
+ provider.enable_service
+ end
- describe "is_active?" do
- before(:each) do
- @current_resource = Chef::Resource::Service.new('rsyslog.service')
- allow(Chef::Resource::Service).to receive(:new).and_return(@current_resource)
- end
+ it "should call '#{systemctl_path} disable service_name' to disable the service" do
+ expect(provider).to receive(:shell_out!).with("#{systemctl_path} disable #{service_name}").and_return(shell_out_success)
+ provider.disable_service
+ end
+ end
- it "should return true if '/bin/systemctl is-active service_name' returns 0" do
- expect(@provider).to receive(:shell_out).with('/bin/systemctl is-active rsyslog.service --quiet').and_return(@shell_out_success)
- expect(@provider.is_active?).to be_true
- end
+ describe "is_active?" do
+ before(:each) do
+ provider.current_resource = current_resource
+ current_resource.service_name(service_name)
+ allow(provider).to receive(:which).with("systemctl").and_return("#{systemctl_path}")
+ end
- it "should return false if '/bin/systemctl is-active service_name' returns anything except 0" do
- expect(@provider).to receive(:shell_out).with('/bin/systemctl is-active rsyslog.service --quiet').and_return(@shell_out_failure)
- expect(@provider.is_active?).to be_false
- end
- end
+ it "should return true if '#{systemctl_path} is-active service_name' returns 0" do
+ expect(provider).to receive(:shell_out).with("#{systemctl_path} is-active #{service_name} --quiet").and_return(shell_out_success)
+ expect(provider.is_active?).to be true
+ end
- describe "is_enabled?" do
- before(:each) do
- @current_resource = Chef::Resource::Service.new('rsyslog.service')
- allow(Chef::Resource::Service).to receive(:new).and_return(@current_resource)
- end
+ it "should return false if '#{systemctl_path} is-active service_name' returns anything except 0" do
+ expect(provider).to receive(:shell_out).with("#{systemctl_path} is-active #{service_name} --quiet").and_return(shell_out_failure)
+ expect(provider.is_active?).to be false
+ end
+ end
- it "should return true if '/bin/systemctl is-enabled service_name' returns 0" do
- expect(@provider).to receive(:shell_out).with('/bin/systemctl is-enabled rsyslog.service --quiet').and_return(@shell_out_success)
- expect(@provider.is_enabled?).to be_true
- end
+ it "should return true if '#{systemctl_path} is-enabled service_name' returns 0" do
+ expect(provider).to receive(:shell_out).with("#{systemctl_path} is-enabled #{service_name} --quiet").and_return(shell_out_success)
+ expect(provider.is_enabled?).to be true
+ end
- it "should return false if '/bin/systemctl is-enabled service_name' returns anything except 0" do
- expect(@provider).to receive(:shell_out).with('/bin/systemctl is-enabled rsyslog.service --quiet').and_return(@shell_out_failure)
- expect(@provider.is_enabled?).to be_false
+ it "should return false if '#{systemctl_path} is-enabled service_name' returns anything except 0" do
+ expect(provider).to receive(:shell_out).with("#{systemctl_path} is-enabled #{service_name} --quiet").and_return(shell_out_failure)
+ expect(provider.is_enabled?).to be false
+ end
end
end
end
diff --git a/spec/unit/provider_resolver_spec.rb b/spec/unit/provider_resolver_spec.rb
index 927cca4f58..c56207c554 100644
--- a/spec/unit/provider_resolver_spec.rb
+++ b/spec/unit/provider_resolver_spec.rb
@@ -33,11 +33,11 @@ describe Chef::ProviderResolver do
node
end
- let(:provider_resolver) { Chef::ProviderResolver.new(node) }
+ let(:provider_resolver) { Chef::ProviderResolver.new(node, resource, action) }
let(:action) { :start }
- let(:resolved_provider) { provider_resolver.resolve(resource, action) }
+ let(:resolved_provider) { provider_resolver.resolve }
let(:provider) { nil }
@@ -63,11 +63,34 @@ describe Chef::ProviderResolver do
allow(resource).to receive(:service_name).and_return("ntp")
end
- shared_examples_for "a debian platform with upstart and update-rc.d" do
+ shared_examples_for "an ubuntu platform with upstart, update-rc.d and systemd" do
before do
- stub_service_providers(:debian, :invokercd, :upstart)
+ stub_service_providers(:debian, :invokercd, :upstart, :systemd)
+ end
+
+ it "when only the SysV init script exists, it returns a Service::Debian provider" do
+ allow(Chef::Platform::ServiceHelpers).to receive(:config_for_service).with("ntp")
+ .and_return( [ :initd, :systemd ] )
+ expect(resolved_provider).to eql(Chef::Provider::Service::Systemd)
+ end
+
+ it "when both SysV and Upstart scripts exist, it returns a Service::Upstart provider" do
+ allow(Chef::Platform::ServiceHelpers).to receive(:config_for_service).with("ntp")
+ .and_return( [ :initd, :upstart, :systemd ] )
+ expect(resolved_provider).to eql(Chef::Provider::Service::Systemd)
+ end
+
+ it "when only the Upstart script exists, it returns a Service::Upstart provider" do
+ allow(Chef::Platform::ServiceHelpers).to receive(:config_for_service).with("ntp")
+ .and_return( [ :upstart, :systemd ] )
+ expect(resolved_provider).to eql(Chef::Provider::Service::Systemd)
end
+ it "when both do not exist, it calls the old style provider resolver and returns a Debian Provider" do
+ allow(Chef::Platform::ServiceHelpers).to receive(:config_for_service).with("ntp")
+ .and_return( [ :systemd ] )
+ expect(resolved_provider).to eql(Chef::Provider::Service::Systemd)
+ end
it "when only the SysV init script exists, it returns a Service::Debian provider" do
allow(Chef::Platform::ServiceHelpers).to receive(:config_for_service).with("ntp")
.and_return( [ :initd ] )
@@ -89,7 +112,137 @@ describe Chef::ProviderResolver do
it "when both do not exist, it calls the old style provider resolver and returns a Debian Provider" do
allow(Chef::Platform::ServiceHelpers).to receive(:config_for_service).with("ntp")
.and_return( [ ] )
- expect(resolved_provider).to eql(Chef::Provider::Service::Debian)
+ expect(resolved_provider).to eql(Chef::Provider::Service::Systemd)
+ end
+ end
+
+ shared_examples_for "an ubuntu platform with upstart and update-rc.d" do
+ before do
+ stub_service_providers(:debian, :invokercd, :upstart)
+ end
+
+ # needs to be handled by the highest priority init.d handler
+ context "when only the SysV init script exists" do
+ before do
+ allow(Chef::Platform::ServiceHelpers).to receive(:config_for_service).with("ntp")
+ .and_return( [ :initd ] )
+ end
+
+ it "enables init, invokercd, debian and upstart providers" do
+ expect(provider_resolver.enabled_handlers).to include(
+ Chef::Provider::Service::Debian,
+ Chef::Provider::Service::Init,
+ Chef::Provider::Service::Invokercd,
+ Chef::Provider::Service::Upstart,
+ )
+ end
+
+ it "supports all the enabled handlers except for upstart" do
+ expect(provider_resolver.supported_handlers).to include(
+ Chef::Provider::Service::Debian,
+ Chef::Provider::Service::Init,
+ Chef::Provider::Service::Invokercd,
+ )
+ expect(provider_resolver.supported_handlers).to_not include(
+ Chef::Provider::Service::Upstart,
+ )
+ end
+
+ it "returns a Service::Debian provider" do
+ expect(resolved_provider).to eql(Chef::Provider::Service::Debian)
+ end
+ end
+
+ # on ubuntu this must be handled by upstart, the init script will exit 1 and fail
+ context "when both SysV and Upstart scripts exist" do
+ before do
+ allow(Chef::Platform::ServiceHelpers).to receive(:config_for_service).with("ntp")
+ .and_return( [ :initd, :upstart ] )
+ end
+
+ it "enables init, invokercd, debian and upstart providers" do
+ expect(provider_resolver.enabled_handlers).to include(
+ Chef::Provider::Service::Debian,
+ Chef::Provider::Service::Init,
+ Chef::Provider::Service::Invokercd,
+ Chef::Provider::Service::Upstart,
+ )
+ end
+
+ it "supports all the enabled handlers" do
+ expect(provider_resolver.supported_handlers).to include(
+ Chef::Provider::Service::Debian,
+ Chef::Provider::Service::Init,
+ Chef::Provider::Service::Invokercd,
+ Chef::Provider::Service::Upstart,
+ )
+ end
+
+ it "returns a Service::Upstart provider" do
+ expect(resolved_provider).to eql(Chef::Provider::Service::Upstart)
+ end
+ end
+
+ # this case is a pure-upstart script which is easy
+ context "when only the Upstart script exists" do
+ before do
+ allow(Chef::Platform::ServiceHelpers).to receive(:config_for_service).with("ntp")
+ .and_return( [ :upstart ] )
+ end
+
+ it "enables init, invokercd, debian and upstart providers" do
+ expect(provider_resolver.enabled_handlers).to include(
+ Chef::Provider::Service::Debian,
+ Chef::Provider::Service::Init,
+ Chef::Provider::Service::Invokercd,
+ Chef::Provider::Service::Upstart,
+ )
+ end
+
+ it "supports only the upstart handler" do
+ expect(provider_resolver.supported_handlers).to include(
+ Chef::Provider::Service::Upstart,
+ )
+ expect(provider_resolver.supported_handlers).to_not include(
+ Chef::Provider::Service::Debian,
+ Chef::Provider::Service::Init,
+ Chef::Provider::Service::Invokercd,
+ )
+ end
+
+ it "returns a Service::Upstart provider" do
+ expect(resolved_provider).to eql(Chef::Provider::Service::Upstart)
+ end
+ end
+
+ # this case is important to get correct for why-run when no config is setup
+ context "when both do not exist" do
+ before do
+ allow(Chef::Platform::ServiceHelpers).to receive(:config_for_service).with("ntp")
+ .and_return( [ ] )
+ end
+
+ it "enables init, invokercd, debian and upstart providers" do
+ expect(provider_resolver.enabled_handlers).to include(
+ Chef::Provider::Service::Debian,
+ Chef::Provider::Service::Init,
+ Chef::Provider::Service::Invokercd,
+ Chef::Provider::Service::Upstart,
+ )
+ end
+
+ it "no providers claim to support the resource" do
+ expect(provider_resolver.supported_handlers).to_not include(
+ Chef::Provider::Service::Upstart,
+ Chef::Provider::Service::Debian,
+ Chef::Provider::Service::Init,
+ Chef::Provider::Service::Invokercd,
+ )
+ end
+
+ it "returns a Debian Provider" do
+ expect(resolved_provider).to eql(Chef::Provider::Service::Upstart)
+ end
end
end
@@ -104,6 +257,12 @@ describe Chef::ProviderResolver do
.and_return( [ :initd ] )
expect(resolved_provider).to eql(Chef::Provider::Service::Insserv)
end
+
+ it "uses the Service::Insserv Provider when there is no config" do
+ allow(Chef::Platform::ServiceHelpers).to receive(:config_for_service).with("ntp")
+ .and_return( [ ] )
+ expect(resolved_provider).to eql(Chef::Provider::Service::Insserv)
+ end
end
context "when the user has installed upstart" do
@@ -111,7 +270,7 @@ describe Chef::ProviderResolver do
stub_service_providers(:debian, :invokercd, :insserv, :upstart)
end
- it "when only the SysV init script exists, it returns a Service::Debian provider" do
+ it "when only the SysV init script exists, it returns an Insserv provider" do
allow(Chef::Platform::ServiceHelpers).to receive(:config_for_service).with("ntp")
.and_return( [ :initd ] )
expect(resolved_provider).to eql(Chef::Provider::Service::Insserv)
@@ -132,12 +291,18 @@ describe Chef::ProviderResolver do
it "when both do not exist, it calls the old style provider resolver and returns a Debian Provider" do
allow(Chef::Platform::ServiceHelpers).to receive(:config_for_service).with("ntp")
.and_return( [ ] )
- expect(resolved_provider).to eql(Chef::Provider::Service::Insserv)
+ expect(resolved_provider).to eql(Chef::Provider::Service::Upstart)
end
end
end
- describe "on Linux" do
+ describe "on Ubuntu 14.10" do
+ let(:os) { "linux" }
+ let(:platform) { "ubuntu" }
+ let(:platform_family) { "debian" }
+ let(:platform_version) { "14.04" }
+
+ it_behaves_like "an ubuntu platform with upstart, update-rc.d and systemd"
end
describe "on Ubuntu 14.04" do
@@ -146,7 +311,7 @@ describe Chef::ProviderResolver do
let(:platform_family) { "debian" }
let(:platform_version) { "14.04" }
- it_behaves_like "a debian platform with upstart and update-rc.d"
+ it_behaves_like "an ubuntu platform with upstart and update-rc.d"
end
describe "on Ubuntu 10.04" do
@@ -155,7 +320,7 @@ describe Chef::ProviderResolver do
let(:platform_family) { "debian" }
let(:platform_version) { "10.04" }
- it_behaves_like "a debian platform with upstart and update-rc.d"
+ it_behaves_like "an ubuntu platform with upstart and update-rc.d"
end
# old debian uses the Debian provider (does not have insserv or upstart, or update-rc.d???)
diff --git a/spec/unit/resource/timestamped_deploy_spec.rb b/spec/unit/resource/timestamped_deploy_spec.rb
index 2af9d8bb0f..eca6c570d4 100644
--- a/spec/unit/resource/timestamped_deploy_spec.rb
+++ b/spec/unit/resource/timestamped_deploy_spec.rb
@@ -20,35 +20,14 @@ require 'spec_helper'
describe Chef::Resource::TimestampedDeploy, "initialize" do
- let(:node) {
- node = Chef::Node.new
- node.automatic_attrs[:os] = 'linux'
- node.automatic_attrs[:platform_family] = 'rhel'
- node
- }
- let(:events) { Chef::EventDispatch::Dispatcher.new }
- let(:provider_resolver) { Chef::ProviderResolver.new(node) }
- let(:run_context) {
- run_context = Chef::RunContext.new(node, {}, events)
- run_context.provider_resolver = provider_resolver
- run_context
- }
- let(:resource) { Chef::Resource::TimestampedDeploy.new("stuff", run_context) }
+ static_provider_resolution(
+ resource: Chef::Resource::TimestampedDeploy,
+ provider: Chef::Provider::Deploy::Timestamped,
+ name: :deploy,
+ action: :deploy,
+ os: 'linux',
+ platform_family: 'rhel',
+ )
- it "should return a Chef::Resource::TimestampedDeploy" do
- expect(resource).to be_a_kind_of(Chef::Resource::TimestampedDeploy)
- end
-
- it "should set the resource_name to :timestamped_deploy" do
- expect(resource.resource_name).to eql(:deploy)
- end
-
- it "should leave the provider nil" do
- expect(resource.provider).to eql(nil)
- end
-
- it "should resolve to a Chef::Provider::Deploy::Timestamped" do
- expect(resource.provider_for_action(:install)).to be_a(Chef::Provider::Deploy::Timestamped)
- end
end
diff --git a/spec/unit/runner_spec.rb b/spec/unit/runner_spec.rb
index 9bd4199418..b30f818da1 100644
--- a/spec/unit/runner_spec.rb
+++ b/spec/unit/runner_spec.rb
@@ -99,13 +99,15 @@ describe Chef::Runner do
end
context "when we fall through to old Chef::Platform resolution" do
+ let(:provider_resolver) { Chef::ProviderResolver.new(node, first_resource, nil) }
before do
# set up old Chef::Platform resolution instead of provider_resolver
Chef::Platform.set(
:resource => :cat,
:provider => Chef::Provider::SnakeOil
)
- allow(run_context.provider_resolver).to receive(:maybe_dynamic_provider_resolution).with(first_resource, anything()).and_return(nil)
+ allow(Chef::ProviderResolver).to receive(:new).and_return(provider_resolver)
+ allow(provider_resolver).to receive(:maybe_dynamic_provider_resolution).with(first_resource, anything()).and_return(nil)
end
it "should use the platform provider if it has one" do