You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@vcl.apache.org by Jeffrey Wisman <je...@csueastbay.edu> on 2010/03/10 06:54:14 UTC

Re: Yet Another VMware ESX Provisioning Module

Sean,
We're very interested in using this module.  Can you provide a step-by-step
instruction on how to make this available as a provisioning module?  We're
running ESX 4.0 on our host server.  Do we place the module into
/usr/local/vcl/lib/VCL/Module/Provisioning ?  What is the next step?
Getting into the database somehow?  Please let me know.

Thanks,
Jeff



On Wed, Feb 24, 2010 at 1:16 PM, Sean Dilda <se...@duke.edu> wrote:

> I've written a provisioning module for VCL that we use here at Duke that
> I'd like to share for possible inclusion in VCL.  The module is based off
> VCL 2.1.
>
> This module is designed to work against VirtualCenter/vCenter, but should
> be able to work directly with an ESX host as well.  It works a little
> differently from the existing ESX modules in that it uses the VMware perl
> API directly instead of calling the helper apps.  In addition, it also
> greatly reduces the amount of disk space and deployment time necessary.
>
> Instead of cloning the VM for deployment, this module uses ESX to create a
> snapshot of the golden image disk, and uses that for the deployed VM.  This
> means the only disk space used for the deployed VM is the differences
> between it and the master.  Likewise, no time is needed to copy all the
> bits, so creating the VM takes seconds instead of minutes.
>
>
> Internally we call the module 'esxduke' to distinguish it from the existing
> ESX module.  Going forward is there a better name for this module?  Also,
> what should be done from here to have this included in VCL?
>
>
> Thanks,
>
>
> Sean
>
> #!/usr/bin/perl -w
>
> ###############################################################################
> # Copyright 2010 Duke University and Apache Software Foundation
> #
> # 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.
>
> ###############################################################################
>
> package VCL::Module::Provisioning::esxduke;
>
> # 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);
>
> # Use VMware's perl libraries
> use VMware::VIRuntime;
> use VMware::VILib;
> use VMware::VIExt;
>
>
>
>
> ##############################################################################
>
> =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;
>
>
> ##############################################################################
>
> =head1 OBJECT METHODS
>
> =cut
>
>
> #/////////////////////////////////////////////////////////////////////////////
>
> =head2 initialize
>
>  Parameters  :
>  Returns     :
>  Description :
>
> =cut
>
> # A provisioning object is created for each request.  So this initialize is
> done once per request.
> sub initialize {
>        my $self = shift;
>        if (!defined ($self) ) {
>                return 0;
>        }
>        notify($ERRORS{'DEBUG'}, 0, "Duke vmware ESX module initialized");
>        return 1;
> } ## end sub initialize
>
> sub _checkConnection{
>        my $self = shift;
>        if (!$VMware::VICommon::is_connected) {
>                # Login to the ESX/VC server
>                my $retval;
>                eval {
>                        local $SIG{__DIE__};   # We don't want vcld's die
> handler getting this
>                        $retval = Util::connect('https://' .
> $self->data->get_vmhost_hostname . "/sdk/webService",
> $self->data->get_vmhost_profile_username(),
> $self->data->get_vmhost_profile_password());
>                };
>                if ($@ || !$retval) {
>                        notify($ERRORS{'CRITICAL'}, 0, "Could not login to "
> . $self->data->get_vmhost_hostname . ": " . $@);
>                        return 0;
>                }
>        }
>        return 1;
> }
>
>
> #/////////////////////////////////////////////////////////////////////////////
>
> =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) !~ /esxduke/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 $user_name            = $self->data->get_user_login_id . "@" .
> $self->data->get_user_affiliation_name;
>
>        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 $vmhost_username = $self->data->get_vmhost_profile_username();
>        my $vmhost_password = $self->data->get_vmhost_profile_password();
>
>        $vmhost_hostname =~ /([-_a-zA-Z0-9]*)(\.?)/;
>        my $vmhost_shortname = $1;
>
>        $self->_checkConnection();
>
>        notify($ERRORS{'OK'},    0, "Entered ESX Duke module, loading
> $image_name on $computer_shortname (on $vmhost_hostname) for $user_name
> (reservation $reservation_id)");
>
>        my $newVm;
>        my $newVmPath;
>        my $task;
>        my $vmView = $self->_getvmView(0);
>        my $imageDatastore;
>        my $datacenter;
>
>        my $fileManager = VIExt::get_file_manager();
>
>        # These should be somehow configurable in the future
>        my $resourcePoolName = "VCL-TEST";
>        my $folderName = "VCL-TEST";
>        my $datastoreName = "VCL-TEST-01";
>
>        if(open(CONF, "/etc/vcl/vcld.conf")){
>                my  @conf=<CONF>;
>                close(CONF);
>                foreach $line (@conf) {
>                  #resourcePool
>                  if($line =~ /^RESOURCEPOOLNAME=([\S]*)/){
>                                chomp($line);
>                                $resourcePoolName=$1;
>                        }
>                        #folderName
>                        if($line =~ /^FOLDERNAME=([\S]*)/){
>                                chomp($line);
>                                $folderName=$1;
>                        }
>                        #datastoreName
>                        if($line =~ /^DATASTORENAME=([\S]*)/){
>                                chomp($line);
>                                $datastoreName=$1;
>                        }
>                }
>        }
>
>        # Get some info on our base image
>        my $imageView = $self->_getimageView();
>        if (! $imageView) {
>                return 0;
>        }
>
>        my $parentView = Vim::get_view(mo_ref => $imageView->{parent});
>        while (ref($parentView) ne 'Datacenter') {
>                $parentView = Vim::get_view(mo_ref =>
> $parentView->{parent});
>        }
>        $datacenter = $parentView;
>
>        $imageDatastore = Vim::get_view(mo_ref =>
> @{$imageView->{datastore}}[0]);
>
>        my $resourcePool = Vim::find_entity_view(view_type =>
> 'ResourcePool', filter => {'name' => $resourcePoolName}, begin_entity =>
> $datacenter);
>        if (! defined($resourcePool)) {
>                notify($ERRORS{'WARNING'}, 0, "ERROR: esxduke->load could
> not find resource pool $resourcePoolName");
>                return 0;
>        }
>        my $folder = Vim::find_entity_view(view_type => 'Folder', filter =>
> {'name' => $folderName}, begin_entity => $datacenter);
>        if (! defined($folder)) {
>                notify($ERRORS{'WARNING'}, 0, "ERROR: esxduke->load could
> not find folder $folderName");
>                return 0;
>        }
>
>        if ($vmView) {
>                notify($ERRORS{'DEBUG'}, 0, "Removing old copy of
> $computer_shortname");
>                if (!$self->_removeOldVM()) {
>                        return 0;
>                }
>        }
>
>        # Copy file down
>        my $service = Vim::get_vim_service();
>        my ($mode, $datacenter_foo, $datastore, $filepath) =
> VIExt::parse_remote_path($imageView->{config}->{files}->{vmPathName});
>        #my ($mode, $datacenter_foo, $datastore, $filepath) =
> VIExt::parse_remote_path($imageView->{config}->{files}->{vmPathName});
>        $filepath =~ m/(.*)\/.*/;
>        my $imageDir = $1;
>        my $resp = VIExt::http_get_file($mode, $filepath, $datastore,
> $datacenter->{name});
>        if (!defined($resp) || !$resp->is_success) {
>                notify($ERRORS{'WARNING'}, 0, "ERROR: esxduke->load could
> not get config for $image_name");
>                return 0;
>        }
>        # Edit file
>        my $newvmx = $resp->content;
>        $newvmx =~ s/^displayName = .*$/displayName =
> \"$computer_shortname\"/gm;
>        $newvmx =~ s/^extendedConfigFile = .*$/extendedConfigFile =
> \"$computer_shortname.vmxf\"/gm;
>        $newvmx =~ s/^scsi0:0.filename = .*$/scsi0:0.filename = \"FOO\"/gm;
>        $newvmx =~ s/^nvram = .*$/nvram = \"$computer_shortname.nvram\"/gm;
>
>        $newvmx =~ s/^uuid.location = .*$//gm;
>        $newvmx =~ s/^uuid.bios = .*$//gm;
>        $newvmx =~ s/^sched.swap.derivedName = .*$//gm;
>        $newvmx =~ s/^sched.mem.max = .*$//gm;
>        $newvmx =~ s/^annotation = .*$//gm;
>        my $timeStr = localtime;
>        $newvmx .= "annotation = \"$image_name created for $user_name at
> $timeStr\"\n";
>
>        $newvmx =~ s/^ethernet0.networkName = .*$/ethernet0.networkName =
> \"$virtualswitch0\"/gm;
>        $newvmx =~ s/^ethernet1.networkName = .*$/ethernet1.networkName =
> \"$virtualswitch1\"/gm;
>
>        if (!$VMWARE_MAC_ETH0_GENERATED && defined($vmclient_eth0MAC)) {
>                # Make sure the address type is set right and we have a
> .address line
>                if ($newvmx !~ /^ethernet0.addressType = \"static\"$/m) {
>                        $newvmx .= "ethernet0.addressType = \"static\"\n";
>                        $newvmx .= "ethernet0.address = \"XXX\"\n";
>                }
>                $newvmx =~ s/^ethernet0.address = .*$/ethernet0.address =
> \"$vmclient_eth0MAC\"/gm;
>        } else {
>                $newvmx =~ s/^ethernet0.addressType =
> \"static\"$/ethernet0.addressType = \"generated\"/gm;
>        }
>        if (!$VMWARE_MAC_ETH1_GENERATED && defined($vmclient_eth1MAC)) {
>                # Make sure the address type is set right and we have a
> .address line
>                if ($newvmx !~ /^ethernet1.addressType = \"static\"$/m) {
>                        $newvmx .= "ethernet1.addressType = \"static\"\n";
>                        $newvmx .= "ethernet1.address = \"XXX\"\n";
>                }
>                $newvmx =~ s/^ethernet1.address = .*$/ethernet1.address =
> \"$vmclient_eth1MAC\"/gm;
>        } else {
>                $newvmx =~ s/^ethernet1.addressType =
> \"static\"$/ethernet1.addressType = \"generated\"/gm;
>        }
>
>        my $imageDSUUID;
>        if (defined($imageDatastore->{vmfs}->{uuid})) {
>                $imageDSUUID = $imageDatastore->{vmfs}->{uuid};
>        } else {
>                # Use the name if its NFS, not preferred, but I don't know
> how to get the UUID for an NFS datastore
>                $imageDSUUID = $imageDatastore->info->name;
>        }
>
>        # This is ugly, but I don't know a better way to make sure I catch
> all the disks.  If anyone has a better way, please let me know
>        my @vmxlines = split(/\n/, $newvmx);
>        for $line (@vmxlines) {
>                # Make sure the scsi filename isn't an absolute path before
> we make it an absolute path
>                if ($line !~ /scsi\d:\d{1,2}.fileName = "\/.*"/) {
>                        $line =~ s/scsi(\d:\d{1,2}).fileName =
> "(.*)"/scsi$1.fileName = "\/vmfs\/volumes\/$imageDSUUID\/$imageDir\/$2"/;
>                }
>        }
>        $newvmx = join("\n", @vmxlines) . "\n";
>
>        # Upload
>        # Need to make sure this directory doesn't already exist...
>        _deleteDirectory($datastoreName, $computer_shortname, $datacenter);
>        eval {
>                $fileManager->MakeDirectory(name => "[$datastoreName] " .
> $computer_shortname, datacenter => $datacenter);
>        };
>        if ($@) {
>                notify($ERRORS{'WARNING'}, 0, "ERROR: Unable to create
> directory [$datastoreName] " . $computer_shortname . ": " .
> ($@->fault_string));
>                return 0;
>        }
>
>        # Based on VIExt::http_put_file
>        my $serviceURI = URI::URL->new($service->{vim_soap}->{url});
>        my $userAgent = $service->{vim_soap}->{user_agent};
>
>        $newVmPath = $computer_shortname . "/" . $computer_shortname .
> ".vmx";
>        my $attempt = 1;
>        while ($attempt <= 3) {
>                my $req = VIExt::build_http_request("PUT", "folder",
> $serviceURI, $newVmPath, $datastoreName, $datacenter->{name});
>                $req->header('Content-Type', 'application/octet-stream');
>                $req->header('Content-Length', length($newvmx));
>                $req->content($newvmx);
>                $resp = $userAgent->request($req);
>                if (!$resp || !$resp->is_success) {
>                        notify($ERRORS{'WARNING'}, 0, "ERROR: Unable to
> upload [$datastoreName] $newVmPath: " . $resp->message . ": " .
> $resp->content);
>                        $attempt += 1;
>                        sleep 3;
>                        next;
>                } else {
>                        last;
>                }
>        }
>
>        if (!$resp || !$resp->is_success) {
>                return 0;
>        }
>        if ($attempt > 1) {
>                notify($ERRORS{'OK'}, 0, "Uploaded new vmx file on attempt
> number $attempt");
>        }
>
>        $newVmPath = "[$datastoreName]" . " $newVmPath";
>
>        $attempt = 1;
>        my $result;
>        while ($attempt <= 3) {
>                $task = $folder->RegisterVM_Task(path => $newVmPath, name =>
> $computer_shortname, asTemplate => "false", pool => $resourcePool);
>                $result = _checkTask($task, "registering
> $computer_shortname");
>                if (!$result) {
>                        $attempt += 1;
>                        sleep 3;
>                        next;
>                } else {
>                        last;
>                }
>        }
>
>        if (!$resp) {
>                return 0;
>        }
>        if ($attempt > 1) {
>                notify($ERRORS{'OK'}, 0, "Registered VM on attempt number
> $attempt");
>        }
>
>        $vmView = $self->_getvmView();
>
>        $task = $vmView->CreateSnapshot_Task(name => 'linked clone from
> vcl-image-' . $self->data->get_image_name, memory => "false", quiesce =>
> "true");
>        if (!_checkTask($task, "creating snapshot of $computer_shortname"))
> {
>                return 0;
>        }
>
>        if ($vmclient_OSname =~ /winxp/) {
>                # I am hard coding this for now... I am sure we can pass it
> in or read it from the db
>                _customizeVm('vcl-xp', $computer_shortname , $vmView);
>        }
>
>        $task = $vmView->PowerOnVM_Task();
>        if (!_checkTask($task, "powering on $computer_shortname")) {
>                return 0;
>        }
>
>
>        #Set some variable
>        my $wait_loops = 0;
>        my $arpstatus  = 0;
>        my $client_ip;
>
>        if ($VMWARE_MAC_ETH0_GENERATED) {
>                # allowing vmware to generate the MAC address
>                # find out what MAC got assigned
>                # find out what IP address is assigned to this MAC
>                my $devices = $vmView->config->hardware->device;
>                my $mac_addr;
>                foreach my $dev (@$devices) {
>                        next unless ($dev->isa("VirtualEthernetCard"));
>                        notify($ERRORS{'DEBUG'}, 0, "deviceinfo->summary:
> $dev->deviceinfo->summary");
>                        notify($ERRORS{'DEBUG'}, 0, "virtualswitch0:
> $virtualswitch0");
>                        if ($dev->deviceInfo->summary eq $virtualswitch0) {
>                                $mac_addr = $dev->macAddress;
>                                last;
>                        }
>                }
>                if (!$mac_addr) {
>                        notify($ERRORS{'WARNING'}, 0, "Failed to find MAC
> address");
>                        return 0;
>                }
>                notify($ERRORS{'DEBUG'}, 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
>                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 > 24) {
>                                        notify($ERRORS{'WARNING'}, 0,
> "waited acceptable amount of time for dhcp, please check $computer_shortname
> on $vmhost_shortname");
>                                        return 0;
>                                }
>                                else {
>                                        $wait_loops++;
>                                        notify($ERRORS{'OK'}, 0, "going to
> sleep 10 seconds, waiting for computer to DHCP. Try $wait_loops");
>                                        sleep 10;
>                                }
>                        } ## end else [ if ($arpoutput =~
> /^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}).*?$mac_addr/mi)
>                } ## end while (!$arpstatus)
>
>
>
>                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`;
>        } ## end if ($VMWARE_MAC_ETH0_GENERATED)
>        else {
>                notify($ERRORS{'DEBUG'}, 0, "IP is known for
> $computer_shortname");
>        }
>        # 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);
>                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 > 150) {
>                                notify($ERRORS{'WARNING'}, 0, "waited
> acceptable amount of time for sshd to become active, please check
> $computer_shortname on $vmhost_shortname");
>                                #need to check power, maybe reboot it. for
> now fail it
>                                return 0;
>                        }
>                        else {
>                                $wait_loops++;
>                                # to give post config a chance
>                                notify($ERRORS{'DEBUG'}, 0, "going to sleep
> 10 seconds, waiting for computer to start SSH. Try $wait_loops");
>                                sleep 10;
>                        }
>                }    # 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...");
> #### Sean
> ### Why call getdynamicaddress?  It doesn't work.  Should we instead just
> write a local method
> #### to get the ip from another means?
> #### Liz
>                        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")
>
>        # Perform post load tasks
>        return 1;
> } ## end sub load
>
> #/////////////////////////////////////////////////////////////////////////
>
> =head2 node_status
>
>  Parameters  : $nodename, $log
>  Returns     : array of related status checks
>  Description : checks on sshd, currentimage
>
> =cut
>
> sub node_status {
>        my $self = shift;
>
>        my ($package, $filename, $line, $sub) = caller(0);
>
>        my $vmpath             = 0;
>        my $datastorepath      = 0;
>        my $requestedimagename = 0;
>        my $vmhost_type        = 0;
>        my $vmhost_hostname    = 0;
>        my $vmhost_imagename   = 0;
>        my $image_os_type      = 0;
>        my $vmclient_shortname = 0;
>        my $request_forimaging = 0;
>        my $identity_keys      = 0;
>        my $log                = 0;
>        my $computer_node_name = 0;
>
>
>        # Check if subroutine was called as a class method
>        if (ref($self) !~ /esxduke/i) {
>                notify($ERRORS{'OK'}, 0, "subroutine was called as a
> function");
>                if (ref($self) eq 'HASH') {
>                        $log = $self->{logfile};
>                        #notify($ERRORS{'DEBUG'}, $log, "self is a hash
> reference");
>
>                        $vmpath             =
> $self->{vmhost}->{vmprofile}->{vmpath};
>                        $datastorepath      =
> $self->{vmhost}->{vmprofile}->{datastorepath};
>                        $requestedimagename =
> $self->{imagerevision}->{imagename};
>                        $vmhost_type        =
> $self->{vmhost}->{vmprofile}->{vmtype}->{name};
>                        $vmhost_hostname    = $self->{vmhost}->{hostname};
>                        $vmhost_imagename   = $self->{vmhost}->{imagename};
>                        $image_os_type      = $self->{image}->{OS}->{type};
>                        $computer_node_name = $self->{computer}->{hostname};
>                        $identity_keys      =
> $self->{managementnode}->{keys};
>
>                } ## end if (ref($self) eq 'HASH')
>                    # Check if node_status returned an array ref
>                elsif (ref($self) eq 'ARRAY') {
>                        notify($ERRORS{'DEBUG'}, $log, "self is a array
> reference");
>                }
>
>                $vmclient_shortname = $1 if ($computer_node_name =~
> /([-_a-zA-Z0-9]*)(\.?)/);
>        } ## end if (ref($self) !~ /esx/i)
>        else {
>
>                # try to contact vm
>                # $self->data->get_request_data;
>                # get state of vm
>                $vmpath             =
> $self->data->get_vmhost_profile_vmpath;
>                $datastorepath      =
> $self->data->get_vmhost_profile_datastore_path;
>                $requestedimagename = $self->data->get_image_name;
>                $vmhost_type        = $self->data->get_vmhost_type;
>                $vmhost_hostname    = $self->data->get_vmhost_hostname;
>                $vmhost_imagename   = $self->data->get_vmhost_image_name;
>                $image_os_type      = $self->data->get_image_os_type;
>                $vmclient_shortname = $self->data->get_computer_short_name;
>                $request_forimaging = $self->data->get_request_forimaging();
>        } ## end else [ if (ref($self) !~ /esx/i)
>
>        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};
>        }
>
>        #
>        #my $vmx_directory = "$requestedimagename$vmclient_shortname";
>        #my $myvmx         =
> "$vmpath/$requestedimagename$vmclient_shortname/$requestedimagename$vmclient_shortname.vmx";
>        #my $mybasedirname = $requestedimagename;
>        #my $myimagename   = $requestedimagename;
>
>        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 @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) !~ /esxduke/i) {
>                notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a
> function, it must be called as a class method");
>                return 0;
>        }
>
>        my $image_view = $self->_getimageView(0);
>        if (! $image_view) {
>                return 0;
>        }
>        return 1;
>
> } ## end sub does_image_exist
>
>
> #/////////////////////////////////////////////////////////////////////////////
>
> =head2  getimagesize
>
>  Parameters  : imagename
>  Returns     : 0 failure or size of image
>  Description : in size of Kilobytes
>
> =cut
>
> # Need to implement
> sub get_image_size {
>        my $self = shift;
>        if (ref($self) !~ /esxduke/i) {
>                notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a
> function, it must be called as a class method");
>                return 0;
>        }
>
>        # Just a placeholder - not sure if this value even matters
>        return 1;
> } ## end sub get_image_size
>
> sub power_off {
>        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 0;
>        }
>
>        my $task;
>        my $computer_shortname = $self->data->get_computer_short_name;
>        my $vmView = $self->_getvmView();
>        if (!$vmView) {
>                return 0;
>        }
>        if ($vmView->{runtime}->{powerState}->val eq "poweredOff") {
>                # VM is turned off, so just return happily
>                return 1;
>        }
>        $task = $vmView->PowerOffVM_Task();
>        if (!_checkTask($task, "powering off " . $computer_shortname)) {
>                return 0;
>        }
>        return 1;
> }
>
> sub power_on {
>        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 0;
>        }
>
>        my $task;
>        my $computer_shortname = $self->data->get_computer_short_name;
>        my $vmView = $self->_getvmView();
>        if (!$vmView) {
>                return 0;
>        }
>        if ($vmView->{runtime}->{powerState}->val eq "poweredOn") {
>                # VM is turned on, so just return happily
>                return 1;
>        }
>        $task = $vmView->PowerOnVM_Task();
>        if (!_checkTask($task, "powering on " . $computer_shortname)) {
>                return 0;
>        }
>        return 1;
> }
>
> sub power_reset {
>        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 0;
>        }
>
>        my $task;
>        my $computer_shortname = $self->data->get_computer_short_name;
>        my $vmView = $self->_getvmView();
>        if (!$vmView) {
>                return 0;
>        }
>        $task = $vmView->ResetVM_Task();
>        if (!_checkTask($task, "reseting on " . $computer_shortname)) {
>                return 0;
>        }
>        return 1;
> }
>
> sub power_status {
>        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 0;
>        }
>
>        my $task;
>        my $computer_shortname = $self->data->get_computer_short_name;
>        my $vmView = $self->_getvmView();
>        if (!$vmView) {
>                return;
>        }
>        $vmView->update_view_data();
>        if ($vmView->runtime->powerState->val eq 'poweredOn') {
>                return "on";
>        } elsif ($vmView->runtime->powerState->val eq 'poweredOff') {
>                return "off";
>        } else {
>                notify($ERRORS{'WARNING'}, 0, "Unable to determin power
> status.  VMware reports powerState: " . $vmView->runtime->powerState->val);
>                return;
>        }
> }
>
>
> #/////////////////////////////////////////////////////////////////////////////
>
> =head2 capture
>
>  Parameters  : $request_data_hash_reference
>  Returns     : 1 if sucessful, 0 if failed
>  Description : Creates a new vmware image.
>
> =cut
>
> sub capture {
>        my $self = shift;
>        if (ref($self) !~ /esxduke/i) {
>                notify($ERRORS{'CRITICAL'}, 0, "subroutine was called as a
> function, it must be called as a class method");
>                return 0;
>        }
>
>        my ($package, $filename, $line, $sub) = caller(0);
>
>        # Store some hash variables into local variables
>        # to pass to write_current_image routine
>        my $request_data = $self->data->get_request_data;
>
>        if (!$request_data) {
>                notify($ERRORS{'WARNING'}, 0, "unable to retrieve request
> data hash");
>                return 0;
>        }
>
>        # Store some hash variables into local variables
>        my $request_id     = $self->data->get_request_id;
>        my $reservation_id = $self->data->get_reservation_id;
>
>        my $image_id       = $self->data->get_image_id;
>        my $image_os_name  = $self->data->get_image_os_name;
>        my $image_identity = $self->data->get_image_identity;
>        my $image_os_type  = $self->data->get_image_os_type;
>        my $image_name     = $self->data->get_image_name();
>
>        my $computer_id        = $self->data->get_computer_id;
>        my $computer_shortname = $self->data->get_computer_short_name;
>        my $computer_nodename  = $computer_shortname;
>        my $computer_hostname  = $self->data->get_computer_hostname;
>        my $computer_type      = $self->data->get_computer_type;
>
>        my $vmtype_name             = $self->data->get_vmhost_type_name;
>        my $vmhost_vmpath           =
> $self->data->get_vmhost_profile_vmpath;
>        my $vmprofile_vmdisk        =
> $self->data->get_vmhost_profile_vmdisk;
>        my $vmprofile_datastorepath =
> $self->data->get_vmhost_profile_datastore_path;
>        my $vmhost_hostname         = $self->data->get_vmhost_hostname;
>        my $host_type               = $self->data->get_vmhost_type;
>        my $vmhost_imagename        = $self->data->get_vmhost_image_name;
>
>        my ($hostIdentity, $hostnodename);
>        if ($host_type eq "blade") {
>                $hostnodename = $1 if ($vmhost_hostname =~
> /([-_a-zA-Z0-9]*)(\.?)/);
>                $hostIdentity = $IDENTITY_bladerhel;
>        }
>        else {
>                #using FQHN
>                $hostnodename = $vmhost_hostname;
>                $hostIdentity = $IDENTITY_linux_lab if ($vmhost_imagename =~
> /^(realmrhel)/);
>        }
>        # Assemble a consistent prefix for notify messages
>        my $notify_prefix = "req=$request_id, res=$reservation_id:";
>
>
>        # Print some preliminary information
>        notify($ERRORS{'OK'}, 0, "$notify_prefix new name: $image_name");
>        notify($ERRORS{'OK'}, 0, "$notify_prefix computer_name:
> $computer_shortname");
>        notify($ERRORS{'OK'}, 0, "$notify_prefix vmhost_hostname:
> $vmhost_hostname");
>        notify($ERRORS{'OK'}, 0, "$notify_prefix vmtype_name:
> $vmtype_name");
>
>        my $vmView = $self->_getvmView();
>        if (!$vmView) {
>                return 0;
>        }
>
>        my $imageFolderName = "VCL-TEST";
>        my $imageDatastoreName = "VCL-IMAGES-TEST-01";
>
>        if(open(CONF, "/etc/vcl/vcld.conf")){
>                my  @conf=<CONF>;
>                close(CONF);
>                foreach $line (@conf) {
>                        #folderName
>                        if($line =~ /^IMAGEFOLDERNAME=([\S]*)/){
>                                chomp($line);
>                                $imageFolderName=$1;
>                        }
>                        #datastoreName
>                        if($line =~ /^IMAGEDATASTORENAME=([\S]*)/){
>                                chomp($line);
>                                $imageDatastoreName=$1;
>                        }
>                }
>        }
>
>        my $parentView = Vim::get_view(mo_ref => $vmView->{parent});
>        while (ref($parentView) ne 'Datacenter') {
>                $parentView = Vim::get_view(mo_ref =>
> $parentView->{parent});
>        }
>        my $datacenter = $parentView;
>        my $datastoreView;
>        my $datastores = Vim::get_views(mo_ref_array =>
> $datacenter->{datastore});
>        foreach (@$datastores) {
>                if ($_->{info}->{name} eq $imageDatastoreName) {
>                        $datastoreView = $_;
>                        last;
>                }
>        }
>        if (!defined($datastoreView)) {
>                notify($ERRORS{'CRITICAL'}, 0, "Unable to find datastore
> $imageDatastoreName");
>                return 0;
>        }
>        my $folder = Vim::find_entity_view(view_type => 'Folder', filter =>
> {'name' => $imageFolderName}, begin_entity => $datacenter);
>        if (! defined($folder)) {
>                notify($ERRORS{'CRITICAL'}, 0, "ERROR: esxduke->capture
> could not find folder $imageFolderName");
>                return 0;
>        }
>
>        # Modify currentimage.txt
>        if (write_currentimage_txt($self->data)) {
>                notify($ERRORS{'OK'}, 0, "$notify_prefix currentimage.txt
> updated on $computer_shortname");
>        }
>        else {
>                notify($ERRORS{'WARNING'}, 0, "$notify_prefix unable to
> update currentimage.txt on $computer_shortname");
>                return 0;
>        }
>
>        # Set some vm paths and names
>        my $vmx_directory  = "$reservation_id$computer_shortname";
>        my $vmx_image_name = "$reservation_id$computer_shortname";
>        my $vmx_path       =
> "$vmhost_vmpath/$vmx_directory/$vmx_image_name.vmx";
>
>        my @sshcmd;
>
>        # Check if pre_capture() subroutine has been implemented by the OS
> module
>        if ($self->os->can("pre_capture")) {
>                # Call OS pre_capture() - it should perform all OS steps
> necessary to capture an image
>                # pre_capture() should shut down the computer when it is
> done
>                notify($ERRORS{'OK'}, 0, "calling OS module's pre_capture()
> subroutine");
>
>                if (!$self->os->pre_capture({end_state => 'off'})) {
>                        notify($ERRORS{'WARNING'}, 0, "OS module
> pre_capture() failed");
>                        return 0;
>                }
>
>        }
>        # Get the power status, make sure computer is off
>        my $power_status = $self->power_status();
>        notify($ERRORS{'DEBUG'}, 0, "retrieved power status:
> $power_status");
>        if ($power_status eq 'off') {
>                notify($ERRORS{'OK'}, 0, "verified $computer_nodename power
> is off");
>        }
>        elsif ($power_status eq 'on') {
>                notify($ERRORS{'WARNING'}, 0, "$computer_nodename power is
> still on, turning computer off");
>
>                # Attempt to power off computer
>                if ($self->power_off()) {
>                        notify($ERRORS{'OK'}, 0, "$computer_nodename was
> powered off");
>                }
>                else {
>                        notify($ERRORS{'WARNING'}, 0, "failed to power off
> $computer_nodename");
>                        return 0;
>                }
>        }
>        else {
>                notify($ERRORS{'WARNING'}, 0, "failed to determine power
> status of $computer_nodename");
>                return 0;
>        }
>
>        # Clone with new image name: $image_name
>
>        my $relocateSpec = VirtualMachineRelocateSpec->new(datastore =>
> $datastoreView, transform =>
> VirtualMachineRelocateTransformation->new('sparse'));
>        my $cloneSpec = VirtualMachineCloneSpec->new(powerOn => 0, template
> => 1, location => $relocateSpec);
>
>        notify($ERRORS{'OK'}, 0, "Cloning $computer_shortname to
> vcl-image-$image_name");
>
>        my $task = $vmView->CloneVM_Task(folder => $folder, name =>
> "vcl-image-" . $image_name, spec => $cloneSpec);
>        return _checkTask($task, "Cloning $computer_shortname");
>
> } ## end sub capture
>
>
> sub _getvmView {
>        my $self = shift;
>        my $is_warning = shift;
>        my $notify_level = $ERRORS{'WARNING'};
>
>        if (defined($is_warning) && !$is_warning) {
>                $notify_level = $ERRORS{'DEBUG'};
>        }
>
>        unless (ref($self) && $self->isa('VCL::Module')) {
>                notify($ERRORS{'CRITICAL'}, 0, "subroutine can only be
> called as a VCL::Module module object method");
>                return 0;
>        }
>        if (defined($self->{_vmView})) {
>                return $self->{_vmView};
>        }
>
>        $self->_checkConnection();
>        my $computer_shortname   = $self->data->get_computer_short_name;
>        my $vmView = Vim::find_entity_view(view_type => 'VirtualMachine',
> filter => {'name' => $computer_shortname });
>        if (!$vmView) {
>                notify($notify_level, 0, "Could not find VM
> $computer_shortname");
>                return 0;
>        }
>        $self->{_vmView} = $vmView;
>
>        return $vmView;
> }
>
> sub _getimageView {
>        my $self = shift;
>        my $is_crit = shift;
>        my $notify_level = $ERRORS{'CRITICAL'};
>
>        if (defined($is_crit) && !$is_crit) {
>                $notify_level = $ERRORS{'DEBUG'};
>        }
>
>        unless (ref($self) && $self->isa('VCL::Module')) {
>                notify($ERRORS{'CRITICAL'}, 0, "subroutine can only be
> called as a VCL::Module module object method");
>                return 0;
>        }
>        if (defined($self->{_imageView})) {
>                return $self->{_imageView};
>        }
>
>        $self->_checkConnection();
>        my $image_name = $self->data->get_image_name;
>        my $imageView = Vim::find_entity_view(view_type => 'VirtualMachine',
> filter => {'name' => "vcl-image-$image_name"});
>        if (!$imageView) {
>                notify($notify_level, 0, "Could not find image
> vcl-image-$image_name");
>                return 0;
>        }
>        if ($imageView->{snapshot}) {
>                # This is always crit. If we're called from does_image_exist
> we want to log the weird state of the image existing but being invalid
>                notify($ERRORS{'CRITICAL'}, 0, "ERROR: vcl-image-$image_name
> is an invalid image, it has a snapshot");
>                return 0;
>        }
>        $self->{_imageView} = $imageView;
>
>        return $imageView;
> }
>
> sub _removeOldVM {
>
>        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 0;
>        }
>
>        my $task;
>        my (@deviceSpecs, $vmDevices, $vmConfigSpec);
>
>        my $vmView = $self->_getvmView();
>
>        if ($vmView->{runtime}->{powerState}->val ne "poweredOff") {
>                notify($ERRORS{'DEBUG'}, 0, "Powering off " .
> $vmView->{name});
>                $task = $vmView->PowerOffVM_Task();
>                if (!_checkTask($task, "powering off " . $vmView->{name})) {
>                        return 0;
>                }
>        }
>
>        # We simply unregister the VM.  The _deleteDirectory function will
>        # clean up the files.  If we were to Destroy the VM, VMware would
>        # wipe out the disk of the image, which we need to avoid.
>        $vmView->UnregisterVM();
>
>        $self->{_vmView} = undef;
>        return 1;
>
> }
>
> sub _checkTask {
>        my ($task, $taskName) = @_;
>
>        my $taskView = Vim::get_view(mo_ref => $task);
>        while (1) {
>                # Sometimes FileManager->DeleteDatastoreFile() gives us an
> odd task, so this is to give us a shot of making it a normal task
>                if (!defined $taskView->{info}) {
>                        my $attempt = 1;
>                        while ($attempt <= 3) {
>                                $taskView->update_view_data();
>                                if (defined $taskView->{info}) {
>                                        last;
>                                } else {
>                                        $attempt += 1;
>                                        sleep 1;
>                                }
>                        }
>                        if (!defined $taskView->{info}) {
>                                notify($ERRORS{'WARNING'}, 0, "ERROR: Could
> not get valid task for $taskName");
>                                return 0;
>                        }
>                }
>
>                if ($taskView->info->state->val eq "success") {
>                        return 1;
>                } elsif ($taskView->info->state->val eq "error") {
>                        notify($ERRORS{'WARNING'}, 0, "ERROR: $taskName: " .
> $taskView->info->error->localizedMessage);
>                        return 0;
>                }
>                sleep 1;
>                $taskView->update_view_data();
>        }
> }
>
> sub _customizeVm {
>        my ($customSpec, $nodeName, $view ) = @_;
>
>        my $customView = Vim::get_view(mo_ref =>
> Vim::get_service_content()->customizationSpecManager);
>        my $customizationSpec = $customView->GetCustomizationSpec ('name' =>
> $customSpec)->spec;
>
>        # We need to set the machine name in this spec
>        _setMachineName($nodeName, $customizationSpec);
>        my $task = $view->CustomizeVM_Task(spec => $customizationSpec);
>        if (_checkTask($task, "customizing $nodeName")){
>                notify($ERRORS{'OK'}, 0, "success setting custom specs");
>        }
> }
>
> sub _setMachineName {
>        my ($vmName, $customizationSpec) = @_;
>
>        my @machineName = split(/\./,$vmName);
>        my $cust_name = CustomizationFixedName->new (name =>
> $machineName[0]);
>        $customizationSpec->identity->userData->computerName ($cust_name);
>        return;
> }
>
> sub _deleteDirectory {
>        my ($dsName, $dirname, $datacenter) = @_;
>        my $ds;
>
>        foreach my $ds2 (@{$datacenter->{'datastore'}}) {
>                my $ds_view = Vim::get_view(mo_ref => $ds2);
>                if ($ds_view->info->name eq $dsName) {
>                        $ds = $ds_view;
>                        last;
>                }
>        }
>
>        if (!defined($ds)) {
>                notify($ERRORS{'WARNING'}, 0, "Could not find datastore
> $dsName");
>                return 0;
>        }
>
>        my $ds_browser = Vim::get_view(mo_ref => $ds->browser);
>
>        my $search_spec = HostDatastoreBrowserSearchSpec->new(matchPattern
> => [$dirname]);
>        my $browse_result = $ds_browser->SearchDatastore(datastorePath =>
> "[$dsName]", searchSpec => $search_spec);
>        # Only do the delete if the file exists
>        if (defined $browse_result->file) {
>                eval {
>                        my $fileManager = Vim::get_view(mo_ref =>
> Vim::get_service_content()->fileManager);
>                        my $task =
> $fileManager->DeleteDatastoreFile_Task(name => "[$dsName] $dirname",
> datacenter => $datacenter);
>                        if (!_checkTask($task, "deleting [$dsName]
> $dirname")) {
>                                return 0;
>                        }
>                };
>                if ($@) {
>                        notify($ERRORS{'WARNING'}, 0, "Error trying to
> delete [$dsName] $dirname: " . ($@->fault_string));
>                }
>        }
> }
>
>
>
> initialize();
>
> END {
>        Util::disconnect();
> }
>
>
> #/////////////////////////////////////////////////////////////////////////////
>
> 1;
> __END__
>
> =head1 SEE ALSO
>
> L<http://cwiki.apache.org/VCL/>
>
> =cut
>
>