Description: Reverts lockfile behaviour to previous model
 This reverts commit fcac8f7163c99884fc6b75e3851c4a5e16a3ff07, which
 was a backwards-compatibility workaround intended to handle some new
 behavior related to puppet agent lockfiles that was introduced in
 2.7.10.  The fix is being reverted because we've decided to remove
 the new lockfile behavior from the 2.7.x series entirely, and push
 it out to 3.x.
Author: cprice <chris@puppetlabs.com>
Origin: upstream, https://github.com/puppetlabs/puppet/commit/62738187b8a1ba1bd2b5e0737836741b8019a924
Bug: http://projects.puppetlabs.com/issues/12844

Index: puppet-2.7.11/lib/puppet/agent.rb
===================================================================
--- puppet-2.7.11.orig/lib/puppet/agent.rb	2012-04-11 03:31:00.967885412 -0500
+++ puppet-2.7.11/lib/puppet/agent.rb	2012-04-11 03:31:40.763886355 -0500
@@ -8,9 +8,6 @@
   require 'puppet/agent/locker'
   include Puppet::Agent::Locker
 
-  require 'puppet/agent/disabler'
-  include Puppet::Agent::Disabler
-
   attr_reader :client_class, :client, :splayed
 
   # Just so we can specify that we are "the" instance.
@@ -35,9 +32,10 @@
       return
     end
     if disabled?
-      Puppet.notice "Skipping run of #{client_class}; administratively disabled: #{disable_message}"
+      Puppet.notice "Skipping run of #{client_class}; administratively disabled; use 'puppet #{client_class} --enable' to re-enable."
       return
     end
+
     result = nil
     block_run = Puppet::Application.controlled_run do
       splay
Index: puppet-2.7.11/lib/puppet/agent/disabler.rb
===================================================================
--- puppet-2.7.11.orig/lib/puppet/agent/disabler.rb	2012-04-11 03:31:01.003885412 -0500
+++ /dev/null	1970-01-01 00:00:00.000000000 +0000
@@ -1,27 +0,0 @@
-require 'puppet/util/anonymous_filelock'
-
-module Puppet::Agent::Disabler
-  # Let the daemon run again, freely in the filesystem.
-  def enable
-    disable_lockfile.unlock
-  end
-
-  # Stop the daemon from making any catalog runs.
-  def disable(msg='')
-    disable_lockfile.lock(msg)
-  end
-
-  def disable_lockfile
-    @disable_lockfile ||= Puppet::Util::AnonymousFilelock.new(lockfile_path+".disabled")
-
-    @disable_lockfile
-  end
-
-  def disabled?
-    disable_lockfile.locked?
-  end
-
-  def disable_message
-    disable_lockfile.message
-  end
-end
Index: puppet-2.7.11/lib/puppet/agent/locker.rb
===================================================================
--- puppet-2.7.11.orig/lib/puppet/agent/locker.rb	2012-04-11 03:31:00.983885408 -0500
+++ puppet-2.7.11/lib/puppet/agent/locker.rb	2012-04-11 03:31:40.763886355 -0500
@@ -3,6 +3,16 @@
 # Break out the code related to locking the agent.  This module is just
 # included into the agent, but having it here makes it easier to test.
 module Puppet::Agent::Locker
+  # Let the daemon run again, freely in the filesystem.
+  def enable
+    lockfile.unlock(:anonymous => true)
+  end
+
+  # Stop the daemon from making any catalog runs.
+  def disable
+    lockfile.lock(:anonymous => true)
+  end
+
   # Yield if we get a lock, else do nothing.  Return
   # true/false depending on whether we get the lock.
   def lock
@@ -25,6 +35,10 @@
   end
 
   def running?
-    lockfile.locked?
+    lockfile.locked? and !lockfile.anonymous?
+  end
+
+  def disabled?
+    lockfile.locked? and lockfile.anonymous?
   end
 end
Index: puppet-2.7.11/lib/puppet/application/agent.rb
===================================================================
--- puppet-2.7.11.orig/lib/puppet/application/agent.rb	2012-04-11 03:31:01.023885412 -0500
+++ puppet-2.7.11/lib/puppet/application/agent.rb	2012-04-11 03:31:40.763886355 -0500
@@ -39,12 +39,7 @@
   end
 
   option("--centrallogging")
-
-  option("--disable [MESSAGE]") do |message|
-    options[:disable] = true
-    options[:disable_message] = message
-  end
-
+  option("--disable")
   option("--enable")
   option("--debug","-d")
   option("--fqdn FQDN","-f")
@@ -106,7 +101,7 @@
 USAGE
 -----
 puppet agent [--certname <name>] [-D|--daemonize|--no-daemonize]
