Class: Chef::RunLock
- Inherits:
-
Object
- Object
- Chef::RunLock
- Includes:
- Mixin::CreatePath
- Defined in:
- lib/chef/run_lock.rb
Overview
== Chef::RunLock Provides an interface for acquiring and releasing a system-wide exclusive lock.
Used by Chef::Client to ensure only one instance of chef-client (or solo) is modifying the system at a time.
Instance Attribute Summary collapse
-
#mutex ⇒ Object
readonly
Returns the value of attribute mutex.
-
#runlock ⇒ Object
readonly
Returns the value of attribute runlock.
-
#runlock_file ⇒ Object
readonly
Returns the value of attribute runlock_file.
Instance Method Summary collapse
-
#acquire ⇒ Object
Acquire the system-wide lock.
- #acquire_lock ⇒ Object
- #create_lock ⇒ Object
-
#initialize(lockfile) ⇒ RunLock
constructor
Create a new instance of RunLock === Arguments * :lockfile::: the full path to the lockfile.
-
#release ⇒ Object
Release the system-wide lock.
- #save_pid ⇒ Object
-
#test ⇒ Object
Tests and if successful acquires the system-wide lock.
-
#wait ⇒ Object
Waits until acquiring the system-wide lock.
Methods included from Mixin::CreatePath
Constructor Details
#initialize(lockfile) ⇒ RunLock
Create a new instance of RunLock === Arguments
- :lockfile::: the full path to the lockfile.
46 47 48 49 50 51 |
# File 'lib/chef/run_lock.rb', line 46 def initialize(lockfile) @runlock_file = lockfile @runlock = nil @mutex = nil @runpid = nil end |
Instance Attribute Details
#mutex ⇒ Object (readonly)
Returns the value of attribute mutex.
40 41 42 |
# File 'lib/chef/run_lock.rb', line 40 def mutex @mutex end |
#runlock ⇒ Object (readonly)
Returns the value of attribute runlock.
39 40 41 |
# File 'lib/chef/run_lock.rb', line 39 def runlock @runlock end |
#runlock_file ⇒ Object (readonly)
Returns the value of attribute runlock_file.
41 42 43 |
# File 'lib/chef/run_lock.rb', line 41 def runlock_file @runlock_file end |
Instance Method Details
#acquire ⇒ Object
Acquire the system-wide lock. Will block indefinitely if another process already has the lock and Chef::Config[:run_lock_timeout] is not set. Otherwise will block for Chef::Config[:run_lock_timeout] seconds and exit if the lock is not acquired.
Each call to acquire should have a corresponding call to #release.
The implementation is based on File#flock (see also: flock(2)).
Either acquire() or test() methods should be called in order to get the ownership of run_lock.
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
# File 'lib/chef/run_lock.rb', line 64 def acquire if timeout_given? begin Timeout.timeout(time_to_wait) do unless test if time_to_wait > 0.0 wait else exit_from_timeout end end end rescue Timeout::Error exit_from_timeout end else wait unless test end end |
#acquire_lock ⇒ Object
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 |
# File 'lib/chef/run_lock.rb', line 140 def acquire_lock if ChefUtils.windows? acquire_win32_mutex else # 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 # Target mode does not have run locks, because concurrency is intended elsif Chef::Config.target_mode? true else false end end end |
#create_lock ⇒ Object
133 134 135 136 137 |
# File 'lib/chef/run_lock.rb', line 133 def create_lock # ensure the runlock_file path exists create_path(File.dirname(runlock_file)) @runlock = File.open(runlock_file, "a+") end |
#release ⇒ Object
Release the system-wide lock.
117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
# File 'lib/chef/run_lock.rb', line 117 def release if runlock if ChefUtils.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 # it available if you need to break the lock. reset end end |
#save_pid ⇒ Object
107 108 109 110 111 112 113 114 |
# File 'lib/chef/run_lock.rb', line 107 def save_pid runlock.truncate(0) runlock.rewind # truncate doesn't reset position to 0. runlock.write(Process.pid.to_s) # flush the file fsync flushes the system buffers # in addition to ruby buffers runlock.fsync end |
#test ⇒ Object
Tests and if successful acquires the system-wide lock. Returns true if the lock is acquired, false otherwise.
Either acquire() or test() methods should be called in order to get the ownership of run_lock.
90 91 92 93 |
# File 'lib/chef/run_lock.rb', line 90 def test create_lock acquire_lock end |
#wait ⇒ Object
Waits until acquiring the system-wide lock.
98 99 100 101 102 103 104 105 |
# File 'lib/chef/run_lock.rb', line 98 def wait Chef::Log.warn("#{ChefUtils::Dist::Infra::PRODUCT} #{runpid} is running, will wait for it to finish and then run.") if ChefUtils.windows? mutex.wait else runlock.flock(File::LOCK_EX) end end |