puppet 4.2.1-x64-mingw32 → 4.2.2-x64-mingw32

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of puppet might be problematic. Click here for more details.

Files changed (40) hide show
  1. data/Rakefile +20 -0
  2. data/ext/osx/puppet.plist +2 -2
  3. data/ext/solaris/smf/puppet +44 -0
  4. data/ext/solaris/smf/puppet.xml +44 -0
  5. data/ext/suse/client.init +2 -2
  6. data/ext/suse/server.init +2 -2
  7. data/install.rb +21 -39
  8. data/lib/puppet/application/cert.rb +16 -0
  9. data/lib/puppet/configurer.rb +2 -2
  10. data/lib/puppet/defaults.rb +2 -1
  11. data/lib/puppet/file_system/windows.rb +3 -1
  12. data/lib/puppet/parser/compiler.rb +1 -3
  13. data/lib/puppet/parser/functions/inline_template.rb +2 -2
  14. data/lib/puppet/parser/resource.rb +13 -10
  15. data/lib/puppet/pops/evaluator/evaluator_impl.rb +5 -1
  16. data/lib/puppet/pops/issues.rb +4 -0
  17. data/lib/puppet/pops/model/factory.rb +4 -3
  18. data/lib/puppet/pops/model/model_meta.rb +4 -1
  19. data/lib/puppet/pops/parser/egrammar.ra +10 -0
  20. data/lib/puppet/pops/parser/eparser.rb +1279 -1148
  21. data/lib/puppet/pops/parser/lexer2.rb +6 -0
  22. data/lib/puppet/pops/validation/checker4_0.rb +17 -1
  23. data/lib/puppet/pops/validation/validator_factory_4_0.rb +3 -1
  24. data/lib/puppet/provider/exec.rb +6 -1
  25. data/lib/puppet/provider/package/yum.rb +9 -3
  26. data/lib/puppet/provider/service/launchd.rb +36 -7
  27. data/lib/puppet/provider/service/systemd.rb +10 -2
  28. data/lib/puppet/reference/configuration.rb +10 -4
  29. data/lib/puppet/type/package.rb +9 -6
  30. data/lib/puppet/util/execution.rb +18 -2
  31. data/lib/puppet/version.rb +1 -1
  32. data/spec/unit/file_system_spec.rb +20 -0
  33. data/spec/unit/pops/parser/lexer2_spec.rb +13 -0
  34. data/spec/unit/pops/validator/validator_spec.rb +24 -0
  35. data/spec/unit/provider/package/yum_spec.rb +15 -0
  36. data/spec/unit/provider/service/launchd_spec.rb +85 -10
  37. data/spec/unit/provider/service/systemd_spec.rb +1 -0
  38. data/spec/unit/type/exec_spec.rb +16 -8
  39. metadata +3053 -3029
  40. checksums.yaml +0 -7
@@ -131,7 +131,13 @@ class Puppet::Pops::Parser::Lexer2
131
131
  "type" => [:TYPE, 'type', 4],
132
132
  "attr" => [:ATTR, 'attr', 4],
133
133
  "private" => [:PRIVATE, 'private', 7],
134
+ # The following tokens exist in reserved form. Later they will be made
135
+ # live subject to a feature switch.
136
+ "application" => [:APPLICATION_R, 'application', 11],
137
+ "consumes" => [:CONSUMES_R, 'consumes', 8],
138
+ "produces" => [:PRODUCES_R, 'produces', 8],
134
139
  }
140
+
135
141
  KEYWORDS.each {|k,v| v[1].freeze; v.freeze }
136
142
  KEYWORDS.freeze
137
143
 
@@ -299,6 +299,12 @@ class Puppet::Pops::Validation::Checker4_0
299
299
  'runtime' => true,
300
300
  }
301
301
 
302
+ FUTURE_RESERVED_WORDS = {
303
+ 'application' => true,
304
+ 'produces' => true,
305
+ 'consumes' => true
306
+ }
307
+
302
308
  # for 'class', 'define', and function