-  [-d|--debug] [--detailed-exitcodes] [--digest <digest>] [--disable [message]] [--enable]
+  [-d|--debug] [--detailed-exitcodes] [--digest <digest>] [--disable] [--enable]
   [--fingerprint] [-h|--help] [-l|--logdest syslog|<file>|console]
   [--no-client] [--noop] [-o|--onetime] [--serve <handler>] [-t|--test]
   [-v|--verbose] [-V|--version] [-w|--waitforcert <seconds>]
@@ -210,9 +205,6 @@
   not want the central configuration to override the local state until
   everything is tested and committed.
 
-  Disable can also take an optional message that will be reported by the
-  'puppet agent' at the next disabled run.
-
   'puppet agent' uses the same lock file while it is running, so no more
   than one 'puppet agent' process is working at a time.
 
@@ -394,7 +386,7 @@
     if options[:enable]
       agent.enable
     elsif options[:disable]
-      agent.disable(options[:disable_message] || 'reason not specified')
+      agent.disable
     end
     exit(0)
   end
Index: puppet-2.7.11/lib/puppet/util/anonymous_filelock.rb
===================================================================
--- puppet-2.7.11.orig/lib/puppet/util/anonymous_filelock.rb	2012-04-11 03:31:00.947885406 -0500
+++ /dev/null	1970-01-01 00:00:00.000000000 +0000
@@ -1,36 +0,0 @@
-
-class Puppet::Util::AnonymousFilelock
-  attr_reader :lockfile
-
-  def initialize(lockfile)
-    @lockfile = lockfile
-  end
-
-  def anonymous?
-    true
-  end
-
-  def lock(msg = '')
-    return false if locked?
-
-    File.open(@lockfile, 'w') { |fd| fd.print(msg) }
-    true
-  end
-
-  def unlock
-    if locked?
-      File.unlink(@lockfile)
-      true
-    else
-      false
-    end
-  end
-
-  def locked?
-    File.exists? @lockfile
-  end
-
-  def message
-    return File.read(@lockfile) if locked?
-  end
-end
\ No newline at end of file
Index: puppet-2.7.11/lib/puppet/util/pidlock.rb
===================================================================
--- puppet-2.7.11.orig/lib/puppet/util/pidlock.rb	2012-04-11 03:31:00.935885411 -0500
+++ puppet-2.7.11/lib/puppet/util/pidlock.rb	2012-04-11 03:31:40.767886354 -0500
@@ -1,10 +1,20 @@
 require 'fileutils'
-require 'puppet/util/anonymous_filelock'
 
-class Puppet::Util::Pidlock < Puppet::Util::AnonymousFilelock
+class Puppet::Util::Pidlock
+  attr_reader :lockfile
+
+  def initialize(lockfile)
+    @lockfile = lockfile
+  end
 
   def locked?
     clear_if_stale
+    return true if File.exists? @lockfile
+
+    # HACK!  There was a temporary change to the lockfile behavior introduced in 2.7.10 and 2.7.11, and reverted
+    # in 2.7.12.  We need to pull some chicanery to be backwards-compatible with those versions.  For more info,
+    # see the comments on the method... and this hack should be removed for the 3.x series.
+    handle_2_7_10_disabled_lockfile
     File.exists? @lockfile
   end
 
@@ -13,36 +23,39 @@
   end
 
   def anonymous?
-    false
+    return false unless File.exists?(@lockfile)
+    File.read(@lockfile) == ""
   end
 
-  def lock
-    return mine? if locked?
+  def lock(opts = {})
+    opts = {:anonymous => false}.merge(opts)
 
-    File.open(@lockfile, "w") { |fd| fd.write(Process.pid) }
-    true
+    if locked?
+      mine?
+    else
+      if opts[:anonymous]
+        File.open(@lockfile, 'w') { |fd| true }
+      else
+        File.open(@lockfile, "w") { |fd| fd.write(Process.pid) }
+      end
+      true
+    end
   end
 
   def unlock(opts = {})
-    if mine?
-      begin
-        File.unlink(@lockfile)
-      rescue Errno::ENOENT
-        # Someone deleted it for us ...and so we do nothing.  No point whining
-        # about a problem that the user can't actually do anything about.
-      rescue SystemCallError => e
-        # This one is a real failure though.  No idea what went wrong, but it
-        # is most likely "read only file(system)" or wrong permissions or
-        # something like that.
-        Puppet.err "Could not remove PID file #{@lockfile}: #{e}"
-        puts e.backtrace if Puppet[:trace]
-      end
+    return false unless locked?
+
+    opts = {:anonymous => false}.merge(opts)
+
+    if mine? or (opts[:anonymous] and anonymous?)
+      File.unlink(@lockfile)
       true
     else
       false
     end
   end
 
