Use FlexRAIDCmd within PowerShell scripts to gracefully stop FlexRAID

When using FlexRAID in Real-Time mode, the Pool must be stopped before stopping the service, i.e., also before shutting down the server. The best approach is to define a Shutdown Task in Windows to manage this...

Click to Read More

The Shutdown Task will run a Powershell Script using the FlexRaidClient to query the state of FlexRAID and trigger actions...

The FlexRaidClient for windows, named FlexRaidCmd.exe, is not installed by default with the service. It must be downloaded as an Option here.

The syntax is: FlexRAIDClient Host Port Timeout Command

Once installed, one can use the Command "view" in a cmd prompt RUN AS Administrator on the server to Start/Stop the pool:

FlexRAIDCMD localhost - - view class1_0 start
FlexRAIDCMD localhost - - view class1_0 stop

The - -  are used as "default values" for the Port and Timeout parameters
class1_0 must be used for the new driver (=> class1) and to access the first pool (=> ID = 0).

Starting the pool takes about ~50 seconds.
Stopping the pool takes less than 10 seconds.

If the command fails due to a syntax error, the error message can be found in the file log.log
If the command succeed, there is nothing logged at all in the log file but a message displayed in the console (cmd prompt)

Quote

{"success": true, "status": null, "commandMessages": [{"messageCode": "successStoragePoolStarted", "messageData": ["V"]}], "serverMessages": null}
=> Le pool de stockage est bien démarré pour le volume: V:...

Notice: In a normal cmd prompt (not run as admin), the command returns an error due to an access denied on the log file:

Quote

log4j:ERROR setFile(null,true) call failed.
java.io.FileNotFoundException: log.log

Notice: if the Web UI was open before executing a Start/Stop, it must be reopened (or refreshed: CTRL-F5) otherwise it does not display the new state of the pool.

Regarding the log.log file, this one has better be located in a fix location. Edit the file log4j.properties and set a path like:

log4j.appender.default.File=C:/FlexRaid/FlexRAIDCmd.log

Pay attention to the path separator! It's not the one used by Windows but the one used in Java!

To shutdown the FlexRaid server after stopping the pool, use the command shutdown-server.

FlexRaid localhost - - shutdown-server

If the pool is still running, we get the following response:

Quote

{"success": false, "status": null, "commandMessages": [{"messageCode": "errorShutdownNotAllowedStoragePoolServiceRunning", "messageData": []}], serverMessages": null}
=> Pour pouvoir arrêter le service "host", le service de pool de stockage doit être arrêté!

If the service stops successfully, we get :

Quote

{"success": true, "status": null, "commandMessages": [{"messageCode": "successServerShutingDown", "messageData": []}], "serverMessages": null}
=> Arrêt du serveur en cours...

To restart the service, we can use:

net start "FlexRaid"

Notice: I didn't find yet on the forum the difference between 'FlexRaid localhost - - shutdown-server' and 'net stop "FlexRaid'. To my knowledge 'net stop' is synchronous and therefore maybe preferred to stop the service properly before shutting down ?! (FlexRaid message seems to indicate it's asynchronous)

Notice: If I run "FlexRaid localhost -- shutdown-server" while the service is not running, I get obviously an exception "Connection refused: connect : ConnectException" but also this message in the log file (log.log):

Quote

ERROR: Unexpected character ('A' (code 65)): expected a valid value (number, String, array, object, 'true', 'false' or 'null')
at [Source: java.io.StringReader@2f3d698; line: 1, column: 2] org.codehaus.jackson.JsonParseException: Unexpected character ('A' (code 65)): expected a valid value (number, String, array, object, 'true', 'false' or 'null')
at [Source: java.io.StringReader@2f3d698; line: 1, column: 2]

Now, here is how to create a "shutdown task" in the Local Group Policies of a Windows Server 2012:

1) Enable script execution on the server
a) On the Start Screen right-click the Windows PowerShell tile and run it As Administrator
b) execute "Set-ExecutionPolicy RemoteSigned" in that shell and answer "Y"

2) Create the script
a) Create a file "StopFlexRaid.ps1" in your "FlexRaid Client" folder (e.g.).
b) Type the script found bellow in the file (change the path to FlexRaidCmd)

3) Use the script as Shutdown Script
a) On the Start Screen, type "gpedit.msc" and run it.
b) Go to the node "Computer Configuration\Windows Settings\Scripts (Startup/Shutdown)".
c)  Edit "Shutdown" and in the tab "PowerShell script", "Add" StopFlexRaid.ps1