303
309
  def check_NamedDefinition(o)
304
310
  top(o.eContainer, o)
@@ -309,6 +315,12 @@ class Puppet::Pops::Validation::Checker4_0
309
315
  if RESERVED_TYPE_NAMES[o.name()]
310
316
  acceptor.accept(Issues::RESERVED_TYPE_NAME, o, {:name => o.name})
311
317
  end
318
+
319
+ # This is perhaps not ideal but it's very difficult to pass a ReservedWord through
320
+ # the mechanism that creates qualified names (namestack, namepop etc.)
321
+ if FUTURE_RESERVED_WORDS[o.name]
322
+ acceptor.accept(Issues::FUTURE_RESERVED_WORD, o, {:word => o.name})
323
+ end
312
324
  end
313
325
 
314
326
  def check_FunctionDefinition(o)
@@ -495,7 +507,11 @@ class Puppet::Pops::Validation::Checker4_0
495
507
  end
496
508
 
497
509
  def check_ReservedWord(o)
498
- acceptor.accept(Issues::RESERVED_WORD, o, :word => o.word)
510
+ if o.future
511
+ acceptor.accept(Issues::FUTURE_RESERVED_WORD, o, :word => o.word)
512
+ else
513
+ acceptor.accept(Issues::RESERVED_WORD, o, :word => o.word)
514
+ end
499
515
  end
500
516
 
501
517
  def check_SelectorExpression(o)
@@ -23,7 +23,9 @@ class Puppet::Pops::Validation::ValidatorFactory_4_0 < Puppet::Pops::Validation:
23
23
  p[Issues::RT_NO_STORECONFIGS_EXPORT] = Puppet[:storeconfigs] ? :ignore : :warning
24
24
  p[Issues::RT_NO_STORECONFIGS] = Puppet[:storeconfigs] ? :ignore : :warning
25
25
 
26
- p[Issues::NAME_WITH_HYPHEN] = :error
26
+ p[Issues::FUTURE_RESERVED_WORD] = :deprecation
27
+
28
+ p[Issues::NAME_WITH_HYPHEN] = :error
27
29
  p[Issues::EMPTY_RESOURCE_SPECIALIZATION] = :ignore
28
30
  p
29
31
  end
@@ -47,7 +47,12 @@ class Puppet::Provider::Exec < Puppet::Provider
47
47
  end
48
48
  end
49
49
 
50
- Timeout::timeout(resource[:timeout]) do
50
+ # Ruby 2.1 and later interrupt execution in a way that bypasses error
51
+ # handling by default. Passing Timeout::Error causes an exception to be
52
+ # raised that can be rescued inside of the block by cleanup routines.
53
+ #
54
+ # This is backwards compatible all the way to Ruby 1.8.7.
55
+ Timeout::timeout(resource[:timeout], Timeout::Error) do
51
56
  # note that we are passing "false" for the "override_locale" parameter, which ensures that the user's
52
57
  # default/system locale will be respected. Callers may override this behavior by setting locale-related
53
58
  # environment variables (LANG, LC_ALL, etc.) in their 'environment' configuration.
@@ -151,9 +151,15 @@ Puppet::Type.type(:package).provide :yum, :parent => :rpm, :source => :rpm do
151
151
  end
152
152
  end
153
153
 
154
- args = ["-d", "0", "-e", "0", "-y", install_options, operation, wanted].compact
155
- yum *args
156
-
154
+ # Yum on el-4 and el-5 returns exit status 0 when trying to install a package it doesn't recognize;
155
+ # ensure we capture output to check for errors.
156
+ no_debug = if Facter.value(:operatingsystemmajrelease).to_i > 5 then ["-d", "0"] else [] end
157
+ args = no_debug + ["-e", "0", "-y", install_options, operation, wanted].compact
158
+ output = yum *args
159
+
160
+ if output =~ /^No package #{wanted} available\.$/
161
+ raise Puppet::Error, "Could not find package #{wanted}"
162
+ end
157
163
 
