172 lines
4.9 KiB
Ruby
172 lines
4.9 KiB
Ruby
module Vagrant
|
|
class VM
|
|
include Vagrant::Util
|
|
|
|
attr_accessor :vm
|
|
attr_reader :actions
|
|
attr_accessor :from
|
|
|
|
class << self
|
|
# Executes a specific action
|
|
def execute!(action_klass, *args)
|
|
vm = new
|
|
vm.add_action(action_klass, *args)
|
|
vm.execute!
|
|
end
|
|
|
|
# Unpack the specified vm package
|
|
def unpackage(package_path)
|
|
working_dir = package_path.chomp(File.extname(package_path))
|
|
new_base_dir = File.join(Vagrant.config[:vagrant][:home], File.basename(package_path, '.*'))
|
|
|
|
# Exit if folder of same name exists
|
|
# TODO provide a way for them to specify the directory name
|
|
error_and_exit(<<-error) if File.exists?(new_base_dir)
|
|
The directory `#{File.basename(package_path, '.*')}` already exists under #{Vagrant.config[:vagrant][:home]}. Please
|
|
remove it, rename your packaged VM file, or (TODO) specifiy an
|
|
alternate directory
|
|
error
|
|
|
|
logger.info "Creating working dir: #{working_dir} ..."
|
|
FileUtils.mkpath(working_dir)
|
|
|
|
logger.info "Decompressing the packaged VM: #{package_path} ..."
|
|
decompress(package_path, working_dir)
|
|
|
|
logger.info "Moving the unpackaged VM to #{new_base_dir} ..."
|
|
FileUtils.mv(working_dir, Vagrant.config[:vagrant][:home])
|
|
|
|
#Return the ovf file for importation
|
|
Dir["#{new_base_dir}/*.ovf"].first
|
|
end
|
|
|
|
def decompress(path, dir, file_delimeter=Vagrant.config[:package][:delimiter_regex])
|
|
file = nil
|
|
Zlib::GzipReader.open(path) do |gz|
|
|
begin
|
|
gz.each_line do |line|
|
|
|
|
# If the line is a file delimiter create new file and write to it
|
|
if line =~ file_delimeter
|
|
|
|
#Write the the part of the line belonging to the previous file
|
|
if file
|
|
file.write $1
|
|
file.close
|
|
end
|
|
|
|
#Open a new file with the name contained in the delimiter
|
|
file = File.open(File.join(dir, $2), 'w')
|
|
|
|
#Write the rest of the line to the new file
|
|
file.write $3
|
|
else
|
|
file.write line
|
|
end
|
|
end
|
|
ensure
|
|
file.close if file
|
|
end
|
|
end
|
|
end
|
|
|
|
# Finds a virtual machine by a given UUID and either returns
|
|
# a Vagrant::VM object or returns nil.
|
|
def find(uuid)
|
|
vm = VirtualBox::VM.find(uuid)
|
|
return nil if vm.nil?
|
|
new(vm)
|
|
end
|
|
end
|
|
|
|
def initialize(vm=nil)
|
|
@vm = vm
|
|
@actions = []
|
|
end
|
|
|
|
def add_action(action_klass, *args)
|
|
@actions << action_klass.new(self, *args)
|
|
end
|
|
|
|
def execute!
|
|
# Call the prepare method on each once its
|
|
# initialized, then call the execute! method
|
|
[:prepare, :execute!].each do |method|
|
|
@actions.each do |action|
|
|
action.send(method)
|
|
end
|
|
end
|
|
end
|
|
|
|
# Invokes an "around callback" which invokes before_name and
|
|
# after_name for the given callback name, yielding a block between
|
|
# callback invokations.
|
|
def invoke_around_callback(name, *args)
|
|
invoke_callback("before_#{name}".to_sym, *args)
|
|
yield
|
|
invoke_callback("after_#{name}".to_sym, *args)
|
|
end
|
|
|
|
def invoke_callback(name, *args)
|
|
# Attempt to call the method for the callback on each of the
|
|
# actions
|
|
results = []
|
|
@actions.each do |action|
|
|
results << action.send(name, *args) if action.respond_to?(name)
|
|
end
|
|
results
|
|
end
|
|
|
|
def destroy
|
|
if @vm.running?
|
|
logger.info "VM is running. Forcing immediate shutdown..."
|
|
@vm.stop(true)
|
|
end
|
|
|
|
logger.info "Destroying VM and associated drives..."
|
|
@vm.destroy(:destroy_image => true)
|
|
end
|
|
|
|
def saved?
|
|
@vm.saved?
|
|
end
|
|
|
|
def save_state
|
|
logger.info "Saving VM state..."
|
|
@vm.save_state(true)
|
|
end
|
|
|
|
# TODO the longest method, needs to be split up
|
|
def package(name, to)
|
|
delimiter = Vagrant.config[:package][:delimiter]
|
|
folder = FileUtils.mkpath(File.join(to, name))
|
|
logger.info "Creating working directory: #{folder} ..."
|
|
|
|
ovf_path = File.join(folder, "#{name}.ovf")
|
|
tar_path = "#{folder}.box"
|
|
|
|
logger.info "Exporting required VM files to working directory ..."
|
|
@vm.export(ovf_path)
|
|
|
|
logger.info "Packaging VM into #{tar_path} ..."
|
|
Zlib::GzipWriter.open(tar_path) do |gz|
|
|
Dir.new(folder).each do |file|
|
|
next if File.directory?(file)
|
|
# Delimit the files, and guarantee new line for next file if not the first
|
|
gz.write "#{delimiter}#{file}#{delimiter}"
|
|
File.open(File.join(folder, file)).each { |line| gz.write(line) }
|
|
end
|
|
end
|
|
|
|
logger.info "Removing working directory ..."
|
|
FileUtils.rm_r(folder)
|
|
|
|
tar_path
|
|
end
|
|
|
|
def powered_off?; @vm.powered_off? end
|
|
|
|
def export(filename); @vm.export(filename, {}, true) end
|
|
end
|
|
end
|