Module: Veewee::Provider::Kvm::BoxCommand
- Included in:
- Box
- Defined in:
- lib/veewee/provider/kvm/box/up.rb,
lib/veewee/provider/kvm/box/halt.rb,
lib/veewee/provider/kvm/box/build.rb,
lib/veewee/provider/kvm/box/create.rb,
lib/veewee/provider/kvm/box/destroy.rb,
lib/veewee/provider/kvm/box/poweroff.rb,
lib/veewee/provider/kvm/box/helper/ip.rb,
lib/veewee/provider/kvm/box/validate_kvm.rb,
lib/veewee/provider/kvm/box/helper/status.rb,
lib/veewee/provider/kvm/box/export_vagrant.rb,
lib/veewee/provider/kvm/box/helper/console_type.rb
Instance Method Summary collapse
- #add_floppy ⇒ Object
- #add_virtio_drivers ⇒ Object
- #build(options) ⇒ Object
-
#console_type(sequence, type_options = {}) ⇒ Object
Type on the console.
-
#create(options = {}) ⇒ Object
Create a new vm.
- #create_server(options) ⇒ Object
-
#create_volume(options) ⇒ Object
Create the volume of a new vm.
-
#destroy(options = {}) ⇒ Object
Destroy a vm.
- #destroy_vm ⇒ Object
- #destroy_volume ⇒ Object
- #exists? ⇒ Boolean
- #exists_vm? ⇒ Boolean
- #exists_volume? ⇒ Boolean
- #export_vagrant(options) ⇒ Object
- #halt(options = {}) ⇒ Object
- #ip_address ⇒ Object
- #poweroff(options = {}) ⇒ Object
- #running? ⇒ Boolean
- #stop(options = {}) ⇒ Object
- #template_metadatafile(size) ⇒ Object
- #up(options = {}) ⇒ Object
- #validate_kvm(options) ⇒ Object
Instance Method Details
#add_floppy ⇒ Object
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 |
# File 'lib/veewee/provider/kvm/box/create.rb', line 61 def add_floppy env.logger.info 'Adding floppy disk' # Get a raw libvirt connection conn = @connection.client # Retrieve the domain domain=conn.lookup_domain_by_name(name) # Retrieve the existing XML from the domain domain_xml=domain.xml_desc # Convert the xml nokogiri doc domain_doc=Nokogiri::XML(domain_xml) # Find the device section devices=domain_doc.xpath('/domain/devices').first # The floppy xml representation floppy_xml="<disk type='file' device='floppy'><driver name='qemu' type='raw'/><source file='"+ File.join(definition.path, "virtualfloppy.img") + "'/><target dev='fda' bus='fdc'/><address type='drive' controller='0' bus='0' unit='0'/></disk> <controller type='fdc' index='0'>" # Convert the floppy xml to nokogiri floppy_doc=Nokogiri::XML(floppy_xml) # Add the floppy to the devices section devices.add_child(floppy_doc.root) # Get the raw xml of the changed document new_xml=domain_doc.to_xml # Undefine the existing domain domain.undefine # Re-define the domain conn.define_domain_xml(new_xml) end |
#add_virtio_drivers ⇒ Object
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 |
# File 'lib/veewee/provider/kvm/box/create.rb', line 99 def add_virtio_drivers env.logger.info 'Adding virtio drivers for windows system to the virtual machine' # Get a raw libvirt connection conn = @connection.client # Retrieve the domain domain=conn.lookup_domain_by_name(name) # Retrieve the existing XML from the domain domain_xml=domain.xml_desc # Convert the xml nokogiri doc domain_doc=Nokogiri::XML(domain_xml) # Find the device section devices=domain_doc.xpath('/domain/devices').first # get latest version of virtio drivers url ='http://alt.fedoraproject.org/pub/alt/virtio-win/latest/images/bin/' filename = open(url).read.scan(/\"(virtio-win-.*.iso)\"/).first.first download_iso(url + filename, filename) path = File.join(env.config.veewee.iso_dir, filename) # The disk xml representation disk_xml="<disk type='file' device='cdrom'><driver name='qemu' type='raw'/><source file='" + path + "'/><target dev='hdd' bus='ide'/></disk>" # Convert the disk xml to nokogiri disk_doc=Nokogiri::XML(disk_xml) # Add the floppy to the devices section devices.add_child(disk_doc.root) # Get the raw xml of the changed document new_xml=domain_doc.to_xml # Undefine the existing domain domain.undefine # Re-define the domain conn.define_domain_xml(new_xml) env.logger.info 'Add search path for virtio drivers to Autounattend.xml' # parse Autoattend.xml to document FileUtils.copy(File.join(definition.path, 'Autounattend.xml'), File.join(definition.path, 'Autounattend.xml.virtio')) doc = Nokogiri::XML.parse(File.read(File.join(definition.path, 'Autounattend.xml'))) # determine platform and windows version platform = definition.os_type_id.end_with?("_64") ? "amd64" : "x86" version = case definition.os_type_id.downcase when /windows-?7/ 'win7' when /windows-?2008/ 'win7' when /windows-?8/ 'win8' when /xp/ 'xp' when /vista/ 'vista' else raise 'could not determine windows version' end # create new element component=Nokogiri::XML(%Q|<component name="Microsoft-Windows-PnpCustomizationsWinPE" processorArchitecture="#{platform}" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <DriverPaths> <PathAndCredentials wcm:keyValue="1" wcm:action="add"> <Path>e:\\#{version}\\#{platform}</Path> </PathAndCredentials> </DriverPaths> </component>|) doc.xpath('//unattend:settings[@pass="windowsPE"]', 'unattend' => 'urn:schemas-microsoft-com:unattend').first.add_child component.root file = File.open(File.join(definition.path, 'Autounattend.xml'), 'w') file.write(doc) file.close end |
#build(options) ⇒ Object
5 6 7 |
# File 'lib/veewee/provider/kvm/box/build.rb', line 5 def build() super() end |
#console_type(sequence, type_options = {}) ⇒ Object
Type on the console
10 11 12 13 14 15 |
# File 'lib/veewee/provider/kvm/box/helper/console_type.rb', line 10 def console_type(sequence,={}) tcp_port=@connection.servers.all(:name => name).first.display[:port] display_port=tcp_port.to_i - 5900 ui.success "Sending keystrokes to VNC port :#{display_port} - TCP port: #{tcp_port}" vnc_type(sequence,"127.0.0.1",display_port) end |
#create(options = {}) ⇒ Object
Create a new vm
9 10 11 12 13 14 15 16 17 |
# File 'lib/veewee/provider/kvm/box/create.rb', line 9 def create(={}) # Assemble the Virtualmachine and set all the memory and other stuff" create_server() create_volume() add_virtio_drivers if File.exists?(File.join(definition.path, 'Autounattend.xml')) self.create_floppy("virtualfloppy.img") FileUtils.move(File.join(definition.path, 'Autounattend.xml.virtio'), File.join(definition.path, 'Autounattend.xml')) if File.exists?(File.join(definition.path, 'Autounattend.xml.virtio')) add_floppy unless definition.floppy_files.nil? end |
#create_server(options) ⇒ Object
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
# File 'lib/veewee/provider/kvm/box/create.rb', line 19 def create_server() # set volume pool name to user specified volume pool and fall back to first available volume pool if ["pool_name"] raise Veewee::Error, "Specified storage pool #{["pool_name"]} does not exist" if @connection.pools.select { |pool| pool.name == ["pool_name"] }.empty? volume_pool_name = ["pool_name"] end volume_pool_name ||= @connection.pools.first.name env.logger.info "Using storage pool #{volume_pool_name}" # set network name to user specified network and fall back to default network or first available network if ["network_name"] raise Veewee::Error, "Specified network #{["network_name"]} does not exist" if @connection.networks.select { |net| net.name == ["network_name"] }.empty? network_name = ["network_name"] end network_name ||= "default" unless @connection.networks.select { |net| net.name == 'default' }.empty? network_name ||= @connection.networks.first.name env.logger.info "Using network #{network_name}" # Create the "server" attributes = { :name => name, :memory_size => definition.memory_size.to_i*1024, :cpus => definition.cpu_count.to_i, :volume_capacity => "#{definition.disk_size}M", :domain_type => ['use_emulation'] ? 'qemu' : 'kvm', :iso_file => definition.iso_file, :arch => definition.os_type_id.end_with?("_64") ? "x86_64" : "i686", :iso_dir => env.config.veewee.iso_dir, :volume_pool_name => volume_pool_name, :volume_format_type => definition.disk_format, :network_nat_network => network_name } @connection.servers.create(attributes) end |
#create_volume(options) ⇒ Object
Create the volume of a new vm
57 58 59 |
# File 'lib/veewee/provider/kvm/box/create.rb', line 57 def create_volume() # Creating the volume is part of the server creation end |
#destroy(options = {}) ⇒ Object
Destroy a vm
6 7 8 9 10 11 12 13 14 15 16 17 18 |
# File 'lib/veewee/provider/kvm/box/destroy.rb', line 6 def destroy(={}) unless exists_vm? or exists_volume? env.ui.error "Error:: You tried to destroy a non-existing box '#{name}'" raise Veewee::Error,"Error:: You tried to destroy a non-existing box '#{name}'" end self.poweroff if running? destroy_vm if exists_vm? vol_exists = exists_volume? env.logger.info "Volume exists?: #{vol_exists}" destroy_volume if vol_exists end |
#destroy_vm ⇒ Object
20 21 22 23 |
# File 'lib/veewee/provider/kvm/box/destroy.rb', line 20 def destroy_vm matched_servers=@connection.servers.all(:name => name) matched_servers.first.destroy() unless matched_servers.nil? end |
#destroy_volume ⇒ Object
25 26 27 |
# File 'lib/veewee/provider/kvm/box/destroy.rb', line 25 def destroy_volume @connection.volumes.all(:name => @volume_name).first.destroy end |
#exists? ⇒ Boolean
13 14 15 |
# File 'lib/veewee/provider/kvm/box/helper/status.rb', line 13 def exists? exists_volume? || exists_vm? end |
#exists_vm? ⇒ Boolean
21 22 23 24 25 26 27 |
# File 'lib/veewee/provider/kvm/box/helper/status.rb', line 21 def exists_vm? begin @connection.list_domains(:name => name) rescue Libvirt::RetrieveError false end end |
#exists_volume? ⇒ Boolean
17 18 19 |
# File 'lib/veewee/provider/kvm/box/helper/status.rb', line 17 def exists_volume? !@connection.list_volumes(:name => @volume_name).first.empty? end |
#export_vagrant(options) ⇒ Object
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
# File 'lib/veewee/provider/kvm/box/export_vagrant.rb', line 7 def export_vagrant() # Check if box already exists unless self.exists? ui.info "#{name} is not found, maybe you need to build it first?" exit end if File.exists?("#{name}.box") if ["force"] env.logger.debug("#{name}.box exists, but --force was provided") env.logger.debug("removing #{name}.box first") FileUtils.rm("#{name}.box") env.logger.debug("#{name}.box removed") else raise Veewee::Error, "export file #{name}.box already exists. Use --force option to overwrite." end end # We need to shutdown first if self.running? ui.info "Vagrant requires the box to be shutdown, before it can export" ui.info "Sudo also needs to work for user #{definition.ssh_user}" ui.info "Performing a clean shutdown now." self.halt #Wait for state poweroff while (self.running?) do ui.info ".",{:new_line => false} sleep 1 end ui.info "" ui.info "Machine #{name} is powered off cleanly" end # Vagrant requires a relative path for output of boxes boxdir=Pathname.new(Dir.pwd) full_path=File.join(boxdir,name+".box") path1=Pathname.new(full_path) path2=Pathname.new(Dir.pwd) box_path=File.(path1.relative_path_from(path2).to_s) if File.exists?("#{box_path}") raise Veewee::Error, "box #{name}.box already exists" end # Create temp directory current_dir = FileUtils.pwd ui.info "Creating a temporary directory for export" tmp_dir = Dir.mktmpdir env.logger.debug("Create temporary directory for export #{tmp_dir}") server = @connection.servers.all(:name => name).first volume = server.volumes.find(&:path) begin ui.info "Adding additional files" # Handling the Vagrantfile if ["vagrantfile"].to_s == "" # Prepare the vagrant erb template_path = File.join(File.dirname(__FILE__),'..','templates',"Vagrantfile") ui.info("Creating Vagrantfile") FileUtils.cp(template_path, File.join(tmp_dir,'Vagrantfile')) else f = ["vagrantfile"] env.logger.debug("Including vagrantfile: #{f}") FileUtils.cp(f,File.join(tmp_dir,"Vagrantfile")) end # Inject a metadata.json file File.open(File.join(tmp_dir, 'metadata.json'), 'w') {|f| f.write((volume.capacity)) } # Handling other includes unless ["include"].nil? ["include"].each do |f| env.logger.debug("Including file: #{f}") FileUtils.cp(f,File.join(tmp_dir,f)) end end # Final image must be qcow2 for vagrant-libvirt # This also allows us to make the image sparse again after zerodisk.sh has run # both qemu-img and virt-sparsify can do this, but the latter is better volume_out = File.join(tmp_dir, 'box.img') if ['sparsify'] ui.info "Sparsifying and copying the box volume" command = "virt-sparsify --machine-readable #{volume.path} --convert qcow2 #{volume_out}" else ui.info "Copying the box volume" command = "qemu-img convert -O qcow2 #{volume.path} #{volume_out}" end env.logger.debug("Source volume: #{volume.path}") env.logger.debug(command) shell_exec command ui.info "Packaging the box" FileUtils.cd(tmp_dir) command = "tar -cvf '#{box_path}' ." env.logger.debug(command) shell_exec (command) rescue Errno::ENOENT => ex raise Veewee::Error, "#{ex}" rescue Error => ex raise Veewee::Error, "Packaging of the box failed:\n+#{ex}" ensure # Remove temporary directory ui.info "Cleaning up temporary directory" env.logger.debug("Removing temporary dir #{tmp_dir}") FileUtils.rm_rf(tmp_dir) FileUtils.cd(current_dir) end ui.info "" ui.info "To import it into vagrant type:" ui.info "vagrant box add '#{name}' '#{box_path}'" ui.info "" ui.info "To use it:" ui.info "vagrant init '#{name}'" ui.info "vagrant up --provider=libvirt" ui.info "vagrant ssh" end |
#halt(options = {}) ⇒ Object
6 7 8 9 |
# File 'lib/veewee/provider/kvm/box/halt.rb', line 6 def halt(={}) matched_servers=@connection.servers.all(:name => name) matched_servers.first.halt unless matched_servers.nil? end |
#ip_address ⇒ Object
5 6 7 8 9 |
# File 'lib/veewee/provider/kvm/box/helper/ip.rb', line 5 def ip_address ip=@connection.servers.all(:name => "#{name}").first.public_ip_address return [*ip].first unless ip.nil? return ip end |
#poweroff(options = {}) ⇒ Object
6 7 8 9 |
# File 'lib/veewee/provider/kvm/box/poweroff.rb', line 6 def poweroff(={}) matched_servers=@connection.servers.all(:name => name) matched_servers.first.stop unless matched_servers.nil? end |
#running? ⇒ Boolean
5 6 7 8 9 10 11 |
# File 'lib/veewee/provider/kvm/box/helper/status.rb', line 5 def running? if exists_vm? @connection.servers.all(:name => name).first.ready? else false end end |
#stop(options = {}) ⇒ Object
11 12 13 14 |
# File 'lib/veewee/provider/kvm/box/halt.rb', line 11 def stop(={}) matched_servers=@connection.servers.all(:name => name) matched_servers.first.stop unless matched_servers.nil? end |
#template_metadatafile(size) ⇒ Object
132 133 134 135 136 137 138 |
# File 'lib/veewee/provider/kvm/box/export_vagrant.rb', line 132 def size { "provider" => "libvirt", "format" => "qcow2", "virtual_size" => size+1 # fog rounds down }.to_json end |
#up(options = {}) ⇒ Object
6 7 8 9 10 11 12 13 14 |
# File 'lib/veewee/provider/kvm/box/up.rb', line 6 def up(={}) matched_servers=@connection.servers.all(:name => name) matched_servers.first.start unless matched_servers.nil? rescue Libvirt::Error => e warn " Libvirt Error! Make sure your user has permissions to run anything. " raise e end |
#validate_kvm(options) ⇒ Object
6 7 8 9 10 |
# File 'lib/veewee/provider/kvm/box/validate_kvm.rb', line 6 def validate_kvm() ( [ 'kvm', 'puppet', 'chef'],) end |