158
164
  # If a version was specified, query again to see if it is a matching version
159
165
  if should
@@ -65,12 +65,27 @@ Puppet::Type.type(:service).provide :launchd, :parent => :base do
65
65
  ]
66
66
  end
67
67
 
68
+ # Gets the current Darwin version, example 10.6 returns 9 and 10.10 returns 14
69
+ # See https://en.wikipedia.org/wiki/Darwin_(operating_system)#Release_history
70
+ # for more information.
71
+ #
72
+ # @api private
73
+ def self.get_os_version
74
+ @os_version ||= Facter.value(:operatingsystemmajrelease).to_i
75
+ end
76
+
68
77
  # Defines the path to the overrides plist file where service enabling
69
78
  # behavior is defined in 10.6 and greater.
70
79
  #
80
+ # With the rewrite of launchd in 10.10+, this moves and slightly changes format.
81
+ #
71
82
  # @api private
72
83
  def self.launchd_overrides
73
- "/var/db/launchd.db/com.apple.launchd/overrides.plist"
84
+ if self.get_os_version < 14
85
+ "/var/db/launchd.db/com.apple.launchd/overrides.plist"
86
+ else
87
+ "/var/db/com.apple.xpc.launchd/disabled.plist"
88
+ end
74
89
  end
75
90
 
76
91
  # Caching is enabled through the following three methods. Self.prefetch will
@@ -219,8 +234,10 @@ Puppet::Type.type(:service).provide :launchd, :parent => :base do
219
234
  did_enable_job = false
220
235
  cmds = []
221
236
  cmds << :launchctl << :load
237
+ # always add -w so it always starts the job, it is a noop if it is not needed, this means we do
238
+ # not have to rescan all launchd plists.
239
+ cmds << "-w"
222
240
  if self.enabled? == :false || self.status == :stopped # launchctl won't load disabled jobs
223
- cmds << "-w"
224
241
  did_enable_job = true
225
242
  end
226
243
  cmds << job_path
@@ -277,7 +294,11 @@ Puppet::Type.type(:service).provide :launchd, :parent => :base do
277
294
 
278
295
  if FileTest.file?(self.class.launchd_overrides) and overrides = self.class.read_plist(self.class.launchd_overrides)
279
296
  if overrides.has_key?(resource[:name])
280
- overrides_disabled = overrides[resource[:name]]["Disabled"] if overrides[resource[:name]].has_key?("Disabled")
297
+ if self.class.get_os_version < 14
298
+ overrides_disabled = overrides[resource[:name]]["Disabled"] if overrides[resource[:name]].has_key?("Disabled")
299
+ else
300
+ overrides_disabled = overrides[resource[:name]]
301
+ end
281
302
  end
282
303
  end
283
304
 
@@ -296,13 +317,21 @@ Puppet::Type.type(:service).provide :launchd, :parent => :base do
296
317
  # without actually loading/unloading the job.
297
318
  def enable
298
319
  overrides = self.class.read_plist(self.class.launchd_overrides)
299
- overrides[resource[:name]] = { "Disabled" => false }
320
+ if self.class.get_os_version < 14
321
+ overrides[resource[:name]] = { "Disabled" => false }
322
+ else
323
+ overrides[resource[:name]] = false
324
+ end
300
325
  Plist::Emit.save_plist(overrides, self.class.launchd_overrides)
301
326
  end
302
327
 
303
328
  def disable
304
- job_path, job_plist = plist_from_label(resource[:name])
305
- job_plist["Disabled"] = true
306
- Plist::Emit.save_plist(job_plist, job_path)
329
+ overrides = self.class.read_plist(self.class.launchd_overrides)
330
+ if self.class.get_os_version < 14
331
+ overrides[resource[:name]] = { "Disabled" => true }
332
+ else
333
+ overrides[resource[:name]] = true
334
+ end
335
+ Plist::Emit.save_plist(overrides, self.class.launchd_overrides)
307
336
  end
308
337
  end