+  private
   def lock_pid
     if File.exists? @lockfile
       File.read(@lockfile).to_i
@@ -51,7 +64,6 @@
     end
   end
 
-  private
   def clear_if_stale
     return if lock_pid.nil?
 
@@ -65,4 +77,41 @@
       File.unlink(@lockfile)
     end
   end
+
+
+  ######################################################################################
+  # Backwards compatibility hack
+  ######################################################################################
+  # A change to lockfile behavior was introduced in 2.7.10 and 2.7.11; basically,
+  # instead of using a single lockfile to indicate both administrative disabling of
+  # the agent *and* the case where an agent run is already in progress, we started using
+  # two separate lockfiles: the 'normal' one for the "run in progress" case, and a
+  # separate one with a ".disabled" extension to indicate administrative disabling.
+  #
+  # This was determined to cause incompatibilities with mcollective, so the behavior
+  # was reverted for 2.7.12.  Unfortunately this leaves the possibility that someone
+  # may have run "agent --disable" to administratively disable a 2.7.10 or 2.7.11
+  # agent, and then upgraded to a newer version.  This method exists only to
+  # provide backwards compatibility.  Basically, it just recognizes the 2.7.10/2.7.11
+  # ".disabled" lock file, warns, and cleans it up.
+  #
+  # This should be removed for the 3.x series.
+  #
+  # For more information, please see tickets #12844, #3757, #4836, and #11057
+  #
+  # -- cprice 2012-03-01
+  #
+  def handle_2_7_10_disabled_lockfile
+    disabled_lockfile_path = @lockfile + ".disabled"
+    if (File.exists?(disabled_lockfile_path))
+      Puppet.warning("Found special lockfile '#{disabled_lockfile_path}'; this file was " +
+          "generated by a call to 'puppet agent --disable' in puppet 2.7.10 or 2.7.11. " +
+          "The expected lockfile path is '#{@lockfile}'; renaming the lock file.")
+      File.rename(disabled_lockfile_path, @lockfile)
+    end
+  end
+  private :handle_2_7_10_disabled_lockfile
+  ######################################################################################
+  # End backwards compatibility hack
+  ######################################################################################
 end
Index: puppet-2.7.11/spec/unit/agent/disabler_spec.rb
===================================================================
--- puppet-2.7.11.orig/spec/unit/agent/disabler_spec.rb	2012-04-11 03:31:01.055885411 -0500
+++ /dev/null	1970-01-01 00:00:00.000000000 +0000
@@ -1,60 +0,0 @@
-#!/usr/bin/env rspec
-require 'spec_helper'
-require 'puppet/agent'
-require 'puppet/agent/locker'
-
-class LockerTester
-  include Puppet::Agent::Disabler
-end
-
-describe Puppet::Agent::Disabler do
-  before do
-    @locker = LockerTester.new
-    @locker.stubs(:lockfile_path).returns "/my/lock"
-  end
-
-  it "should use an AnonymousFilelock instance as its disable_lockfile" do
-    @locker.disable_lockfile.should be_instance_of(Puppet::Util::AnonymousFilelock)
-  end
-
-  it "should use 'lockfile_path' to determine its disable_lockfile path" do
-    @locker.expects(:lockfile_path).returns "/my/lock"
-    lock = Puppet::Util::AnonymousFilelock.new("/my/lock")
-    Puppet::Util::AnonymousFilelock.expects(:new).with("/my/lock.disabled").returns lock
-
-    @locker.disable_lockfile
-  end
-
-  it "should reuse the same lock file each time" do
-    @locker.disable_lockfile.should equal(@locker.disable_lockfile)
-  end
-
-  it "should lock the anonymous lock when disabled" do
-    @locker.disable_lockfile.expects(:lock)
-
-    @locker.disable
-  end
-
-  it "should disable with a message" do
-    @locker.disable_lockfile.expects(:lock).with("disabled because")
-
-    @locker.disable("disabled because")
-  end
-
-  it "should unlock the anonymous lock when enabled" do
-    @locker.disable_lockfile.expects(:unlock)
-
-    @locker.enable
-  end
-
-  it "should check the lock if it is disabled" do
-    @locker.disable_lockfile.expects(:locked?)
-
-    @locker.disabled?
-  end
-
-  it "should report the disable message when disabled" do
-    @locker.disable_lockfile.expects(:message).returns("message")
-    @locker.disable_message.should == "message"
-  end
-end
Index: puppet-2.7.11/spec/unit/agent/locker_spec.rb
===================================================================
--- puppet-2.7.11.orig/spec/unit/agent/locker_spec.rb	2012-04-11 03:31:01.063885414 -0500
+++ puppet-2.7.11/spec/unit/agent/locker_spec.rb	2012-04-11 03:31:40.767886354 -0500
@@ -29,6 +29,18 @@
     @locker.lockfile.should equal(@locker.lockfile)
   end
 
