chef 12.0.0.rc.0-x86-mingw32 → 12.0.0-x86-mingw32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +1 -1
  3. data/lib/chef/api_client/registration.rb +3 -1
  4. data/lib/chef/chef_fs/data_handler/group_data_handler.rb +4 -0
  5. data/lib/chef/config.rb +46 -38
  6. data/lib/chef/event_loggers/windows_eventlog.rb +5 -6
  7. data/lib/chef/exceptions.rb +13 -1
  8. data/lib/chef/file_content_management/tempfile.rb +33 -5
  9. data/lib/chef/knife.rb +11 -3
  10. data/lib/chef/knife/bootstrap.rb +8 -7
  11. data/lib/chef/mixin/deep_merge.rb +15 -54
  12. data/lib/chef/mixin/which.rb +37 -0
  13. data/lib/chef/node.rb +14 -25
  14. data/lib/chef/node/attribute.rb +227 -41
  15. data/lib/chef/node/attribute_collections.rb +117 -3
  16. data/lib/chef/node/immutable_collections.rb +6 -6
  17. data/lib/chef/platform/provider_priority_map.rb +3 -2
  18. data/lib/chef/platform/service_helpers.rb +37 -8
  19. data/lib/chef/provider/service/aixinit.rb +1 -1
  20. data/lib/chef/provider/service/arch.rb +1 -1
  21. data/lib/chef/provider/service/debian.rb +5 -1
  22. data/lib/chef/provider/service/init.rb +4 -0
  23. data/lib/chef/provider/service/insserv.rb +5 -1
  24. data/lib/chef/provider/service/invokercd.rb +5 -1
  25. data/lib/chef/provider/service/redhat.rb +5 -1
  26. data/lib/chef/provider/service/systemd.rb +50 -32
  27. data/lib/chef/provider/service/upstart.rb +5 -2
  28. data/lib/chef/provider_resolver.rb +30 -16
  29. data/lib/chef/resource.rb +2 -1
  30. data/lib/chef/resources.rb +7 -0
  31. data/lib/chef/run_context.rb +0 -5
  32. data/lib/chef/run_list/run_list_expansion.rb +2 -2
  33. data/lib/chef/shell.rb +2 -2
  34. data/lib/chef/util/selinux.rb +2 -10
  35. data/lib/chef/version.rb +1 -1
  36. data/lib/chef/workstation_config_loader.rb +1 -1
  37. data/spec/support/shared/unit/resource/static_provider_resolution.rb +1 -6
  38. data/spec/unit/api_client/registration_spec.rb +22 -0
  39. data/spec/unit/application/knife_spec.rb +6 -2
  40. data/spec/unit/chef_fs/data_handler/group_handler_spec.rb +63 -0
  41. data/spec/unit/config_spec.rb +5 -5
  42. data/spec/unit/knife/bootstrap_spec.rb +27 -1
  43. data/spec/unit/knife_spec.rb +5 -0
  44. data/spec/unit/mixin/deep_merge_spec.rb +0 -40
  45. data/spec/unit/node/attribute_spec.rb +37 -50
  46. data/spec/unit/node_spec.rb +321 -13
  47. data/spec/unit/provider/file/content_spec.rb +23 -2
  48. data/spec/unit/provider/service/systemd_service_spec.rb +173 -158
  49. data/spec/unit/provider_resolver_spec.rb +175 -10
  50. data/spec/unit/resource/timestamped_deploy_spec.rb +8 -29
  51. data/spec/unit/runner_spec.rb +3 -1
  52. metadata +147 -221
  53. data/spec/.DS_Store +0 -0
  54. data/spec/data/.DS_Store +0 -0
  55. data/spec/data/lwrp/.DS_Store +0 -0
  56. data/spec/data/lwrp/providers/.DS_Store +0 -0
  57. data/spec/data/lwrp/resources/.DS_Store +0 -0
  58. data/spec/data/lwrp_override/.DS_Store +0 -0
  59. data/spec/data/lwrp_override/providers/.DS_Store +0 -0
  60. data/spec/data/lwrp_override/resources/.DS_Store +0 -0
@@ -63,7 +63,7 @@ class Chef
63
63
  MUTATOR_METHODS.each do |mutator|
64
64
  class_eval(<<-METHOD_DEFN, __FILE__, __LINE__)
65
65
  def #{mutator}(*args, &block)
66
- root.reset_cache
66
+ root.reset_cache(root.top_level_breadcrumb)
67
67
  super
