Monday, July 18, 2011

RightFax Integration Module in a Collective

By:Rik Hoffelder


The RightFax Shared Services Collective is a wonderful feature that allows load balance and failover in a shared nothing architecture. There is an exception to this however the Integration Module cannot run on multiple nodes when sharing the same Inbox. When this is done you end up with duplication of faxes.

As shown below a typical environment will use two or more collective servers with the IM. It reads from Inboxes on a clustered file share with all application servers feeding to this location. This makes for a great high availability solution, but doesn't solve the IM problem.



To workaround this problem most administrators disable the IM service on all but one collective server. In the event of a primary server failure they manually start the service on another collective member. This is an acceptable workaround however it has two flaws. The first is that it’s a manual process. The second issue occurs when the original server is recovered. You have to remember to shutdown the IM service on the other server.

As a field consultant I have encountered this situation on numerous occasions. In a few cases the project required that I provide some mechanism to fail this over automatically. There are a few ways to accomplish this outside of RightFax depending on what you have available. So for those of you that have struggled with this situation here’s how I accomplished it using a VB Script. I also have lightly tested PowerShell version. Note that neither script is sanctioned or supported by OpenText.

The script, RFMonitor.VBS, uses a CSV input file named RFMonitor.INI. This file provides the services and servers used as input varibles for the script. The fields are RF Service Monitored, Primary Server, Secondary Server. I run the script as a scheduled task on a separate server (management server) every 10 minutes.

It essentially pings the primary to make sure it’s up, if not it fails over to the secondary immediately. If the primary is up it verifies the services are running, if not it fails over. It also checks to see if the IM service is running on both servers. If so, it stops it on the secondary. This has been tested extensively and is running in a couple of production environments.

RFMonitor.INI

RFPROD,FAXSRV02,FAXSRV01,
RFSERVER,FAXSRV02,FAXSRV01,
RFDOCTRANS,FAXSRV02,FAXSRV01,
RFPAGE,FAXSRV02,FAXSRV01,
RFQUEUE,FAXSRV02,FAXSRV01,
RFREMOTE,FAXSRV02,FAXSRV01,
RFRPC,FAXSRV02,FAXSRV01,
RFIsoConv,FAXSRV02,FAXSRV01,
CapaSync,FAXSRV02,FAXSRV01,
RFEMAIL,FAXSRV02,FAXSRV01,
RFMIME,FAXSRV02,FAXSRV01,
RFWORK1,FAXSRV02,FAXSRV01,
RFWORK2,FAXSRV02,FAXSRV01,
RFWORK3,FAXSRV02,FAXSRV01,


RFMonitor.VBS

On Error Resume Next
'##### Open and parse CSV for varibles #####
Const ForReading = 1
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFile = objFSO.OpenTextFile("rfmonitor.ini", ForReading)
Do Until objFile.AtEndOfStream
strLine = objFile.ReadLine
arrFields = Split(strLine, Chr(44))
strSvc = arrFields(0)
strMainSrv = arrFields(1)
strBkupSrv = arrFields(2)
Call CheckMainSrv()
Loop
'##### Check Main Server Availability #####
Sub CheckMainSrv()
strComputer = "."
Set objShell = CreateObject("WScript.Shell")
Set objWshScriptExec = objShell.Exec("ping " & strMainSrv)
Set objStdOut = objWshScriptExec.StdOut

While Not objStdOut.AtEndOfStream
strLine = objStdOut.ReadLine
If InStr(strLine,"Reply from") Then
Call CheckBkupSrv()
Else
Set LogError = Wscript.CreateObject("Wscript.Shell")
LogError.LogEvent 1, strMainSrv & " " & "is unreachable, starting services on" & " " & strBkupSrv
Call StartBkupSrv()
End If
Wend
End Sub

'##### Check Backup Server Availability #####
Sub CheckBkupSrv()

strComputer = "."
Set objShell = CreateObject("WScript.Shell")
Set objWshScriptExec = objShell.Exec("ping " & strBkupSrv)
Set objStdOut = objWshScriptExec.StdOut