+  it "should use the lock file to anonymously lock the process when disabled" do
+    @locker.lockfile.expects(:lock).with(:anonymous => true)
+
+    @locker.disable
+  end
+
+  it "should use the lock file to anonymously unlock the process when enabled" do
+    @locker.lockfile.expects(:unlock).with(:anonymous => true)
+
+    @locker.enable
+  end
+
   it "should have a method that yields when a lock is attained" do
     @locker.lockfile.expects(:lock).returns true
 
Index: puppet-2.7.11/spec/unit/agent_backward_compatibility_spec.rb
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ puppet-2.7.11/spec/unit/agent_backward_compatibility_spec.rb	2012-04-11 03:31:40.767886354 -0500
@@ -0,0 +1,152 @@
+#!/usr/bin/env rspec
+require 'spec_helper'
+require 'puppet/agent'
+
+
+############################################################################
+#                                  NOTE                                    #
+############################################################################
+#                                                                          #
+# This entire spec is only here for backwards compatibility from 2.7.12+   #
+# with 2.7.10 and 2.7.11. The entire file should be able to be removed     #
+# for the 3.x series.                                                      #
+#                                                                          #
+# For more info, see the comments on the #handle_2_7_10_disabled_lockfile  #
+# method in pidlock.rb                                                     #
+#                                                                          #
+# --cprice 2012-03-01                                                      #
+############################################################################
+
+class AgentTestClient
+  def run
+    # no-op
+  end
+  def stop
+    # no-op
+  end
+end
+
+describe Puppet::Agent do
+  include PuppetSpec::Files
+
+  let(:agent) { Puppet::Agent.new(AgentTestClient) }
+
+  describe "in order to be backwards-compatibility with versions 2.7.10 and 2.7.11" do
+
+    describe "when the 2.7.10/2.7.11 'disabled' lockfile exists" do
+
+      # the "normal" lockfile
+      let(:lockfile_path) { tmpfile("agent_spec_lockfile") }
+
+      # the 2.7.10/2.7.11 "disabled" lockfile
+      # (can't use PuppetSpec::Files.tmpfile here because we need the ".disabled" file to have *exactly* the same
+      #   path/name as the original file, plus the ".disabled" suffix.)
+      let(:disabled_lockfile_path) { lockfile_path + ".disabled" }
+
+      # some regexes to match log messages
+      let(:warning_regex) { /^Found special lockfile '#{disabled_lockfile_path}'.*renaming/ }
+      let(:disabled_regex) { /^Skipping run of .*; administratively disabled/ }
+
+      before(:each) do
+        # create the 2.7.10 "disable" lockfile.
+        FileUtils.touch(disabled_lockfile_path)
+
+        # stub in our temp lockfile path.
+        AgentTestClient.expects(:lockfile_path).returns lockfile_path
+      end
+
+      after(:each) do
+        # manually clean up the files that we didn't create via PuppetSpec::Files.tmpfile
+        begin
+          File.unlink(disabled_lockfile_path)
+        rescue Errno::ENOENT
+          # some of the tests expect for the agent code to take care of deleting this file,
+          # so it may (validly) not exist.
+        end
+      end
+
+      describe "when the 'regular' lockfile also exists" do
+        # the logic here is that if a 'regular' lockfile already exists, then there is some state that the
+        # current version of puppet is responsible for dealing with.  All of the tests in this block are
+        # simply here to make sure that our backwards-compatibility hack does *not* interfere with this.
+        #
+        # Even if the ".disabled" lockfile exists--it can be dealt with at another time, when puppet is
+        # in *exactly* the state that we want it to be in (mostly meaning that the 'regular' lockfile
+        # does not exist.)
+
+        before(:each) do
+          # create the "regular" lockfile
+          FileUtils.touch(lockfile_path)
+        end
+
+        it "should be recognized as 'disabled'" do
+          agent.should be_disabled
+        end
+
+        it "should not try to start a new agent run" do
+          AgentTestClient.expects(:new).never
+          Puppet.expects(:notice).with(regexp_matches(disabled_regex))
+
+          agent.run
+        end
+
+        it "should not delete the 2.7.10/2.7.11 lockfile" do
+          agent.run
+
+          File.exists?(disabled_lockfile_path).should == true
+        end
+
+        it "should not print the warning message" do
+          Puppet.expects(:warning).with(regexp_matches(warning_regex)).never
+
+          agent.run
+        end
+      end
+
+      describe "when the 'regular' lockfile does not exist" do
+        # this block of tests is for actually testing the backwards compatibility hack.  This
+        # is where we're in a clean state and we know it's safe(r) to muck with the lockfile
+        # situation.
+
+        it "should recognize that the agent is disabled" do
+          agent.should be_disabled
+        end
+
+        describe "when an agent run is requested" do
+          it "should not try to start a new agent run" do
+            AgentTestClient.expects(:new).never
+            Puppet.expects(:notice).with(regexp_matches(disabled_regex))
+
+            agent.run
+          end
+
+          it "should warn, remove the 2.7.10/2.7.11 lockfile, and create the 'normal' lockfile" do
+            Puppet.expects(:warning).with(regexp_matches(warning_regex))
+
+            agent.run
+
+            File.exists?(disabled_lockfile_path).should == false
+            File.exists?(lockfile_path).should == true
+          end
+        end
+
+        describe "when running --enable" do
+          it "should recognize that the agent is disabled" do
+            agent.should be_disabled
+          end
+
+          it "should warn and clean up the 2.7.10/2.7.11 lockfile" do
+            Puppet.expects(:warning).with(regexp_matches(warning_regex))
+
+            agent.enable
+
+            File.exists?(disabled_lockfile_path).should == false
+            File.exists?(lockfile_path).should == false
+          end
+        end
+      end
+    end
+  end
+
+
+end
Index: puppet-2.7.11/spec/unit/agent_spec.rb
===================================================================
--- puppet-2.7.11.orig/spec/unit/agent_spec.rb	2012-04-11 03:31:01.079885412 -0500
+++ puppet-2.7.11/spec/unit/agent_spec.rb	2012-04-11 03:31:40.771886354 -0500
@@ -24,7 +24,6 @@
 
     # So we don't actually try to hit the filesystem.
     @agent.stubs(:lock).yields
