Login Enterprise Status Board – Part 2

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! 🙂

Leave a Reply