Notice:
- Shutdown scripts are run as Local System, and they have the full rights that are associated with being able to run as Local System.
- Shutdown scripts are run synchronously. The Server should wait on the script before shutting down.

Here is the StopFlexRaid script:


$srvName = "FlexRAID"
$flexCmd = "C:\Program Files (x86)\FlexRAID 2.0 Client\FlexRAIDCMD.exe"
$servicePrior = Get-Service $srvName
#"$srvName is currently " + $servicePrior.status

function ExitWithCode
{
 param
 (
 $exitcode
 )
 "Exit with code $exitcode"
 #$host.SetShouldExit($exitcode)
 #exit
}

$flexCmd = "C:\Program Files (x86)\FlexRAID 2.0 Client\FlexRAIDCMD.exe"

function ExecuteFRCmd([string]$cmd, [string]$hostname="localhost", [string]$port="-", [string]$timeout="-")
{
 $error.clear()

$pinfo = New-Object System.Diagnostics.ProcessStartInfo
 $pinfo.FileName = $flexCmd
 $pinfo.RedirectStandardError = $true
 $pinfo.RedirectStandardOutput = $true
 $pinfo.UseShellExecute = $false
 $pinfo.Arguments = "$hostname $port $timeout $cmd"
 $p = New-Object System.Diagnostics.Process
 $p.StartInfo = $pinfo
 $p.Start() | Out-Null
 $p.WaitForExit()
 $output = $p.StandardOutput.ReadToEnd()

 if ( $error.count -eq 0)
 {
 # Clean the JSON message (remove the trailing text (=> blabla))
 $output = $output -replace '(?<First>.*)=>.+', '${First}'
 }
 else
 {
 $output = $null
 }

 return $output
}

function IsAnyTaskRunning()
{
 $running = $FALSE

 $state = ExecuteFRCmd("status")

if ($state -eq $null)
 {
 throw "Command failed to execute"
 }
 else
 {
 #Write-Host "States: $state"

$process = $state | ConvertFrom-Json

 $message = $process.commandMessages.messageCode
 if ($message -eq "successNoProcessSinceServerStartup")
 {
 #Write-Host "No Process started since Server startup"
 }
 else
 {
 $processID = $process.status.referenceCode

do {
 $state = ExecuteFRCmd("status "+$processID)
 $process = $state | ConvertFrom-Json

switch ($process.status.status)
 {
 { @("STATUS_STARTED", "STATUS_PROCESSING", "STATUS_PAUSING", "STATUS_RESUMED", "STATUS_RESUMING") -contains $_ }
 {
 #Write-Host task $processID - $process.status.task - is running
 $running = $TRUE
 }
 { @("STATUS_COMPLETED", "STATUS_ABORTED", "STATUS_ABORTING", "STATUS_PAUSED") -contains $_ }
 {
 #Write-Host task $processID - $process.status.task - is not running
 }
 }

 $processID -=1
 } while (($processID -gt 0) -and ($running -eq $FALSE))
 }
 }

 return $running
}

Write-Eventlog -Logname 'Application' -source 'FlexRAID' -eventID 1 -EntryType Warning -Category 0 -message "Graceful FlexRAID Shutdown triggered"