@@ -105,7 +105,7 @@ Puppet::Type.type(:service).provide :systemd, :parent => :base do
105
105
  end
106
106
 
107
107
  def enable
108
- output = systemctl("unmask", @resource[:name])
108
+ self.unmask
109
109
  output = systemctl("enable", @resource[:name])
110
110
  rescue Puppet::ExecutionFailure
111
111
  raise Puppet::Error, "Could not enable #{self.name}: #{output}", $!.backtrace
@@ -113,7 +113,6 @@ Puppet::Type.type(:service).provide :systemd, :parent => :base do
113
113
 
114
114
  def mask
115
115
  self.disable
116
-
117
116
  begin
118
117
  output = systemctl("mask", @resource[:name])
119
118
  rescue Puppet::ExecutionFailure
@@ -121,11 +120,20 @@ Puppet::Type.type(:service).provide :systemd, :parent => :base do
121
120
  end
122
121
  end
123
122
 
123
+ def unmask
124
+ begin
125
+ output = systemctl("unmask", @resource[:name])
126
+ rescue Puppet::ExecutionFailure
127
+ raise Puppet::Error, "Could not unmask #{self.name}: #{output}", $!.backtrace
128
+ end
129
+ end
130
+
124
131
  def restartcmd
125
132
  [command(:systemctl), "restart", @resource[:name]]
126
133
  end
127
134
 
128
135
  def startcmd
136
+ self.unmask
129
137
  [command(:systemctl), "start", @resource[:name]]
130
138
  end
131
139
 
