Author: arkurth
Date: Fri Jul 15 19:06:50 2016
New Revision: 1752866

URL: http://svn.apache.org/viewvc?rev=1752866&view=rev
Log:
VCL-967
Added subroutines to libvirt.pm:
get_node_network_info
get_node_network_xml_string
get_node_interface_info
get_node_interface_xml_string

Added check to libvirt.pm::initialize to make sure the VM networks configured 
in the VM profile actually exist on the VM host. If not, a critical message is 
sent.

Updated libvirt.pm::generate_domain_xml to check if the VM network matches a 
virtual network on the host. If so, the interface type gets set to 'network'. 
Otherwise, it gets set to 'bridge'.

Modified:
    vcl/trunk/managementnode/lib/VCL/Module/Provisioning/libvirt.pm

Modified: vcl/trunk/managementnode/lib/VCL/Module/Provisioning/libvirt.pm
URL: 
http://svn.apache.org/viewvc/vcl/trunk/managementnode/lib/VCL/Module/Provisioning/libvirt.pm?rev=1752866&r1=1752865&r2=1752866&view=diff
==============================================================================
--- vcl/trunk/managementnode/lib/VCL/Module/Provisioning/libvirt.pm (original)
+++ vcl/trunk/managementnode/lib/VCL/Module/Provisioning/libvirt.pm Fri Jul 15 
19:06:50 2016
@@ -89,11 +89,10 @@ sub initialize {
                notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a 
function, it must be called as a class method");
                return;
        }
-
+       
+       my $request_state_name = $self->data->get_request_state_name();
        my $node_name = $self->data->get_vmhost_short_name();
-       my $vmhost_username = $self->data->get_vmhost_profile_username();
-       my $vmhost_password = $self->data->get_vmhost_profile_password();
-
+       
        # Get the absolute path of the libvirt drivers directory
        my $driver_directory_path = 
