Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

KVM provider: Fixed Windows support #465

Merged
merged 7 commits into from

3 participants

Florian Feldhaus Patrick Debois Keno Fischer
Florian Feldhaus

Support for Windows operating systems was broken in the KVM provider. This pull request fixes open issues with the floppy drive which is needed for the unattended installation. This pull request also adds a cdrom drive with the latest windows virtio drivers.

This fix has been tested with the Windows 7 templates and should also work with Windows 2008 and Windows 8 templates.

ffeldhaus added some commits
Florian Feldhaus ffeldhaus KVM provider: Fixed undef method 9976627
Florian Feldhaus ffeldhaus KVM provider: Fixed Windows support
* fixed adding of floppy drive to KVM machines
* support for adding virtio drivers to KVM machines
827f84e
Patrick Debois
Owner

@ffeldhaus thanks! interesting work for the virtio drivers.

I'm wondering why you switched from the @raw object to the qemu:///system system?
I personally use kvm over ssh and therefore have another connections string. this is going through $HOME/.fog to specify things

Florian Feldhaus

For me the raw connection was not working with Fog. As I couldn't find any documentation I used qemu:///system as it is done in the methods check_default_network and check_pool. If you could point me to some documentation for the Fog code regarding the raw connection, I'd be glad to go through the KVM provider and replace all occurrences of qemu:///system with the raw connection as I guess it would make the connection handling more generic?

Florian Feldhaus

I found the issue with the Fog raw connection. In one of the last versions the name was changed from raw to client. As the documentation is sparse, I couldn't find it directly.
As the KVM provider mixes the usage of Fog with the direct usage of Libvirt, I would suggest to go through all KVM classes and replace all occurances of Libvirt with Fog. I would volunteer to do the work, but suggest to do it in another pull request. As this pull request shouldn't break any previous functionality, I would be glad if it could be merged before I start with the next pull request, so that I could include these classes in the next pull request (and keep additional functionality like in this pull request separate from a KVM provider code cleanup).

Patrick Debois
Owner

IIRC one of the reasons I was using libvirt system directly was to test if kvm had a default pool configured.

but yes I agree that it makes sense to do all via raw.

Florian Feldhaus

Ok, then I will go through the KVM classes, rewrite them and create a separate pull request.

Patrick Debois
Owner

Realized that we might have to enforce an recent enough fog version for this. to make sure it works.

ffeldhaus added some commits
Florian Feldhaus ffeldhaus Merge branch 'master' of git://github.com/jedi4ever/veewee into kvm-w…
…indows
7b9d55b
Florian Feldhaus ffeldhaus KVM Provider
- improved code structure
48e613d
Florian Feldhaus ffeldhaus KVM Provider
- improved checking of network and storage pool during creation of servers
- replaced not properly implemented KVM options with one option for the network name and one for the storage pool name
- replaced all occurrences of direct libvirt usage with fog.io in create
- improved documentation to reflect the changes above
de8b1a7
Florian Feldhaus

I updated this pull request to be in line with the changes introduced in pull request #472. As the previously available options were not listed in lib/veewee/command/kvm.rb I checked the libvirt documentation and came up with only the two options pool-name and network-name. If libvirt is properly set up with a storage pool and a network definition, these two options should be sufficient.

Patrick Debois
Owner

@ffeldhaus seems I can't auto merge with the current state? could you check?

Florian Feldhaus

There was something missing in the first merge I did. You should be able to merge the pull request now.

Patrick Debois
Owner

Page still shows - This pull request cannot be automatically merged.

Patrick Debois jedi4ever merged commit 1b78473 into from
Patrick Debois
Owner

@ffeldhaus it worked . thanks!

Pete Cheslock petecheslock referenced this pull request from a commit
Commit has since been removed from the repository and is no longer available.
Keno Fischer

This really belongs in the Autounattend.xml file in the definition rather than silently doing that behind the user's back. That's asking for all kinds of trouble.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Jan 6, 2013
  1. Florian Feldhaus
  2. Florian Feldhaus

    KVM provider: Fixed Windows support

    ffeldhaus authored
    * fixed adding of floppy drive to KVM machines
    * support for adding virtio drivers to KVM machines
Commits on Jan 9, 2013
  1. Florian Feldhaus