$wid = [System.Security.Principal.WindowsIdentity]::GetCurrent()
$prp = new-object System.Security.Principal.WindowsPrincipal($wid)
$adm = [System.Security.Principal.WindowsBuiltInRole]::Administrator
$IsAdmin = $prp.IsInRole($adm)
if (-not $IsAdmin) {
 write-host "Current powershell process is not running with Administrator privileges"

$message = "Graceful FlexRAID Shutdown not running with adhoc rights..."
 Write-Eventlog -Logname 'Application' -source 'FlexRAID' -eventID 1 -EntryType Error -Category 0 -message $message
 cmd /c shutdown -a
 ExitWithCode -exitcode 2
}
elseif ($servicePrior.status -eq "Stopped")
{
 "$srvName is already " + $servicePrior.status
}
elseif ($servicePrior.status -ne "Running")
{
 "$srvName is not Running but " + $servicePrior.status
}
else
{
 $running = IsAnyTaskRunning
 if ($running -eq $TRUE)
 {
 $message = "FlexRAID process(es) still running and preventing Server to shutdown..."
 $message
 Write-Eventlog -Logname 'Application' -source 'FlexRAID' -eventID 1 -EntryType Error -Category 0 -message $message
 cmd /c shutdown -a
 ExitWithCode -exitcode 2
 }
 else
 {
 "Wait on the Storage Pool to stop. This can take a few seconds."

 $state = ExecuteFRCmd("view class1_0 stop")

 $state
 $abort = "False"

 if ( $state -eq $null)
 {
 "Storage Pool failed to stop"
 $error[0]
 $message = "FlexRaid Storage Pool failed to stop and is preventing Server to shutdown: " + $error[0]
 $message
 Write-Eventlog -Logname 'Application' -source 'FlexRAID' -eventID 1 -EntryType Error -Category 0 -message $message
 cmd /c shutdown -a
 ExitWithCode -exitcode 2
 }
 else
 {
 $process = $state | ConvertFrom-Json

 $message = $process.commandMessages.messageCode
 if ($message -eq "successStoragePoolStopped")
 {
 "Storage Pool successfuly stopped"
 Write-Eventlog -Logname 'Application' -source 'FlexRAID' -eventID 1 -EntryType Warning -Category 0 -message "Storage Pool stopped before shutting down"
 }
 else
 {
 if ($message -eq "errorNoActiveStoratePool")
 {
 "Storage Pool actually not started"
 }
 else
 {
 $abort = "True"
 $event = "FlexRaid Storage Pool failed to stop, preventing Server to shutdown: " + $state
 $event
 Write-Eventlog -Logname 'Application' -source 'FlexRAID' -eventID 1 -EntryType Error -Category 0 -message $event
 cmd /c shutdown -a
 ExitWithCode -exitcode 3
 }
 }

 if ($abort -eq "False")
 {
 $error.clear()
 Stop-Service $srvName
 if ( $error.count -eq 0)
 {
 Write-Host -NoNewLine "Waiting on $srvName to stop "
 $timeout = new-timespan -Minutes 1
 $sw = [diagnostics.stopwatch]::StartNew()
 while (((Get-Service $srvName).status -ne "Stopped") -and ($sw.elapsed -lt $timeout))
 {
 Write-Host -NoNewLine "."
 sleep 1
 }
 "."
 }

 $serviceAfter = Get-Service $srvName
 if ($serviceAfter.status -eq "Stopped")
 {
 "$srvName is now " + $serviceAfter.status
 ExitWithCode -exitcode 0
 }
 else
 {
 "$srvName failed to stop. It is now " + $serviceAfter.status
 ExitWithCode -exitcode 1
 }
 }
 }
 }
}

Here is the code to start FlexRaid, useful while testing.


$srvName = "FlexRAID"
$flexCmd = "C:\Program Files (x86)\FlexRAID 2.0 Client\FlexRAIDCMD.exe"
$servicePrior = Get-Service $srvName
#"$srvName is currently " + $servicePrior.status

function ExitWithCode
{
 param
 (
 $exitcode
 )
 "Exit with code $exitcode"
 #$host.SetShouldExit($exitcode)
 #exit
}

if ( ($servicePrior.status -ne "Stopped") -and ($servicePrior.status -ne "Running"))
{
 "$srvName is not Stopped but " + $servicePrior.status
}
else
{
 if ($servicePrior.status -eq "Running")
 {
 "$srvName is already " + $servicePrior.status
 }
 else
 {
 Start-Service $srvName

 Write-Host -NoNewLine "Waiting on $srvName to start "
 $timeout = new-timespan -Minutes 1
 $sw = [diagnostics.stopwatch]::StartNew()
 while (((Get-Service $srvName).status -ne "Running") -and ($sw.elapsed -lt $timeout))
 {
 Write-Host -NoNewLine "."
 sleep 1
 }
 "."
 }

 $serviceAfter = Get-Service $srvName
 if ($serviceAfter.status -eq "Running")
 {
 "$srvName is now " + $serviceAfter.status

 $error.clear()
 "Wait on the Storage Pool to start. This can take a while."
 $stopPool = Start-Process $flexCmd -ArgumentList "localhost - - view class1_0 start" -NoNewWindow -Wait -PassThru

 if ( $error.count -eq 0)
 {
 ExitWithCode -exitcode 0
 }
 else
 {
 "Storage Pool failed to start"
 $error[0]
 ExitWithCode -exitcode 2
 }
 }
 else
 {
 "$srvName failed to start. It is now " + $serviceAfter.status
 ExitWithCode -exitcode 1
 }
}

2 thoughts on “Use FlexRAIDCmd within PowerShell scripts to gracefully stop FlexRAID

  1. I though I could "pause" the FlexRAID processes currently running and let the server shutdown. But processes may not be resumed anymore if FlexRAID service is restarted :(

Leave a Reply

Your email address will not be published. Required fields are marked *