Appendix B, Script for Virtual Server Host Clustering
The following Visual Basic script ensures that in a Virtual Server host cluster, the guest functions correctly when a failover or other cluster-related process occurs. The script also triggers restart of the guest if the guest stops running. The script is configured as a Generic Script resource in the cluster.
To use the script, carefully copy only the script text (not including "Havm.vbs") into a text editor such as Notepad and then save the script, using Havm.vbs as the filename. When saving the file, be sure to save it in a way that does not add linebreaks.
Havm.vbs
'*******************************************************************************************************************************************************
'Global variables
'*******************************************************************************************************************************************************
'Script Version
ScriptVersion = "1.0"
'Flagged TRUE if the virtual machine has ever responded to an additions heartbeat.
VirtualMachineHasHeartbeat = FALSE
'Used by Terminate() to make failure recovery decisions.
VirtualMachineFailedOnline = FALSE
'Time in miliseconds to wait to save/restore state.
Timeout = 300000
'Stores the percentage of received heartbeats over 1 time block at which the guest is considered dead.
AdditionsIsAliveHeartbeatThreshold = 0
'*******************************************************************************************************************************************************
'Open()
'
'Check to see if "Virtual Server" service is running. If not attempt to start it.
'
'Check to see if the following private properties exist. If not, create/set them:
' VirtualMachineName - Stores the name of the virtual machine that is made highly available by this resource. (User has to set it explicitly)
' UseAdditionsIsAlive - 1 to use the additions heartbeat code path in IsAlive(), 0 to not use that code path. (Default is 1)
' AdditionsIsAliveFailureRecoveryAction - 1 to turn off vm, 0 to save state. (Default is 1)
'*******************************************************************************************************************************************************
Function Open()
On Error Resume Next
Resource.LogInformation("Entering Open() for Virtual Server Host Clustering Generic Script Version " & ScriptVersion)
Set wmiProvider = GetObject("winmgmts:/root/cimv2")
Set vsService = wmiProvider.Get("win32_service='Virtual Server'")
vsServiceState = vsService.State
If uCase(vsServiceState) <> "RUNNING" Then
returnValue = vsService.StartService()
'Check if the call to start the service succeeded or not. 0 or 10 means it did.
If (returnValue <> 0) and (returnValue <> 10) Then
Resource.LogInformation("Attempt to start 'Virtual Server' service on this machine failed with error " & returnValue)
Open = returnValue
Exit Function
End If
End If
If Resource.PropertyExists("VirtualMachineName") = FALSE Then
Resource.AddProperty("VirtualMachineName")
End If
If Resource.PropertyExists("UseAdditionsIsAlive") = FALSE Then
Resource.AddProperty("UseAdditionsIsAlive")
Resource.UseAdditionsIsAlive = 1
End If
If Resource.PropertyExists("AdditionsIsAliveFailureRecoveryAction") = FALSE Then
Resource.AddProperty("AdditionsIsAliveFailureRecoveryAction")
Resource.AdditionsIsAliveFailureRecoveryAction = 1
End If
End Function
'*******************************************************************************************************************************************************
'Online()
'
'Issue a start control to the virtual machine.
'
'If the virtual machine is already in "Running" state, this can either mean the virtual machine has very recently failed, or it is really up and running.
'Handle the worst case by setting VirtualMachineFailedOnline = TRUE, which will cause Terminate() to attempt to save the state.
'*******************************************************************************************************************************************************
Function Online( )
On Error Resume Next
If Resource.VirtualMachineName = "" Then
Resource.LogInformation("The VirtualMachineName private property is blank. Please run the following command on any one node of the cluster to correct the problem: cluster.exe res """ & Resource.Name & """ /priv VirtualMachineName=" & """name of virtual machine""" )
Online = 13 '13 - The data is invalid.
Exit Function
Else
Resource.LogInformation("Entering Online() for " & Resource.VirtualMachineName)
End If
Set virtualServer = CreateObject("VirtualServer.Application")
Set vm = virtualserver.FindVirtualMachine(Resource.VirtualMachineName)
Set state = vm.Startup()
Select Case err.number <> 0
Case err.number = "-1610349312"
'Handle the case where the virtual machine is already in "Running" state at the time the resource is brought online.
If vm.state = 5 Then
Resource.LogInformation("Startup() was called for virtual machine " & Resource.VirtualMachineName & ", however it was already in the started state. Setting VirtualMachineFailedOnline = TRUE")
VirtualMachineFailedOnline = TRUE
Online = 1
Exit Function
End If
Case err.number = "2147614729"
If vm.state = 5 Then
Resource.LogInformation("Startup() was called for virtual machine " & Resource.VirtualMachineName & ", however it was already in the started state. Setting VirtualMachineFailedOnline = TRUE")
VirtualMachineFailedOnline = TRUE
Online = 1
Exit Function
End If
Case err.number = "2684617984"
If vm.state = 5 Then
Resource.LogInformation("Startup() was called for virtual machine " & Resource.VirtualMachineName & ", however it was already in the started state. Setting VirtualMachineFailedOnline = TRUE")
VirtualMachineFailedOnline = TRUE
Online = 1
Exit Function
End If
Case Else
Resource.LogInformation("Startup() for virtual machine " & Resource.VirtualMachineName & " failed with error " & err.number)
Online = err.number
Exit Function
End Select
Call state.WaitForCompletion(Timeout)
If state.IsComplete = TRUE Then
Online = 0
End If
End Function
'*******************************************************************************************************************************************************
'LooksAlive()
'
'Return success
'*******************************************************************************************************************************************************
Function LooksAlive()
LooksAlive = TRUE
End Function
'*******************************************************************************************************************************************************
'IsAlive()
'
'If UseAdditionsIsAlive = 1 and if VirtualMachineHasHeartbeat = TRUE and if vm.GuestOS.HeartbeatPercentage =< AdditionsIsAliveHeartbeatThreshold set IsAlive to FALSE and exit function.
'If UseAdditionsIsAlive = 1 and if VirtualMachineHasHeartbeat = TRUE and if vm.GuestOS.heartbeatpercentage > AdditionsIsAliveHeartbeatThreshold set IsAlive to TRUE and exit function.
'If UseAdditionsIsAlive <> 1 or if VirtualMachineHasHeartbeat <> TRUE, then attempt to set VirtualMachineHasHeartbeat and do basic IsAlive.
'*******************************************************************************************************************************************************
Function IsAlive()
On Error Resume Next
IsAlive = FALSE
Set virtualServer = CreateObject("VirtualServer.Application")
Set vm = virtualserver.FindVirtualMachine(Resource.VirtualMachineName)
If (Resource.UseAdditionsIsAlive = 1) Then
If VirtualMachineHasHeartbeat = TRUE Then
If vm.GuestOS.HeartbeatPercentage <= AdditionsIsAliveHeartbeatThreshold Then
IsAlive = FALSE
Exit Function
Else
IsAlive = TRUE
Exit Function
End If
End If
End If
'Set VirtualMachineHasHeartbeat
VirtualMachineHasHeartbeat = vm.GuestOS.IsHeartbeating
'Do basic IsAlive check
If vm.state = 3 or vm.state = 4 or vm.state = 5 Then
IsAlive = TRUE
End If
End Function
'*******************************************************************************************************************************************************
'Offline()
'
'Issue a save state control to the virtual machine.
'
'If the virtual machine is not already in the "Running" state, assume success.
'*******************************************************************************************************************************************************
Function Offline()
On Error Resume Next
Resource.LogInformation("Entering Offline() for " & Resource.VirtualMachineName)
Set virtualServer = CreateObject("VirtualServer.Application")
Set vm = VirtualServer.FindVirtualMachine(Resource.VirtualMachineName)
Set state = vm.Save()
Select Case err.number <> 0
'Handle the case where the virtual machine is not already in the "Running" state at the time the resource is taken offline.
Case err.number = "2684617222"
Resource.LogInformation("Save() was called for virtual machine " & Resource.VirtualMachineName & ", however it was not in the started state.")
'Handle another case where the virtual machine is not already in the "Running" state at the time the resource is taken offline.
Case err.number = "-1610350074"
Resource.LogInformation("Save() was called for virtual machine " & Resource.VirtualMachineName & ", however it was not in the started state.")
Case Else
Resource.LogInformation("Save() for virtual machine " & Resource.VirtualMachineName & " failed with error " & err.number)
Offline = err.number
Exit Function
End Select
Call state.WaitForCompletion(Timeout)
If state.IsComplete = TRUE Then
Offline = 0
End If
End Function
'*******************************************************************************************************************************************************
'Terminate()
'
'If Online() failed because the virtual machine was already "Running" (VirtualMachineFailedOnline = FALSE), then Terminate() needs to attempt to save state.
'If UseAdditionsIsAlive = 1 and VirtualMachineHasHeartbeat = TRUE, then take failure action specified by AdditionsIsAliveFailureRecoveryAction.
'*******************************************************************************************************************************************************
Function Terminate()
On Error Resume Next
Set virtualServer = CreateObject("VirtualServer.Application")
Set vm = virtualserver.FindVirtualMachine(Resource.VirtualMachineName)
If VirtualMachineFailedOnline = TRUE Then
Set state = vm.Save()
Call state.WaitForCompletion(Timeout)
Exit Function
End If
If Resource.UseAdditionsIsAlive = 1 AND virtualMachineHasHeartbeat = TRUE Then
If Resource.AdditionsIsAliveFailureRecoveryAction = 0 Then
Set state = vm.Save()
Call state.WaitForCompletion(Timeout)
Exit Function
Else
Set state = vm.TurnOff()
Call state.WaitForCompletion(Timeout)
Exit Function
End If
End If
End Function
'*******************************************************************************************************************************************************
'Close()
'
'Return success
'*******************************************************************************************************************************************************
Function Close()
Close = 0
End Function