68
68
  end
69
69
  METHOD_DEFN
@@ -128,7 +128,7 @@ class Chef
128
128
  MUTATOR_METHODS.each do |mutator|
129
129
  class_eval(<<-METHOD_DEFN, __FILE__, __LINE__)
130
130
  def #{mutator}(*args, &block)
131
- root.reset_cache
131
+ root.reset_cache(root.top_level_breadcrumb)
132
132
  super
133
133
  end
134
134
  METHOD_DEFN
@@ -140,6 +140,7 @@ class Chef
140
140
  end
141
141
 
142
142
  def [](key)
143
+ root.top_level_breadcrumb ||= key
143
144
  value = super
144
145
  if !key?(key)
145
146
  value = self.class.new(root)
@@ -150,10 +151,11 @@ class Chef
150
151
  end
151
152
 
152
153
  def []=(key, value)
154
+ root.top_level_breadcrumb ||= key
153
155
  if set_unless? && key?(key)
154
156
  self[key]
155
157
  else
156
- root.reset_cache
158
+ root.reset_cache(root.top_level_breadcrumb)
157
159
  super
158
160
  end
159
161
  end
@@ -209,5 +211,117 @@ class Chef
209
211
 
210
212
  end
211
213
 
214
+ # == MultiMash
215
+ # This is a Hash-like object that contains multiple VividMashes in it. Its
216
+ # purpose is so that the user can descend into the mash and delete a subtree
217
+ # from all of the Mash objects (used to delete all values in a subtree from
218
+ # default, force_default, role_default and env_default at the same time). The
219
+ # assignment operator strictly does assignment (does no merging) and works
220
+ # by deleting the subtree and then assigning to the last mash which passed in
221
+ # the initializer.
222
+ #
223
+ # A lot of the complexity of this class comes from the fact that at any key
224
+ # value some or all of the mashes may walk off their ends and become nil or
225
+ # true or something. The schema may change so that one precidence leve may
226
+ # be 'true' object and another may be a VividMash. It is also possible that
227
+ # one or many of them may transition from VividMashes to Hashes or Arrays.
228
+ #
229
+ # It also supports the case where you may be deleting a key using node.rm
230
+ # in which case if intermediate keys all walk off into nil then you don't want
231
+ # to be autovivifying keys as you go. On the other hand you may be using
232
+ # node.force_default! in which case you'll wind up with a []= operator at the
233
+ # end and you want autovivification, so we conditionally have to support either
234
+ # operation.
235
+ #
236
+ # @todo: can we have an autovivify class that decorates a class that doesn't
237
+ # autovivify or something so that the code is less awful?
238
+ #
239
+ class MultiMash
240
+ attr_reader :root
241
+ attr_reader :mashes
242
+ attr_reader :opts
243
+ attr_reader :primary_mash
244
+
245
+ # Initialize with an array of mashes. For the delete return value to work
246
+ # properly the mashes must come from the same attribute level (i.e. all
247
+ # override or all default, but not a mix of both).
248
+ def initialize(root, primary_mash, mashes, opts={})
249
+ @root = root
250
+ @primary_mash = primary_mash
251
+ @mashes = mashes
252
+ @opts = opts
253
+ @opts[:autovivify] = true if @opts[:autovivify].nil?
254
+ end
255
+
256
+ def [](key)
257
+ # handle the secondary mashes
258
+ new_mashes = []
259
+ mashes.each do |mash|
260
+ new_mash = safe_evalute_key(mash, key)
261
+ # secondary mashes never autovivify so once they fall into nil, we just stop tracking them
262
+ new_mashes.push(new_mash) unless new_mash.nil?
263
+ end
264
+
265
+ new_primary_mash = safe_evalute_key(primary_mash, key)
266
+
267
+ if new_primary_mash.nil? && @opts[:autovivify]
268
+ primary_mash[key] = VividMash.new(root)
269
+ new_primary_mash = primary_mash[key]
270
+ end
271
+
272
+ MultiMash.new(root, new_primary_mash, new_mashes, opts)
273
+ end
274
+
275
+ def []=(key, value)
276
+ if primary_mash.nil?
277
+ # This theoretically should never happen since node#force_default! setter methods will autovivify and
278
+ # node#rm methods do not end in #[]= operators.
279
+ raise TypeError, "No autovivification was specified initially on a method chain ending in assignment"
280
+ end
281
+ ret = delete(key)
282
+ primary_mash[key] = value
283
+ ret
284
+ end
285
+
286
+ # mash.element('foo', 'bar') is the same as mash['foo']['bar']
287
+ def element(key = nil, *subkeys)
288
+ return self if key.nil?
289
+ submash = self[key]
290
+ subkeys.empty? ? submash : submash.element(*subkeys)
291
+ end
292
+
293
+ def delete(key)
294
+ # the return value is a deep merge which is correct semantics when
295
+ # merging between attributes on the same level (this would be incorrect
296
+ # if passed both override and default attributes which would need hash_only
297
+ # merging).
298
+ ret = mashes.inject(Mash.new) do |merged, mash|
299
+ Chef::Mixin::DeepMerge.merge(merged, mash)
300
+ end
301
+ ret = Chef::Mixin::DeepMerge.merge(ret, primary_mash)
302
+ mashes.each do |mash|
303
+ mash.delete(key) if mash.respond_to?(:delete)
304
+ end
305
+ primary_mash.delete(key) if primary_mash.respond_to?(:delete)
306
+ ret[key]
307
+ end
308
+
309
+ private
310
+
311
+ def safe_evalute_key(mash, key)
312
+ if mash.respond_to?(:[])
313
+ if mash.respond_to?(:has_key?)
314
+ if mash.has_key?(key)
315
+ return mash[key] if mash[key].respond_to?(:[])
316
+ end
317
+ elsif !mash[key].nil?
318
+ return mash[key] if mash[key].respond_to?(:[])
319
+ end
320
+ end
321
+ return nil
322
+ end
323
+
324
+ end
325
+
212
326
  end
213
327
  end
@@ -78,9 +78,7 @@ class Chef
78
78
  # Ruby 1.8 blocks can't have block arguments, so we must use string eval:
79
79
  class_eval(<<-METHOD_DEFN, __FILE__, __LINE__)
80
80
  def #{mutator_method_name}(*args, &block)
81
- msg = "Node attributes are read-only when you do not specify which precedence level to set. " +
82
- %Q(To set an attribute use code like `node.default["key"] = "value"')
83
- raise Exceptions::ImmutableAttributeModification, msg
81
+ raise Exceptions::ImmutableAttributeModification
84
82
  end
85
83
  METHOD_DEFN
86
84
  end
@@ -157,6 +155,10 @@ class Chef
157
155
  end
158
156
  end
159
157
 
158
+ def public_method_that_only_deep_merge_should_use(key, value)
159
+ internal_set(key, immutablize(value))
160
+ end
161
+
160
162
  alias :attribute? :has_key?
161
163
 
162
164
  # Redefine all of the methods that mutate a Hash to raise an error when called.
@@ -165,9 +167,7 @@ class Chef
165
167
  # Ruby 1.8 blocks can't have block arguments, so we must use string eval:
166
168
  class_eval(<<-METHOD_DEFN, __FILE__, __LINE__)
167
169
  def #{mutator_method_name}(*args, &block)
168
- msg = "Node attributes are read-only when you do not specify which precedence level to set. " +
169
- %Q(To set an attribute use code like `node.default["key"] = "value"')
170
- raise Exceptions::ImmutableAttributeModification, msg
170
+ raise Exceptions::ImmutableAttributeModification
171
171
  end
172
172
  METHOD_DEFN
173
173
  end
@@ -34,9 +34,10 @@ class Chef
34
34
  ], platform_family: "gentoo"
35
35
 
