You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@vcl.apache.org by Sean Dilda <se...@duke.edu> on 2010/02/24 22:16:41 UTC

Yet Another VMware ESX Provisioning Module

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

Re: Yet Another VMware ESX Provisioning Module

Posted by Jeffrey Wisman <je...@csueastbay.edu>.
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
>
>