summaryrefslogtreecommitdiff
path: root/lib/chef/run_lock.rb
diff options
context:
space:
mode:
authorsersut <serdar@opscode.com>2013-10-10 15:21:46 -0700
committersersut <serdar@opscode.com>2013-10-14 16:19:09 -0700
commit818b8378f9a5795ab388bfbe7950c9635213ccc5 (patch)
tree6309a938d27a569c4df46c0c264a563454cca3d0 /lib/chef/run_lock.rb
parent59e15c6268d99ed2f97cc39dddf17d844ca63d9b (diff)
downloadchef-818b8378f9a5795ab388bfbe7950c9635213ccc5.tar.gz
Windows support for Chef::Runlock.
This ensures that if someone does a manual chef-client run, it doesn't fail if the chef is configured as a service on windows and if there is a chef-client run happening right now. The newly started run will wait for the old run to finish and continue after it.
Diffstat (limited to 'lib/chef/run_lock.rb')
-rw-r--r--lib/chef/run_lock.rb53
1 files changed, 41 insertions, 12 deletions
diff --git a/lib/chef/run_lock.rb b/lib/chef/run_lock.rb
index 2ddf02973a..09f6100bee 100644
--- a/lib/chef/run_lock.rb
+++ b/lib/chef/run_lock.rb
@@ -17,6 +17,9 @@
require 'chef/mixin/create_path'
require 'fcntl'
+if Chef::Platform.windows?
+ require 'chef/win32/mutex'
+end
class Chef
@@ -30,6 +33,7 @@ class Chef
include Chef::Mixin::CreatePath
attr_reader :runlock
+ attr_reader :mutex
attr_reader :runlock_file
# Create a new instance of RunLock
@@ -38,6 +42,7 @@ class Chef
def initialize(lockfile)
@runlock_file = lockfile
@runlock = nil
+ @mutex = nil
end
# Acquire the system-wide lock. Will block indefinitely if another process
@@ -58,17 +63,32 @@ class Chef
# ensure the runlock_file path exists
create_path(File.dirname(runlock_file))
@runlock = File.open(runlock_file,'a+')
- # if we support FD_CLOEXEC (linux, !windows), then use it.
- # NB: ruby-2.0.0-p195 sets FD_CLOEXEC by default, but not ruby-1.8.7/1.9.3
- if Fcntl.const_defined?('F_SETFD') && Fcntl.const_defined?('FD_CLOEXEC')
- runlock.fcntl(Fcntl::F_SETFD, runlock.fcntl(Fcntl::F_GETFD, 0) | Fcntl::FD_CLOEXEC)
- end
- # Flock will return 0 if it can acquire the lock otherwise it
- # will return false
- if runlock.flock(File::LOCK_NB|File::LOCK_EX) == 0
- true
+
+ if Chef::Platform.windows?
+ # Since flock mechanism doesn't exist on windows we are using
+ # platform Mutex.
+ # We are creating a "Global" mutex here so that non-admin
+ # users can not DoS chef-client by creating the same named
+ # mutex we are using locally.
+ # Mutex name is case-sensitive contrary to other things in
+ # windows. "\" is the only invalid character.
+ # @mutex = Chef::ReservedNames::Win32::Mutex.new("Global\\serdar:/_-running.pid")
+ @mutex = Chef::ReservedNames::Win32::Mutex.new("Global\\#{runlock_file.gsub(/[\\]/, "/").downcase}")
+ mutex.test
else
- false
+ # If we support FD_CLOEXEC, then use it.
+ # NB: ruby-2.0.0-p195 sets FD_CLOEXEC by default, but not
+ # ruby-1.8.7/1.9.3
+ if Fcntl.const_defined?('F_SETFD') && Fcntl.const_defined?('FD_CLOEXEC')
+ runlock.fcntl(Fcntl::F_SETFD, runlock.fcntl(Fcntl::F_GETFD, 0) | Fcntl::FD_CLOEXEC)
+ end
+ # Flock will return 0 if it can acquire the lock otherwise it
+ # will return false
+ if runlock.flock(File::LOCK_NB|File::LOCK_EX) == 0
+ true
+ else
+ false
+ end
end
end
@@ -78,7 +98,11 @@ class Chef
def wait
runpid = runlock.read.strip.chomp
Chef::Log.warn("Chef client #{runpid} is running, will wait for it to finish and then run.")
- runlock.flock(File::LOCK_EX)
+ if Chef::Platform.windows?
+ mutex.wait
+ else
+ runlock.flock(File::LOCK_EX)
+ end
end
def save_pid
@@ -93,7 +117,11 @@ class Chef
# Release the system-wide lock.
def release
if runlock
- runlock.flock(File::LOCK_UN)
+ if Chef::Platform.windows?
+ mutex.release
+ else
+ runlock.flock(File::LOCK_UN)
+ end
runlock.close
# Don't unlink the pid file, if another chef-client was waiting, it
# won't be recreated. Better to leave a "dead" pid file than not have
@@ -106,6 +134,7 @@ class Chef
def reset
@runlock = nil
+ @mutex = nil
end
end