36
36
  priority :service, [
37
- # on debian-ish system if an upstart script exists that always wins
38
- Chef::Provider::Service::Upstart,
37
+ # we can determine what systemd supports accurately
39
38
  Chef::Provider::Service::Systemd,
39
+ # on debian-ish system if an upstart script exists that must win over sysv types
40
+ Chef::Provider::Service::Upstart,
40
41
  Chef::Provider::Service::Insserv,
41
42
  Chef::Provider::Service::Debian,
42
43
  Chef::Provider::Service::Invokercd,
@@ -18,6 +18,7 @@
18
18
 
19
19
  # XXX: mixing shellout into a mixin into classes has to be code smell
20
20
  require 'chef/mixin/shell_out'
21
+ require 'chef/mixin/which'
21
22
 
22
23
  class Chef
23
24
  class Platform
@@ -25,12 +26,21 @@ class Chef
25
26
  class << self
26
27
 
27
28
  include Chef::Mixin::ShellOut
29
+ include Chef::Mixin::Which
28
30
 
29
31
  # This helper is mostly used to sort out the mess of different
30
32
  # linux mechanisms that can be used to start services. It does
31
33
  # not necessarily need to linux-specific, but currently all our
32
34
  # other service providers are narrowly platform-specific with no
33
35
  # alternatives.
36
+ #
37
+ # NOTE: if a system has (for example) chkconfig installed then we
38
+ # should report that chkconfig is installed. The fact that a system
39
+ # may also have systemd installed does not mean that we do not
40
+ # report that systemd is also installed. This module is purely for
41
+ # discovery of all the alternatives, handling the priority of the
42
+ # different services is NOT a design concern of this module.
43
+ #
34
44
  def service_resource_providers
35
45
  service_resource_providers = []
36
46
 
@@ -55,8 +65,7 @@ class Chef
55
65
  service_resource_providers << :redhat
56
66
  end
57
67
 
58
- if ::File.exist?("/bin/systemctl")
59
- # FIXME: look for systemd as init provider
68
+ if systemd_sanity_check?
60
69
  service_resource_providers << :systemd
61
70
  end
62
71
 
@@ -86,7 +95,7 @@ class Chef
86
95
  configs << :usr_local_etc_rcd
87
96
  end
88
97
 
89
- if ::File.exist?("/bin/systemctl") && platform_has_systemd_unit?(service_name)
98
+ if systemd_sanity_check? && platform_has_systemd_unit?(service_name)
90
99
  configs << :systemd
91
100
  end
92
101
 
@@ -95,17 +104,37 @@ class Chef
95
104
 
96
105
  private
97
106
 
98
- def extract_systemd_services(output)
107
+ def systemctl_path
108
+ if @systemctl_path.nil?
109
+ @systemctl_path = which("systemctl")
110
+ end
111
+ @systemctl_path
112
+ end
113
+
114
+ def systemd_sanity_check?
115
+ systemctl_path && File.exist?("/proc/1/comm") && File.open("/proc/1/comm").gets.chomp == "systemd"
116
+ end
117
+
118
+ def extract_systemd_services(command)
119
+ output = shell_out!(command).stdout
99
120
  # first line finds e.g. "sshd.service"
100
- services = output.lines.split.map { |l| l.split[0] }
121
+ services = []
122
+ output.each_line do |line|
123
+ fields = line.split
124
+ services << fields[0] if fields[1] == "loaded" || fields[1] == "not-found"
125
+ end
101
126
  # this splits off the suffix after the last dot to return "sshd"
102
- services += services.map { |s| s.sub(/(.*)\..*/, '\1') }
127
+ services += services.select {|s| s.match(/\.service$/) }.map { |s| s.sub(/(.*)\.service$/, '\1') }
128
+ rescue Mixlib::ShellOut::ShellCommandFailed
129
+ false
103
130
  end
104
131
 
105
132
  def platform_has_systemd_unit?(service_name)
106
- services = extract_systemd_services(shell_out!("systemctl --all").stdout) +
107
- extract_systemd_services(shell_out!("systemctl --list-unit-files").stdout)
133
+ services = extract_systemd_services("#{systemctl_path} --all") +
134
+ extract_systemd_services("#{systemctl_path} list-unit-files")
108
135
  services.include?(service_name)
136
+ rescue Mixlib::ShellOut::ShellCommandFailed
137
+ false
109
138
  end
110
139
  end
111
140
  end
@@ -114,4 +114,4 @@ class Chef
114
114
  end
115
115
  end
116
116
  end
117
- end
117
+ end
@@ -23,7 +23,7 @@ class Chef::Provider::Service::Arch < Chef::Provider::Service::Init
23
23
  provides :service, platform_family: "arch"
24
24
 
25
25
  def self.supports?(resource, action)
26
- ::File.exist?("/etc/rc.d/#{resource.service_name}")
26
+ Chef::Platform::ServiceHelpers.config_for_service(resource.service_name).include?(:etc_rcd)
27
27
  end
28
28
 
29
29
  def initialize(new_resource, run_context)
@@ -27,8 +27,12 @@ class Chef
27
27
 
28
28
  provides :service, platform_family: "debian"
29
29
 
30
+ def self.provides?(node, resource)
31
+ super && Chef::Platform::ServiceHelpers.service_resource_providers.include?(:debian)
32
+ end
33
+
30
34
  def self.supports?(resource, action)
31
- Chef::Platform::ServiceHelpers.service_resource_providers.include?(:debian)
35
+ Chef::Platform::ServiceHelpers.config_for_service(resource.service_name).include?(:initd)
32
36
  end
33
37
 
34
38
  def load_current_resource
@@ -28,6 +28,10 @@ class Chef
28
28
 
29
29
  provides :service, os: "!windows"
30
30
 
31
+ def self.supports?(resource, action)
32
+ Chef::Platform::ServiceHelpers.config_for_service(resource.service_name).include?(:initd)
33
+ end
34
+
31
35
  def initialize(new_resource, run_context)
32
36
  super
33
37
  @init_command = "/etc/init.d/#{@new_resource.service_name}"
@@ -26,8 +26,12 @@ class Chef
26
26
 
27
27
  provides :service, os: "linux"
28
28
 
29
+ def self.provides?(node, resource)
30
+ super && Chef::Platform::ServiceHelpers.service_resource_providers.include?(:insserv)
31
+ end
32
+
29
33
  def self.supports?(resource, action)
30
- Chef::Platform::ServiceHelpers.service_resource_providers.include?(:insserv)
34
+ Chef::Platform::ServiceHelpers.config_for_service(resource.service_name).include?(:initd)
31
35
  end
32
36
 
33
37
  def load_current_resource
@@ -25,8 +25,12 @@ class Chef
25
25
 
26
26
  provides :service, platform_family: "debian"
27
27
 
28
+ def self.provides?(node, resource)
29
+ super && Chef::Platform::ServiceHelpers.service_resource_providers.include?(:invokercd)
30
+ end
31
+
28
32
  def self.supports?(resource, action)
29
- Chef::Platform::ServiceHelpers.service_resource_providers.include?(:invokerc)
33
+ Chef::Platform::ServiceHelpers.config_for_service(resource.service_name).include?(:initd)
30
34
  end
31
35
 
32
36
  def initialize(new_resource, run_context)
@@ -28,8 +28,12 @@ class Chef
28
28
 
29
29
  provides :service, platform_family: [ "rhel", "fedora", "suse" ]
30
30
 
31
+ def self.provides?(node, resource)
32
+ super && Chef::Platform::ServiceHelpers.service_resource_providers.include?(:redhat)
33
+ end
34
+
31
35
  def self.supports?(resource, action)
32
- Chef::Platform::ServiceHelpers.service_resource_providers.include?(:redhat)
36
+ Chef::Platform::ServiceHelpers.config_for_service(resource.service_name).include?(:initd)
33
37
  end
34
38
 
35
39
  def initialize(new_resource, run_context)
@@ -18,87 +18,95 @@
18
18
 
19
19
  require 'chef/resource/service'
20
20
  require 'chef/provider/service/simple'
21
+ require 'chef/mixin/which'
21
22
 
22
23
  class Chef::Provider::Service::Systemd < Chef::Provider::Service::Simple
23
24
 
25
+ include Chef::Mixin::Which
26
+
24
27
  provides :service, os: "linux"
25
28
 
29
+ attr_accessor :status_check_success
30
+
31
+ def self.provides?(node, resource)
32
+ super && Chef::Platform::ServiceHelpers.service_resource_providers.include?(:systemd)
33
+ end
34
+
26
35
  def self.supports?(resource, action)
27
- Chef::Platform::ServiceHelpers.service_resource_providers.include?(:systemd)
36
+ Chef::Platform::ServiceHelpers.config_for_service(resource.service_name).include?(:systemd)
28
37
  end
29
38
 
30
39
  def load_current_resource
31
- @current_resource = Chef::Resource::Service.new(@new_resource.name)
32
- @current_resource.service_name(@new_resource.service_name)
40
+ @current_resource = Chef::Resource::Service.new(new_resource.name)
41
+ current_resource.service_name(new_resource.service_name)
33
42
  @status_check_success = true
34
43
 
35
- if @new_resource.status_command
36
- Chef::Log.debug("#{@new_resource} you have specified a status command, running..")
44
+ if new_resource.status_command
45
+ Chef::Log.debug("#{new_resource} you have specified a status command, running..")
37
46
 
38
- unless shell_out(@new_resource.status_command).error?
39
- @current_resource.running(true)
47
+ unless shell_out(new_resource.status_command).error?
48
+ current_resource.running(true)
40
49
  else
41
50
  @status_check_success = false
42
- @current_resource.running(false)
43
- @current_resource.enabled(false)
44
- nil
51
+ current_resource.running(false)
52
+ current_resource.enabled(false)
45
53
  end
46
54
  else
47
- @current_resource.running(is_active?)
55
+ current_resource.running(is_active?)
48
56
  end
49
57
 
50
- @current_resource.enabled(is_enabled?)
51
- @current_resource
58
+ current_resource.enabled(is_enabled?)
59
+ current_resource
52
60
  end
53
61
 
54
62
  def define_resource_requirements
55
63
  shared_resource_requirements
56
64
  requirements.assert(:all_actions) do |a|
57
- a.assertion { @status_check_success }
65
+ a.assertion { status_check_success }
58
66
  # We won't stop in any case, but in whyrun warn and tell what we're doing.
59
- a.whyrun ["Failed to determine status of #{@new_resource}, using command #{@new_resource.status_command}.",
67
+ a.whyrun ["Failed to determine status of #{new_resource}, using command #{new_resource.status_command}.",
60
68
  "Assuming service would have been installed and is disabled"]
61
69
  end
62
70
  end
63
71
 
64
72
  def start_service
65
- if @current_resource.running
66
- Chef::Log.debug("#{@new_resource} already running, not starting")
73
+ if current_resource.running
74
+ Chef::Log.debug("#{new_resource} already running, not starting")
67
75
  else
68
- if @new_resource.start_command
76
+ if new_resource.start_command
69
77
  super
70
78
  else
71
- shell_out_with_systems_locale!("/bin/systemctl start #{@new_resource.service_name}")
79
+ shell_out_with_systems_locale!("#{systemctl_path} start #{new_resource.service_name}")
72
80
  end
73
81
  end
74
82
  end
75
83
 
76
84
  def stop_service
77
- unless @current_resource.running
78
- Chef::Log.debug("#{@new_resource} not running, not stopping")
85
+ unless current_resource.running
86
+ Chef::Log.debug("#{new_resource} not running, not stopping")
79
87
  else
80
- if @new_resource.stop_command
88
+ if new_resource.stop_command
81
89
  super
82
90
  else
83
- shell_out_with_systems_locale!("/bin/systemctl stop #{@new_resource.service_name}")
91
+ shell_out_with_systems_locale!("#{systemctl_path} stop #{new_resource.service_name}")
84
92
  end
85
93
  end
86
94
  end
87
95
 
88
96
  def restart_service
89
- if @new_resource.restart_command
97
+ if new_resource.restart_command
90
98
  super
91
99
  else
92
- shell_out_with_systems_locale!("/bin/systemctl restart #{@new_resource.service_name}")
100
+ shell_out_with_systems_locale!("#{systemctl_path} restart #{new_resource.service_name}")
93
101
  end
94
102
  end
95
103
 
96
104
  def reload_service
97
- if @new_resource.reload_command
105
+ if new_resource.reload_command
98
106
  super
99
107
  else
100
- if @current_resource.running
101
- shell_out_with_systems_locale!("/bin/systemctl reload #{@new_resource.service_name}")
108
+ if current_resource.running
109
+ shell_out_with_systems_locale!("#{systemctl_path} reload #{new_resource.service_name}")
102
110
  else
103
111
  start_service
104
112
  end
@@ -106,18 +114,28 @@ class Chef::Provider::Service::Systemd < Chef::Provider::Service::Simple
106
114
  end
107
115
 
108
116
  def enable_service
109
- shell_out!("/bin/systemctl enable #{@new_resource.service_name}")
117
+ shell_out!("#{systemctl_path} enable #{new_resource.service_name}")
110
118
  end
111
119
 
112
120
  def disable_service
113
- shell_out!("/bin/systemctl disable #{@new_resource.service_name}")
121
+ shell_out!("#{systemctl_path} disable #{new_resource.service_name}")
114
122
  end
115
123
 
116
124
  def is_active?
117
- shell_out("/bin/systemctl is-active #{@new_resource.service_name} --quiet").exitstatus == 0
125
+ shell_out("#{systemctl_path} is-active #{new_resource.service_name} --quiet").exitstatus == 0
118
126
  end
119
127
 
120
128
  def is_enabled?
121
- shell_out("/bin/systemctl is-enabled #{@new_resource.service_name} --quiet").exitstatus == 0
129
+ shell_out("#{systemctl_path} is-enabled #{new_resource.service_name} --quiet").exitstatus == 0
122
130
  end
131
+
132
+ private
133
+
134
+ def systemctl_path
135
+ if @systemctl_path.nil?
136
+ @systemctl_path = which("systemctl")
137
+ end
138
+ @systemctl_path
139
+ end
140
+
123
141
  end