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/