@@ -22,10 +22,16 @@ config = Puppet::Util::Reference.newreference(:configuration, :depth => 1, :doc
22
22
 
23
23
  # Now print the data about the item.
24
24
  val = object.default
25
- if name.to_s == "vardir"
26
- val = "/opt/puppetlabs/puppet/cache"
27
- elsif name.to_s == "confdir"
28
- val = "/etc/puppetlabs/puppet"
25
+ if name.to_s == 'vardir'
26
+ val = 'Unix/Linux: /opt/puppetlabs/puppet/cache -- Windows: C:\ProgramData\PuppetLabs\puppet\cache -- Non-root user: ~/.puppetlabs/opt/puppet/cache'
27
+ elsif name.to_s == 'confdir'
28
+ val = 'Unix/Linux: /etc/puppetlabs/puppet -- Windows: C:\ProgramData\PuppetLabs\puppet\etc -- Non-root user: ~/.puppetlabs/etc/puppet'
29
+ elsif name.to_s == 'codedir'
30
+ val = 'Unix/Linux: /etc/puppetlabs/code -- Windows: C:\ProgramData\PuppetLabs\code -- Non-root user: ~/.puppetlabs/etc/code'
31
+ elsif name.to_s == 'rundir'
32
+ val = 'Unix/Linux: /var/run/puppetlabs -- Windows: C:\ProgramData\PuppetLabs\puppet\var\run -- Non-root user: ~/.puppetlabs/var/run'
33
+ elsif name.to_s == 'logdir'
34
+ val = 'Unix/Linux: /var/log/puppetlabs/puppet -- Windows: C:\ProgramData\PuppetLabs\puppet\var\log -- Non-root user: ~/.puppetlabs/var/log'
29
35
  end
30
36
 
31
37
  # Leave out the section information; it was apparently confusing people.
@@ -404,8 +404,9 @@ module Puppet
404
404
  end
405
405
 
406
406
  newparam(:configfiles) do
407
- desc "Whether configfiles should be kept or replaced. Most packages
408
- types do not support this parameter. Defaults to `keep`."
407
+ desc "Whether to keep or replace modified config files when installing or
408
+ upgrading a package. This only affects the `apt` and `dpkg` providers.
409
+ Defaults to `keep`."
409
410
 
410
411
  defaultto :keep
411
412
 
@@ -456,10 +457,12 @@ module Puppet
456
457
  key and value pair are interpreted in a provider specific way. Each
457
458
  option will automatically be quoted when passed to the install command.
458
459
 
459
- On Windows, this is the **only** place in Puppet where backslash
460
- separators should be used. Note that backslashes in double-quoted
461
- strings _must_ be double-escaped and backslashes in single-quoted
462
- strings _may_ be double-escaped.
460
+ With Windows packages, note that file paths in an install option must
461
+ use backslashes. (Since install options are passed directly to the
462
+ installation command, forward slashes won't be automatically converted
463
+ like they are in `file` resources.) Note also that backslashes in
464
+ double-quoted strings _must_ be escaped and backslashes in single-quoted
465
+ strings _can_ be escaped.
463
466
  EOT
464
467
  end
465
468
 
@@ -1,3 +1,4 @@
1
+ require 'timeout'
1
2
  require 'puppet/file_system/uniquefile'
2
3
 
3
4
  module Puppet
@@ -192,8 +193,23 @@ module Puppet::Util::Execution
192
193
  if execution_stub = Puppet::Util::ExecutionStub.current_value
193
194
  return execution_stub.call(*exec_args)
194
195
  elsif Puppet.features.posix?
195
- child_pid = execute_posix(*exec_args)
196
- exit_status = Process.waitpid2(child_pid).last.exitstatus
196
+ child_pid = nil
197
+ begin
198
+ child_pid = execute_posix(*exec_args)
199
+ exit_status = Process.waitpid2(child_pid).last.exitstatus
200
+ child_pid = nil
201
+ rescue Timeout::Error => e
202
+ # NOTE: For Ruby 2.1+, an explicit Timeout::Error class has to be
203
+ # passed to Timeout.timeout in order for there to be something for
204
+ # this block to rescue.
205
+ unless child_pid.nil?
206
+ Process.kill(:TERM, child_pid)
207
+ # Spawn a thread to reap the process if it dies.
208
+ Thread.new { Process.waitpid(child_pid) }
209
+ end
210
+
211
+ raise e
212
+ end
197
213
  elsif Puppet.features.microsoft_windows?
198
214
  process_info = execute_windows(*exec_args)
199
215
  begin
@@ -7,7 +7,7 @@
7
7
 
8
8
 
9
9
  module Puppet
10
- PUPPETVERSION = '4.2.1'
10
+ PUPPETVERSION = '4.2.2'
11
11
 
12
12
  ##
13
13
  # version is a public API method intended to always provide a fast and
@@ -446,6 +446,26 @@ describe "Puppet::FileSystem" do
446
446
  expect(Puppet::FileSystem.readlink(symlink)).to eq(missing_file.to_s)
447
447
  end
448
448
 
449
+ it "should be able to unlink a dangling symlink pointed at a file" do
450
+ symlink = tmpfile("somefile_link")
451
+ Puppet::FileSystem.symlink(file, symlink)
452
+ ::File.delete(file)
453
+ Puppet::FileSystem.unlink(symlink)
454
+
455
+ expect(Puppet::FileSystem).to_not be_exist(file)
456
+ expect(Puppet::FileSystem).to_not be_exist(symlink)
457
+ end
458
+
459
+ it "should be able to unlink a dangling symlink pointed at a directory" do
460
+ symlink = tmpfile("somedir_link")
461
+ Puppet::FileSystem.symlink(dir, symlink)
462
+ Dir.rmdir(dir)
463
+ Puppet::FileSystem.unlink(symlink)
464
+
465
+ expect(Puppet::FileSystem).to_not be_exist(dir)
466
+ expect(Puppet::FileSystem).to_not be_exist(symlink)
467
+ end
468
+
449
469
  it "should delete only the symlink and not the target when calling unlink instance method" do
450
470
  [file, dir].each do |target|
451
471
  symlink = tmpfile("#{Puppet::FileSystem.basename(target)}_link")
@@ -91,12 +91,25 @@ describe 'Lexer2' do
91
91
  "true" => :BOOLEAN,
92
92
  "in" => :IN,
93
93
  "unless" => :UNLESS,
94
+ "private" => :PRIVATE,
95
+ "type" => :TYPE,
96
+ "attr" => :ATTR,
94
97
  }.each do |string, name|