-    @agent.stubs(:disabled?).returns(false)
 
     # make Puppet::Application safe for stubbing; restore in an :after block; silence warnings for this.
     without_warnings { Puppet::Application = Class.new(Puppet::Application) }
@@ -58,6 +57,7 @@
     client.expects(:run)
 
     @agent.stubs(:running?).returns false
+    @agent.stubs(:disabled?).returns false
     @agent.run
   end
 
@@ -66,24 +66,34 @@
     @agent.lockfile_path.should == "/my/lock"
   end
 
-  it "should be considered running if the lock file is locked" do
+  it "should be considered running if the lock file is locked and not anonymous" do
     lockfile = mock 'lockfile'
 
-    @agent.expects(:lockfile).returns lockfile
+    @agent.expects(:lockfile).returns(lockfile).twice
     lockfile.expects(:locked?).returns true
+    lockfile.expects(:anonymous?).returns false
 
     @agent.should be_running
   end
 
+  it "should be considered disabled if the lock file is locked and anonymous" do
+    lockfile = mock 'lockfile'
+
+    @agent.expects(:lockfile).returns(lockfile).at_least_once
+    lockfile.expects(:locked?).returns(true).at_least_once
+    lockfile.expects(:anonymous?).returns(true).at_least_once
+
+    @agent.should be_disabled
+  end
+
   describe "when being run" do
     before do
-      AgentTestClient.stubs(:lockfile_path).returns "/my/lock"
       @agent.stubs(:running?).returns false
+      @agent.stubs(:disabled?).returns false
     end
 
     it "should splay" do
       @agent.expects(:splay)
-      @agent.stubs(:running?).returns false
 
       @agent.run
     end
@@ -94,9 +104,9 @@
       @agent.run
     end
 
-    it "should do nothing if disabled" do
-      @agent.expects(:disabled?).returns(true)
-      AgentTestClient.expects(:new).never
+    it "should display an informative message if the agent is administratively disabled" do
+      @agent.expects(:disabled?).returns true
+      Puppet.expects(:notice).with(regexp_matches(/Skipping run of .*; administratively disabled/))
       @agent.run
     end
 
Index: puppet-2.7.11/spec/unit/application/agent_spec.rb
===================================================================
--- puppet-2.7.11.orig/spec/unit/application/agent_spec.rb	2012-04-11 03:31:01.071885415 -0500
+++ puppet-2.7.11/spec/unit/application/agent_spec.rb	2012-04-11 03:31:40.771886354 -0500
@@ -91,7 +91,7 @@
       @puppetd.command_line.stubs(:args).returns([])
     end
 
