Hi,

On Fri, Apr 08, 2011 at 11:38:23AM +0200, Nhan Ngo Dinh wrote:
> Logging added

Many thanks. Please see below for a few more comments, mainly
about the meta-data.

Lars, any more comments on from you?

Cheers,

Dejan

> Regards,
> Nhan

> #!/usr/bin/perl
> #
> # External STONITH module for VMWare vCenter/ESX
> #
> # Author:  Nhan Ngo Dinh
> # License: GNU General Public License (GPL)
> #
> 
> require 5.010;
> 
> use strict;
> use warnings;
> use VMware::VIRuntime;
> 
> sub dielog {
>       my $msg = "[";
>       $msg .= "$ARGV[0]" if defined($ARGV[0]);
>       $msg .= " $ARGV[1]" if defined($ARGV[1]);
>       $msg .= "]";
>       ( $_ ) = @_;
>       $msg .= " $_";
>       system("ha_log.sh", "err", "$msg");
>       die();
> }
> 
> # Define command groups
> my @configCommands = qw{getconfignames getinfo-devid getinfo-devname 
> getinfo-devdescr getinfo-devurl getinfo-xml};
> my @actionCommands = qw{reset on off};
> my @netCommands = (@actionCommands, qw{status gethosts});
> 
> # Process command line arguments
> my $command = $ARGV[0] || dielog("No command specified\n");
> 
> # Command belongs to the group of commands that do not require any connection 
> to VMware vCenter
> if ($command ~~ @configCommands) {
>       if ($command eq "getconfignames") {
>               print 
> "VI_SERVER\nVI_PORTNUMBER\nVI_PROTOCOL\nVI_SERVICEPATH\nVI_CREDSTORE\nHOSTLIST\nRESETPOWERON\n";
>       }
>       elsif ($command eq "getinfo-devid") {
>               print "VMware vCenter STONITH device\n";
>       }
>       elsif ($command eq "getinfo-devname") {
>               print "VMware vCenter STONITH device\n";
>       }
>       elsif ($command eq "getinfo-devdescr") {
>               print "VMWare vCenter STONITH device\n";
>       }
>       elsif ($command eq "getinfo-devurl") {
>               print "http://www.vmware.com/\n";;
>       }
>       elsif ($command eq "getinfo-xml") {
>               print q{<parameters>
> <parameter name="HOSTLIST" required="1">
> <content type="string"/>
> <shortdesc lang="en">List of hosts and virtual machines (required)</shortdesc>
> <longdesc lang="en">
> The list of hosts that the VMware vCenter STONITH device controls.
> Syntax is:
>   hostname1[=VirtualMachineName1];hostname2[=VirtualMachineName2]
> 
> NOTE: omit =VirtualMachineName if hostname and virtual machine names are 
> identical
> 
> Example:
>   cluster1=VMCL1;cluster2=VMCL2
> </longdesc>
> </parameter>
> <parameter name="VI_SERVER">
> <content type="string"/>
> <shortdesc lang="en">VMware vCenter address</shortdesc>
> <longdesc lang="en">
> The VMware vCenter address (default: localhost)

The defaults should go into the content element (see other
stonith plugins, e.g. external/ipmi).

> </longdesc>
> </parameter>
> <parameter name="VI_PROTOCOL">
> <content type="string"/>
> <shortdesc lang="en">VMware vCenter protocol</shortdesc>
> <longdesc lang="en">
> The VMware vCenter protocol (default: https)
> </longdesc>
> </parameter>
> <parameter name="VI_PORTNUMBER">
> <content type="string"/>
> <shortdesc lang="en">VMware vCenter port number</shortdesc>
> <longdesc lang="en">
> The VMware vCenter port number (default: 443)
> </longdesc>
> </parameter>
> <parameter name="VI_SERVICEPATH">
> <content type="string"/>
> <shortdesc lang="en">VMware vCenter service path</shortdesc>
> <longdesc lang="en">
> The VMware vCenter services path (default: /sdk)
> </longdesc>
> </parameter>
> <parameter name="VI_CREDSTORE" required="1">
> <content type="string"/>
> <shortdesc lang="en">VMware vCenter credentials store file</shortdesc>
> <longdesc lang="en">
> VMware vCenter credentials store file
> </longdesc>
> </parameter>
> <parameter name="RESETPOWERON">
> <content type="string"/>
> <shortdesc lang="en">PowerOnVM on reset</shortdesc>
> <longdesc lang="en">
> Enable/disable a PowerOnVM on reset when the target virtual machine is off
> Allowed values: 0, 1

This should default to 1. For better or worse, that's what
stonith prescribes and other plugins adhere to.

> </longdesc>
> </parameter>
> </parameters>} . "\n";
>       }
>       else { dielog("Invalid command specified: $command\n"); }
> }
> 
> # Command belongs to the group of commands that require connecting to VMware 
> vCenter
> elsif ($command ~~ @netCommands) {
> 
>       # A valid VI_CREDSTORE is required to avoid interactive prompt
>       ( exists $ENV{'VI_CREDSTORE'} ) || dielog("VI_CREDSTORE not 
> specified\n");
> 
>       # HOSTLIST is mandatory
>       exists $ENV{'HOSTLIST'} || dielog("HOSTLIST not specified\n");
> 
>       # Parse HOSTLIST to %host_to_vm and %vm_to_host
>       my @hostlist = split(';', $ENV{'HOSTLIST'});
>       my %host_to_vm = ();
>       my %vm_to_host = ();
>       foreach my $host (@hostlist) {
>               my @config = split(/=/, $host);
>               my $key = $config[0]; my $value = $config[1];
>               if (!defined($value)) { $value = $config[0]; }
>               $host_to_vm{$key} = $value;
>               $vm_to_host{(lc $value)} = $key;
>       }
> 
>       eval {
>               # VI API: reads options from the environment variables into 
> appropriate data structures for validation.
>               Opts::parse();
>               # VI API: ensures that input values from environment variable 
> are complete, consistent and valid.
>               Opts::validate();
>               # VI API: establishes a session with the VirtualCenter 
> Management Server or ESX Server Web service
>               Util::connect();
>       };
>       if ($@) {
>               # This is just a placeholder for any error handling procedure
>               dielog($@);
>       }
> 
>       # Command belongs to the group of commands that performs actions on 
> Virtual Machines
>       if ($command ~~ @actionCommands) {
> 
>               my $targetHost = $ARGV[1] || dielog("No target specified\n");
> 
>               # Require that specified target host exists in the specified 
> HOSTLIST
>               if (exists $host_to_vm{$targetHost}) {
> 
>                       my $vm;
>                       my $esx;
>                       eval {
>                               # VI API: searches the inventory tree for a 
> VirtualMachine managed entity whose name matches
>                               # the name of the virtual machine assigned to 
> the target host in HOSTLIST
>                               $vm = Vim::find_entity_view(view_type => 
> "VirtualMachine", filter => { name => qr/\Q$host_to_vm{$targetHost}\E/i });
> 
>                               # VI API: retrieves the properties of the 
> managed object reference runtime.host of the VirtualMachine
>                               # managed entity obtained by the previous 
> command
>                               # NOTE: This is essentially a workaround to 
> vSphere Perl SDK
>                               # to allow pointing to the right HostSystem. 
> This is probably
>                               # done by changing the current HostSystem in 
> the Web Service
>                               # session context. WARNING: Do not use the same 
> session for any
>                               # other concurrent operation.
>                               $esx = Vim::get_view(mo_ref => 
> $vm->{"runtime"}{"host"})->name;
>                       };
>                       if ($@) {
>                               if (ref($@) eq "SoapFault") { 
> dielog("$@->detail\n"); }
>                       }
> 
>                       my $powerState = 
> $vm->get_property('runtime.powerState')->val;
>                       if ($powerState eq "suspended") {
>                               # This implementation assumes that suspending a 
> cluster node can cause
>                               # severe failures on shared resources, thus any 
> failover operation should
>                               # be blocked.
>                               dielog("Machine is in a suspended state\n");
>                       }
> 
>                       eval {
>                               if ($command eq "reset") {
>                                       if ($powerState eq "poweredOn") {
>                                               $vm->ResetVM();
>                                               system("ha_log.sh", "info", 
> "Machine $esx:$vm->{'name'} has been reset");
>                                       } else {
>                                               system("ha_log.sh", "warn", 
> "Tried to ResetVM $esx:$vm->{'name'} that was $powerState");
>                                               # Start a virtual machine on 
> reset only if explicitly allowed by RESETPOWERON
>                                               if ($powerState eq "poweredOff" 
> && exists $ENV{'RESETPOWERON'} && $ENV{'RESETPOWERON'} eq 1) {
>                                                       $vm->PowerOnVM();
>                                                       system("ha_log.sh", 
> "info", "Machine $esx:$vm->{'name'} has been powered on");
>                                               }
>                                       }
>                               }
>                               elsif ($command eq "off") {
>                                       if ($powerState eq "poweredOn") {
>                                               $vm->PowerOffVM();
>                                               system("ha_log.sh", "info", 
> "Machine $esx:$vm->{'name'} has been powered off");
>                                       } else {
>                                               system("ha_log.sh", "warn", 
> "Tried to PowerOffVM $esx:$vm->{'name'} that was $powerState");
> 
>                                       }
>                               }
>                               elsif ($command eq "on") {
>                                       if ($powerState eq "poweredOff") {
>                                               $vm->PowerOnVM();
>                                               system("ha_log.sh", "info", 
> "Machine $esx:$vm->{'name'} has been powered on");
>                                       } else {
>                                               system("ha_log.sh", "warn", 
> "Tried to PowerOnVM $esx:$vm->{'name'} that was $powerState");
>                                       }
>                               }
>                               else { dielog("Invalid command specified: 
> $command\n"); }
>                       };
>                       if ($@) {
>                               if (ref($@) eq "SoapFault") { 
> dielog("$@->detail\n"); }
>                       }
> 
>               } else { dielog("Invalid target specified\n"); }
>       } else {
>       # Command belongs to the group of commands that lookup the status of 
> VMware vCenter and/or virtual machines
>               if ($command eq "status") {
>                       eval {
>                               # VI API: Searches the inventory tree for all 
> VirtualMachine managed objects
>                               my $vms = Vim::find_entity_views(view_type => 
> "VirtualMachine");
>                       };
>                       if ($@) {
>                               if (ref($@) eq "SoapFault") { 
> dielog("$@->detail\n"); }

Is this the only error which can happen? If not, then no error
will be logged in that case. Ditto for another occurence below.

>                       }
>               }
>               elsif ($command eq "gethosts") {
>                       # Create a regular expression to make vCenter find all 
> the virtual machine matching
>                       # mirtual machine names specified in HOSTLIST

                        # virtual ...

>                       # NOTE: this implementation make "gethosts" check that 
> entries in HOSTLIST are consistent with VMware vCenter VM directory
>                       my $regex = join "|", map { qr/\Q$_\E/i } values 
> %host_to_vm;
>                       eval {
>                               my $vms = Vim::find_entity_views(view_type => 
> "VirtualMachine", filter => { name => qr/^($regex)$/ });
>                               foreach my $vm (@$vms) { print "$vm_to_host{(lc 
> $vm->name)}\n" if exists $vm_to_host{(lc $vm->name)}; }
>                       };
>                       if ($@) {
>                               if (ref($@) eq "SoapFault") { 
> dielog("$@->detail\n"); }
>                       }
>               }
>               else { dielog("Invalid command specified: $command\n"); }
>       }
>       eval {
>               Util::disconnect();
>       };
>       if ($@) {
>               # This is just a placeholder for any error handling procedure
>               dielog($@);
>       }
> }
> else { dielog("Invalid command specified: $command\n"); }
> 
> exit(0);
_______________________________________________________
Linux-HA-Dev: Linux-HA-Dev@lists.linux-ha.org
http://lists.linux-ha.org/mailman/listinfo/linux-ha-dev
Home Page: http://linux-ha.org/

Reply via email to