While Not objStdOut.AtEndOfStream
strLine = objStdOut.ReadLine
If InStr(strLine,"Reply from") Then
Call CheckSvcType()
Else
Set LogError = Wscript.CreateObject("Wscript.Shell")
LogError.LogEvent 1, strMainSrv & " " & "is unreachable, checking services on" & " " & strMainSrv
Call StartMainSrv()
End If
Wend

End Sub

'##### Check Service Type #####
Sub CheckSvcType()

If strSvc = "RFPROD" Then
Call CheckIMSvc()
ElseIf strSvc = "RIGHTFAXONFAX011024" Then
Call CheckGPSvc()
ElseIf strSvc = strSvc Then
Call CheckSvcState()
End If
End Sub

'##### Check State of Services Fail As Needed #####
Sub CheckSvcState()

strQ1 = "Select * from Win32_Service"
strQ2 = "Where Name = '" & strSvc & "'"
strQuery = strQ1 & " " & strQ2

Set objWMIService = GetObject("winmgmts:" & "{impersonationLevel=impersonate}!\\" & strMainSrv & "\root\cimv2")
Set colListOfServices = objWMIService.ExecQuery(strQuery)
For Each objService in colListOfServices
If ObjService.State = "Stopped" Then
Set LogError = Wscript.CreateObject("Wscript.Shell")
LogError.LogEvent 1, objService.DisplayName & " " & "service has stopped on" & " " & strMainSrv
Call SvcFail()
Else
End If
Next

End Sub
'##### Check Integration Module service state #####
Sub CheckIMSvc()
Set objWMIService = GetObject("winmgmts:" & "{impersonationLevel=impersonate}!\\" & strMainSrv & "\root\cimv2")
Set colListOfServices = objWMIService.ExecQuery("Select * from Win32_Service Where Name ='RFPROD'")
For Each objService in colListOfServices
If ObjService.State = "Stopped" Then
Set LogError = Wscript.CreateObject("Wscript.Shell")
LogError.LogEvent 1, objService.DisplayName & " " & "service has stopped on" & " " & strMainSrv
Call StartRFProdSvc()
Else
Call CheckDupIMSvc()
End If
Next
End Sub
'##### Check Get PAID service state #####
Sub CheckGPSvc()
Set objWMIService = GetObject("winmgmts:" & "{impersonationLevel=impersonate}!\\" & strMainSrv & "\root\cimv2")
Set colListOfServices = objWMIService.ExecQuery("Select * from Win32_Service Where Name ='RIGHTFAXONFAX011024'")
For Each objService in colListOfServices
If ObjService.State = "Stopped" Then
Set LogError = Wscript.CreateObject("Wscript.Shell")
LogError.LogEvent 1, objService.DisplayName & " " & "service has stopped on" & " " & strMainSrv
Call StartGPSvc()
Else
Call CheckDupGPSvc()
End If
Next
End Sub
'##### Start RFPROD Service Routine #####
Sub StartRFProdSvc()
Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\" & strBkupSrv & "\root\cimv2")
Set colServiceList = objWMIService.ExecQuery _
("Select * from Win32_Service where Name='RFPROD'")
For Each objService in colServiceList
errReturn = objService.StartService()
Set LogError = Wscript.CreateObject("Wscript.Shell")
LogError.LogEvent 0, objService.DisplayName & " " & "service has been started on" & " " & strBkupSrv & " " & "Failover Completed!"
Next
End Sub
'##### Start GetPaid Service Routine
Sub StartGPSvc()

Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\" & strBkupSrv & "\root\cimv2")

Set colServiceList = objWMIService.ExecQuery _
("Select * from Win32_Service where Name='RIGHTFAXONFAX011024'")

For Each objService in colServiceList
errReturn = objService.StartService()
Set LogError = Wscript.CreateObject("Wscript.Shell")
LogError.LogEvent 0, objService.DisplayName & " " & "service has been started on" & " " & strBkupSrv & " " & "Failover Completed!"
Next
End Sub

