Added: incubator/vcl/trunk/managementnode/lib/VCL/Module/Provisioning/libvirt/KVM.pm URL: http://svn.apache.org/viewvc/incubator/vcl/trunk/managementnode/lib/VCL/Module/Provisioning/libvirt/KVM.pm?rev=1214348&view=auto ============================================================================== --- incubator/vcl/trunk/managementnode/lib/VCL/Module/Provisioning/libvirt/KVM.pm (added) +++ incubator/vcl/trunk/managementnode/lib/VCL/Module/Provisioning/libvirt/KVM.pm Wed Dec 14 17:15:17 2011 @@ -0,0 +1,887 @@ +#!/usr/bin/perl -w +############################################################################### +# $Id$ +############################################################################### +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +############################################################################### + +=head1 NAME + +VCL::Provisioning::libvirt::KVM - Libvirt hypervisor driver module to allow +support for the KVM hypervisor + +=head1 DESCRIPTION + + This is a driver module to allow the main libvirt.pm provisioning module to + support KVM hosts. It performs the KVM-specific tasks not handled by libvirt + itself. + +=cut + +############################################################################## +package VCL::Module::Provisioning::libvirt::KVM; + +# Specify the lib path using FindBin +use FindBin; +use lib "$FindBin::Bin/../../../.."; + +# Configure inheritance +use base qw(VCL::Module::Provisioning::libvirt); + +# Specify the version of this module +our $VERSION = '2.2.1'; + +# Specify the version of Perl to use +use 5.008000; + +use strict; +use warnings; +use diagnostics; +use English qw( -no_match_vars ); +use File::Basename; + +use VCL::utils; + +############################################################################## + +=head1 OBJECT METHODS + +=cut + +#///////////////////////////////////////////////////////////////////////////// + +=head2 initialize + + Parameters : none + Returns : boolean + Description : Checks if the node has KVM installed by checking if /usr/bin/qemu + exists. Returns true if the file exists, false otherwise. + +=cut + +sub initialize { + my $self = shift; + unless (ref($self) && $self->isa('VCL::Module')) { + notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method"); + return; + } + + my $node_name = $self->data->get_vmhost_short_name(); + my ($driver_name) = ref($self) =~ /::([^:]+)$/; + + # Check to see if qemu exists on the VM host + my $test_file_path = '/usr/bin/qemu'; + if ($self->vmhost_os->file_exists($test_file_path)) { + notify($ERRORS{'DEBUG'}, 0, "$driver_name driver module successfully initialized, verified '$test_file_path' exists on $node_name"); + return 1; + } + else { + notify($ERRORS{'DEBUG'}, 0, "$driver_name driver module not initialized, '$test_file_path' does NOT exist on $node_name"); + return; + } +} + +#///////////////////////////////////////////////////////////////////////////// + +=head2 get_domain_type + + Parameters : none + Returns : string + Description : Returns 'kvm'. This is specified in the domain XML definition: + <domain type='kvm'> + + +=cut + +sub get_domain_type { + my $self = shift; + unless (ref($self) && $self->isa('VCL::Module')) { + notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method"); + return; + } + + return 'kvm'; +} + +#///////////////////////////////////////////////////////////////////////////// + +=head2 get_disk_driver_name + + Parameters : none + Returns : string + Description : Returns 'qemu'. The disk driver name is specified in the domain + XML definition: + <domain ...> + <devices> + <disk ...> + <driver name='qemu' ...> + +=cut + +sub get_disk_driver_name { + my $self = shift; + unless (ref($self) && $self->isa('VCL::Module')) { + notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method"); + return; + } + return 'qemu'; +} + +#///////////////////////////////////////////////////////////////////////////// + +=head2 get_disk_format + + Parameters : none + Returns : string + Description : Returns 'qcow2'. The disk format is specified in the domain XML + definition: + <domain ...> + <devices> + <disk ...> + <driver type='qcow2' ...> + +=cut + +sub get_disk_format { + my $self = shift; + unless (ref($self) && $self->isa('VCL::Module')) { + notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method"); + return; + } + return 'qcow2'; +} + +#///////////////////////////////////////////////////////////////////////////// + +=head2 get_disk_file_extension + + Parameters : none + Returns : string + Description : Returns 'qcow2'. This is used by libvirt.pm as the file extension + of the virtual disk file paths. + +=cut + +sub get_disk_format { + my $self = shift; + unless (ref($self) && $self->isa('VCL::Module')) { + notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method"); + return; + } + return 'qcow2'; +} + +#///////////////////////////////////////////////////////////////////////////// + +=head2 pre_define + + Parameters : none + Returns : boolean + Description : Performs the KVM-specific steps prior to defining a domain: + * Checks if the master image file exists on the node, If it does + not exist, attempts to copy image from repository to the node + * Creates a copy on write image which will be used by the domain + being loaded + +=cut + +sub pre_define { + my $self = shift; + unless (ref($self) && $self->isa('VCL::Module')) { + notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method"); + return; + } + + my $image_name = $self->data->get_image_name(); + my $node_name = $self->data->get_vmhost_short_name(); + my $copy_on_write_file_path = $self->get_copy_on_write_file_path(); + my $master_image_file_path = $self->get_master_image_file_path(); + + if ($self->vmhost_os->file_exists($master_image_file_path)) { + notify($ERRORS{'DEBUG'}, 0, "master image file exists in the datastore on $node_name: $master_image_file_path"); + } + else { + notify($ERRORS{'DEBUG'}, 0, "master image file does NOT exist in the datastore on $node_name: $master_image_file_path"); + + # Check the files found in the repository + # Attempt to determine which files are actual virtual disk files + my @repository_image_file_paths = $self->find_repository_image_file_paths(); + if (@repository_image_file_paths) { + # Attempt to copy the virtual disk from the repository to the datastore + if ($self->copy_virtual_disk(\@repository_image_file_paths, $master_image_file_path)) { + notify($ERRORS{'DEBUG'}, 0, "copied master image from repository to datastore"); + } + else { + notify($ERRORS{'WARNING'}, 0, "unable to prepare virtual disk, failed to copy master image from repository to datastore"); + return; + } + } + else { + notify($ERRORS{'WARNING'}, 0, "unable to prepare virtual disk, failed to locate virtual disk file in the repository"); + return; + } + } + + if (!$self->create_copy_on_write_image($master_image_file_path, $copy_on_write_file_path)) { + notify($ERRORS{'WARNING'}, 0, "failed to prepare virtual disk, unable to create copy on write image"); + return; + } + + return 1; +} + +############################################################################## + +=head1 PRIVATE METHODS + +=cut + +#///////////////////////////////////////////////////////////////////////////// + +=head2 get_virtual_disk_file_info + + Parameters : $virtual_disk_file_path + Returns : hash reference + Description : Calls 'qemu-img info' to retrieve the virtual disk information. + Builds a hash based on the output. Example: + "backing_file" => "/var/lib/libvirt/images/vmwarewinxp-base234-v23.qcow2 (actual path: /var/lib/libvirt/images/vmwarewinxp-base234-v23.qcow2)", + "backing_file_actual_path" => "/var/lib/libvirt/images/vmwarewinxp-base234-v23.qcow2", + "cluster_size" => 65536, + "disk_size" => "423M", + "disk_size_bytes" => 443547648, + "file_format" => "qcow2", + "image" => "/var/lib/libvirt/images/vclv99-37_234-v23.qcow2", + "snapshot" => { + 1 => { + "date" => "2011-12-07 14:43:12", + "tag" => "snap1", + "vm_clock" => "00:00:00.000", + "vm_size" => 0 + } + }, + "virtual_size" => "20G (21474836480 bytes)", + "virtual_size_bytes" => "21474836480" + +=cut + +sub get_virtual_disk_file_info { + my $self = shift; + unless (ref($self) && $self->isa('VCL::Module')) { + notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method"); + return; + } + + my $virtual_disk_file_path = shift; + if (!$virtual_disk_file_path) { + notify($ERRORS{'WARNING'}, 0, "unable to retrieve image info, file path argument was not supplied"); + return; + } + + # Return cached copy of virtual disk file info if it exists + return $self->{virtual_disk_file_info}{$virtual_disk_file_path} if defined($self->{virtual_disk_file_info}{$virtual_disk_file_path}); + + my $node_name = $self->data->get_vmhost_short_name(); + + my $command = "qemu-img info \"$virtual_disk_file_path\""; + my ($exit_status, $output) = $self->vmhost_os->execute($command); + if (!defined($exit_status)) { + notify($ERRORS{'WARNING'}, 0, "failed to execute command to retrieve image info on $node_name"); + return; + } + elsif ($exit_status) { + notify($ERRORS{'DEBUG'}, 0, "unable to retrieve image info on $node_name, output:\n" . join("\n", @$output)); + return; + } + else { + notify($ERRORS{'DEBUG'}, 0, "retrieved image info, output:\n" . join("\n", @$output)); + + my $virtual_disk_file_info; + for my $line (@$output) { + # Output example: + # image: vclv99-37_234-v23.qcow2 + # file format: qcow2 + # virtual size: 20G (21474836480 bytes) + # disk size: 423M + # cluster_size: 65536 + # backing file: /var/lib/libvirt/images/vmwarewinxp-base234-v23.qcow2 (actual path: /var/lib/libvirt/images/vmwarewinxp-base234-v23.qcow2) + # Snapshot list: + # ID TAG VM SIZE DATE VM CLOCK + # 1 snap1 0 2011-12-07 14:43:12 00:00:00.000 + + # Skip the 'Snapshot list:' and snapshot header lines + if ($line =~ /^(Snapshot list|ID)/i) { + next; + } + # ID TAG SIZE DATE CLOCK + elsif ($line =~ /^(\d+)\s+(.+)\s+(\d+)\s+([\d\-:\.]+ [\d:]+)\s+([\d:\.]+)/g) { + my $id = $1; + my $tag = $2; + my $vm_size = $3; + my $date = $4; + my $vm_clock = $5; + + # Remove trailing spaces from the tag + $tag =~ s/\s+$//; + + $virtual_disk_file_info->{snapshot}{$id} = { + 'tag' => $tag, + 'vm_size' => $vm_size, + 'date' => $date, + 'vm_clock' => $vm_clock, + }; + } + elsif ($line =~ /([\w_ ]+):\s*(.+)/) { + my $property = $1; + my $value = $2; + + if ($property =~ /disk size/i) { + # Calculate the number of bytes from the "disk size" line: + # "disk_size" => "16K", + # "disk_size" => "2.7M", + + my $disk_size_bytes; + my ($disk_size, $units) = $value =~ /([\d\.]+)(\w)/; + + if ($units =~ /K/) { + $disk_size_bytes = ($disk_size * 1024 ** 1); + } + elsif ($units =~ /M/) { + $disk_size_bytes = ($disk_size * 1024 ** 2); + } + elsif ($units =~ /G/) { + $disk_size_bytes = ($disk_size * 1024 ** 3); + } + elsif ($units =~ /T/) { + $disk_size_bytes = ($disk_size * 1024 ** 4); + } + else { + $disk_size_bytes = $disk_size; + } + + $virtual_disk_file_info->{disk_size_bytes} = int($disk_size_bytes); + } + elsif ($property =~ /virtual size/i) { + # Extract the number of bytes from the "virtual size" line: + # "virtual_size" => "15M (15728640 bytes)" + my ($virtual_size_bytes) = $value =~ /(\d+) bytes/; + $virtual_disk_file_info->{virtual_size_bytes} = $virtual_size_bytes; + } + elsif ($property =~ /backing file/i) { + # Extract the actual path from the "backing file" line: + my ($actual_path) = $value =~ /actual path: ([^\)]+)/; + $virtual_disk_file_info->{backing_file_actual_path} = $actual_path; + } + + $property = lc($property); + $property =~ s/\s+/_/g; + $virtual_disk_file_info->{$property} = $value; + } + } + + notify($ERRORS{'DEBUG'}, 0, "retrieved virtual disk file info:\n" . format_data($virtual_disk_file_info)); + $self->{virtual_disk_file_info}{$virtual_disk_file_path} = $virtual_disk_file_info; + return $virtual_disk_file_info; + } +} + +#///////////////////////////////////////////////////////////////////////////// + +=head2 get_virtual_disk_size_bytes + + Parameters : $image_name (optional) + Returns : integer + Description : Returns the size of the virtual disk in bytes. + +=cut + +sub get_virtual_disk_size_bytes { + my $self = shift; + unless (ref($self) && $self->isa('VCL::Module')) { + notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method"); + return; + } + + # Attempt to get the image name argument + my $image_name = shift; + if (!$image_name) { + $image_name = $self->data->get_image_name() || return; + } + + my $node_name = $self->data->get_vmhost_short_name(); + + # Check if the virtual disk image files reside in the repository + my @virtual_disk_file_paths; + + # Check if the virtual disk image resides in the datastore + my $master_image_file_path = $self->get_master_image_file_path(); + + # Check if the virtual disk exists on the VM host + if ($self->vmhost_os->file_exists($master_image_file_path)) { + @virtual_disk_file_paths = ($master_image_file_path); + } + else { + @virtual_disk_file_paths = $self->find_repository_image_file_paths(); + + if (!@virtual_disk_file_paths) { + notify($ERRORS{'WARNING'}, 0, "virtual disk for image $image_name does not exist in repository or datastore on $node_name"); + return; + } + } + + my $total_used_bytes; + my $total_reserved_bytes; + my $total_virtual_bytes; + + for my $virtual_disk_file_path (@virtual_disk_file_paths) { + # Get the bytes used from the VM host OS's 'du' command + my ($used_bytes, $reserved_bytes) = $self->vmhost_os->get_file_size($virtual_disk_file_path); + $total_used_bytes += $used_bytes; + $total_reserved_bytes += $reserved_bytes; + + # Attempt to retrieve the virtual disk file info + # get_virtual_disk_file_info will return false if it is unable to retrieve info for the file + my $virtual_disk_file_info = $self->get_virtual_disk_file_info($virtual_disk_file_path); + + if ($virtual_disk_file_info) { + my $virtual_bytes = $virtual_disk_file_info->{virtual_size_bytes}; + $total_virtual_bytes += $virtual_bytes; + } + else { + notify($ERRORS{'WARNING'}, 0, "unable to determine virtual disk size, information could not be retrieved for virtual disk file: $virtual_disk_file_path"); + return; + } + } + + notify($ERRORS{'DEBUG'}, 0, "size of $image_name image:\n" . + "used: " . get_file_size_info_string($total_used_bytes) . "\n" . + "reserved: " . get_file_size_info_string($total_reserved_bytes) . "\n" . + "virtual: " . get_file_size_info_string($total_virtual_bytes) + ); + + if (wantarray) { + return ($total_used_bytes, $total_reserved_bytes, $total_virtual_bytes); + } + else { + return $total_reserved_bytes; + } + +} ## end sub get_virtual_disk_size_bytes + +#///////////////////////////////////////////////////////////////////////////// + +=head2 copy_virtual_disk + + Parameters : $source_file_paths, $destination_file_path, $disk_format (optional) + Returns : boolean + Description : Calls qemu-img to copy a virtual disk image. The destination disk + format can be specified as an argument. If omitted, qcow2 is + used. + +=cut + +sub copy_virtual_disk { + my $self = shift; + unless (ref($self) && $self->isa('VCL::Module')) { + notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method"); + return; + } + + my ($source_file_paths, $destination_file_path, $disk_format) = @_; + + if (!$source_file_paths || !$destination_file_path) { + notify($ERRORS{'WARNING'}, 0, "unable to copy virtual disk, source and destination file path arguments were not passed"); + return; + } + elsif (ref($source_file_paths)) { + if (ref($source_file_paths) ne 'ARRAY') { + notify($ERRORS{'WARNING'}, 0, "unable to copy virtual disk, source file path argument was passed as a reference by reference type is not ARRAY"); + return; + } + else { + # Join the array of file paths into a string + $source_file_paths = join('" "', @$source_file_paths); + } + } + + if (!$disk_format) { + $disk_format = $self->data->get_vmhost_profile_vmdisk_format() || 'qcow2'; + } + + my $node_name = $self->data->get_vmhost_short_name(); + my $image_os_type = $self->data->get_image_os_type(); + + my $source_size_bytes = $self->get_image_size_bytes() || 0; + + # Get a semaphore so that multiple processes don't try to copy the image at the same time + my $semaphore_id = "$node_name:$destination_file_path"; + my $semaphore_timeout_minutes = 60; + my $semaphore = $self->get_semaphore($semaphore_id, (60 * $semaphore_timeout_minutes), 5) || return; + + my $start_time = time; + my $command = "qemu-img convert -O $disk_format -o preallocation=metadata \"$source_file_paths\" \"$destination_file_path\""; + notify($ERRORS{'DEBUG'}, 0, "attempting to copy/convert virtual disk:\nsource file path(s):\n" . join("\n", split(/" "/, $source_file_paths)) . "\ndestination file path: $destination_file_path\ndestination disk format: $disk_format\nsource image size: " . get_file_size_info_string($source_size_bytes)); + my ($exit_status, $output) = $self->vmhost_os->execute($command, 0, 1800); + if (!defined($exit_status)) { + notify($ERRORS{'WARNING'}, 0, "failed to execute command to convert image $node_name: '$command'"); + return; + } + elsif ($exit_status) { + notify($ERRORS{'WARNING'}, 0, "unable to copy/convert virtual disk on $node_name\ncommand: '$command'\noutput:\n" . join("\n", @$output)); + return; + } + else { + notify($ERRORS{'DEBUG'}, 0, "copied/converted virtual disk on $node_name, command: '$command', output:\n" . join("\n", @$output)); + } + + # Calculate how long it took to copy + my $duration_seconds = (time - $start_time); + my $minutes = ($duration_seconds / 60); + $minutes =~ s/\..*//g; + my $seconds = ($duration_seconds - ($minutes * 60)); + if (length($seconds) == 0) { + $seconds = "00"; + } + elsif (length($seconds) == 1) { + $seconds = "0$seconds"; + } + + my $image_size_bytes = $self->vmhost_os->get_file_size($destination_file_path); + + # Get a string which displays various copy rate information + my $copy_speed_info_string = get_copy_speed_info_string($image_size_bytes, $duration_seconds); + notify($ERRORS{'OK'}, 0, "copied image on $node_name: $destination_file_path'\n$copy_speed_info_string"); + + # Update the registry if this is a Windows image + if ($image_os_type =~ /windows/i && !$self->update_windows_image($destination_file_path)) { + notify($ERRORS{'WARNING'}, 0, "failed to make Windows-specific changes to $destination_file_path after it was copied/converted"); + return; + } + + return 1; +} + +#///////////////////////////////////////////////////////////////////////////// + +=head2 create_copy_on_write_image + + Parameters : $master_image_file_path, $copy_on_write_file_path + Returns : boolean + Description : Calls qemu-img to create a copy on write virtual disk image based + on the master image. The resulting image is written to by the VM + when it makes changes to its hard disk. Multiple VMs may utilize + the master image file. Each writes to its own copy on write image + file. The master image file is not altered. + +=cut + +sub create_copy_on_write_image { + my $self = shift; + unless (ref($self) && $self->isa('VCL::Module')) { + notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it must be called as a class method"); + return; + } + + my ($master_image_file_path, $copy_on_write_file_path, $disk_format) = @_; + + if (!$master_image_file_path || !$copy_on_write_file_path) { + notify($ERRORS{'WARNING'}, 0, "unable to create copy on write image, master and copy on write image file path arguments were not passed"); + return; + } + + my $node_name = $self->data->get_vmhost_short_name(); + + if (!$disk_format) { + $disk_format = $self->data->get_vmhost_profile_vmdisk_format() || 'qcow2'; + } + + notify($ERRORS{'DEBUG'}, 0, "creating copy on write image on $node_name\nmaster disk image: $master_image_file_path\ncopy on write image: $copy_on_write_file_path\nformat: $disk_format"); + my $command = "qemu-img create -f $disk_format -b \"$master_image_file_path\" \"$copy_on_write_file_path\""; + my ($exit_status, $output) = $self->vmhost_os->execute($command); + if (!defined($exit_status)) { + notify($ERRORS{'WARNING'}, 0, "failed to execute command to create copy on write image on $node_name: '$command'"); + return; + } + elsif ($exit_status) { + notify($ERRORS{'WARNING'}, 0, "failed to create copy on write image on $node_name, command: '$command', output:\n" . join("\n", @$output)); + return; + } + else { + notify($ERRORS{'DEBUG'}, 0, "created copy on write image: $copy_on_write_file_path, output:\n" . join("\n", @$output)); + return 1; + } +} + +#///////////////////////////////////////////////////////////////////////////// + +=head2 update_windows_image + + Parameters : $virtual_disk_file_path + Returns : boolean + Description : Runs virt-win-reg to update the registry of the image specified + by the $virtual_disk_file_path argument. The virt-win-reg utility + is provided by libguestfs-tools. This subroutine returns true if + virt-win-reg isn't installed. + + Adds registry keys to disable VMware services. If the image is + Windows 5.x, registry keys are added to enable the builtin IDE + drivers. This allows Windows images converted from VMware using a + SCSI virtual disk to be loaded on KVM. + +=cut + +sub update_windows_image { + my $self = shift; + unless (ref($self) && $self->isa('VCL::Module')) { + notify($ERRORS{'CRITICAL'}, 0, "subroutine can only be called as a VCL::Module module object method"); + return; + } + + my $virtual_disk_file_path = shift; + if (!$virtual_disk_file_path) { + notify($ERRORS{'WARNING'}, 0, "virtual disk file path argument was not supplied"); + return; + } + + my $node_name = $self->data->get_vmhost_short_name(); + + # Construct a string containing .reg file contents + # Add keys to disable VMware services if they are installed + my $registry_contents .= <<'EOF'; +Windows Registry Editor Version 5.00 + +[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\VClone] +"Start"=dword:00000004 + +[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\vmci] +"Start"=dword:00000004 + +[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\vmmouse] +"Start"=dword:00000004 + +[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\vmscsi] +"Start"=dword:00000004 + +[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\VMTools] +"Start"=dword:00000004 + +[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\vmx_svga] +"Start"=dword:00000004 + +[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\vmxnet] +"Start"=dword:00000004 +EOF + + # Check if the guest OS module is for Windows 5.x + # Add registry entries to enable the Windows IDE drivers + if ($self->os->isa('VCL::Module::OS::Windows::Version_5')) { + notify($ERRORS{'DEBUG'}, 0, "guest OS is Windows 5.x, adding registry keys to enable IDE drivers"); + $registry_contents .= <<'EOF'; + +[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\CriticalDeviceDatabase\primary_ide_channel] +"ClassGUID"="{4D36E96A-E325-11CE-BFC1-08002BE10318}" +"Service"="atapi" + +[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\CriticalDeviceDatabase\secondary_ide_channel] +"ClassGUID"="{4D36E96A-E325-11CE-BFC1-08002BE10318}" +"Service"="atapi" + +[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\CriticalDeviceDatabase\*pnp0600] +"ClassGUID"="{4D36E96A-E325-11CE-BFC1-08002BE10318}" +"Service"="atapi" + +[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\CriticalDeviceDatabase\gendisk] +"ClassGUID"="{4D36E967-E325-11CE-BFC1-08002BE10318}" +"Service"="disk" + +[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\CriticalDeviceDatabase\pci#cc_0101] +"ClassGUID"="{4D36E96A-E325-11CE-BFC1-08002BE10318}" +"Service"="pciide" + +[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\CriticalDeviceDatabase\pci#ven_0e11&dev_ae33] +"ClassGUID"="{4D36E96A-E325-11CE-BFC1-08002BE10318}" +"Service"="pciide" + +[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\CriticalDeviceDatabase\pci#ven_1039&dev_0601] +"ClassGUID"="{4D36E96A-E325-11CE-BFC1-08002BE10318}" +"Service"="pciide" + +[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\CriticalDeviceDatabase\pci#ven_1039&dev_5513] +"ClassGUID"="{4D36E96A-E325-11CE-BFC1-08002BE10318}" +"Service"="pciide" + +[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\CriticalDeviceDatabase\pci#ven_1042&dev_1000] +"ClassGUID"="{4D36E96A-E325-11CE-BFC1-08002BE10318}" +"Service"="pciide" + +[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\CriticalDeviceDatabase\pci#ven_105a&dev_4d33] +"ClassGUID"="{4D36E96A-E325-11CE-BFC1-08002BE10318}" +"Service"="pciide" + +[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\CriticalDeviceDatabase\pci#ven_1095&dev_0640] +"ClassGUID"="{4D36E96A-E325-11CE-BFC1-08002BE10318}" +"Service"="pciide" + +[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\CriticalDeviceDatabase\pci#ven_1095&dev_0646] +"ClassGUID"="{4D36E96A-E325-11CE-BFC1-08002BE10318}" +"Service"="pciide" + +[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\CriticalDeviceDatabase\pci#ven_1095&dev_0646&REV_05] +"ClassGUID"="{4D36E96A-E325-11CE-BFC1-08002BE10318}" +"Service"="pciide" + +[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\CriticalDeviceDatabase\pci#ven_1095&dev_0646&REV_07] +"ClassGUID"="{4D36E96A-E325-11CE-BFC1-08002BE10318}" +"Service"="pciide" + +[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\CriticalDeviceDatabase\pci#ven_1095&dev_0648] +"ClassGUID"="{4D36E96A-E325-11CE-BFC1-08002BE10318}" +"Service"="pciide" + +[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\CriticalDeviceDatabase\pci#ven_1095&dev_0649] +"ClassGUID"="{4D36E96A-E325-11CE-BFC1-08002BE10318}" +"Service"="pciide" + +[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\CriticalDeviceDatabase\pci#ven_1097&dev_0038] +"ClassGUID"="{4D36E96A-E325-11CE-BFC1-08002BE10318}" +"Service"="pciide" + +[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\CriticalDeviceDatabase\pci#ven_10ad&dev_0001] +"ClassGUID"="{4D36E96A-E325-11CE-BFC1-08002BE10318}" +"Service"="pciide" + +[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\CriticalDeviceDatabase\pci#ven_10ad&dev_0150] +"ClassGUID"="{4D36E96A-E325-11CE-BFC1-08002BE10318}" +"Service"="pciide" + +[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\CriticalDeviceDatabase\pci#ven_10b9&dev_5215] +"ClassGUID"="{4D36E96A-E325-11CE-BFC1-08002BE10318}" +"Service"="pciide" + +[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\CriticalDeviceDatabase\pci#ven_10b9&dev_5219] +"ClassGUID"="{4D36E96A-E325-11CE-BFC1-08002BE10318}" +"Service"="pciide" + +[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\CriticalDeviceDatabase\pci#ven_10b9&dev_5229] +"ClassGUID"="{4D36E96A-E325-11CE-BFC1-08002BE10318}" +"Service"="pciide" + +[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\CriticalDeviceDatabase\pci#ven_1106&dev_0571] +"Service"="pciide" +"ClassGUID"="{4D36E96A-E325-11CE-BFC1-08002BE10318}" + +[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\CriticalDeviceDatabase\pci#ven_8086&dev_1222] +"ClassGUID"="{4D36E96A-E325-11CE-BFC1-08002BE10318}" +"Service"="intelide" + +[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\CriticalDeviceDatabase\pci#ven_8086&dev_1230] +"ClassGUID"="{4D36E96A-E325-11CE-BFC1-08002BE10318}" +"Service"="intelide" + +[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\CriticalDeviceDatabase\pci#ven_8086&dev_2411] +"ClassGUID"="{4D36E96A-E325-11CE-BFC1-08002BE10318}" +"Service"="intelide" + +[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\CriticalDeviceDatabase\pci#ven_8086&dev_2421] +"ClassGUID"="{4D36E96A-E325-11CE-BFC1-08002BE10318}" +"Service"="intelide" + +[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\CriticalDeviceDatabase\pci#ven_8086&dev_7010] +"ClassGUID"="{4D36E96A-E325-11CE-BFC1-08002BE10318}" +"Service"="intelide" + +[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\CriticalDeviceDatabase\pci#ven_8086&dev_7111] +"ClassGUID"="{4D36E96A-E325-11CE-BFC1-08002BE10318}" +"Service"="intelide" + +[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\CriticalDeviceDatabase\pci#ven_8086&dev_7199] +"ClassGUID"="{4D36E96A-E325-11CE-BFC1-08002BE10318}" +"Service"="intelide" + +[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\atapi] +"ErrorControl"=dword:00000001 +"Group"="SCSI miniport" +"Start"=dword:00000000 +"Tag"=dword:00000019 +"Type"=dword:00000001 +"DisplayName"="Standard IDE/ESDI Hard Disk Controller" +"ImagePath"=hex(2):53,00,79,00,73,00,74,00,65,00,6d,00,33,00,32,00,5c,00,44,00,\ + 52,00,49,00,56,00,45,00,52,00,53,00,5c,00,61,00,74,00,61,00,70,00,69,00,2e,\ + 00,73,00,79,00,73,00,00,00 + +[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\IntelIde] +"ErrorControl"=dword:00000001 +"Group"="System Bus Extender" +"Start"=dword:00000000 +"Tag"=dword:00000004 +"Type"=dword:00000001 +"ImagePath"=hex(2):53,00,79,00,73,00,74,00,65,00,6d,00,33,00,32,00,5c,00,44,00,\ + 52,00,49,00,56,00,45,00,52,00,53,00,5c,00,69,00,6e,00,74,00,65,00,6c,00,69,\ + 00,64,00,65,00,2e,00,73,00,79,00,73,00,00,00 + +[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\PCIIde] +"ErrorControl"=dword:00000001 +"Group"="System Bus Extender" +"Start"=dword:00000000 +"Tag"=dword:00000003 +"Type"=dword:00000001 +"ImagePath"=hex(2):53,00,79,00,73,00,74,00,65,00,6d,00,33,00,32,00,5c,00,44,00,\ + 52,00,49,00,56,00,45,00,52,00,53,00,5c,00,70,00,63,00,69,00,69,00,64,00,65,\ + 00,2e,00,73,00,79,00,73,00,00,00 +EOF + } + + # Create a text file on the VM host containing the registry contents + my $virtual_disk_file_base_name = fileparse($virtual_disk_file_path, qr/\.[^\.]*$/i); + my $temp_reg_file_path = "/tmp/$virtual_disk_file_base_name.reg"; + if (!$self->vmhost_os->create_text_file($temp_reg_file_path, $registry_contents)) { + return; + } + + # Attempt to run virt-win-reg to merge the registry contents into the registry on the virtual disk + notify($ERRORS{'DEBUG'}, 0, "attempting to merge $temp_reg_file_path into $virtual_disk_file_path"); + my ($exit_status, $output) = $self->vmhost_os->execute("virt-win-reg --merge $virtual_disk_file_path $temp_reg_file_path"); + if (!defined($output)) { + notify($ERRORS{'WARNING'}, 0, "failed to execute command to merge $temp_reg_file_path into $virtual_disk_file_path"); + return; + } + elsif (grep(/command not found/i, @$output)) { + notify($ERRORS{'OK'}, 0, "unable to merge $temp_reg_file_path into $virtual_disk_file_path, virt-win-reg is not installed on $node_name"); + return 1; + } + elsif ($exit_status ne '0') { + notify($ERRORS{'WARNING'}, 0, "failed to merge $temp_reg_file_path into $virtual_disk_file_path, exit status: $exit_status, output:\n" . join("\n", @$output)); + return; + } + else { + notify($ERRORS{'OK'}, 0, "merged $temp_reg_file_path into $virtual_disk_file_path"); + } + + # Delete the temporary registry file on the VM host + $self->vmhost_os->delete_file($temp_reg_file_path); + + return 1; +} + +#///////////////////////////////////////////////////////////////////////////// + +1; +__END__ + +=head1 SEE ALSO + +L<http://cwiki.apache.org/VCL/> + +=cut
Propchange: incubator/vcl/trunk/managementnode/lib/VCL/Module/Provisioning/libvirt/KVM.pm ------------------------------------------------------------------------------ svn:eol-style = native Propchange: incubator/vcl/trunk/managementnode/lib/VCL/Module/Provisioning/libvirt/KVM.pm ------------------------------------------------------------------------------ svn:keywords = Date Revision Author HeadURL Id