Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

286 lines (236 sloc) 11.173 kB
module Veewee
module Provider
module Core
module BoxCommand
def build(options={})
if definition.nil?
raise Veewee::Error,"Could not find the definition. Make sure you are one level above the definitions directory when you execute the build command."
end
# Requires valid definition
ui.info "Building Box #{name} with Definition #{definition.name}:"
options.each do |name,value|
ui.info "- #{name} : #{value}"
end
# Checking regexp of postinstall include/excludes
validate_postinstall_regex(options)
# Check the iso file we need to build the box
definition.verify_iso(options)
if self.exists?
# check if --force option was given
if options['force']==true
self.destroy
self.reload
else
ui.error("you need to provide --force because the box #{name} already exists",:prefix => false)
raise Veewee::Error,"you need to provide --force because the box #{name} already exists"
end
end
# By now the box should have been gone, just checking again
if self.exists?
ui.error("The box should have been deleted by now. Something went terribly wrong. Sorry",:prefix => false)
raise Veewee::Error, "The box should have been deleted by now. Something went terribly wrong. Sorry"
end
self.create(options)
# Check the GUI mode required
env.logger.info "Provider asks the box to start: GUI enabled? #{!options['nogui']}"
self.up(options)
# Waiting for it to boot
ui.info "Waiting #{definition.boot_wait.to_i} seconds for the machine to boot"
sleep definition.boot_wait.to_i
# Calculate an available kickstart port
unless definition.kickstart_port.nil?
guessed_port=guess_free_port(definition.kickstart_port.to_i,7199).to_s
if guessed_port.to_s!=definition.kickstart_port
ui.warn "Changing kickstart port from #{definition.kickstart_port} to #{guessed_port}"
definition.kickstart_port=guessed_port.to_s
end
end
# Let fill's in the variable we need
boot_sequence=fill_sequence(definition.boot_cmd_sequence,{
:ip =>host_ip_as_seen_by_guest,
:port => definition.kickstart_port.to_s,
:name => name
})
# Type the boot sequence
self.console_type(boot_sequence)
self.handle_kickstart(options)
# Wait for an ipaddress
# This needs to be done after the kickstart:
# As the dhcp request will likely occur just before the kickstart fetch
until !self.ip_address.nil?
env.logger.info "wait for Ip address"
sleep 2
end
self.transfer_buildinfo(options)
# Filtering post install files based upon --postinstall-include and --postinstall--exclude
definition.postinstall_files=filter_postinstall_files(options)
self.handle_postinstall(options)
ui.success "The box #{name} was build successfully!"
ui.info "You can now login to the box with:"
if (definition.winrm_user && definition.winrm_password)
env.ui.info winrm_command_string
else
env.ui.info ssh_command_string
end
return self
end
def validate_postinstall_regex(options)
env.logger.info "Checking the postinstall excludes"
unless options["postinstall_exclude"].nil?
options["postinstall_exclude"].each do |p|
begin
r=::Regexp.new(p)
rescue ::RegexpError => ex
raise Veewee::Error ,"\nError in postinstall exclude (ruby regexp) pattern: #{p}:\n- #{ex}"
end
end
end
env.logger.info "Checking the postinstall includes"
unless options["postinstall_include"].nil?
options["postinstall_include"].each do |p|
begin
r=Regexp.new(p)
rescue RegexpError => ex
raise Veewee::Error ,"\nError in postinstall include (ruby regexp) pattern: #{p}:\n- #{ex}"
end
end
end
end
def filter_postinstall_files(options)
new_definition=definition.clone
env.logger.info "Applying the postinstall excludes"
unless options["postinstall_exclude"].nil?
options["postinstall_exclude"].each do |p|
env.logger.info "Exclude pattern #{p}"
new_definition.postinstall_files.reject! { |f| f.match(p) }
end
end
env.logger.info "Applying the postinstall includes"
unless options["postinstall_include"].nil?
options["postinstall_include"].each do |p|
env.logger.info "Include pattern #{p}"
new_definition.postinstall_files.collect! { |f| f.match(p) ? f.gsub(/^_/,""): f}
end
end
env.logger.info "filtered postinstall files:"
new_definition.postinstall_files.each do |p|
env.logger.info "- "+p
end
return new_definition.postinstall_files
end
# This will take a sequence and fill in the variables specified in the options
# f.i. options={:ip => "name"} will substitute "%IP%" -> "name"
def fill_sequence(sequence,options)
filled=sequence.dup
options.each do |key,value|
filled.each do |s|
s.gsub!("%#{key.to_s.upcase}%",value)
end
end
return filled
end
def build_info
[ {:filename => ".veewee_version",:content => "#{Veewee::VERSION}"}]
end
# This function handles all the post-install scripts
# It requires a definition to find all the necessary information
def handle_kickstart(options)
# Handling the kickstart by web
kickstartfiles=definition.kickstart_file
if kickstartfiles.nil? || kickstartfiles.length == 0
env.ui.info "Skipping webserver as no kickstartfile was specified"
else
env.ui.info "Starting a webserver #{definition.kickstart_ip}:#{definition.kickstart_port}\n"
end
# Check if the kickstart is an array or a single string
if kickstartfiles.is_a?(String)
# Let's turn it into an array
kickstartfiles=kickstartfiles.split
end
# For each kickstart file spinup a webserver and wait for the file to be fetched
unless kickstartfiles.nil?
kickstartfiles.each do |kickfile|
wait_for_http_request(kickfile,{
:port => definition.kickstart_port,
:host => definition.kickstart_ip,
:timeout => definition.kickstart_timeout,
:web_dir => definition.path
})
end
end
end
# This function handles all the post-install scripts
# It requires a box(to login to) and a definition(listing the postinstall files)
def handle_postinstall(options)
# Transfer all postinstall files
definition.postinstall_files.each do |postinstall_file|
# Filenames of postinstall_files are relative to their definition
filename=File.join(definition.path,postinstall_file)
self.copy_to_box(filename,File.basename(filename))
if not (definition.winrm_user && definition.winrm_password)
self.exec("chmod +x \"#{File.basename(filename)}\"")
end
end
# Prepare a pre_poinstall file if needed (not nil , or not empty)
unless definition.pre_postinstall_file.to_s.empty?
pre_filename=File.join(definition.path, definition.pre_postinstall_file)
self.copy_to_box(filename,File.basename(pre_filename))
if (definition.winrm_user && definition.winrm_password)
# not implemented on windows yet
else
self.exec("chmod +x \"#{File.basename(pre_filename)}\"")
# Inject the call to the real script by executing the first argument (it will be the postinstall script file name to be executed)
self.exec("execute=\"\\n# We must execute the script passed as the first argument\\n\\$1\" && printf \"%b\\n\" \"$execute\" >> #{File.basename(pre_filename)}")
end
end
# Now iterate over the postinstall files
definition.postinstall_files.each do |postinstall_file|
# Filenames of postinstall_files are relative to their definition
filename=File.join(definition.path,postinstall_file)
unless File.basename(postinstall_file).start_with?("_")
unless definition.pre_postinstall_file.to_s.empty?
raise 'not implemented on windows yet' if (definition.winrm_user && definition.winrm_password)
# Filename of pre_postinstall_file are relative to their definition
pre_filename=File.join(definition.path, definition.pre_postinstall_file)
# Upload the pre postinstall script if not already transfered
command = "./" + File.basename(pre_filename)
command = sudo(command) + " ./"+File.basename(filename)
else
if (definition.winrm_user && definition.winrm_password)
# no sudo on windows, batch files only please?
self.exec(File.basename(filename))
else
self.exec(sudo("./"+File.basename(filename)))
end
end
self.exec(command)
else
env.logger.info "Skipping postinstallfile #{postinstall_file}"
end
end
end
# Transfer information provide by the Provider to the box
#
#
def transfer_buildinfo(options)
build_info.each do |info|
begin
infofile=Tempfile.open("#{info[:filename]}")
# Force binary mode to prevent windows from putting CR-LF end line style
# http://www.ruby-forum.com/topic/127453#568546
infofile.binmode
infofile.puts "#{info[:content]}"
infofile.rewind
infofile.close
self.copy_to_box(infofile.path,info[:filename])
infofile.delete
rescue RuntimeError => ex
ui.error("Error transfering file #{info[:filename]} failed, possible not enough permissions to write? #{ex}",:prefix => false)
raise Veewee::Error,"Error transfering file #{info[:filename]} failed, possible not enough permissions to write? #{ex}"
end
end
end
end #Module
end #Module
end #Module
end #Module
Jump to Line
Something went wrong with that request. Please try again.