'##### Check RFPROD Serivce on second node, stop if running #####
Sub CheckDupIMSvc()

Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\" & strBkupSrv & "\root\cimv2")

Set colServiceList = objWMIService.ExecQuery _
("Select * from Win32_Service where Name='RFPROD'")

For Each objService in colServiceList
If ObjService.State = "Running" Then
Set LogError = Wscript.CreateObject("Wscript.Shell")
LogError.LogEvent 2, objService.DisplayName & " " & "Service is running on" & " " & strBkupSrv & " " & "stopping service to prevent duplicates!"

errReturn = objService.StopService()
Set LogError = Wscript.CreateObject("Wscript.Shell")
LogError.LogEvent 0, objService.DisplayName & " " & "service has been stopped on" & " " & strBkupSrv
Else
End If
Next
End Sub

'##### Check RFPROD Serivce on second node, stop if running #####
Sub CheckDupGPSvc()

Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\" & strBkupSrv & "\root\cimv2")

Set colServiceList = objWMIService.ExecQuery _
("Select * from Win32_Service where Name='RIGHTFAXONFAX011024'")

For Each objService in colServiceList
If ObjService.State = "Running" Then
Set LogError = Wscript.CreateObject("Wscript.Shell")
LogError.LogEvent 2, objService.DisplayName & " " & "Service is running on" & " " & strBkupSrv & " " & "stopping service to prevent duplicates!"

errReturn = objService.StopService()
Set LogError = Wscript.CreateObject("Wscript.Shell")
LogError.LogEvent 0, objService.DisplayName & " " & "service has been stopped on" & " " & strBkupSrv
Else
End If
Next
End Sub

'##### Other Service Failure #####
Sub SvcFail()

Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\" & strMainSrv & "\root\cimv2")

Set colServiceList = objWMIService.ExecQuery _
("Select * from Win32_Service where Name='RFPROD'")

For Each objService in colServiceList
If ObjService.State = "Running" Then
Set LogError = Wscript.CreateObject("Wscript.Shell")
LogError.LogEvent 2, objService.DisplayName & " " & "Service is running on" & " " & strMainSrv & " " & "stopping service to failover!"

errReturn = objService.StopService()
Set LogError = Wscript.CreateObject("Wscript.Shell")
LogError.LogEvent 0, objService.DisplayName & " " & "service has been stopped on" & " " & strMainSrv
Else
End If
Next

Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\" & strMainSrv & "\root\cimv2")

Set colServiceList = objWMIService.ExecQuery _
("Select * from Win32_Service where Name='RIGHTFAXONFAX011024'")

For Each objService in colServiceList
If ObjService.State = "Running" Then
Set LogError = Wscript.CreateObject("Wscript.Shell")
LogError.LogEvent 2, objService.DisplayName & " " & "Service is running on" & " " & strMainSrv & " " & "stopping service to failover!"

errReturn = objService.StopService()
Set LogError = Wscript.CreateObject("Wscript.Shell")
LogError.LogEvent 0, objService.DisplayName & " " & "service has been stopped on" & " " & strMainSrv
Else
End If
Next
Call StartRFProdSvc()
Call StartGPSvc()
End Sub


'##### Main Server Fail, Start Backup Server #####
Sub StartBkupSrv()

Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\" & strBkupSrv & "\root\cimv2")

Set colServiceList = objWMIService.ExecQuery _
("Select * from Win32_Service where Name='RFPROD'")

For Each objService in colServiceList
If objService.State = "Stopped" Then
errReturn = objService.StartService()
Set LogError = Wscript.CreateObject("Wscript.Shell")
LogError.LogEvent 0, objService.DisplayName & " " & "service has been started on" & " " & strBkupSrv
Else
End If
Next

Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\" & strBkupSrv & "\root\cimv2")