-    [:centrallogging, :enable, :debug, :fqdn, :test, :verbose, :digest].each do |option|
+    [:centrallogging, :disable, :enable, :debug, :fqdn, :test, :verbose, :digest].each do |option|
       it "should declare handle_#{option} method" do
         @puppetd.should respond_to("handle_#{option}".to_sym)
       end
@@ -102,24 +102,6 @@
       end
     end
 
-    describe "when handling --disable" do
-      it "should declare handle_disable method" do
-        @puppetd.should respond_to(:handle_disable)
-      end
-
-      it "should set disable to true" do
-        @puppetd.options.stubs(:[]=)
-        @puppetd.options.expects(:[]=).with(:disable, true)
-        @puppetd.handle_disable('')
-      end
-
-      it "should store disable message" do
-        @puppetd.options.stubs(:[]=)
-        @puppetd.options.expects(:[]=).with(:disable_message, "message")
-        @puppetd.handle_disable('message')
-      end
-    end
-
     it "should set an existing handler on server" do
       Puppet::Network::Handler.stubs(:handler).with("handler").returns(true)
 
@@ -367,20 +349,6 @@
         end
       end
 
-      it "should pass the disable message when disabling" do
-        @puppetd.options.stubs(:[]).with(:disable).returns(true)
-        @puppetd.options.stubs(:[]).with(:disable_message).returns("message")
-        @agent.expects(:disable).with("message")
-        expect { @puppetd.enable_disable_client(@agent) }.to exit_with 0
-      end
-
-      it "should pass the default disable message when disabling without a message" do
-        @puppetd.options.stubs(:[]).with(:disable).returns(true)
-        @puppetd.options.stubs(:[]).with(:disable_message).returns(nil)
-        @agent.expects(:disable).with("reason not specified")
-        expect { @puppetd.enable_disable_client(@agent) }.to exit_with 0
-      end
-
       it "should finally exit" do
         expect { @puppetd.enable_disable_client(@agent) }.to exit_with 0
       end
