You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@vcl.apache.org by yu...@hotmail.com on 2010/02/24 16:52:57 UTC

The Provisioning Module for KVM support

Hi,

Recently, I write the new provisioning module for the KVM support.
Basically, what I am doing is that, installed kvm in one of our blade and
host OS is Fedora 11, kernel linux 2.6.30.8-64 bits. So you can use command
"qemu-system-x86_64" to run your virtual machine.

1. Assuming your host machine has two Ethernet cards, eth0 is private
network and eth1 is public network. You have to configure your host
machine's network and setup bridges for each virtual machine.

The configure procedure is following:

ifconfig eth0 up
ifconfig eth1 up
modprobe 8021q
vconfig add eth0 0
vconfig add eth1 5
brctl addbr br0
brctl addbr br1
brctl addif br0 eth0
brctl addif br1 eth1
ifconfig br0 yourPrivateIP/netmask up
ifconfig br1 yourPublicIP/netmask up
route add default gw yourDefaultGatewayIP br1
modprobe kvm
modprobe kvm-intel (for intel CPU)


Finally, you have to copy the Management Node's public to the KVM host's
authorized key repository, so vcld can login to the KVM host by key
authentication.

Now your host machine should be ready for receiving request from VCL.

2. After configuring the KVM host machine, now you have change several
things on the Management Node.

Two files you have to add to your vcl provisioning directory, one is mac and
the other is kvm.pm.

mac is simple script to generate random mac address. My mac is following:

#!/bin/sh
echo -n $(echo -n 00:0C:29:C3; for i in `seq 1 2`;
do echo -n `echo ":$RANDOM$RANDOM" | cut -n -c -3` ;done)




Then my kvm.pm provisioning code is following:

#!/usr/bin/perl -w

# 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.

##############################################################################
# $Id: vmware.pm 1953 2008-12-12 14:23:17Z arkurth $
##############################################################################

=head1 NAME

VCL::Provisioning::kvm - VCL module to support the kvm provisioning engine

=cut
##############################################################################
package VCL::Module::Provisioning::kvm;

# Include File Copying for Perl
use File::Copy;

# Specify the lib path using FindBin
use FindBin;
use lib "$FindBin::Bin/../../..";

# Configure inheritance
use base qw(VCL::Module::Provisioning);

# Specify the version of this module
our $VERSION = '1.00';

# Specify the version of Perl to use
use 5.008000;

use strict;
use warnings;
use diagnostics;

use VCL::utils;
use Fcntl qw(:DEFAULT :flock);

# Used to query for the MAC address once a host has been registered
use VMware::VIRuntime;
use VMware::VILib;
use threads;

##############################################################################

=head1 CLASS ATTRIBUTES

=cut

=head2 %VMWARE_CONFIG

 Data type   : hash
 Description : %VMWARE_CONFIG is a hash containing the general VMWARE
configuration
               for the management node this code is running on. Since the
data is
the same for every instance of the VMWARE class, a class attribute
is used and the hash is shared among all instances. This also
means that the data only needs to be retrieved from the database
once.

=cut

#my %VMWARE_CONFIG;

# Class attributes to store VMWWARE configuration details
# This data also resides in the %VMWARE_CONFIG hash
# Extract hash data to scalars for ease of use
my $IMAGE_LIB_ENABLE  = $IMAGELIBENABLE;
my $IMAGE_LIB_USER    = $IMAGELIBUSER;
my $IMAGE_LIB_KEY     = $IMAGELIBKEY;
my $IMAGE_LIB_SERVERS = $IMAGESERVERS;
my $kvm_hostname;
my $kvm_minram;
my $kvm_dir;
my $kvm_imagename;
my $kvm_eth0MAC;
my $kvm_eth1MAC;
##############################################################################

=head1 OBJECT METHODS

=cut

#/////////////////////////////////////////////////////////////////////////////

=head2 initialize

 Parameters  :
 Returns     :
 Description :

=cut

sub initialize {
notify($ERRORS{'DEBUG'}, 0, "KVM module initialized");
return 1;
}


# Power on virtual machine on the KVM

