Class: MotherBrain::ChefMutex
- Inherits:
-
Object
- Object
- MotherBrain::ChefMutex
- Extended by:
- Forwardable
- Includes:
- Celluloid, Celluloid::Notifications, MB::Mixin::Services, Logging
- Defined in:
- lib/mb/chef_mutex.rb
Overview
Allows for motherbrain clients to lock a chef resource. A mutex is created with a type and name. Sending #lock to the mutex will then store a data bag item with mutex, the requestor’s client_name, and the current time. An attempt to lock an already-locked mutex will fail if the lock is owned by someone else, or succeed if the lock is owned by the current user.
Constant Summary collapse
- DATA_BAG =
"_motherbrain_locks_".freeze
- LOCK_TYPES =
[ :chef_environment ]
Instance Attribute Summary collapse
-
#force ⇒ Object
readonly
Returns the value of attribute force.
-
#job ⇒ Object
readonly
Returns the value of attribute job.
-
#name ⇒ Object
readonly
Returns the value of attribute name.
-
#report_job_status ⇒ Object
readonly
Returns the value of attribute report_job_status.
-
#type ⇒ Object
readonly
Returns the value of attribute type.
-
#unlock_on_failure ⇒ Object
readonly
Returns the value of attribute unlock_on_failure.
Class Method Summary collapse
-
.synchronize(options, &block) ⇒ Object
Create a new ChefMutex and run the given block of code within it.
Instance Method Summary collapse
- #data_bag_id ⇒ String
-
#initialize(options = {}) ⇒ ChefMutex
constructor
A new instance of ChefMutex.
-
#lock ⇒ Boolean
Attempts to create a lock.
-
#locked? ⇒ Boolean
Returns whether or not the object is locked.
-
#synchronize ⇒ Boolean
Obtains a lock, runs the block, and releases the lock when the block completes.
- #to_s ⇒ String
-
#unlock ⇒ Boolean
Attempts to unlock the lock.
Methods included from Logging
add_argument_header, dev, filename, #log_exception, logger, #logger, reset, set_logger, setup
Constructor Details
#initialize(options = {}) ⇒ ChefMutex
Returns a new instance of ChefMutex.
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
# File 'lib/mb/chef_mutex.rb', line 72 def initialize( = {}) = .reverse_merge( force: false, unlock_on_failure: true ) type, name = .find { |key, value| LOCK_TYPES.include? key } @type = type @name = name @force = [:force] @job = [:job] @report_job_status = [:report_job_status] @unlock_on_failure = [:unlock_on_failure] lock_manager.register(Actor.current) end |
Instance Attribute Details
#force ⇒ Object (readonly)
Returns the value of attribute force.
54 55 56 |
# File 'lib/mb/chef_mutex.rb', line 54 def force @force end |
#job ⇒ Object (readonly)
Returns the value of attribute job.
55 56 57 |
# File 'lib/mb/chef_mutex.rb', line 55 def job @job end |
#name ⇒ Object (readonly)
Returns the value of attribute name.
52 53 54 |
# File 'lib/mb/chef_mutex.rb', line 52 def name @name end |
#report_job_status ⇒ Object (readonly)
Returns the value of attribute report_job_status.
56 57 58 |
# File 'lib/mb/chef_mutex.rb', line 56 def report_job_status @report_job_status end |
#type ⇒ Object (readonly)
Returns the value of attribute type.
51 52 53 |
# File 'lib/mb/chef_mutex.rb', line 51 def type @type end |
#unlock_on_failure ⇒ Object (readonly)
Returns the value of attribute unlock_on_failure.
57 58 59 |
# File 'lib/mb/chef_mutex.rb', line 57 def unlock_on_failure @unlock_on_failure end |
Class Method Details
.synchronize(options, &block) ⇒ Object
Create a new ChefMutex and run the given block of code within it. Terminate the ChefMutex after the block of code finishes executing.
30 31 32 33 34 35 |
# File 'lib/mb/chef_mutex.rb', line 30 def synchronize(, &block) mutex = new() mutex.synchronize(&block) ensure mutex.terminate end |
Instance Method Details
#data_bag_id ⇒ String
91 92 93 94 95 96 97 98 99 |
# File 'lib/mb/chef_mutex.rb', line 91 def data_bag_id result = to_s.dup result.downcase! result.gsub! /[^\w]+/, "-" # dasherize result.gsub! /^-+|-+$/, "" # remove dashes from beginning/end result end |
#lock ⇒ Boolean
Attempts to create a lock. Fails if the lock already exists.
109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
# File 'lib/mb/chef_mutex.rb', line 109 def lock unless type raise InvalidLockType, "Must pass a valid lock type (#{LOCK_TYPES})" end log.info { "Locking #{to_s}" } if job job.set_status "Locking #{to_s}" job.report_running if report_job_status end report(attempt_lock) end |
#locked? ⇒ Boolean
Returns whether or not the object is locked.
127 128 129 |
# File 'lib/mb/chef_mutex.rb', line 127 def locked? !!read end |
#synchronize ⇒ Boolean
Obtains a lock, runs the block, and releases the lock when the block completes. Raises a ResourceLocked error if the lock was unobtainable. If the block raises an error, the resource is unlocked, unless unlock_on_failure: true is passed in to the option hash.
139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 |
# File 'lib/mb/chef_mutex.rb', line 139 def synchronize unless lock current_lock = read err = "Resource #{current_lock['id']} locked by #{current_lock['client_name']}" err << " since #{current_lock['time']} (PID #{current_lock['process_id']})" raise ResourceLocked.new(err) end yield unlock rescue => ex ex = ex.respond_to?(:cause) ? ex.cause : ex unless ex.is_a?(ResourceLocked) unlock if unlock_on_failure end abort(ex) end |
#to_s ⇒ String
102 103 104 |
# File 'lib/mb/chef_mutex.rb', line 102 def to_s "#{type}:#{name}" end |
#unlock ⇒ Boolean
Attempts to unlock the lock. Fails if the lock doesn’t exist, or if it is held by someone else
166 167 168 169 170 171 172 173 174 175 |
# File 'lib/mb/chef_mutex.rb', line 166 def unlock if job job.report_running if report_job_status job.set_status("Unlocking #{to_s}") end attempt_unlock report(true) end |