Index: puppet-2.7.11/spec/unit/util/anonymous_filelock_spec.rb
===================================================================
--- puppet-2.7.11.orig/spec/unit/util/anonymous_filelock_spec.rb	2012-04-11 03:31:01.039885413 -0500
+++ /dev/null	1970-01-01 00:00:00.000000000 +0000
@@ -1,78 +0,0 @@
-#!/usr/bin/env rspec
-require 'spec_helper'
-
-require 'puppet/util/anonymous_filelock'
-
-describe Puppet::Util::AnonymousFilelock do
-  require 'puppet_spec/files'
-  include PuppetSpec::Files
-
-  before(:each) do
-    @lockfile = tmpfile("lock")
-    @lock = Puppet::Util::AnonymousFilelock.new(@lockfile)
-  end
-
-  it "should be anonymous" do
-    @lock.should be_anonymous
-  end
-
-  describe "#lock" do
-    it "should return false if already locked" do
-      @lock.stubs(:locked?).returns(true)
-      @lock.lock.should be_false
-    end
-
-    it "should return true if it successfully locked" do
-      @lock.lock.should be_true
-    end
-
-    it "should create a lock file" do
-      @lock.lock
-
-      File.should be_exists(@lockfile)
-    end
-
-    it "should create a lock file containing a message" do
-      @lock.lock("message")
-
-      File.read(@lockfile).should == "message"
-    end
-  end
-
-  describe "#unlock" do
-    it "should return true when unlocking" do
-      @lock.lock
-      @lock.unlock.should be_true
-    end
-
-    it "should return false when not locked" do
-      @lock.unlock.should be_false
-    end
-
-    it "should clear the lock file" do
-      File.open(@lockfile, 'w') { |fd| fd.print("locked") }
-      @lock.unlock
-      File.should_not be_exists(@lockfile)
-    end
-  end
-
-  it "should be locked when locked" do
-    @lock.lock
-    @lock.should be_locked
-  end
-
-  it "should not be locked when not locked" do
-    @lock.should_not be_locked
-  end
-
-  it "should not be locked when unlocked" do
-    @lock.lock
-    @lock.unlock
-    @lock.should_not be_locked
-  end
-
-  it "should return the lock message" do
-    @lock.lock("lock message")
-    @lock.message.should == "lock message"
-  end
-end
\ No newline at end of file
Index: puppet-2.7.11/spec/unit/util/pidlock_spec.rb
===================================================================
--- puppet-2.7.11.orig/spec/unit/util/pidlock_spec.rb	2012-04-11 03:31:01.047885410 -0500
+++ /dev/null	1970-01-01 00:00:00.000000000 +0000
@@ -1,208 +0,0 @@
-#!/usr/bin/env rspec
-require 'spec_helper'
-
-require 'puppet/util/pidlock'
-
-describe Puppet::Util::Pidlock do
-  require 'puppet_spec/files'
-  include PuppetSpec::Files
-
-  before(:each) do
-    @lockfile = tmpfile("lock")
-    @lock = Puppet::Util::Pidlock.new(@lockfile)
-  end
-
-  it "should not be anonymous" do
-    @lock.should_not be_anonymous
-  end
-
-  describe "#lock" do
-    it "should not be locked at start" do
-      @lock.should_not be_locked
-    end
-
-    it "should not be mine at start" do
-      @lock.should_not be_mine
-    end
-
-    it "should become locked" do
-      @lock.lock
-      @lock.should be_locked
-    end
-
-    it "should become mine" do
-      @lock.lock
-      @lock.should be_mine
-    end
-
-    it "should be possible to lock multiple times" do
-      @lock.lock
-      lambda { @lock.lock }.should_not raise_error
-    end
-
-    it "should return true when locking" do
-      @lock.lock.should be_true
-    end
-
-    it "should return true if locked by me" do
-      @lock.lock
-      @lock.lock.should be_true
-    end
-
-    it "should return false if locked by someone else" do
-      Process.stubs(:kill)
-      File.open(@lockfile, "w") { |fd| fd.print('0') }
-
-      @lock.lock.should be_false
-    end
-
-    it "should create a lock file" do
-      @lock.lock
-      File.should be_exists(@lockfile)
-    end
-
-    it "should create a lock file containing our pid" do
-      @lock.lock
-      File.read(@lockfile).to_i.should == Process.pid.to_i
-    end
-  end
-
-  describe "#unlock" do
-    it "should not be locked anymore" do
-      @lock.lock
-      @lock.unlock
-      @lock.should_not be_locked
-    end
-
-    it "should return false if not locked" do
-      @lock.unlock.should be_false
-    end
-
-    it "should return true if properly unlocked" do
-      @lock.lock
-      @lock.unlock.should be_true
-    end
-
-    it "should get rid of the lock file" do
-      @lock.lock
-      @lock.unlock
-      File.should_not be_exists(@lockfile)
-    end
-
-    it "should not warn if the lockfile was deleted by someone else" do
-      @lock.lock
-      File.unlink(@lockfile)
-
-      Puppet.expects(:err).never # meh
-      @lock.unlock
-    end
-
-    it "should warn if the lockfile can't be deleted" do
-      @lock.lock
-      File.expects(:unlink).with(@lockfile).raises(Errno::EIO)
-      Puppet.expects(:err).with do |argument|
-        argument.should =~ /Input\/output error/
-      end
-      @lock.unlock
-
-      # This is necessary because our cleanup code uses File.unlink
-      File.unstub(:unlink)
-      @lock.unlock
-    end
-  end
-
-  describe "#locked?" do
-    it "should return true if locked" do
-      @lock.lock
-      @lock.should be_locked
-    end
-  end
-
-  describe "with a stale lock" do
-    before(:each) do
-      Process.stubs(:kill).with(0, 6789)
-      Process.stubs(:kill).with(0, 1234).raises(Errno::ESRCH)
-      Process.stubs(:pid).returns(6789)
-      File.open(@lockfile, 'w') { |fd| fd.write("1234") }
-    end
-
-    it "should not be locked" do
-      @lock.should_not be_locked
-    end
-
-    describe "#lock" do
-      it "should clear stale locks" do
-        @lock.locked?
-        File.should_not be_exists(@lockfile)
-      end
-
-      it "should replace with new locks" do
-        @lock.lock
-        File.should be_exists(@lockfile)
-        @lock.lock_pid.should == 6789
-        @lock.should be_mine
-        @lock.should be_locked
-      end
-    end
-
-    describe "#unlock" do
-      it "should not be allowed" do
-        @lock.unlock.should be_false
-      end
-
-      it "should not remove the lock file" do
-        @lock.unlock
-        File.should be_exists(@lockfile)
-      end
-    end
-  end
-
-  describe "with another process lock" do
-    before(:each) do
-      Process.stubs(:kill).with(0, 6789)
-      Process.stubs(:kill).with(0, 1234)
-      Process.stubs(:pid).returns(6789)
-      File.open(@lockfile, 'w') { |fd| fd.write("1234") }
-    end
-
-    it "should be locked" do
-      @lock.should be_locked
-    end
-
-    it "should not be mine" do
-      @lock.should_not be_mine
-    end
-
-    describe "#lock" do
-      it "should not be possible" do
-        @lock.lock.should be_false
-      end
-
-      it "should not overwrite the lock" do
-        @lock.lock
-        @lock.should_not be_mine
-      end
-    end
-
-    describe "#unlock" do
-      it "should not be possible" do
-        @lock.unlock.should be_false
-      end
-
-      it "should not remove the lock file" do
-        @lock.unlock
-        File.should be_exists(@lockfile)
-      end
-
-      it "should still not be our lock" do
-        @lock.unlock
-        @lock.should_not be_mine
-      end
-
-      it "should not warn" do
-        Puppet.expects(:err).never
-        @lock.unlock
-      end
-    end
-  end
-end
Index: puppet-2.7.11/test/util/pidlock.rb
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ puppet-2.7.11/test/util/pidlock.rb	2012-04-11 03:31:40.775886355 -0500
@@ -0,0 +1,126 @@
+require File.expand_path(File.dirname(__FILE__) + '/../lib/puppettest')
+
+require 'puppet/util/pidlock'
+require 'fileutils'
+
+# This is *fucked* *up*
+Puppet.debug = false
+
+class TestPuppetUtilPidlock < Test::Unit::TestCase
+  include PuppetTest
+
+  def setup
+    super
+    @workdir = tstdir
+  end
+
+  def teardown
+    super
+    FileUtils.rm_rf(@workdir)
+  end
+
+  def test_00_basic_create
+    l = nil
+    assert_nothing_raised { l = Puppet::Util::Pidlock.new(@workdir + '/nothingmuch') }
+
+    assert_equal Puppet::Util::Pidlock, l.class
+
+    assert_equal @workdir + '/nothingmuch', l.lockfile
+  end
+
+  def test_10_uncontended_lock
+    l = Puppet::Util::Pidlock.new(@workdir + '/test_lock')
+
+    assert !l.locked?
+    assert !l.mine?
+    assert l.lock
+    assert l.locked?
+    assert l.mine?
+    assert !l.anonymous?
+    # It's OK to call lock multiple times
+    assert l.lock
+    assert l.unlock
+    assert !l.locked?
+    assert !l.mine?
+  end
+
+  def test_20_someone_elses_lock
+    childpid = nil
+    l = Puppet::Util::Pidlock.new(@workdir + '/someone_elses_lock')
+
+    # First, we need a PID that's guaranteed to be (a) used, (b) someone
+    # else's, and (c) around for the life of this test.
+    childpid = fork { loop do; sleep 10; end }
+
+    File.open(l.lockfile, 'w') { |fd| fd.write(childpid) }
+
+    assert l.locked?
+    assert !l.mine?
+    assert !l.lock
+    assert l.locked?
+    assert !l.mine?
+    assert !l.unlock
+    assert l.locked?
+    assert !l.mine?
+  ensure
+    Process.kill("KILL", childpid) unless childpid.nil?
+  end
+
+  def test_30_stale_lock
+    # This is a bit hard to guarantee, but we need a PID that is definitely
+    # unused, and will stay so for the the life of this test.  Our best
+    # bet is to create a process, get it's PID, let it die, and *then*
+    # lock on it.
+    childpid = fork { exit }
+
+    # Now we can't continue until we're sure that the PID is dead
+    Process.wait(childpid)
+
+    l = Puppet::Util::Pidlock.new(@workdir + '/stale_lock')
+
+    # locked? should clear the lockfile
+    File.open(l.lockfile, 'w') { |fd| fd.write(childpid) }
+    assert File.exists?(l.lockfile)
+    assert !l.locked?
+    assert !File.exists?(l.lockfile)
+
+    # lock should replace the lockfile with our own
+    File.open(l.lockfile, 'w') { |fd| fd.write(childpid) }
+    assert File.exists?(l.lockfile)
+    assert l.lock
+    assert l.locked?
+    assert l.mine?
+
+    # unlock should fail, and should *not* molest the existing lockfile,
+    # despite it being stale
+    File.open(l.lockfile, 'w') { |fd| fd.write(childpid) }
+    assert File.exists?(l.lockfile)
+    assert !l.unlock
+    assert File.exists?(l.lockfile)
+  end
+
+  def test_40_not_locked_at_all
+    l = Puppet::Util::Pidlock.new(@workdir + '/not_locked')
+
+    assert !l.locked?
+    # We can't unlock if we don't hold the lock
+    assert !l.unlock
+  end
+
+  def test_50_anonymous_lock
+    l = Puppet::Util::Pidlock.new(@workdir + '/anonymous_lock')
+
+    assert !l.locked?
+    assert l.lock(:anonymous => true)
+    assert l.locked?
+    assert l.anonymous?
+    assert !l.mine?
+    assert "", File.read(l.lockfile)
+    assert !l.unlock
+    assert l.locked?
+    assert l.anonymous?
+    assert l.unlock(:anonymous => true)
+    assert !File.exists?(l.lockfile)
+  end
+end
+