sub poweron {
my @chown_command = ("ssh",
$kvm_hostname,"-l","root","qemu-system-x86_64 -m $kvm_minram
$kvm_dir/$kvm_imagename-flat.vmdk -nographic -net
nic,vlan=0,macaddr=$kvm_eth0MAC -net tap,vlan=0 -net
nic,vlan=5,macaddr=$kvm_eth1MAC -net tap,vlan=5,script=/etc/qemu-ifup1");
notify($ERRORS{'DEBUG'}, 0, "Poweron Command:@chown_command");
if (system(@chown_command) >> 8) {
print "Fail! $! \n";
# insert load log here perhaps
return 0;
}
else {notify($ERRORS{'DEBUG'}, 0, "Success to Poweron VM");}
return 0;
}

#/////////////////////////////////////////////////////////////////////////////

=head2 provision

 Parameters  : hash
 Returns     : 1(success) or 0(failure)
 Description : loads virtual machine with requested image

=cut

sub load {
my $self = shift;

#check to make sure this call is for the esx module
if (ref($self) !~ /kvm/i) {
notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it
must be called as a class method");
return 0;
}

my $request_data = shift;
my ($package, $filename, $line, $sub) = caller(0);
notify($ERRORS{'DEBUG'}, 0,
"****************************************************");

# get various useful vars from the database
my $request_id     = $self->data->get_request_id;
my $reservation_id = $self->data->get_reservation_id;
my $vmhost_hostname           = $self->data->get_vmhost_hostname;
my $image_name     = $self->data->get_image_name;
my $computer_shortname  = $self->data->get_computer_short_name;
my $vmclient_computerid = $self->data->get_computer_id;
my $vmclient_imageminram      = $self->data->get_image_minram;
my $image_os_name  = $self->data->get_image_os_name;
my $image_os_type  = $self->data->get_image_os_type;
my $image_identity = $self->data->get_image_identity;

my $virtualswitch0    = $self->data->get_vmhost_profile_virtualswitch0;
my $virtualswitch1    = $self->data->get_vmhost_profile_virtualswitch1;
# my $vmclient_eth0MAC          =
$self->data->get_computer_eth0_mac_address;
# my $vmclient_eth1MAC          =
$self->data->get_computer_eth1_mac_address;
my $vmclient_OSname           = $self->data->get_image_os_name;

my $vmclient_eth0MAC = `sh
/usr/local/vcl/lib/VCL/Module/Provisioning/mac`;
my $vmclient_eth1MAC = `sh
/usr/local/vcl/lib/VCL/Module/Provisioning/mac`;
# get image_id
my $image_id     = $self->data->get_image_id;

my $datastorepath4vmx = "/mnt/vcl/inuse/$computer_shortname";

#eventually get these from a config file or database

my $datastore_share_path = "/mnt/export";

notify($ERRORS{'OK'}, 0, "Entered kvm module, loading $image_name on
$computer_shortname (on $vmhost_hostname) for reservation $reservation_id");

# query the host to see if the vm currently exists
my $sshd_status_1 = _sshd_status("$computer_shortname", $image_name,
"linux"); if
 ($sshd_status_1 eq "on")
{
my @chown_command = ("ssh",$computer_shortname,"-l","root","shutdown -h
now");
if (system(@chown_command) >> 8) {
print "Fail! $! \n";
# insert load log here perhaps
return 0;
}
else {sleep 10; print "Success to shutdown:$computer_shortname $!\n";}
}
my $remove_vm_output = `rm -rf $datastorepath4vmx`;
notify($ERRORS{'DEBUG'}, 0, "Output from remove command is:
$remove_vm_output");

# copy appropriate vmdk file
my $newdir = $datastorepath4vmx;
if (!mkdir($newdir)) {
notify($ERRORS{'CRITICAL'}, 0, "Could not create new directory: $!");
# return 0;
}
notify($ERRORS{'OK'}, 0, "$request_id $reservation_id $vmhost_hostname
$image_name $computer_shortname $vmclient_computerid $vmclient_imageminram
$image_os_name $image_os_type $image_identity $virtualswitch0
$virtualswitch1 $vmclient_eth0MAC $vmclient_eth1MAC $vmclient_OSname");

### Checkout Images ######
#########################################################################
        my $whoami = 'admin';
        my $dir = "/mnt/vcl";

# copy appropriate vmdk file
my $from = "$dir/golden/$image_name/$image_name.vmdk";
my $to   = "$datastorepath4vmx/$image_name.vmdk";
if (!copy($from, $to)) {
notify($ERRORS{'CRITICAL'}, 0, "Could not copy vmdk file!");
return 0;
}
notify($ERRORS{'DEBUG'}, 0, "COPIED VMDK SUCCESSFULLY");


# Copy the (large) -flat.vmdk file
# This uses ssh to do the copy locally, copying over nfs is too costly
$from = "$dir/golden/$image_name/$image_name-flat.vmdk";
$to   = "$datastorepath4vmx/$image_name-flat.vmdk";
if (!copy($from, $to)) {
notify($ERRORS{'CRITICAL'}, 0, "Could not copy vmdk-flat file!");
return 0;
}

        notify($ERRORS{'DEBUG'}, 0, "Copy image is success");

#########################################################################

# Turn new vm on
notify($ERRORS{'OK'}, 0, "$vmhost_hostname $vmclient_imageminram
$image_name $vmclient_eth0MAC $vmclient_eth1MAC");
$kvm_hostname = $vmhost_hostname;
$kvm_minram = $vmclient_imageminram;
$kvm_imagename = $image_name;
$kvm_eth0MAC = $vmclient_eth0MAC;
$kvm_eth1MAC = $vmclient_eth1MAC;

my $thr = threads->new(\&poweron);
$thr->detach;
sleep(3); # Wait for booting
my $mac_addr = $vmclient_eth1MAC;

notify($ERRORS{'OK'}, 0, "Queried MAC address is $mac_addr");

# Query ARP table for $mac_addr to find the IP (waiting for machine to
come up if necessary)
# The DHCP negotiation should add the appropriate ARP entry for us
my $arpstatus = 0;
my $wait_loops = 0;
my $client_ip;
while (!$arpstatus) {
my $arpoutput = `arp -n`;
if ($arpoutput =~ /^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}).*?$mac_addr/mi)
{
$client_ip = $1;
$arpstatus = 1;
notify($ERRORS{'OK'}, 0, "$computer_shortname now has ip $client_ip");
}
else {
if ($wait_loops > 48) {
notify($ERRORS{'CRITICAL'}, 0, "waited acceptable amount of time for
dhcp, please check $computer_shortname on $vmhost_hostname");
return 0;
}
else {
$wait_loops++;
notify($ERRORS{'OK'}, 0, "going to sleep 5 seconds, waiting for
computer to DHCP. Try $wait_loops");
sleep 5;
}
}
}


notify($ERRORS{'OK'}, 0, "Found IP address $client_ip");

# Delete existing entry for $computer_shortname in /etc/hosts (if any)
notify($ERRORS{'OK'}, 0, "Removing old hosts entry");
my $sedoutput = `sed -i "/.*\\b$computer_shortname\$/d" /etc/hosts`;
notify($ERRORS{'DEBUG'}, 0, $sedoutput);

# Add new entry to /etc/hosts for $computer_shortname
`echo -e "$client_ip\t$computer_shortname" >> /etc/hosts`;

# Start waiting for SSH to come up
my $sshdstatus = 0;
$wait_loops = 0;
my $sshd_status = "off";
notify($ERRORS{'DEBUG'}, 0, "Waiting for ssh to come up on
$computer_shortname");
while (!$sshdstatus) {
$sshd_status = _sshd_status($computer_shortname, $image_name,
$image_os_type);
notify($ERRORS{'DEBUG'}, 0, "SSH status: $sshd_status");
if ($sshd_status eq "on") {
$sshdstatus = 1;
notify($ERRORS{'OK'}, 0, "$computer_shortname now has active sshd
running");
}
else {
#either sshd is off or N/A, we wait
if ($wait_loops > 48) {
notify($ERRORS{'CRITICAL'}, 0, "waited acceptable amount of time
for sshd to become active, please check $computer_shortname on
$vmhost_hostname");
#need to check power, maybe reboot it. for now fail it
return 0;
}
else {
$wait_loops++;
# to give post config a chance
notify($ERRORS{'OK'}, 0, "going to sleep 5 seconds, waiting for
computer to start SSH. Try $wait_loops");
sleep 5;
}
}    # else
}    #while

# Set IP info
if ($IPCONFIGURATION ne "manualDHCP") {
#not default setting
if ($IPCONFIGURATION eq "dynamicDHCP") {
insertloadlog($reservation_id, $vmclient_computerid,
"dynamicDHCPaddress", "collecting dynamic IP address for node");
notify($ERRORS{'DEBUG'}, 0, "Attempting to query vmclient for its
public IP...");
my $assignedIPaddress = getdynamicaddress($computer_shortname,
$vmclient_OSname,$image_os_type);
if ($assignedIPaddress) {
#update computer table
notify($ERRORS{'DEBUG'}, 0, " Got dynamic address from vmclient,
attempting to update database");
if (update_computer_address($vmclient_computerid,
$assignedIPaddress)) {
notify($ERRORS{'DEBUG'}, 0, " succesfully updated IPaddress of
node $computer_shortname");
}
else {
notify($ERRORS{'CRITICAL'}, 0, "could not update dynamic address
$assignedIPaddress for $computer_shortname $image_name");
return 0;
}
} ## end if ($assignedIPaddress)
else {
notify($ERRORS{'CRITICAL'}, 0, "could not fetch dynamic address from
$computer_shortname $image_name");
insertloadlog($reservation_id, $vmclient_computerid, "failed",
"could not collect dynamic IP address for node");
return 0;
}
} ## end if ($IPCONFIGURATION eq "dynamicDHCP")
elsif ($IPCONFIGURATION eq "static") {
notify($ERRORS{'CRITICAL'}, 0, "STATIC ASSIGNMENT NOT SUPPORTED. See
vcld.conf");
return 0;
#insertloadlog($reservation_id, $vmclient_computerid,
"staticIPaddress", "setting static IP address for node");
#if (setstaticaddress($computer_shortname, $vmclient_OSname,
$vmclient_publicIPaddress)) {
# # good set static address
#}
}
} ## end if ($IPCONFIGURATION ne "manualDHCP")
return 1;

} ## end sub load

#/////////////////////////////////////////////////////////////////////////////

=head2 capture

 Parameters  : $request_data_hash_reference
 Returns     : 1 if sucessful, 0 if failed
 Description : Creates a new vmware image.

=cut

sub capture {
notify($ERRORS{'DEBUG'}, 0,
"**********************************************************");
notify($ERRORS{'OK'}, 0, "Entering KVM Capture routine");
my $self = shift;


#check to make sure this call is for the kvm module
if (ref($self) !~ /kvm/i) {
notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it
must be called as a class method");
return 0;
}

my $request_data = shift;
my ($package, $filename, $line, $sub) = caller(0);
my $vmhost_hostname    = $self->data->get_vmhost_hostname;
my $new_imagename   = $self->data->get_image_name;
my $computer_shortname  = $self->data->get_computer_short_name;
my $image_identity = $self->data->get_image_identity;
        my $vmhost_username = "root";
        my $vmhost_password = 's3cur$tyw0rks';
        my $datastore_ip = "ning11.cnl.ncsu.edu";
my $datastore_share_path = "/mnt/export";


my $inuse_image = "/mnt/vcl/inuse/$computer_shortname";
my $new_golden = "/mnt/vcl/golden/$new_imagename";


# Find old image name:
my $oldimage;
if (open(LISTFILES, "ls -1 $inuse_image 2>&1 |")) {
my @list = <LISTFILES>;
close(LISTFILES);
my $numfiles = @list;
#figure out old name
foreach my $a (@list) {
chomp($a);
if ($a =~ /(.*)-(v[0-9]*)\.vmdk/) {
$oldimage = "$1-$2";
}
}
} else {
notify($ERRORS{'CRITICAL'}, 0, "LS failed");
return 0;
}
notify($ERRORS{'DEBUG'}, 0, "found previous name= $oldimage");

notify($ERRORS{'OK'}, 0, "SSHing to node to configure currentimage.txt");
my @sshcmd = run_ssh_command($computer_shortname, $image_identity, "echo
$new_imagename > /root/currentimage.txt", "root");

my $sshd_status_2 = _sshd_status("$computer_shortname", $oldimage,
"linux"); if
 ($sshd_status_2 eq "on")
{
my @chown_command = ("ssh",$computer_shortname,"-l","root","shutdown -h
now");
if (system(@chown_command) >> 8) {
print "Fail! $! \n";
# insert load log here perhaps
return 0;
}
else {print "Shutdown:$computer_shortname $!\n";}
}

notify($ERRORS{'OK'}, 0, "Waiting 20 seconds for power off");
sleep(20);


### Mirage Checkin Images ######
#########################################################################
# copy appropriate vmdk file
my $newdir = $new_golden;
if (!mkdir($newdir)) {
notify($ERRORS{'CRITICAL'}, 0, "Could not create new directory: $!");
return 0;
}

my $output;
notify($ERRORS{'OK'}, 0, "Rewriting VMDK and VMX files with new image
name");
$output = `sed -i 's/$oldimage/$new_imagename/'
$inuse_image/$oldimage.vmx`;
notify($ERRORS{'DEBUG'}, 0, "VMX sed: $output");
$output = `sed -i 's/$oldimage/$new_imagename/'
$inuse_image/$oldimage.vmdk`;

sleep(1);
my $from = "$inuse_image/$oldimage.vmdk";
my $to = "$new_golden/$new_imagename.vmdk";
#my $to = "$new_golden/$new_imagename.vmdk-meta";
notify($ERRORS{'DEBUG'}, 0, "Preparing to copy vmdk from $from to $to");
if (!copy($from, $to)) {
notify($ERRORS{'CRITICAL'}, 0, "Could not copy VMDK file! $!");
# insert load log here perhaps
return 0;
}
notify($ERRORS{'DEBUG'}, 0, "COPIED VMX SUCCESSFULLY");

$from = "$inuse_image/.mirage";
$to = "$new_golden/.mirage";
notify($ERRORS{'DEBUG'}, 0, "Preparing to copy .mirage from $from to
$to");
if (!copy($from, $to)) {
notify($ERRORS{'CRITICAL'}, 0, "Could not copy .mirage file! $!");
# insert load log here perhaps
return 0;
}
notify($ERRORS{'DEBUG'}, 0, "COPIED VMX SUCCESSFULLY");


# Copy the (large) -flat.vmdk file
# This uses ssh to do the copy locally on the nfs server.
$from =
"$datastore_share_path/inuse/$computer_shortname/$oldimage-flat.vmdk";
$to =
"$datastore_share_path/golden/$new_imagename/$new_imagename-flat.vmdk";
notify($ERRORS{'DEBUG'}, 0, "Preparing to ssh to $datastore_ip copy
vmdk-flat from $from to $to");
#my @move_command = ("ssh", $datastore_ip, "-i", $image_identity, "-o",
"BatchMode yes", "mv $from $to");
my @move_command = ("ssh", $datastore_ip, "-i", $image_identity, "-o",
"BatchMode yes", "cp -p $from $to");
notify($ERRORS{'OK'}, 0, "SSHing to copy vmdk-flat file");
if (system(@move_command) >> 8) {
notify($ERRORS{'CRITICAL'}, 0, "Could not copy VMDK-flat file! $!");
# insert load log here perhaps
return 0;
}
notify($ERRORS{'DEBUG'}, 0, "COPIED VMX SUCCESSFULLY");

my $new_dir = "$datastore_share_path/golden/$new_imagename";
        my $comments = "checkin $new_imagename back";

        my $dbh = VCL::utils::getnewdbh();

        my $new_vcl_image_id     = $self->data->get_image_id;
        notify($ERRORS{'DEBUG'}, 0, "new_vcl_image_id is:
$new_vcl_image_id");

my $whoami = 'admin'; 
#VCL::Module::Provisioning::mirage::checkinImage($vmhost_username, $new_dir, 
$new_imagename, $comments, $new_vcl_image_id, $dbh);


my $string1 =
substr($oldimage,index($oldimage,"-")+1,rindex($oldimage,"-")-index($oldimage,"-")-1);
my $string2 =
substr($new_imagename,index($new_imagename,"-")+1,rindex($new_imagename,"-")-index($new_imagename,"-")-1);
# print "$string1 and $string2\n";

        notify($ERRORS{'DEBUG'}, 0, "New Image is done: $new_vcl_image_id");
return 1;
} ## end sub capture


#/////////////////////////////////////////////////////////////////////////
=head2 node_status

 Parameters  : $nodename, $log
 Returns     : array of related status checks
 Description : checks on sshd, currentimage

=cut

sub node_status {
my $self = shift;

# Check if subroutine was called as a class method
if (ref($self) !~ /kvm/i) {
notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it
must be called as a class method");
return 0;
}

#my ($vmhash) = shift;

my ($package, $filename, $line, $sub) = caller(0);

# try to contact vm
# $self->data->get_request_data;
# get state of vm
my $vmpath             = $self->data->get_vmhost_profile_vmpath;
my $datastorepath      = $self->data->get_vmhost_profile_datastore_path;
my $requestedimagename = $self->data->get_image_name;
my $vmhost_type        = $self->data->get_vmhost_type;
my $vmhost_hostname    = $self->data->get_vmhost_hostname;
my $vmhost_imagename   = $self->data->get_vmhost_image_name;
my $image_os_type  = $self->data->get_image_os_type;
my $vmclient_shortname = $self->data->get_computer_short_name;
my $request_forimaging              =
$self->data->get_request_forimaging();

notify($ERRORS{'OK'}, 0, "Entering node_status, checking status of
$vmclient_shortname");
notify($ERRORS{'DEBUG'}, 0, "request_for_imaging: $request_forimaging");
notify($ERRORS{'DEBUG'}, 0, "requeseted image name: $requestedimagename");

my ($hostnode, $identity);

# Create a hash to store status components
my %status;

# Initialize all hash keys here to make sure they're defined
$status{status}       = 0;
$status{currentimage} = 0;
$status{ping}         = 0;
$status{ssh}          = 0;
$status{vmstate}      = 0;    #on or off
$status{image_match}  = 0;

if ($vmhost_type eq "blade") {
$hostnode = $1 if ($vmhost_hostname =~ /([-_a-zA-Z0-9]*)(\.?)/);
$identity = $IDENTITY_bladerhel;    #if($vm{vmhost}{imagename} =~
/^(rhel|rh3image|rh4image|fc|rhfc)/);
}
else {
#using FQHN
$hostnode = $vmhost_hostname;
$identity = $IDENTITY_linux_lab if ($vmhost_imagename =~
/^(realmrhel)/);
}

if (!$identity) {
notify($ERRORS{'CRITICAL'}, 0, "could not set ssh identity variable for
image $vmhost_imagename type= $vmhost_type host= $vmhost_hostname");
}

# Check if node is pingable
notify($ERRORS{'DEBUG'}, 0, "checking if $vmclient_shortname is
pingable");
if (_pingnode($vmclient_shortname)) {
$status{ping} = 1;
notify($ERRORS{'OK'}, 0, "$vmclient_shortname is pingable
($status{ping})");
}
else {
notify($ERRORS{'OK'}, 0, "$vmclient_shortname is not pingable
($status{ping})");
$status{status} = 'RELOAD';
return $status{status};
}

#
notify($ERRORS{'DEBUG'}, 0, "Trying to ssh...");

#can I ssh into it
my $sshd = _sshd_status($vmclient_shortname, $requestedimagename,
$image_os_type);


#is it running the requested image
if ($sshd eq "on") {

notify($ERRORS{'DEBUG'}, 0, "SSH good, trying to query image name");

$status{ssh}          = 1;
$identity = $IDENTITY_bladerhel;
#my $identity = $IDENTITY_bladerhel;
my @sshcmd = run_ssh_command($vmclient_shortname, $identity, "cat
currentimage.txt");
$status{currentimage} = $sshcmd[1][0];

notify($ERRORS{'DEBUG'}, 0, "Image name: $status{currentimage}");

if ($status{currentimage}) {
chomp($status{currentimage});
if ($status{currentimage} =~ /$requestedimagename/) {
$status{image_match} = 1;
notify($ERRORS{'OK'}, 0, "$vmclient_shortname is loaded with
requestedimagename $requestedimagename");
}
else {
notify($ERRORS{'OK'}, 0, "$vmclient_shortname reports current image
is currentimage= $status{currentimage} requestedimagename=
$requestedimagename");
}
} ## end if ($status{currentimage})
} ## end if ($sshd eq "on")

# Determine the overall machine status based on the individual status
results
if ($status{ssh} && $status{image_match}) {
$status{status} = 'READY';
}
else {
$status{status} = 'RELOAD';
}

notify($ERRORS{'DEBUG'}, 0, "status set to $status{status}");


if($request_forimaging){
$status{status} = 'RELOAD';
notify($ERRORS{'OK'}, 0, "request_forimaging set, setting status to
RELOAD");
}

notify($ERRORS{'DEBUG'}, 0, "returning node status hash reference
(\$node_status->{status}=$status{status})");
return \%status;

} ## end sub node_status

sub does_image_exist {
my $self = shift;
if (ref($self) !~ /kvm/i) {
notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it
must be called as a class method");
return 0;
}

my $image_name = $self->data->get_image_name();
if (!$image_name) {
notify($ERRORS{'CRITICAL'}, 0, "unable to determine if image exists,
unable to determine image name");
return 0;
}

my $IMAGEREPOSITORY = "/mnt/vcl/golden";

if (open(IMAGES, "/bin/ls -1 $IMAGEREPOSITORY 2>&1 |")) {
my @images = <IMAGES>;
close(IMAGES);
foreach my $i (@images) {
if ($i =~ /$image_name/) {
notify($ERRORS{'OK'}, 0, "image $image_name exists");
return 1;
}
}
} ## end if (open(IMAGES, "/bin/ls -1 $IMAGEREPOSITORY 2>&1 |"...

notify($ERRORS{'WARNING'}, 0, "image $IMAGEREPOSITORY/$image_name does NOT
exists");
return 0;

} ## end sub does_image_exist

#/////////////////////////////////////////////////////////////////////////////

=head2  getimagesize

 Parameters  : imagename
 Returns     : 0 failure or size of image
 Description : in size of Kilobytes

=cut

sub get_image_size {
my $self = shift;
if (ref($self) !~ /kvm/i) {
notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a function, it
must be called as a class method");
return 0;
}

# Either use a passed parameter as the image name or use the one stored in
this object's DataStructure
my $image_name = shift;
$image_name = $self->data->get_image_name() if !$image_name;
if (!$image_name) {
notify($ERRORS{'CRITICAL'}, 0, "image name could not be determined");
return 0;
}
notify($ERRORS{'DEBUG'}, 0, "getting size of image: $image_name");

my $IMAGEREPOSITORY = "/mnt/vcl/golden/$image_name";

#list files in image directory, account for main .gz file and any .gz.00X
files
if (open(FILELIST, "/bin/ls -s1 $IMAGEREPOSITORY 2>&1 |")) {
my @filelist = <FILELIST>;
close(FILELIST);
my $size = 0;
foreach my $f (@filelist) {
if ($f =~ /$image_name-flat.vmdk/) {
my ($presize, $blah) = split(" ", $f);
$size += $presize;
}
}
if ($size == 0) {
#strange imagename not found
return 0;
}
return int($size / 1024);
} ## end if (open(FILELIST, "/bin/ls -s1 $IMAGEREPOSITORY 2>&1 |"...

return 0;
} ## end sub get_image_size


initialize();
1;
__END__

=head1 BUGS and LIMITATIONS

 There are no known bugs in this module.
 Please report problems to the VCL team (vcl_help@ncsu.edu).

=head1 AUTHOR

Xianqing Yu <xy...@ncsu.edu>

=head1 SEE ALSO

L<http://vcl.ncsu.edu>

=cut




At last, add the kvm module into your vcl database, table "module" and
"provisioning". Assign virtual machines to the kvm provisioning module. Now
you can make a reservation to test KVM support.:)

If you have any problems, please feel free to contact me.

Thanks,

Xianqing