lib/vagrant-parallels/action/box_register.rb
require 'fileutils'
require 'log4r'
require 'nokogiri'
module VagrantPlugins
module Parallels
module Action
class BoxRegister
@@lock = Mutex.new
def initialize(app, env)
@app = app
@logger = Log4r::Logger.new('vagrant_parallels::action::box_register')
end
def call(env)
# If we don't have a box, nothing to do
if !env[:machine].box
return @app.call(env)
end
# Do the register while locked so that nobody else register
# a box at the same time.
@@lock.synchronize do
lock_key = Digest::MD5.hexdigest(env[:machine].box.name)
env[:machine].env.lock(lock_key, retry: true) do
register_box(env)
end
end
# If we got interrupted, then the import could have been
# interrupted and its not a big deal. Just return out.
return if env[:interrupted]
# Register completed successfully. Continue the chain
@app.call(env)
end
protected
def box_path(env)
res = Dir.glob(env[:machine].box.directory.join('*.{pvm,macvm}')).first
if !res
raise Errors::BoxImageNotFound, name: env[:machine].box.name
end
res
end
def box_id(env)
# Get the box image UUID from XML-based configuration file
tpl_config = File.join(box_path(env), 'config.pvs')
xml = Nokogiri::XML(File.open(tpl_config))
id = xml.xpath('//ParallelsVirtualMachine/Identification/VmUuid').text
if !id
raise Errors::BoxIDNotFound,
name: env[:machine].box.name,
config: tpl_config
end
id.delete('{}')
end
def lease_box_lock(env)
lease_file = env[:machine].box.directory.join('box_lease_count')
# If the temporary file, verify it is not too old. If its older than
# 1 hour, delete it first because previous run may be failed.
if lease_file.file? && lease_file.mtime.to_i < Time.now.to_i - 60 * 60
lease_file.delete
end
# Increment a counter in the file. Create the file if it doesn't exist
FileUtils.touch(lease_file)
File.open(lease_file ,'r+') do |file|
num = file.gets.to_i
file.rewind
file.puts num.next
file.fsync
file.flush
end
end
def register_box(env)
# Increment the lock counter in the temporary lease file
lease_box_lock(env)
# Read the box ID if we have it in the file.
box_id_file = env[:machine].box.directory.join('box_id')
env[:clone_id] = box_id_file.read.chomp if box_id_file.file?
# If we have the ID and the VM exists already, then we
# have nothing to do. Success!
if env[:clone_id] && env[:machine].provider.driver.vm_exists?(env[:clone_id])
@logger.info(
"Box image '#{env[:machine].box.name}' is already registered " +
"(id=#{env[:clone_id]}) - skipping register step.")
return
end
env[:ui].info I18n.t('vagrant_parallels.actions.vm.box.register',
name: env[:machine].box.name)
pvm = box_path(env)
# We need the box ID to be the same for all parallel runs
options = ['--preserve-uuid']
# Register the box VM image
env[:machine].provider.driver.register(pvm, options)
env[:clone_id] = box_id(env)
@logger.info(
"Registered box #{env[:machine].box.name} with id #{env[:clone_id]}")
@logger.debug("Writing box id '#{env[:clone_id]}' to #{box_id_file}")
box_id_file.open('w+') do |f|
f.write(env[:clone_id])
end
end
end
end
end
end