95
98
  it "should lex a keyword from '#{string}'" do
96
99
  expect(tokens_scanned_from(string)).to match_tokens2(name)
97
100
  end
98
101
  end
99
102
 
103
+ {
104
+ "application" => :APPLICATION_R,
105
+ "consumes" => :CONSUMES_R,
106
+ "produces" => :PRODUCES_R,
107
+ }.each do |string, name|
108
+ it "should lex a (future reserved) keyword from '#{string}'" do
109
+ expect(tokens_scanned_from(string)).to match_tokens2(name)
110
+ end
111
+ end
112
+
100
113
  # TODO: Complete with all edge cases
101
114
  [ 'A', 'A::B', '::A', '::A::B',].each do |string|
102
115
  it "should lex a CLASSREF on the form '#{string}'" do
@@ -119,6 +119,30 @@ describe "validating 4x" do
119
119
  end
120
120
  end
121
121
 
122
+ context 'for future reserved words' do
123
+ ['application', 'produces', 'consumes'].each do |word|
124
+ it "produces an issue for the word '#{word}'" do
125
+ source = "$a = #{word}"
126
+ expect(validate(parse(source))).to have_issue(Puppet::Pops::Issues::FUTURE_RESERVED_WORD)
127
+ end
128
+
129
+ it 'produces a warning issue when used as a class name' do
130
+ source = "class #{word} {}"
131
+ expect(validate(parse(source))).to have_issue(Puppet::Pops::Issues::FUTURE_RESERVED_WORD)
132
+ end
133
+
134
+ it 'produces no warning or error when used as a parameter name' do
135
+ source = "define foo($#{word}) { notice $#{word} }"
136
+ expect(validate(parse(source)).diagnostics.empty?).to eq(true)
137
+ end
138
+
139
+ it 'produces no warning or error when used as an attribute name' do
140
+ source = "foo { bar: #{word} => ok }"
141
+ expect(validate(parse(source)).diagnostics.empty?).to eq(true)
142
+ end
143
+ end
144
+ end
145
+
122
146
  context 'for reserved type names' do