"$FindBin::Bin/../lib/VCL/Module/Provisioning/libvirt";
        notify($ERRORS{'DEBUG'}, 0, "libvirt driver module directory path: 
$driver_directory_path");
@@ -136,6 +135,36 @@ sub initialize {
                return;
        }
        
+       # Check if the VM profile virtualswitch0 and virtualswitch1 settings 
match either a defined network or physical interface on the node
+       if ($request_state_name =~ /(new|reload|reinstall|test)/) {
+               my $virtualswitch0 = 
$self->data->get_vmhost_profile_virtualswitch0();
+               my $virtualswitch1 = 
$self->data->get_vmhost_profile_virtualswitch1();
+               
+               my $network_info = $self->get_node_network_info();
+               if (!defined($network_info)) {
+                       notify($ERRORS{'WARNING'}, 0, "failed to initialize 
libvirt provisioning module, network info could not be retrieved from 
$node_name");
+                       return;
+               }
+               
+               my $interface_info = $self->get_node_interface_info();
+               if (!defined($interface_info)) {
+                       notify($ERRORS{'WARNING'}, 0, "failed to initialize 
libvirt provisioning module, interface info could not be retrieved from 
$node_name");
+                       return;
+               }
+               
+               my $vm_network_0_found = 
(defined($network_info->{$virtualswitch0}) || 
defined($interface_info->{$virtualswitch0}));
+               my $vm_network_1_found = 
(defined($network_info->{$virtualswitch1}) || 
defined($interface_info->{$virtualswitch1}));
+               if (!$vm_network_0_found || !$vm_network_1_found) {
+                       notify($ERRORS{'WARNING'}, 0, "failed to initialize 
libvirt provisioning module, VM network settings in VM host profile do not 
correspond to a network or physical interface on $node_name\n" .
+                               "VM network 0 setting: $virtualswitch0" . 
($vm_network_0_found ? '' : ' <-- MISSING!!!') . "\n" .
+                               "VM network 1 setting: $virtualswitch1" . 
($vm_network_1_found ? '' : ' <-- MISSING!!!') . "\n" .
+                               "networks: " . join(', ', sort keys 
%$network_info) . "\n" .
+                               "physical interfaces: " . join(', ', sort keys 
%$interface_info)
+                       );
+                       return;
+               }
+       }
+       
        notify($ERRORS{'DEBUG'}, 0, ref($self) . " provisioning module 
initialized");
        return 1;
 }
@@ -1628,6 +1657,18 @@ sub generate_domain_xml {
        my $eth0_source_device = 
$self->data->get_vmhost_profile_virtualswitch0();
        my $eth1_source_device = 
$self->data->get_vmhost_profile_virtualswitch1();
        
+       my $network_info = $self->get_node_network_info();
+       
+       my $eth0_interface_type = 'bridge';
+       if (defined($network_info->{$eth0_source_device})) {
+               $eth0_interface_type = 'network';
+       }
+       
+       my $eth1_interface_type = 'bridge';
+       if (defined($network_info->{$eth1_source_device})) {
+               $eth1_interface_type = 'network';
+       }
+
        my $eth0_mac_address;
        my $is_eth0_mac_address_random = 
$self->data->get_vmhost_profile_eth0generated(0);
        if ($is_eth0_mac_address_random) {
@@ -1661,7 +1702,7 @@ sub generate_domain_xml {
        #    Most operating systems expect the hardware clock to be kept in 
UTC, and this is the default.
        #    Windows, however, expects it to be in so called 'localtime'."
        my $clock_offset = ($image_os_type =~ /windows/) ? 'localtime' : 'utc';
-
+       
        my $xml_hashref = {
                'type' => $domain_type,
                'description' => [$image_display_name],
@@ -1722,12 +1763,12 @@ sub generate_domain_xml {
                                ],
                                'interface' => [
                                        {
-                                               'type' => 'bridge',
+                                               'type' => $eth0_interface_type,
                                                'mac' => {
                                                        'address' => 
$eth0_mac_address,
                                                },
                                                'source' => {
-                                                       'bridge' => 
$eth0_source_device,
+                                                       $eth0_interface_type => 
$eth0_source_device,
                                                },
                                                'target' => {
                                                        'dev' => 'vnet0',
@@ -1737,12 +1778,12 @@ sub generate_domain_xml {
                                                },
                                        },
                                        {
-                                               'type' => 'bridge',     
+                                               'type' => $eth1_interface_type, 
                                                'mac' => {
                                                        'address' => 
$eth1_mac_address,
                                                },
                                                'source' => {
-                                                       'bridge' => 
$eth1_source_device,
+                                                       $eth1_interface_type => 
$eth1_source_device,
                                                },
                                                'target' => {
                                                        'dev' => 'vnet1',
@@ -1768,6 +1809,7 @@ sub generate_domain_xml {
                ]
        };
        
+       notify($ERRORS{'DEBUG'}, 0, "generated domain XML:\n" . 
format_data($xml_hashref));
        return hash_to_xml_string($xml_hashref, 'domain');
 }
 
@@ -2434,6 +2476,225 @@ sub get_repository_image_semaphore {
        }
 }
 
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 get_node_network_info
+
+ Parameters  : none
+ Returns     : hash reference
+ Description : Retrieves information about all of the networks defined on the
+               node and constructs a hash containing the information. Example:
+               {
+                 "private" => {
+                   "autostart" => "yes",
+                   "persistent" => "yes",
+                   "state" => "active"
+                 },
+                 "public" => {
+                   "autostart" => "yes",
+                   "persistent" => "yes",
+                   "state" => "active"
+                 }
+               }
+
+=cut
+
+sub get_node_network_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 $node_name = $self->data->get_vmhost_short_name();
+       
+       my $command = "virsh net-list --all";
+       my ($exit_status, $output) = $self->vmhost_os->execute($command);
+       if (!defined($output)) {
+               notify($ERRORS{'WARNING'}, 0, "failed to execute virsh command 
to list networks on $node_name");
+               return;
+       }
+       elsif ($exit_status ne '0') {
+               notify($ERRORS{'WARNING'}, 0, "failed to list networks on 
$node_name\ncommand: $command\nexit status: $exit_status\noutput:\n" . 
join("\n", @$output));
+               return;
+       }
+       else {
+               notify($ERRORS{'DEBUG'}, 0, "listed networks on 
$node_name\ncommand: $command\noutput:\n" . join("\n", @$output));
+       }
+
+       # root@bn17-231:/pools# virsh net-list --all
+       #  Name                 State      Autostart     Persistent
+       # ----------------------------------------------------------
+       #  private              active     yes           yes
+       #  public               active     yes           yes
+
+
+       my $info = {};
+       for my $line (@$output) {
+               my ($name, $state, $autostart, $persistent) = $line =~ 
/^\s*([\w_]+)\s+(\w+)\s+(\w+)\s+(\w+)$/g;
+               next if (!defined($name) || $name =~ /Name/);
+               
+               $info->{$name}{state} = $state;
+               $info->{$name}{autostart} = $autostart;
+               $info->{$name}{persistent} = $persistent;
+       }
+       
+       notify($ERRORS{'DEBUG'}, 0, "retrieved network info from $node_name:\n" 
. format_data($info));
+       return $info;
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 get_node_network_xml_string
+
+ Parameters  : $network_name
+ Returns     : string
+ Description : Retrieves the XML definition of a network defined on the node.
+
+=cut
+
+sub get_node_network_xml_string {
+       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 $network_name = shift;
+       if (!defined($network_name)) {
+               notify($ERRORS{'WARNING'}, 0, "network name argument was not 
specified");
+               return;
+       }
+       
+       my $node_name = $self->data->get_vmhost_short_name();
+       
+       my $command = "virsh net-dumpxml --network \"$network_name\"";
+       my ($exit_status, $output) = $self->vmhost_os->execute($command);
+       if (!defined($output)) {
+               notify($ERRORS{'WARNING'}, 0, "failed to execute virsh command 
to retrieve XML definition for '$network_name' network on $node_name");
+               return;
+       }
+       elsif ($exit_status ne '0') {
+               notify($ERRORS{'WARNING'}, 0, "failed to retrieve XML 
definition for '$network_name' network on $node_name\ncommand: $command\nexit 
status: $exit_status\noutput:\n" . join("\n", @$output));
+               return;
+       }
+       else {
+               my $xml_string = join("\n", @$output);
+               notify($ERRORS{'DEBUG'}, 0, "retrieved XML definition for 
'$network_name' network on $node_name\n$xml_string");
+               return $xml_string;
+       }
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 get_node_interface_info
+
+ Parameters  : none
+ Returns     : hash reference
+ Description : Retrieves information about all of the physical host interfaces
+               on the node and constructs a hash containing the information.
+               Example:
+               {
+                 "br0" => {
+                   "mac_address" => "00:50:56:23:00:1c",
+                   "state" => "active"
+                 },
+                 "br1" => {
+                   "mac_address" => "00:50:56:23:00:1d",
+                   "state" => "active"
+                 },
+                 "lo" => {
+                   "mac_address" => "00:00:00:00:00:00",
+                   "state" => "active"
+                 }
+               }
+
+=cut
+
+sub get_node_interface_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 $node_name = $self->data->get_vmhost_short_name();
+       
+       my $command = "virsh iface-list --all";
+       my ($exit_status, $output) = $self->vmhost_os->execute($command);
+       if (!defined($output)) {
+               notify($ERRORS{'WARNING'}, 0, "failed to execute virsh command 
to list physical interfaces on $node_name");
+               return;
+       }
+       elsif ($exit_status ne '0') {
+               notify($ERRORS{'WARNING'}, 0, "failed to list physical 
interfaces on $node_name\ncommand: $command\nexit status: 
$exit_status\noutput:\n" . join("\n", @$output));
+               return;
+       }
+       else {
+               notify($ERRORS{'DEBUG'}, 0, "listed physical interfaces on 
$node_name\ncommand: $command\noutput:\n" . join("\n", @$output));
+       }
+
+       # root@bn17-231:/pools# virsh iface-list --all
+       #  Name                 State      MAC Address
+       # ---------------------------------------------------
+       #  br0                  active     00:50:56:23:00:1c
+       #  br1                  active     00:50:56:23:00:1d
+
+       my $info = {};
+       for my $line (@$output) {
+               my ($name, $state, $mac_address) = $line =~ 
/^\s*(\w+)\s+(\w+)\s+([\w\:]+)$/g;
+               next if (!defined($name) || $name =~ /^(Name|lo)/);
+               
+               $info->{$name}{state} = $state;
+               $info->{$name}{mac_address} = $mac_address;
+       }
+       
+       notify($ERRORS{'DEBUG'}, 0, "retrieved physical interface info from 
$node_name:\n" . format_data($info));
+       return $info;
+}
+
+#/////////////////////////////////////////////////////////////////////////////
+
+=head2 get_node_interface_xml_string
+
+ Parameters  : $interface_name
+ Returns     : string
+ Description : Retrieves the XML definition of a network defined on the node.
+
+=cut
+
+sub get_node_interface_xml_string {
+       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 $interface_name = shift;
+       if (!defined($interface_name)) {
+               notify($ERRORS{'WARNING'}, 0, "interface name argument was not 
specified");
+               return;
+       }
+       
+       my $node_name = $self->data->get_vmhost_short_name();
+       
+       my $command = "virsh iface-dumpxml --interface \"$interface_name\"";
+       my ($exit_status, $output) = $self->vmhost_os->execute($command);
+       if (!defined($output)) {
+               notify($ERRORS{'WARNING'}, 0, "failed to execute virsh command 
to retrieve XML definition for '$interface_name' interface on $node_name");
+               return;
+       }
+       elsif ($exit_status ne '0') {
+               notify($ERRORS{'WARNING'}, 0, "failed to retrieve XML 
definition for '$interface_name' interface on $node_name\ncommand: 
$command\nexit status: $exit_status\noutput:\n" . join("\n", @$output));
+               return;
+       }
+       else {
+               my $xml_string = join("\n", @$output);
+               notify($ERRORS{'DEBUG'}, 0, "retrieved XML definition for 
'$interface_name' interface on $node_name\n$xml_string");
+               return $xml_string;
+       }
+}
+
 #/////////////////////////////////////////////////////////////////////////////
 
 1;


Reply via email to