Created
June 21, 2011 09:57
-
-
Save jbarber/1037554 to your computer and use it in GitHub Desktop.
RHEL5 RHCS fence agent for VMware
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python | |
# | |
# The Following agent has been tested on: | |
# vmrun 2.0.0 build-116503 (from VMware Server 2.0) against: | |
# VMware ESX 3.5 (works correctly) | |
# VMware Server 2.0.0 (works correctly) | |
# VMware ESXi 3.5 update 2 (works correctly) | |
# VMware Server 1.0.7 (works but list/status show only running VMs) | |
# | |
# VI Perl API 1.6 against: | |
# VMware ESX 3.5 | |
# VMware ESXi 3.5 update 2 | |
# VMware Virtual Center 2.5 | |
# | |
import sys, re, pexpect | |
sys.path.append("/usr/lib/fence") | |
from fencing import * | |
#BEGIN_VERSION_GENERATION | |
FENCE_RELEASE_NAME="DEVEL.1231929034"; | |
REDHAT_COPYRIGHT=("Copyright (C) Red Hat, Inc. 2004 All rights reserved.") | |
BUILD_DATE="(built Wed Jan 14 11:46:56 CET 2009)"; | |
#END_VERSION_GENERATION | |
### CONSTANTS #### | |
# VMware type is ESX/ESXi/VC | |
VMWARE_TYPE_ESX=0 | |
# VMware type is Server 1.x | |
VMWARE_TYPE_SERVER1=1 | |
# VMware type is Server 2.x and/or ESX 3.5 up2, ESXi 3.5 up2, VC 2.5 up2 | |
VMWARE_TYPE_SERVER2=2 | |
# Minimum required version of vmrun command | |
VMRUN_MINIMUM_REQUIRED_VERSION=2 | |
# Default path to vmhelper command | |
VMHELPER_COMMAND="fence_vmware_ng_helper" | |
# Default path to vmrun command | |
VMRUN_COMMAND="/usr/bin/vmrun" | |
# Default type of vmware | |
VMWARE_DEFAULT_TYPE="esx" | |
#### GLOBAL VARIABLES #### | |
# Internal type. One of VMWARE_TYPE_, set by #vmware_check_vmware_type | |
vmware_internal_type=VMWARE_TYPE_ESX | |
# If ESX is disconnected, say, that VM is off (don't return previous state) | |
vmware_disconnected_hack=False | |
### FUNCTIONS #### | |
#Split string in simplified DSV format to array of items | |
def dsv_split(dsv_str): | |
delimiter_c=':' | |
escape_c='\\' | |
res=[] | |
status=0 | |
tmp_str="" | |
for x in dsv_str: | |
if (status==0): | |
if (x==delimiter_c): | |
res.append(tmp_str) | |
tmp_str="" | |
elif (x==escape_c): | |
status=1 | |
else: | |
tmp_str+=x | |
elif (status==1): | |
if (x==delimiter_c): | |
tmp_str+=delimiter_c | |
elif (x==escape_c): | |
tmp_str+=escape_c | |
else: | |
tmp_str+=escape_c+x | |
status=0 | |
if (tmp_str!=""): | |
res.append(tmp_str) | |
return res | |
# Return string with command and additional parameters (something like vmrun -h 'host' | |
def vmware_prepare_command(options,add_login_params,additional_params): | |
res=options["-e"] | |
if (add_login_params): | |
if (vmware_internal_type==VMWARE_TYPE_ESX): | |
res+=" --server '%s' --username '%s' --password '%s' "%(options["-a"],options["-l"],options["-p"]) | |
elif (vmware_internal_type==VMWARE_TYPE_SERVER2): | |
res+=" -h 'https://%s/sdk' -u '%s' -p '%s' -T server "%(options["-a"],options["-l"],options["-p"]) | |
elif (vmware_internal_type==VMWARE_TYPE_SERVER1): | |
host_name_array=options["-a"].split(':') | |
res+=" -h '%s' -u '%s' -p '%s' -T server1 "%(host_name_array[0],options["-l"],options["-p"]) | |
if (len(host_name_array)>1): | |
res+="-P '%s' "%(host_name_array[1]) | |
if ((options.has_key("-s")) and (vmware_internal_type==VMWARE_TYPE_ESX)): | |
res+="--datacenter '%s' "%(options["-s"]) | |
if (additional_params!=""): | |
res+=additional_params | |
return res | |
# Log message if user set verbose option | |
def vmware_log(options, message): | |
if options["log"] >= LOG_MODE_VERBOSE: | |
options["debug_fh"].write(message+"\n") | |
# Run command with timeout and parameters. Internaly uses vmware_prepare_command. Returns string | |
# with output from vmrun command. If something fails (command not found, exit code is not 0), fail_usage | |
# function is called (and never return). | |
def vmware_run_command(options,add_login_params,additional_params,additional_timeout): | |
command=vmware_prepare_command(options,add_login_params,additional_params) | |
try: | |
vmware_log(options,command) | |
(res_output,res_code)=pexpect.run(command,SHELL_TIMEOUT+LOGIN_TIMEOUT+additional_timeout,True) | |
if (res_code==None): | |
fail(EC_TIMED_OUT) | |
if ((res_code!=0) and (add_login_params)): | |
vmware_log(options,res_output) | |
fail_usage("%s returned %s"%(options["-e"],res_output)) | |
else: | |
vmware_log(options,res_output) | |
except pexpect.ExceptionPexpect: | |
fail_usage("Cannot run command %s"%(options["-e"])) | |
return res_output | |
# Get outlet list with status as hash table. If you will use add_vm_name, only VM with vmname is | |
# returned. This is used in get_status function | |
def vmware_get_outlets_vi(conn, options, add_vm_name): | |
outlets={} | |
if (add_vm_name): | |
all_machines=vmware_run_command(options,True,("--operation status --vmname '%s'"%(options["-n"])),0) | |
else: | |
all_machines=vmware_run_command(options,True,"--operation list",POWER_TIMEOUT) | |
all_machines_array=all_machines.splitlines() | |
for machine in all_machines_array: | |
machine_array=dsv_split(machine) | |
if (len(machine_array)==4): | |
if (machine_array[0] in outlets): | |
fail_usage("Failed. More machines with same name %s found!"%(machine_array[0])) | |
if (vmware_disconnected_hack): | |
outlets[machine_array[0]]=("",( | |
((machine_array[2].lower() in ["poweredon"]) and | |
(machine_array[3].lower()=="connected")) | |
and "on" or "off")) | |
else: | |
outlets[machine_array[0]]=("",((machine_array[2].lower() in ["poweredon"]) and "on" or "off")) | |
return outlets | |
# Get outlet list with status as hash table. | |
def vmware_get_outlets_vix(conn,options): | |
outlets={} | |
running_machines=vmware_run_command(options,True,"list",0) | |
running_machines_array=running_machines.splitlines()[1:] | |
if (vmware_internal_type==VMWARE_TYPE_SERVER2): | |
all_machines=vmware_run_command(options,True,"listRegisteredVM",0) | |
all_machines_array=all_machines.splitlines()[1:] | |
elif (vmware_internal_type==VMWARE_TYPE_SERVER1): | |
all_machines_array=running_machines_array | |
for machine in all_machines_array: | |
if (machine!=""): | |
outlets[machine]=("",((machine in running_machines_array) and "on" or "off")) | |
return outlets | |
def get_outlets_status(conn, options): | |
if (vmware_internal_type==VMWARE_TYPE_ESX): | |
return vmware_get_outlets_vi(conn,options,False) | |
if ((vmware_internal_type==VMWARE_TYPE_SERVER1) or (vmware_internal_type==VMWARE_TYPE_SERVER2)): | |
return vmware_get_outlets_vix(conn,options) | |
def get_power_status(conn,options): | |
if (vmware_internal_type==VMWARE_TYPE_ESX): | |
outlets=vmware_get_outlets_vi(conn,options,True) | |
else: | |
outlets=get_outlets_status(conn,options,False) | |
if ((vmware_internal_type==VMWARE_TYPE_SERVER2) or (vmware_internal_type==VMWARE_TYPE_ESX)): | |
if (not (options["-n"] in outlets)): | |
fail_usage("Failed: You have to enter existing name of virtual machine!") | |
else: | |
return outlets[options["-n"]][1] | |
elif (vmware_internal_type==VMWARE_TYPE_SERVER1): | |
return ((options["-n"] in outlets) and "on" or "off") | |
def set_power_status(conn, options): | |
if (vmware_internal_type==VMWARE_TYPE_ESX): | |
additional_params="--operation %s --vmname '%s'"%((options["-o"]=="on" and "on" or "off"),options["-n"]) | |
elif ((vmware_internal_type==VMWARE_TYPE_SERVER1) or (vmware_internal_type==VMWARE_TYPE_SERVER2)): | |
additional_params="%s '%s'"%((options["-o"]=="on" and "start" or "stop"),options["-n"]) | |
if (options["-o"]=="off"): | |
additional_params+=" hard" | |
vmware_run_command(options,True,additional_params,POWER_TIMEOUT) | |
# Returns True, if user uses supported vmrun version (currently >=2.0.0) otherwise False. | |
def vmware_is_supported_vmrun_version(options): | |
vmware_help_str=vmware_run_command(options,False,"",0) | |
version_re=re.search("vmrun version (\d\.(\d[\.]*)*)",vmware_help_str.lower()) | |
if (version_re==None): | |
return False # Looks like this "vmrun" is not real vmrun | |
version_array=version_re.group(1).split(".") | |
try: | |
if (int(version_array[0])<VMRUN_MINIMUM_REQUIRED_VERSION): | |
return False | |
except Exception: | |
return False | |
return True | |
# Define new options | |
def vmware_define_defaults(): | |
all_opt["vmware_type"]["default"]=VMWARE_DEFAULT_TYPE | |
# Check vmware type, set vmware_internal_type to one of VMWARE_TYPE_ value and | |
# options["-e"] to path (if not specified) | |
def vmware_check_vmware_type(options): | |
global vmware_internal_type | |
if (not options.has_key("-d")): | |
options["-d"]="esx" | |
else: | |
options["-d"]=options["-d"].lower() | |
if (options["-d"]=="esx"): | |
vmware_internal_type=VMWARE_TYPE_ESX | |
if (not options.has_key("-e")): | |
options["-e"]=VMHELPER_COMMAND | |
elif (options["-d"]=="server2"): | |
vmware_internal_type=VMWARE_TYPE_SERVER2 | |
if (not options.has_key("-e")): | |
options["-e"]=VMRUN_COMMAND | |
elif (options["-d"]=="server1"): | |
vmware_internal_type=VMWARE_TYPE_SERVER1 | |
if (not options.has_key("-e")): | |
options["-e"]=VMRUN_COMMAND | |
else: | |
fail_usage("vmware_type can be esx,server2 or server1!") | |
# Define new options | |
def vmware_define_new_options(): | |
all_opt["exec"]={ | |
"getopt" : "e:", | |
"help" : "-e Command to execute", | |
"order" : 1 }; | |
all_opt["vmware_type"]={ | |
"getopt" : "d:", | |
"help" : "-d Type of VMware to connect", | |
"order" : 1 }; | |
all_opt["vmware_datacenter"]={ | |
"getopt" : "s:", | |
"help" : "-s VMWare datacenter filter", | |
"order" : 2 }; | |
# Main agent method | |
def main(): | |
device_opt = [ "help", "version", "agent", "quiet", "verbose", "debug", | |
"action", "ipaddr", "login", "passwd", "passwd_script", | |
"test", "port", "exec", "vmware_type", | |
"vmware_datacenter", "secure" ] | |
vmware_define_new_options() | |
vmware_define_defaults() | |
options = check_input(device_opt, process_input(device_opt)) | |
# Default is secure connection | |
options["-x"] = 1 | |
# Check vmware type and set path | |
vmware_check_vmware_type(options) | |
# Test user vmrun command version | |
if ((vmware_internal_type==VMWARE_TYPE_SERVER1) or (vmware_internal_type==VMWARE_TYPE_SERVER2)): | |
if (not (vmware_is_supported_vmrun_version(options))): | |
fail_usage("Unsupported version of vmrun command! You must use at least version %d!"%(VMRUN_MINIMUM_REQUIRED_VERSION)) | |
# Operate the fencing device | |
fence_action(None, options, set_power_status, get_power_status) | |
if __name__ == "__main__": | |
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/perl | |
use strict; | |
use warnings; | |
my ($FENCE_RELEASE_NAME, $REDHAT_COPYRIGHT, $BUILD_DATE); | |
#BEGIN_VERSION_GENERATION | |
$FENCE_RELEASE_NAME="DEVEL.1231929034"; | |
$REDHAT_COPYRIGHT=("Copyright (C) Red Hat, Inc. 2004 All rights reserved."); | |
$BUILD_DATE="(built Wed Jan 14 11:46:56 CET 2009)"; | |
#END_VERSION_GENERATION | |
#### FUNCTIONS ##### | |
# Show error message | |
sub show_error { | |
print STDERR @_; | |
} | |
sub my_exit { | |
my ($exit_code)=@_; | |
# Disconnect from server | |
Util::disconnect(); | |
exit $exit_code; | |
} | |
# Convert one field (string) to format acceptable by DSV. This | |
# means replace any : with \: and \ with \\. | |
sub convert_field_to_dsv { | |
my ($input_line)=@_; | |
$input_line =~ s/([\\:])/\\$1/g; | |
return $input_line | |
} | |
#### Global variables ##### | |
# Aditional options | |
my %opts = ( | |
'operation' => { | |
type => "=s", | |
help => "The operation to perform (on,off,list,status). " | |
. "Operations on/off/status require name of the virtual machine", | |
default => "list", | |
required => 0, | |
}, | |
'vmname' => { | |
type => "=s", | |
help => "The name of the virtual machine", | |
required => 0, | |
}, | |
'datacenter' => { | |
type => "=s", | |
help => "The name of the datacenter", | |
required => 0, | |
} | |
); | |
################# | |
##### MAIN ###### | |
################# | |
# Conditional use of VIRuntime | |
eval "use VMware::VIRuntime;"; | |
if ($@) { | |
show_error "Please install VI Perl API package to use this tool!\n"; | |
exit 1; | |
} | |
# Parse options | |
Opts::add_options(%opts); | |
Opts::parse(); | |
Opts::validate(); | |
if (!(Opts::get_option('operation')=~/^(on|off|list|status)$/i)) { | |
show_error "Operation should be on, off, list or status!\n"; | |
exit 2; | |
} | |
my $operation=lc(Opts::get_option('operation')); | |
if (($operation ne 'list') && (!defined Opts::get_option('vmname'))) { | |
show_error "Operation on, off, status require vmname parameter!\n"; | |
exit 2; | |
} | |
# Try connect to machine | |
eval { | |
Util::connect(); | |
}; | |
if ($@) { | |
show_error "Cannot connect to server!\nVMware error:".$@; | |
exit 3; | |
} | |
my ($datacenter, $datacenter_view, $vm_views,$vm); | |
# We are connected to machine | |
# If user want's datacenter, we must first find datacenter | |
my %filter=(view_type => 'VirtualMachine'); | |
if( defined (Opts::get_option('datacenter')) ) { | |
$datacenter = Opts::get_option('datacenter'); | |
$datacenter_view = Vim::find_entity_view(view_type => 'Datacenter', | |
filter => { name => $datacenter }); | |
if (!$datacenter_view) { | |
show_error "Cannot find datacenter ".$datacenter."!\n"; | |
my_exit 4; | |
} | |
$filter{'begin_entity'}=$datacenter_view; | |
} | |
if ($operation ne 'list') { | |
$filter{'filter'}= {"config.name" => Opts::get_option('vmname')}; | |
} | |
$vm_views = Vim::find_entity_views(%filter); | |
my $found=0; | |
# Traverse all found vm | |
foreach $vm(@$vm_views) { | |
if (($operation eq 'list') or ($operation eq 'status')) { | |
if (!$vm->summary->config->template) { | |
print convert_field_to_dsv($vm->name).":". | |
convert_field_to_dsv($vm->summary->config->vmPathName).":". | |
convert_field_to_dsv($vm->runtime->powerState->val).":". | |
convert_field_to_dsv($vm->runtime->connectionState->val)."\n"; | |
} | |
} elsif ($operation eq 'on') { | |
eval { | |
$vm->PowerOnVM(); | |
}; | |
if ($@) { | |
# If error is SoapFault with InvalidPowerState, user maybe use some auto power on tool. | |
# This is not error, warning is enought. | |
if (ref($@) eq 'SoapFault') { | |
if (ref($@->detail) eq 'InvalidPowerState') { | |
show_error "Warning: Cannot power on vm (somebody done it before???) ".Opts::get_option('vmname'). | |
"!\nVMware error:".$@."\n"; | |
} | |
} else { | |
# Some other more serious problem | |
show_error "Cannot power on vm ".Opts::get_option('vmname')."!\nVMware error:".$@."\n"; | |
my_exit 6; | |
} | |
} | |
} elsif ($operation eq 'off') { | |
eval { | |
$vm->PowerOffVM(); | |
}; | |
if ($@) { | |
# If error is SoapFault with InvalidPowerState, user maybe use some auto power off tool. | |
# This is not error, warning is enought. | |
if (ref($@) eq 'SoapFault') { | |
if (ref($@->detail) eq 'InvalidPowerState') { | |
show_error "Warning: Cannot power off vm (somebody done it before???) ".Opts::get_option('vmname'). | |
"!\nVMware error:".$@."\n"; | |
} | |
} else { | |
# Some other more serious problem | |
show_error "Cannot power off vm ".Opts::get_option('vmname')."!\nVMware error:".$@."\n"; | |
my_exit 6; | |
} | |
} | |
} else { | |
show_error "Operation should be on, off or list!\n"; | |
my_exit 2; | |
} | |
$found++; | |
} | |
if ((!$found) && ($operation ne 'list')) { | |
show_error "Cannot find vm ".Opts::get_option('vmname')."!\n"; | |
my_exit 5; | |
} | |
# Should be 0 -> success all, or 6 in case of error | |
my_exit 0; | |
__END__ | |
=head1 NAME | |
fence_vmware_helper - Perform list of virtual machines and | |
poweron, poweroff of operations on virtual machines. | |
=head1 SYNOPSIS | |
fence_vmware_helper --operation <on|off|list|status> [options] | |
=head1 DESCRIPTION | |
This VI Perl command-line utility provides an interface for | |
seven common provisioning operations on one or more virtual | |
machines: powering on, powering off and listing virtual mode. | |
=head1 OPTIONS | |
=head2 GENERAL OPTIONS | |
=over | |
=item B<operation> | |
Operation to be performed. One of the following: | |
<on> (power on one or more virtual machines), | |
<off> (power off one or more virtual machines), | |
<list> (list virtual machines and their status) | |
<status> (same as list, but show only machines with vmname) | |
=item B<vmname> | |
Optional. Name of the virtual machine on which the | |
operation is to be performed. | |
=item B<datacenter> | |
Optional. Name of the datacenter for the virtual machine(s). | |
Operations will be performed on all the virtual machines under the given datacenter. | |
=back | |
=head1 EXAMPLES | |
Power on a virtual machine | |
fence_vmware_helper --username administrator --password administrator --operation on | |
--vmname rhel --server win1 | |
fence_vmware_helper --username administrator --password administrator --operation on | |
--vmname rhel --server win1 --datacenter Datacenter | |
Power off a virtual machine | |
fence_vmware_helper --username administrator --password administrator --operation off | |
--vmname rhel --server win1 | |
perl fence_vmware_helper --username administrator --password administrator --operation off | |
--vmname rhel --server win1 --datacenter Datacenter | |
List of virtual machines | |
fence_vmware_helper --username administrator --password administrator --server win1 | |
fence_vmware_helper --username administrator --password administrator --server win1 | |
--operation list | |
Get status of virtual machine | |
fence_vmware_helper --username administrator --password administrator --server win1 | |
--vmname rhel --operation status | |
=head1 SUPPORTED PLATFORMS | |
All operations supported on ESX 3.0.1 | |
All operations supported on Virtual Center 2.0.1 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment