diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 06:40:13 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 06:40:13 +0000 |
commit | e9be59e1502a41bab9891d96d753102a7dafef0b (patch) | |
tree | c3b2da87c414881f4b53d0964f407c83492d813e /lib/plugins/stonith/external/vcenter | |
parent | Initial commit. (diff) | |
download | cluster-glue-e9be59e1502a41bab9891d96d753102a7dafef0b.tar.xz cluster-glue-e9be59e1502a41bab9891d96d753102a7dafef0b.zip |
Adding upstream version 1.0.12.upstream/1.0.12upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'lib/plugins/stonith/external/vcenter')
-rwxr-xr-x | lib/plugins/stonith/external/vcenter | 280 |
1 files changed, 280 insertions, 0 deletions
diff --git a/lib/plugins/stonith/external/vcenter b/lib/plugins/stonith/external/vcenter new file mode 100755 index 0000000..71a6302 --- /dev/null +++ b/lib/plugins/stonith/external/vcenter @@ -0,0 +1,280 @@ +#!/usr/bin/env 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; + +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 listvms}); + +# 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" default="localhost"/> +<shortdesc lang="en">VMware vCenter address</shortdesc> +<longdesc lang="en"> +The VMware vCenter address +</longdesc> +</parameter> +<parameter name="VI_PROTOCOL"> +<content type="string" default="https"/> +<shortdesc lang="en">VMware vCenter protocol</shortdesc> +<longdesc lang="en"> +The VMware vCenter protocol +</longdesc> +</parameter> +<parameter name="VI_PORTNUMBER"> +<content type="string" default="443"/> +<shortdesc lang="en">VMware vCenter port number</shortdesc> +<longdesc lang="en"> +The VMware vCenter port number +</longdesc> +</parameter> +<parameter name="VI_SERVICEPATH"> +<content type="string" default="/sdk"/> +<shortdesc lang="en">VMware vCenter service path</shortdesc> +<longdesc lang="en"> +The VMware vCenter services path +</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" default="1"/> +<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 +</longdesc> +</parameter> +<parameter name="PERL_LWP_SSL_VERIFY_HOSTNAME"> +<content type="string"/> +<shortdesc lang="en">Enable or disable SSL hostname verification</shortdesc> +<longdesc lang="en"> +To disable SSL hostname verification set this option to 0. +To enable hostname verification, set this option to 1. +This option is actually part of the LWP Perl library. +See LWP(3pm) for more information. +</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) { + + eval { require VMware::VIRuntime; } + or dielog("Missing perl module VMware::VIRuntime. Download and install 'VMware Infrastructure (VI) Perl Toolkit', available at http://www.vmware.com/support/developer/viperltoolkit/ \n"); + + # 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 }); + if (!defined $vm) { + dielog("Machine $targetHost was not found"); + } + + # 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"); } + dielog($@); + } + + 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 $esx:$vm->{'name'} 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'} ne 0)) { + $vm->PowerOnVM(); + system("ha_log.sh", "info", "Machine $esx:$vm->{'name'} has been powered on"); + } else { + dielog("Could not complete $esx:$vm->{'name'} power cycle"); + } + } + } + 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"); } + dielog($@); + } + + } 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") { + # we already connect to the vcenter, no need to do + # anything else in status + ; + } + elsif ($command eq "gethosts") { + foreach my $key (keys(%host_to_vm)) { + print "$key \n"; + } + } + elsif ($command eq "listvms") { + eval { + # VI API: Searches the inventory tree for all VirtualMachine managed objects + my $vms = Vim::find_entity_views(view_type => "VirtualMachine"); + if (defined $vms) { + printf(STDERR "%-50s %-20s\n", "VM Name", "Power state"); + print STDERR "-" x 70 . "\n"; + foreach my $vm (@$vms) { + my $powerState = $vm->get_property('runtime.powerState')->val; + printf("%-50s %-20s\n", $vm->{name}, $powerState); + } + } + }; + } + 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); |