Launchers
In mty last post, I shared a tool that I made to monitor the status of our 6 Login Enterprise Pods. This tool checks the status of Continuous Tests and Test Accounts and display which ones were not enabled.
The next piece that I want to check is the status of the Launcher Agents. With the tests and accounts, the Login Enterprise SQL database has tables that have a column that indicates whether the component is enabled or disabled. Unfortunately, there is no such property for the Launcehrs. Well, to be perfectly honest, there IS a field call Online which is Boolean (true or false). However, as I’m sure most of you are aware of, is that when a Launcher Agent is not communicating with the Appliance, the appliance loses all knowledge of that launcher. Actually, that’s entirely true, either. There IS a table in the database that holds a list of any launcher that ever connected to the appliance, Management.LauncherProperties. But, since there is no way to manage the launchers if they are decommisioned, this is not a viable way to monitor the launcher states. (Note: I did ask LVSI if I could manually remove entries from this table and it is unknown what effect that would have.) So, I wound up creating a text file that contains the name of all the launchers. I used one text file for each pod so that I can be as granular as I want in managing the launchers.
Powershell
So, the approach to get the launcher status is a bit different. Instead of doing a simple SQL query, I used the LE API to enumerate the launchers for each pod. Then I read the contents of the 6 text files that contain the names of the known launcehrs to compare it to. Then I loop through the whole process every 5 minutes, writing out the CSV file to my WWWROOT folder.
This is the function that I used to access the API to enumerate the launchers:
function Get-Launchers {
Param (
[parameter(Mandatory=$true, Position=0)] $fqdn,
[parameter(Mandatory=$true, Position=0)] $token,
[string]$orderBy = "name",
[string]$testType = "continuousTest",
[string]$Direction = "Asc",
[string]$Count = "10000"
)
# this is only required for older version of PowerShell/.NET
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 -bor [Net.SecurityProtocolType]::Tls11
# WARNING: ignoring SSL/TLS certificate errors is a security risk
[System.Net.ServicePointManager]::ServerCertificateValidationCallback = [SSLHandler]::GetSSLHandler()
$Header = @{
"Accept" = "application/json"
"Authorization" = "Bearer $token"
}
$Body = @{
testType = $testType
orderBy = $orderBy
direction = $direction
count = $Count
}
$Parameters = @{
Uri = 'https://' + $fqdn + '/publicApi/v7-preview/launchers'
Headers = $Header
Method = 'GET'
body = $Body
ContentType = 'application/json'
}
$Response = Invoke-RestMethod @Parameters
$Response.items
}
This is taken from the LoginEnterpriseFunctions.ps1 file downloaded from the LVSI support site. I did add two paramters to pass through the URL and Secret of the appliance. This way I can reuse the function for each pod. So, the code I wound up with the get the launchers is:
$Pod1Launchers = Get-Launchers -fqdn <Pod1Url> -token <Pod1token> | Select-Object -Property MachineName
$Pod2Launchers = Get-Launchers -fqdn <Pod1Url> -token <Pod2token> | Select-Object -Property MachineName
$Pod3Launchers = Get-Launchers -fqdn <Pod1Url> -token <Pod3token> | Select-Object -Property MachineName
$Pod4Launchers = Get-Launchers -fqdn <Pod1Url> -token <Pod4token> | Select-Object -Property MachineName
$PodGLaunchers = Get-Launchers -fqdn <Pod1Url> -token <PodFtoken> | Select-Object -Property MachineName
$PodVLaunchers = Get-Launchers -fqdn <Pod1Url> -token <PodVtoken> | Select-Object -Property MachineName
$AllLaunchers = $($Pod1Launchers; $Pod2Launchers; $Pod3Launchers; $Pod4Launchers; $PodGLaunchers; $PodVLaunchers)
As we only need the name of the launcher, I pipe to Select-Object to return just the property MachineName.
Next, I combine all 6 arrays into one to compare this to the known good launchers.
The code reads the contents of each text file and combines them into a single array for comparison.
$Pod1LaunchersKnown = Get-Content "<path>\Pod1Launchers.txt"
$Pod2LaunchersKnown = Get-Content "<path>\Pod2Launchers.txt"
$Pod3LaunchersKnown = Get-Content "<path>\Pod3Launchers.txt"
$Pod4LaunchersKnown = Get-Content "<path>\Pod4Launchers.txt"
$PodGLaunchersKnown = Get-Content "<path>\PodGLaunchers.txt"
$PodVLaunchersKnown = Get-Content "<path>\PodVLaunchers.txt"
$AllLaunchersKnown = $($Pod1LaunchersKnown; $Pod2LaunchersKnown; $Pod3LaunchersKnown; $Pod4LaunchersKnown; $PodGLaunchersKnown; $PodVLaunchersKnown)
Now, it’s a simple matter of comparing the two files and collecting what’s missing from the AllLaunchers compared to the AllLaunchersKnown lists.
$Missing = $($timedate; $AllLaunchersKnown | Where {$Alllaunchers.machinename -NotContains $_})
$Missing | out-file $report
Then I write that file out to the WWWroot folder on the IIS server and add the following section to the .PHP file to display the table.
//Get the Missing Launchers table
//Verify the password (if set)
if( $password === ""){
if(file_exists($Launchersfile)){ // File exists
// Reads lines of file to array
$fileLines = file($Launchersfile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
//Not Empty file
if($fileLines !== array()){
//Extract the existing header from the file
$lineHeader = array_shift($fileLines);
$logOriginalHeader = array_map('trim', str_getcsv(substr($lineHeader,$ignorePreHeader), $delimiter, $enclosure));
//Process the file only if the system could find a valid header
if(count($logOriginalHeader) > 0) {
//Open the table tag
$LaunchOutput="<TABLE style='50%'>";
//Print the table header
$LaunchOutput.="<TR style='background-color: lightgray;text-align:center;'>";
$LaunchOutput.="<th style='width:10px'><B>Row</B></Th>";
foreach ($logOriginalHeader as $field)
$LaunchOutput.="<Th><B>".$field."</B></Th>"; //Add the columns
$LaunchOutput.="</TR>";
//Get each line of the array and print the table files
$Linenumber = 0;
foreach ($fileLines as $line) {
if(trim($line) !== ''){ //Remove blank lines
$Linenumber++;
$arrayFields = array_map('trim', str_getcsv($line, $delimiter, $enclosure)); //Convert line to array
$LaunchOutput.="<TR><TD style='background-color: lightgray;'>".$Linenumber."</TD>";
foreach ($arrayFields as $field)
$LaunchOutput.="<TD>".$field."</TD>"; //Add the columns
$LaunchOutput.="</TR>";
}
}
//Print the table footer
$LaunchOutput.="<TR style='background-color: lightgray;text-align:center;'>";
$LaunchOutput.="<TD><B>Row</B></TD>";
foreach ($logOriginalHeader as $field)
$LaunchOutput.="<TD><B>".$field."</B></TD>"; //Add the columns
$LaunchOutput.="</TR>";
//Close the table tag
$LaunchOutput.="</TABLE>";
}
else $LaunchOutput = "<b>Invalid data format</b>";
}
else $LaunchOutput = "<b>Empty file</b>";
}
else $LaunchOutput = "<b>File not found</b>";
}
else $LaunchOutput = "<b>Invalid password.</b> Enter the password using this URL format: ".$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']."?Password=<b>your_password</b>";
The result is this:
Next steps
I mentioned in the first post that I was looing to run the Poweshell scripts as a service so that it is running all of the time. I am also looking to move away from a browser based board (I hate browser based apps! They are so limited in funtion and formatting options.). So, I will be looking at recreating all of this using Winforms or WPF. Stay tuned! 🙂