Set colServiceList = objWMIService.ExecQuery _
("Select * from Win32_Service where Name='RIGHTFAXONFAX011024'")

For Each objService in colServiceList
If objService.State = "Stopped" Then
errReturn = objService.StartService()
Set LogError = Wscript.CreateObject("Wscript.Shell")
LogError.LogEvent 0, objService.DisplayName & " " & "service has been started on" & " " & strBkupSrv
Else
End If
Next
End Sub


'##### Backup Server Fail, Start Main Server #####
Sub StartMainSrv()
Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\" & strMainSrv & "\root\cimv2")

Set colServiceList = objWMIService.ExecQuery _
("Select * from Win32_Service where Name='RFPROD'")

For Each objService in colServiceList
If objService.State = "Stopped" Then
errReturn = objService.StartService()
Set LogError = Wscript.CreateObject("Wscript.Shell")
LogError.LogEvent 0, objService.DisplayName & " " & "service has been started on" & " " & strMainSrv
Else
End If
Next

Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\" & strMainSrv & "\root\cimv2")

Set colServiceList = objWMIService.ExecQuery _
("Select * from Win32_Service where Name='RIGHTFAXONFAX011024'")

For Each objService in colServiceList
If objService.State = "Stopped" Then
errReturn = objService.StartService()
Set LogError = Wscript.CreateObject("Wscript.Shell")
LogError.LogEvent 0, objService.DisplayName & " " & "service has been started on" & " " & strMainSrv
Else
End If
Next
End Sub


RFMonitor.PS1 (PowerShell Version)

Like I noted earlier, this has barely been tested and never used in a production environment. If you have something better or cleaner, please feel free to share. This was one of the first PS scripts I wrote over 6 years ago, so I’m sure it could use some improvements.


#Script Notes: Ping server, if alive Check service state on main from ini file, start on bkup if stopped,
#checks for RFPROD and GetPaid specificially.

####Check Main and Backup for duplicate RFAXONFAX011024 running, stop on Backup
Function CheckGPDup {$colItem = get-wmiobject -class "Win32_Service" -namespace "root\cimv2" -computername "$Bkup" –filter "Name= 'RFAXONFAX011024'"
$State = $colitem.state
if ("$State" -eq "running")
{write-host "Stopping RFPROD service on Backup server to prevent duplicate faxes."
$colItem1 = get-wmiobject -class "Win32_Service" -namespace "root\cimv2" -computername "$Bkup" –filter "Name= 'RFAXONFAX011024'"
ForEach ($objItem in $colItem1) {$objItem.StopService()}}
else
{write-host "No duplicate RFAXONFAX011024 service running on" $Bkup"."}
}


####Check Main and Backup for duplicate RFPROD running, Stop on Backup
Function CheckRFProdDup {$colItem = get-wmiobject -class "Win32_Service" -namespace "root\cimv2" -computername "$Bkup" –filter "Name= 'RFPROD'"
$State = $colitem.state
if ("$State" -eq "running")
{write-host "Stopping RFPROD service on Backup server to prevent duplicate faxes."
$colItem1 = get-wmiobject -class "Win32_Service" -namespace "root\cimv2" -computername "$Bkup" –filter "Name= 'RFPROD'"
ForEach ($objItem in $colItem1) {$objItem.StopService()}}
else
{write-host "No duplicate RFPROD service running on" $Bkup"."
ChkGPDup}
}


####Failover (Stop on main, start on Backup) for any failed service
Function FailOverRFProdGP {$colItem = get-wmiobject -class "Win32_Service" -namespace "root\cimv2" -computername "$Main" –filter "Name= 'RFPROD'"
ForEach ($objItem in $colItem) {$objItem.StopService()}

$colItem = get-wmiobject -class "Win32_Service" -namespace "root\cimv2" -computername "$Main" –filter "Name= 'RFAXONFAX011024'"
ForEach ($objItem in $colItem) {$objItem.StopService()}

$colItem = get-wmiobject -class "Win32_Service" -namespace "root\cimv2" -computername "$Bkup" –filter "Name= 'RFPROD'"
ForEach ($objItem in $colItem) {$objItem.StartService()}

$colItem = get-wmiobject -class "Win32_Service" -namespace "root\cimv2" -computername "$Bkup" –filter "Name= 'RFAXONFAX011024'"
ForEach ($objItem in $colItem) {$objItem.StartService()}

write-host "RFPROD and RFAXONFAX011024 has been started on" $bkup"."}