Commits on Jan 10, 2013
  1. Florian Feldhaus

    KVM Provider

    ffeldhaus authored
    - improved code structure
  2. Florian Feldhaus

    KVM Provider

    ffeldhaus authored
    - improved checking of network and storage pool during creation of servers
    - replaced not properly implemented KVM options with one option for the network name and one for the storage pool name
    - replaced all occurrences of direct libvirt usage with fog.io in create
    - improved documentation to reflect the changes above
  3. Florian Feldhaus

    Merge branch 'master' of git://github.com/jedi4ever/veewee into kvm-w…

    ffeldhaus authored
    …indows
    
    Conflicts:
    	doc/kvm.md
  4. Florian Feldhaus

    Merge branch 'master' of git://github.com/jedi4ever/veewee into kvm-w…

    ffeldhaus authored
    …indows
    
    Conflicts:
    	doc/kvm.md
This page is out of date. Refresh to see the latest.
50 doc/kvm.md
View
@@ -4,6 +4,9 @@ NOTE: Virtualbox doesn't like KVM to be enabled
## Prerequisites
+Depending on your operating system you may need to install packages for kvm,
+qemu and libvirt.
+
To check if your kernel can run kvm :
# kvm_ok or kvm-ok command (on Ubuntu at least)
@@ -11,10 +14,12 @@ To check if your kernel can run kvm :
# or look for vmx or svm in /proc/cpuinfo
egrep '^flags.*(vmx|svm)' /proc/cpuinfo
-The modules needed are the following : kvm, kvm_intel or kvm-amd.
+The kernel modules needed are the following : kvm, kvm_intel or kvm-amd.
+
+### Storage Pool
-You need to have at least one storage pool defined in libvirt. You can check all
-available storage pools with
+You need to have at least one storage pool defined in libvirt where your VM
+images will be stored. You can check all available storage pools with
virsh pool-list
@@ -33,13 +38,16 @@ VM images in the directory /var/lib/libvirt/images with
EOF
virsh pool-create /tmp/pool.xml
+### Network
+
You need to have at least one network defined. You can check all available
networks with
virsh net-list
-If there is no default network, consult the documentation of your operating
-system to find out how to creat it.
+If there is no network, consult the documentation of your operating
+system to find out how to creat it. More information can also be found in the
+[libvirt documentation](http://libvirt.org/formatdomain.html#elementsNICS).
If you are using libvirt with a URI different than the default `qemu:///system`,
you need to create a config file for fog.io. If your libvirt endpoint is
@@ -49,9 +57,18 @@ file with
cat > ~/.fog << EOF
:default:
:libvirt_uri: qemu+ssh://cloud@myhost.com/system
+ EOF
+
+For more information have a look at the
+[libvirt documentation](http://libvirt.org/drvqemu.html#uris).
## Using VeeWee
+You can always get help by using the the built in help with every command.
+e.g. for the build command use
+
+ veewee kvm help build
+
List available templates
veewee kvm templates
@@ -64,23 +81,8 @@ Build the box using KVM / Quemu (this will take a while)
veewee kvm build 'My Ubuntu 12.10 box'
-You may want to use the VNC console (e.g. through virt-manager) to monitor /
-check the build process.
-
-## Options
-
-There is currently few options supported :
-
-1. **network_type**: the type of network used by this box on libvirt. It could
- be either _network_ (for using the default network) or _bridge_.
-2. **network_bridge_name**: the name of the bridge. It is used just in case
- **network_type** is set to _bridge_.
-3. **pool_name**: the _storage_ pool name to be used when creating the box. If
- not specified, the default one is used.
-
-## Notes
-
-Remove modules:
+You can specify the name of the storage pool and the network to be used when
+building a VM. Use the options`--pool-name` and `--network-name` with the built
+command:
- rmmod kvm_intel
- rmmod kvm
+ veewee kvm build 'My Ubuntu 12.10 box' --pool-name virtimages --network-name default
3  lib/veewee/command/kvm.rb
View
@@ -11,6 +11,8 @@ class Kvm< Veewee::Command::GroupBase
method_option :postinstall_include, :type => :array, :default => [], :aliases => "-i", :desc => "ruby regexp of postinstall filenames to additionally include"
method_option :postinstall_exclude, :type => :array, :default => [], :aliases => "-e", :desc => "ruby regexp of postinstall filenames to exclude"
method_option :use_emulation, :type => :boolean , :default => false, :desc => "Use QEMU emulation"
+ method_option :pool_name, :type => :string, :default => nil, :desc => "Name of the libvirt storage pool to be used"
+ method_option :network_name, :type => :string, :default => "default", :desc => "Name of the libvirt network to be used"
def build(box_name)
venv=Veewee::Environment.new(options)
venv.ui=env.ui
@@ -72,7 +74,6 @@ def undefine(definition_name)
begin
venv=Veewee::Environment.new(options)
venv.ui=env.ui
- venv.undefine(definition_name,options)
venv.definitions.undefine(definition_name,options)
rescue Error => ex
env.ui.error("#{ex}", :prefix=> false)
192 lib/veewee/provider/kvm/box/create.rb
View
@@ -1,4 +1,5 @@
require 'nokogiri'
+require 'fileutils'
module Veewee
module Provider
@@ -7,82 +8,48 @@ module BoxCommand
# Create a new vm
def create(options={})
# Assemble the Virtualmachine and set all the memory and other stuff"
-
-
create_server(options)
create_volume(options)
+ 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
def create_server(options)
- #memory_size,cpu_count, volume_size
- # verify some stuff before trying to create the server
- kvm_options = definition.kvm[:vm_options][0]
- # 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 => options['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
- }
- # Check for network stuff (default, bridge)
- check_network(kvm_options, attributes)
- # Check for pool (storage)
- check_pool(kvm_options, attributes)
- s=@connection.servers.create(attributes)
- end
- # Check the network availability of the defined network for kvm
- def check_network(options, attributes)
- env.logger.info "Checking network"
- if options.nil? or options.empty? or options["network_type"].nil? or options["network_type"] == "network"
- check_default_network
- attributes[:network_interface_type] = "network"
- elsif options["network_type"] == "bridge"
- options["network_bridge_name"].nil?
- if options["network_bridge_name"].nil?
- raise Veewee::Error, "You need to specify a 'network_bridge_name' if you plan to use 'bridge' as network type"
- else
- attributes[:network_interface_type] = "bridge"
- attributes[:network_bridge_name] = "#{options["network_bridge_name"]}"
- end
- else
- raise Veewee::Error, "You specified a 'network_type' that isn't known (#{options["network_type"]})"
+ # set volume pool name to user specified volume pool and fall back to first available volume pool
+ if options["pool_name"]
+ raise Veewee::Error, "Specified storage pool #{options["pool_name"]} does not exist" if @connection.pools.select { |pool| pool.name == options["pool_name"] }.empty?
+ volume_pool_name = options["pool_name"]
end
- end
+ volume_pool_name ||= @connection.pools.first.name
+ env.logger.info "Using storage pool #{volume_pool_name}"
- def check_default_network
- # Nothing specified, we check for default network
- conn = ::Libvirt::open("qemu:///system")
- networks=conn.list_networks
- if networks.count < 1
- raise Veewee::Error, "You need at least one (active) network defined or customize your definition. This needs to be available if you connect to qemu:///system."
+ # set network name to user specified network and fall back to default network or first available network
+ if options["network_name"]
+ raise Veewee::Error, "Specified network #{options["network_name"]} does not exist" if @connection.networks.select { |net| net.name == options["network_name"] }.empty?
+ network_name = options["network_name"]
end
- 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}"
- # Check the given pool and append to attributes
- # Note: volume_pool_name is not working in fog library version 1.7.0.
- # This should be fixed in the next release.
- def check_pool(options, attributes)
- env.logger.info "Checking pool storage"
- if not options.nil? and not options.empty? and not options["pool_name"].nil?
- conn = ::Libvirt::open("qemu:///system")
- # Checking if the pool exists and if it is active
- begin
- storage = conn.lookup_storage_pool_by_name(options["pool_name"])
- rescue Libvirt::RetrieveError
- raise Veewee::Error, "You've specified an non-existent storage pool (#{options["pool_name"]})"
- end
- if storage.active?
- attributes[:volume_pool_name] = options["pool_name"]
- else
- raise Veewee::Error, "The storage pool '#{options["pool_name"]}' is not started. Start it and restart the creation process"
- end
- end
+ # 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 => options['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,
+ :network_nat_network => network_name
+ }
+
+ @connection.servers.create(attributes)
end
# Create the volume of a new vm
@@ -91,11 +58,12 @@ def create_volume(options)
end
def add_floppy
+ env.logger.info 'Adding floppy disk'
# Get a raw libvirt connection
- c=@connection.raw
+ conn = @connection.client
# Retrieve the domain
- domain=c.lookup_domain_by_name(name)
+ domain=conn.lookup_domain_by_name(name)
# Retrieve the existing XML from the domain
domain_xml=domain.xml_desc
@@ -107,8 +75,8 @@ def add_floppy
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(definitition.path,"virtualfloppy.img") +
- "'/><target dev='fda' bus='fdc'/><address type='drive' controller='0' bus='0' unit='0'/></disk>
+ 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
@@ -121,10 +89,92 @@ def add_floppy
new_xml=domain_doc.to_xml
# Undefine the existing domain
- s.undefine
+ domain.undefine
+
+ # Re-define the domain
+ conn.define_domain_xml(new_xml)
+ end
+
+ 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
- c.define_domain_xml(new_xml)
+ 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
end #End Module
38 lib/veewee/provider/kvm/provider.rb
View
@@ -14,37 +14,33 @@ def check_requirements
env.logger.info "Setting libvirt IP Command if not already defined in .fog config file"
Fog.credentials[:libvirt_ip_command] ||= "arp -an |grep $mac|cut -d '(' -f 2 | cut -d ')' -f 1"
+ env.logger.info "Opening a libvirt connection using fog.io"
begin
- env.logger.info "Opening a libvirt connection using fog.io"
conn = Fog::Compute[:libvirt]
- env.logger.info "Libvirt connection established"
+ rescue Exception => ex
+ raise Veewee::Error, "There was a problem opening a connection to libvirt: #{ex}"
+ end
+ env.logger.info "Libvirt connection established"
- env.logger.debug "Found capabilities:"
- env.logger.debug "#{conn.client.capabilities}"
+ env.logger.debug "Found capabilities:"
+ env.logger.debug "#{conn.client.capabilities}"
- env.logger.info "Checking available storagepools"
- conn.pools.any? or raise Veewee::Error, "You need at least one (active) storage pool defined in #{Fog.credentials[:libvirt_uri]}."
+ env.logger.info "Checking libvirt version"
+ # http://www.libvirt.org/html/libvirt-libvirt.html#virGetVersion
+ # format major * 1,000,000 + minor * 1,000 + release
+ conn.client.libversion > 8003 or raise Veewee::Error, "You need at least libvirt version 0.8.3 or higher "
- env.logger.info "Checking available networks"
- conn.networks.any? or raise Veewee::Error,"You need at least one (active) network defined. This needs to be available if you connect to qemu:///system"
+ env.logger.info "Checking available networks"
+ conn.networks.any? or raise Veewee::Error, "You need at least one (active) network defined in #{Fog.credentials[:libvirt_uri]}."
- # http://www.libvirt.org/html/libvirt-libvirt.html#virGetVersion
- # format major * 1,000,000 + minor * 1,000 + release
- env.logger.info "Checking libvirt version"
- if conn.client.libversion < 8003
- raise Veewee::Error, "You need at least libvirt version 0.8.3 or higher "
- end
- rescue Exception => ex
- raise Veewee::Error, "There was a problem opening a connection to libvirt: #{ex}"
- end
+ env.logger.info "Checking available storagepools"
+ conn.pools.any? or raise Veewee::Error, "You need at least one (active) storage pool defined in #{Fog.credentials[:libvirt_uri]}."
- unless self.shell_exec("arp").status == 0
- raise Veewee::Error, "Could not execute the arp command. This is required to find the IP address of the VM"
- end
+ env.logger.info "Checking availability of the arp utility"
+ shell_exec("arp").status.zero? or raise Veewee::Error, "Could not execute the arp command. This is required to find the IP address of the VM"
end
-
def build(definition_name, box_name, options)
super(definition_name, box_name, options)
Something went wrong with that request. Please try again.