Skip to content

Commit

Permalink
Add simple synchronization helper to source. Use during install.
Browse files Browse the repository at this point in the history
When installing cookbooks using infrastructure mode and the same
git source is being used for different refs, a race condition
can occur where the cached respository is modified while a copy
is in progress. To prevent this the source should be locked
during install to prevent any unexpected modifications.
  • Loading branch information
chrisroberts committed Jun 28, 2018
1 parent adcab2c commit cfea3f9
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 21 deletions.
44 changes: 23 additions & 21 deletions lib/batali/command/install.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,27 +24,29 @@ def execute!
units_slice.map do |unit|
Thread.new do
ui.debug "Starting unit install for: #{unit.name}<#{unit.version}>"
if unit.source.respond_to?(:cache_path)
unit.source.cache_path = cache_directory(
Bogo::Utility.snake(unit.source.class.name.split("::").last)
)
end
asset_path = unit.source.asset
final_path = Utility.join_path(install_path, unit.name)
if infrastructure?
final_path << "-#{unit.version}"
end
begin
FileUtils.cp_r(
Utility.join_path(asset_path, "."),
final_path
)
ui.debug "Completed unit install for: #{unit.name}<#{unit.version}>"
rescue => e
ui.debug "Failed unit install for: #{unit.name}<#{unit.version}> - #{e.class}: #{e}"
raise
ensure
unit.source.clean_asset(asset_path)
unit.source.synchronize do
if unit.source.respond_to?(:cache_path)
unit.source.cache_path = cache_directory(
Bogo::Utility.snake(unit.source.class.name.split("::").last)
)
end
asset_path = unit.source.asset
final_path = Utility.join_path(install_path, unit.name)
if infrastructure?
final_path << "-#{unit.version}"
end
begin
FileUtils.cp_r(
Utility.join_path(asset_path, "."),
final_path
)
ui.debug "Completed unit install for: #{unit.name}<#{unit.version}>"
rescue => e
ui.debug "Failed unit install for: #{unit.name}<#{unit.version}> - #{e.class}: #{e}"
raise
ensure
unit.source.clean_asset(asset_path)
end
end
end
end.map(&:join)
Expand Down
11 changes: 11 additions & 0 deletions lib/batali/source.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,21 @@ class Source < Utility
attribute :type, String, :required => true, :default => lambda { self.name } # rubocop:disable Style/RedundantSelf

def initialize(args = {})
@lock = Mutex.new
@cache_path = Utility.clean_path(args.delete(:cache_path))
super
end

# Helper to synchronize access to this source.
#
# @yield Block to be executed
# @return [Object]
def synchronize
@lock.synchronize do
yield
end
end

# @return [String]
def unit_version
raise NotImplementedError.new "Abstract class"
Expand Down

0 comments on commit cfea3f9

Please sign in to comment.