####Check all other services, per ini
Function CheckSvcs {$colItem = get-wmiobject -class "Win32_Service" -namespace "root\cimv2" -computername "$Main" –filter "Name= '$Name'"
$State = $colitem.state
if ("$State" -eq "stopped")
{write-host "Failing over IM and GP to" $Bkup"."
FailOverRFProdGP}
else
{write-host "Service" $Name "is already running on" $Main"."
CheckRFProdDup}
}


####Start RFAXONFAX011024 on Backup
Function StartGPBkup {$colItem = get-wmiobject -class "Win32_Service" -namespace "root\cimv2" -computername "$Bkup" –filter "Name= 'RFAXONFAX011024'"
ForEach ($objItem in $colItem) {
$objItem.StartService()}
write-host "RFAXONFAX011024 has been started on" $bkup"."}

####Start RFPROD on Backup
Function StartRFProdBkup {$colItem = get-wmiobject -class "Win32_Service" -namespace "root\cimv2" -computername "$Bkup" –filter "Name= 'RFPROD'"
ForEach ($objItem in $colItem) {
$objItem.StartService()}
write-host "RFPROD has been started on" $bkup"."}

####Check RFAXONFAX011024
Function CheckGP {$colItem = get-wmiobject -class "Win32_Service" -namespace "root\cimv2" -computername "$Main" –filter "Name= 'RFAXONFAX011024'"
$State = $colitem.state
if ("$State" -eq "stopped")
{write-host "Starting RFAXONFAX011024 service on Backup server."
StartGPBkup}
else
{write-host "Service RFAXONFAX011024 is already running on" $Main"."
CheckSvcs}
}

###Check RFPROD
Function CheckRFProd {$colItem = get-wmiobject -class "Win32_Service" -namespace "root\cimv2" -computername "$Main" –filter "Name= 'RFPROD'"
$State = $colitem.state
if ("$State" -eq "stopped")
{write-host "Starting RFPROD service on Backup server."
StartRFProdBkup}
else
{write-host "Service RFPROD is already running on" $Main"."
CheckGP}
}

#### Open file and pasre varibles ####
$INIFILE = Import-CSV -path "C:\Documents and Settings\rhoffelder\desktop\rfmonitor.ini"

ForEach ($objItem in $INIFILE) {
$Name = $objItem.Name
$Main = $objItem.Main
$Bkup = $objItem.Bkup

#### Ping Main Srver ####
$ping = new-object System.Net.NetworkInformation.Ping
$status = $ping.send($Main)
write-host $status
if($status) {CheckRFProd}

#### Ping Backup Server ####
else {$ping = new-object System.Net.NetworkInformation.Ping
$status = $ping.send($Bkup)
write-host $status
if($status) {FailOverRFProdGP}
Else {"Both servers offline!"}}}
write-host "finished!"





More information on RightFax



1 comment:

  1. Nice, This Post is very much relevant and Informatics. I was in search of such kinda stuff. So, I like this, what You have shared. Thanks a lot ,,. :)

    ReplyDelete

Microsoft Virtualization, Citrix, XENServer, Storage, iscsi, Exchange, Virtual Desktops, XENDesktop, APPSense, Netscaler, Virtual Storage, VM, Unified Comminications, Cisco, Server Virtualization, Thin client, Server Based Computing, SBC, Application Delivery controllers, System Center, SCCM, SCVMM, SCOM, VMware, VSphere, Virtual Storage, Cloud Computing, Provisioning Server, Hypervisor, Client Hypervisor.