123
147
  [# type/Type, is a reserved name but results in syntax error because it is a keyword in lower case form
124
148
  'any',
@@ -181,6 +181,7 @@ describe provider_class do
181
181
  Puppet::Util.stubs(:which).with("rpm").returns("/bin/rpm")
182
182
  provider.stubs(:which).with("rpm").returns("/bin/rpm")
183
183
  Puppet::Util::Execution.expects(:execute).with(["/bin/rpm", "--version"], {:combine => true, :custom_environment => {}, :failonfail => true}).returns("4.10.1\n").at_most_once
184
+ Facter.stubs(:value).with(:operatingsystemmajrelease).returns('6')
184
185
  end
185
186
 
186
187
  it 'should call yum install for :installed' do
@@ -189,6 +190,20 @@ describe provider_class do
189
190
  provider.install
190
191
  end
191
192
 
193
+ context 'on el-5' do
194
+ before(:each) do
195
+ Facter.stubs(:value).with(:operatingsystemmajrelease).returns('5')
196
+ end
197
+
198
+ it 'should catch yum install failures when status code is wrong' do
199
+ resource.stubs(:should).with(:ensure).returns :installed
200
+ provider.expects(:yum).with('-e', '0', '-y', :install, name).returns("No package #{name} available.")
201
+ expect {
202
+ provider.install
203
+ }.to raise_error(Puppet::Error, "Could not find package #{name}")
204
+ end
205
+ end
206
+
192
207
  it 'should use :install to update' do
193
208
  provider.expects(:install)
194
209
  provider.update
@@ -6,8 +6,9 @@ require 'spec_helper'
6
6
  describe Puppet::Type.type(:service).provider(:launchd) do
7
7
  let (:joblabel) { "com.foo.food" }
8
8
  let (:provider) { subject.class }
9
- let (:launchd_overrides) { '/var/db/launchd.db/com.apple.launchd/overrides.plist' }
10
9
  let(:resource) { Puppet::Type.type(:service).new(:name => joblabel, :provider => :launchd) }
10
+ let (:launchd_overrides_6_9) { '/var/db/launchd.db/com.apple.launchd/overrides.plist' }
11
+ let (:launchd_overrides_10_) { '/var/db/com.apple.xpc.launchd/disabled.plist' }
11
12
  subject { resource.provider }
12
13
 
13
14
  describe "the type interface" do
@@ -37,6 +38,56 @@ describe Puppet::Type.type(:service).provider(:launchd) do
37
38
  end
38
39
  end
39
40
 
41
+ [[10, '10.6'], [13, '10.9']].each do |kernel, version|
42
+ describe "when checking whether the service is enabled on OS X #{version}" do
43
+ it "should return true if the job plist says disabled is true and the global overrides says disabled is false" do
44
+ provider.expects(:get_os_version).returns(kernel).at_least_once
45
+ subject.expects(:plist_from_label).returns([joblabel, {"Disabled" => true}])
46
+ provider.expects(:read_plist).with(launchd_overrides_6_9).returns({joblabel => {"Disabled" => false}})
47
+ FileTest.expects(:file?).with(launchd_overrides_6_9).returns(true)
48
+ expect(subject.enabled?).to eq(:true)
49
+ end
50
+ it "should return false if the job plist says disabled is false and the global overrides says disabled is true" do
51
+ provider.expects(:get_os_version).returns(kernel).at_least_once
52
+ subject.expects(:plist_from_label).returns([joblabel, {"Disabled" => false}])
53
+ provider.expects(:read_plist).with(launchd_overrides_6_9).returns({joblabel => {"Disabled" => true}})
54
+ FileTest.expects(:file?).with(launchd_overrides_6_9).returns(true)
55
+ expect(subject.enabled?).to eq(:false)
56
+ end
57
+ it "should return true if the job plist and the global overrides have no disabled keys" do
58
+ provider.expects(:get_os_version).returns(kernel).at_least_once
59
+ subject.expects(:plist_from_label).returns([joblabel, {}])
60
+ provider.expects(:read_plist).with(launchd_overrides_6_9).returns({})
61
+ FileTest.expects(:file?).with(launchd_overrides_6_9).returns(true)
62
+ expect(subject.enabled?).to eq(:true)
63
+ end
64
+ end
65
+ end
66
+
67
+ describe "when checking whether the service is enabled on OS X 10.10" do
68
+ it "should return true if the job plist says disabled is true and the global overrides says disabled is false" do
69
+ provider.expects(:get_os_version).returns(14).at_least_once
70
+ subject.expects(:plist_from_label).returns([joblabel, {"Disabled" => true}])
71
+ provider.expects(:read_plist).with(launchd_overrides_10_).returns({joblabel => false})
72
+ FileTest.expects(:file?).with(launchd_overrides_10_).returns(true)
73
+ expect(subject.enabled?).to eq(:true)
74
+ end
75
+ it "should return false if the job plist says disabled is false and the global overrides says disabled is true" do
76
+ provider.expects(:get_os_version).returns(14).at_least_once
77
+ subject.expects(:plist_from_label).returns([joblabel, {"Disabled" => false}])
78
+ provider.expects(:read_plist).with(launchd_overrides_10_).returns({joblabel => true})
79
+ FileTest.expects(:file?).with(launchd_overrides_10_).returns(true)
80
+ expect(subject.enabled?).to eq(:false)
81
+ end
82
+ it "should return true if the job plist and the global overrides have no disabled keys" do
83
+ provider.expects(:get_os_version).returns(14).at_least_once
84
+ subject.expects(:plist_from_label).returns([joblabel, {}])
85
+ provider.expects(:read_plist).with(launchd_overrides_10_).returns({})
86
+ FileTest.expects(:file?).with(launchd_overrides_10_).returns(true)
87
+ expect(subject.enabled?).to eq(:true)
88
+ end
89
+ end
90
+
40
91
  describe "when starting the service" do
41
92
  it "should call any explicit 'start' command" do
42
93
  resource[:start] = "/bin/false"
@@ -47,13 +98,13 @@ describe Puppet::Type.type(:service).provider(:launchd) do
47
98
  it "should look for the relevant plist once" do
48
99
  subject.expects(:plist_from_label).returns([joblabel, {}]).once
49
100
  subject.expects(:enabled?).returns :true
50
- subject.expects(:execute).with([:launchctl, :load, joblabel])
101
+ subject.expects(:execute).with([:launchctl, :load, "-w", joblabel])
51
102
  subject.start
52
103
  end
53
104
  it "should execute 'launchctl load' once without writing to the plist if the job is enabled" do
54
105
  subject.expects(:plist_from_label).returns([joblabel, {}])
55
106
  subject.expects(:enabled?).returns :true
56
- subject.expects(:execute).with([:launchctl, :load, joblabel]).once
107
+ subject.expects(:execute).with([:launchctl, :load, "-w", joblabel]).once
57
108
  subject.start
58
109
  end
59
110
  it "should execute 'launchctl load' with writing to the plist once if the job is disabled" do
@@ -147,21 +198,45 @@ describe Puppet::Type.type(:service).provider(:launchd) do
147
198
  end
148
199
  end
149
200
 
150
- describe "when enabling the service" do
201
+ [[10, "10.6"], [13, "10.9"]].each do |kernel, version|
202
+ describe "when enabling the service on OS X #{version}" do
203
+ it "should write to the global launchd overrides file once" do
204
+ resource[:enable] = true
205
+ provider.expects(:get_os_version).returns(kernel).at_least_once
206
+ provider.expects(:read_plist).with(launchd_overrides_6_9).returns({})
207
+ Plist::Emit.expects(:save_plist).with(has_entry(resource[:name], {'Disabled' => false}), launchd_overrides_6_9).once
208
+ subject.enable
209
+ end
210
+ end
211
+
212
+ describe "when disabling the service on OS X #{version}" do
213
+ it "should write to the global launchd overrides file once" do
214
+ resource[:enable] = false
215
+ provider.expects(:get_os_version).returns(kernel).at_least_once
216
+ provider.expects(:read_plist).with(launchd_overrides_6_9).returns({})
217
+ Plist::Emit.expects(:save_plist).with(has_entry(resource[:name], {'Disabled' => true}), launchd_overrides_6_9).once
218
+ subject.disable
219
+ end
220
+ end
221
+ end
222
+
223
+ describe "when enabling the service on OS X 10.10" do
151
224
  it "should write to the global launchd overrides file once" do
152
225
  resource[:enable] = true
153
- provider.expects(:read_plist).returns({})
154
- Plist::Emit.expects(:save_plist).once
226
+ provider.expects(:get_os_version).returns(14).at_least_once
227
+ provider.expects(:read_plist).with(launchd_overrides_10_).returns({})
228
+ Plist::Emit.expects(:save_plist).with(has_entry(resource[:name], false), launchd_overrides_10_).once
155
229
  subject.enable
156
230
  end
157
231
  end
158
232
 
159
- describe "when disabling the service" do
233
+ describe "when disabling the service on OS X 10.10" do
160
234
  it "should write to the global launchd overrides file once" do
161
235
  resource[:enable] = false
162
- provider.stubs(:read_plist).returns({})
163
- Plist::Emit.expects(:save_plist).once
164
- subject.enable
236
+ provider.expects(:get_os_version).returns(14).at_least_once
237
+ provider.expects(:read_plist).with(launchd_overrides_10_).returns({})
238
+ Plist::Emit.expects(:save_plist).with(has_entry(resource[:name], true), launchd_overrides_10_).once
239
+ subject.disable
165
240
  end
166
241
  end
167
242