Skip to main content
Skip table of contents

Configure a Synthetic Scenario

Firefox in a headless environment

Set up Synthetic Monitoring with Firefox in a headless environment

Install Gecko driver

Get the latest version from here - https://github.com/mozilla/geckodriver/releases

BASH
wget https://github.com/mozilla/geckodriver/releases/download/v0.28.0/geckodriver-v0.28.0-linux64.tar.gz
tar -xf geckodriver-v0.28.0-linux64.tar.gz
sudo mv geckodriver /usr/bin/geckodriver
cd /usr/bin/
chmod +x geckodriver
geckodriver -v


Install Firefox

Get the latest stable version from here - https://ftp.mozilla.org/pub/firefox/releases/

Ubuntu

CODE
sudo apt update
sudo apt install firefox

CentOS/RHEL

CODE
su
rpm -Uvh http://download.fedoraproject.org/pub/epel/6/i386/epel-release-6-5.noarch.rpm
rpm -Uvh http://rpms.famillecollet.com/enterprise/remi-release-6.rpm
yum install firefox
firefox -v


Settings for Synthetic Web Component

When running Synthetic Web Component in Germain, ensure the following options are applied

Google Chrome in a headless environment

Set up Synthetic Monitoring with Google Chrome in a headless environment

Download/Install Chrome driver

Get latest version - https://chromedriver.chromium.org/downloads

CODE
sudo wget https://chromedriver.storage.googleapis.com/80.0.3987.106/chromedriver_linux64.zip
sudo unzip chromedriver_linux64.zip
sudo mv chromedriver /usr/bin/chromedriver
chromedriver – version


Install Google Chrome

CODE
sudo apt-get update
sudo apt-get install -y libappindicator1 fonts-liberation libasound2 libgconf-2 4 libnspr4 libxss1 libnss3 xdg-utils
wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
sudo dpkg -i google-chrome*.deb
sudo mv /usr/bin/google-chrome-stable /usr/bin/google-chrome

 

Internet Explorer in a "Headless" environment

Set up Synthetic Monitoring with Internet Explorer in a "Headless" mode.

Synthetic Monitoring with IE has a lot of requirements that will need to be filled. Sometimes there are choices. Some easier than others.

Note: Although IE cannot run in a truly headless environment, it is possible to bind a desktop session so it remains open once you are disconnected.

Configure

Prerequisites

  • Available in Germain 8.6.13+

  • Tested with Internet Explorer 11

  • Engine will need to be run in a desktop session

  • User that runs Engine must be an Administrator

  • Host System should allow PowerShell scripts to run

  • Setup a Dedicated Engine Manager / Engine Instance for running the IE Monitoring

    • Same as setting up any engine (Engine Deployment), Only difference is it will only run the Dedicated IE monitoring on it.

    • If you have more than one Engine Manage on the System, you will need to specify a separate port in the Germain GUI (See section “Setting a different port for Engine Manager“)

    • Remember to set a unique name in germain-bootstrap.properties (germain.bootstrap.node="Node Name")

Internet Explorer cannot be run “headless”

So we will need to set up the engine to run in a desktop session.

Solution

Run the Germain in an active desktop session.

This is accomplished by use of the command tscon which we can use to hand off the RDP desktop session we use to connect to the Engine host.

Here is a PowerShell script that will clean up lingering processes from previous runs of the Engine, launch the engine, then hand off the the RDP desktop session (which will disconnect your RDP session)

You will need to edit this script to define the location of the dedicated IE Synthetic Monitoring Engine

start-active-engine.ps1 (WIP, need variables ser for Engine location etc..)
POWERSHELL
### Make sure we are administrator
#Requires -RunAsAdministrator

### Location of dedicated IE Synthetic Monitoring Engine
$EngineUser="germain_engine"
$EngineLocation="C:\Germain\GermainEngineIEMonitor\"

### Clean up related engine & manager
$nodes=@(Get-CimInstance Win32_Process -Filter "name = 'Java.exe'" | Where-Object {$_.CommandLine -like "*apmname=ie_syntheticnode*"})
$nodes | ForEach-Object { Stop-Process -ID $_.processID }
Start-Sleep -s 5
$nodes=@(Get-CimInstance Win32_Process -Filter "name = 'Java.exe'" | Where-Object {$_.CommandLine -like "*apmname=ie_syntheticnode*"})
$nodes | ForEach-Object { Stop-Process -Force -ID $_.processID }
$engns=@(Get-CimInstance Win32_Process -Filter "name = 'Java.exe'" | Where-Object {$_.CommandLine -like "*apmname=ie_syntheticengine*"})
$engns | ForEach-Object { Stop-Process -Force -ID $_.processID }

### clean up iedriver and iexplore processes
Get-Process iedriverserver -ErrorAction SilentlyContinue | stop-process
Get-Process iexplore -ErrorAction SilentlyContinue | stop-process

### Get Engine started

Set-Location $EngineLocation
Start-Process -WorkingDirectory $EngineLocation -FilePath "$($EngineLocation)\bin\startEngineManager.bat"

### Get the Desktop session ID
$ts=((qwinsta).Trim() -replace "\s+","," | ConvertFrom-Csv)
$ts=($ts | Where-Object { $_.username -eq "$EngineUser" })
# #$ts[0].id

### Background the RDP session so iedriverserver doesn't fail to keep running
Start-Process -FilePath "C:\Windows\System32\tscon.exe" -ArgumentList "$($ts[0].id)","/dest:console"

$null = Read-Host -Prompt "Press Enter to continue..."

You will also need to edit your startEngineManager.bat to include -Dapmname=ie_syntheticnode so that the PowerShell script can find the node to shut it down during it’s clean-up phase.

startEngineManager.bat (See line 16)
CODE
@echo off
REM -------------------------------------------------
REM Copyright (C) 2014-2019 Germain Software
REM -------------------------------------------------
SET JAVA="%JAVA_HOME%\bin\java.exe"

REM Identify Germain home
IF NOT "%GERMAIN_HOME%" == "" GOTO start
SET GERMAIN_HOME=%cd%
IF EXIST "%GERMAIN_HOME%\bin\apm-engine-manager.jar" GOTO start
cd ..
SET GERMAIN_HOME=%cd%

:start
cd %GERMAIN_HOME%
SET VMARGS=-Dapmname=ie_syntheticnode -Dgermain.jvm=%JAVA% -Xms256m -Xmx512m -XX:+CrashOnOutOfMemoryError
SET JAR=bin/apm-engine-manager.jar
echo Starting Germain Engine Manager...
%JAVA% %VMARGS% -jar %JAR%

You will need to add an argument to your Engine configuration in the Germain Workspace “Germain State” so that the engine can be identified and closed as well by the PowerShell script. -Dapmname=ie_syntheticengine

One Synthetic Scenario at a time

Note:

  • IE cannot isolate it’s windows from each other. Attempting to run more than one scenario at a time in the same user / session will lead to cross over (cookies, etc…).

  • The IE driver will have trouble if it’s IE window is not the currently focused window.

Solutions

Option 1: Combine all scenarios into one

You can run all you scenarios from one Germain Component and have them take their turn running. One will run each time the component is called.

If you run the Monitor once per minute and have 15 Scenarios in the Component, each Scenario will be run once every 15 minutes.

Note: All Scenarios need to be shorter than the interval that the Monitor runs on.

We have created a framework to be used in the components code.

See Example Compound Component code here
JAVA
log.info("***** Starting: All IE Synthetic Monitoring *****.");
import org.openqa.selenium.ie.*;
import java.io.File;

import java.lang.StringBuilder;

import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;

//Slot tracking file.  Must be writable by user that launched engine.
String rr_path = "C:\\Germain\\GermainEngineIEMonitor\\temp\\rr.txt";
//How many slots to use
int rr_max = 1; //currently uses only the first slot.  Set to 7

//**********************************
// Define user variable here (For when the same values are used in multiple slots)
//**********************************
log.info("***** Preparing Creds");

String username="username";
String password="hexstringofpassword";
String host_name = "ServersName";
String host_hostname = "www.hostname.com";
//convert hex in String to characters
StringBuilder output = new StringBuilder();
for (int i = 0; i < kmp.length(); i+=2) {
    String str = kmp.substring(i, i+2);
    output.append((char)Integer.parseInt(str, 16));
}
password = output;
//Siebel

//Read and update slot tracking file rr_path
int rr_pos;
File f = new File(rr_path);
if(f.exists() && !f.isDirectory()) { 
    // Read rr file
    String t_rr_pos = new String(Files.readAllBytes(Paths.get(rr_path)), StandardCharsets.UTF_8);
    rr_pos = Integer.parseInt(t_rr_pos);
    rr_pos+=1;
    if(rr_pos > rr_max) { rr_pos = 1; }
}else{
    //Make it
    log.info("***** No rr file '" + rr_path + "'");
    rr_pos = 1;
    if (f.createNewFile()) {
        log.info("***** File created: " + f.getName());
    } else {
        log.info("***** Could not create '" + rr_path + "'");
    }    
}
Files.write(Paths.get(rr_path), (""+rr_pos+"").getBytes());

//Temporary Override (If debugging, only run this slot)
//rr_pos = 5;

//Define Slots.  You can always add more slots.
log.info("***** Selected: Slot " + rr_pos + " of " + rr_max);
if(rr_pos == 1) {
    log.info("***************************");
    log.info("***** Slot 1: Running *****");
    log.info("***************************");
	//This is a rough example of a component that logs into a Knowlege Base, searches the Knowlege Base, then times how long it takes to open a specific decision tree
	
    context.system.name = host_name;
    context.system.hostname = host_hostname;
    LocalDateTime scriptStartTime = LocalDateTime.now();
    org.openqa.selenium.support.ui.WebDriverWait wait = new org.openqa.selenium.support.ui.WebDriverWait(driver, 30);


    //Clear Cookies - FAIL Does not clear session
    log.info("*** Clearing Cookies");
    driver.manage().deleteAllCookies();

    //Try to see if we can use a runtime - FAIL Does not clear session
    log.info("***** Clearing Cookies via InetCpl...");
    Runtime.getRuntime()exec("RunDll32.exe InetCpl.cpl,ClearMyTracksByProcess 255");

    // Get the login page
    String base = String.format("https://%s/app/home", host_hostname);
    log.info("***** Getting page");
    driver.get(base);
    //Close Authentication pop-up
    log.info("***** Waiting for Authentication Alert");
    Alert alert = wait.until(ExpectedConditions.alertIsPresent());
    log.info("***** Closing Alert");
    alert.dismiss();

    // Search for username / password input and fill the inputs
    wait.until(org.openqa.selenium.support.ui.ExpectedConditions.visibilityOfElementLocated(By.xpath("//input[@name='username']")));
    log.info("***** Entering Username");
    driver.findElement(By.xpath("//input[@name='username']")).sendKeys(kmu);
    log.info("***** Entering Password");
    driver.findElement(By.xpath("//input[@name='pass']")).sendKeys(kmp);
    log.info("***** Clicking");
    driver.findElement(By.xpath("//a[@title='Login']")).click();

    // Once search page has loaded, wait to let scripts fully execute
    wait.until(org.openqa.selenium.support.ui.ExpectedConditions.visibilityOfElementLocated(By.xpath("//input[@name='searchfield_element_name']")));

    // Perform search 
    driver.findElement(By.xpath("//input[@name='searchfield_element_name']")).sendKeys("Search For This");
    driver.findElement(By.xpath("//button[@class='SubmitButton']")).click();

    // Wait for results
    wait.until(org.openqa.selenium.support.ui.ExpectedConditions.visibilityOfElementLocated(By.xpath("//div[@class='SearchResultTitleAnswer']")));

    //Start Timer
    LocalDateTime startTime = LocalDateTime.now();	

    // Click on result 
    driver.findElement(By.linkText("Target Link Text")).click();

    //Wait for page to load scripted elements
    wait.until(org.openqa.selenium.support.ui.ExpectedConditions.visibilityOfElementLocated(By.xpath("//select[@id='elementIdInDecisionTree']")));

    // Create login transaction
    GenericTransaction tx = new GenericTransaction();
    tx.type = "KB:DT Short Name";
    tx.name = "DT Long Name";
    tx.timestamp = scriptStartTime;
    tx.user.name = credentials.username;
    tx.duration = DateTimeUtils.computeDuration(startTime, LocalDateTime.now());
    tx.success = driver.getPageSource().contains("<select id=\"elementIdInDecisionTree\"");
    datamart.insert(tx, context);
    
    driver.close();

	//If you would like to see the details of the fact being submitted
    //log.info("Synthetic tx: {}", tx);
    log.info("***************************");
    log.info("***** Slot 1: Done ********");
    log.info("***************************");

}
if(rr_pos == 2) {
    log.info("***************************");
    log.info("***** Slot 2: Running *****");
    log.info("***************************");
	//Define Target System in context so submitted fact will contain correct details
    context.system.name = "Example";
    context.system.hostname = "www.example.com";


	//Your Synthetic Monitoring Code here


	//Close driver when done
    driver.close();
	//If you would like to see the details of the fact being submitted
    //log.info("Synthetic tx: {}", tx);
    log.info("***************************");
    log.info("***** Slot 2: Done ********");
    log.info("***************************");
}
if(rr_pos == 3) {
    log.info("***************************");
    log.info("***** Slot 3: Running *****");
    log.info("***************************");
	//Define Target System in context so submitted fact will contain correct details
    context.system.name = "Example";
    context.system.hostname = "www.example.com";


	//Your Synthetic Monitoring Code here


	//Close driver when done
    driver.close();
	//If you would like to see the details of the fact being submitted
    //log.info("Synthetic tx: {}", tx);
    log.info("***************************");
    log.info("***** Slot 3: Done ********");
    log.info("***************************");
}
if(rr_pos == 4) {
    log.info("***************************");
    log.info("***** Slot 4: Running *****");
    log.info("***************************");
	//Define Target System in context so submitted fact will contain correct details
    context.system.name = "Example";
    context.system.hostname = "www.example.com";


	//Your Synthetic Monitoring Code here


	//Close driver when done
    driver.close();
	//If you would like to see the details of the fact being submitted
    //log.info("Synthetic tx: {}", tx);
    log.info("***************************");
    log.info("***** Slot 4: Done ********");
    log.info("***************************");
}
if(rr_pos == 5) {
    log.info("***************************");
    log.info("***** Slot 5: Running *****");
    log.info("***************************");
	//Define Target System in context so submitted fact will contain correct details
    context.system.name = "Example";
    context.system.hostname = "www.example.com";


	//Your Synthetic Monitoring Code here


	//Close driver when done
    driver.close();
	//If you would like to see the details of the fact being submitted
    //log.info("Synthetic tx: {}", tx);
    log.info("***************************");
    log.info("***** Slot 5: Done ********");
    log.info("***************************");
}
if(rr_pos == 6) {
    log.info("***************************");
    log.info("***** Slot 6: Running *****");
    log.info("***************************");
	//Define Target System in context so submitted fact will contain correct details
    context.system.name = "Example";
    context.system.hostname = "www.example.com";


	//Your Synthetic Monitoring Code here


	//Close driver when done
    driver.close();
	//If you would like to see the details of the fact being submitted
    //log.info("Synthetic tx: {}", tx);
    log.info("***************************");
    log.info("***** Slot 6: Done ********");
    log.info("***************************");
}
if(rr_pos == 7) {
    log.info("***************************");
    log.info("***** Slot 7: Running *****");
    log.info("***************************");
	//Define Target System in context so submitted fact will contain correct details
    context.system.name = "Example";
    context.system.hostname = "www.example.com";


	//Your Synthetic Monitoring Code here


	//Close driver when done
    driver.close();
	//If you would like to see the details of the fact being submitted
    //log.info("Synthetic tx: {}", tx);
    log.info("***************************");
    log.info("***** Slot 7: Done ********");
    log.info("***************************");
}

log.info("***** Exiting: All IE Synthetic Monitoring *****.");

Note:

  • context.system.name must be set for each slot in the Component script.

  • context.system.hostname must be set for each slot in the Component script.

Note: In the script above there is a variable tt_path defined. This is the path to a text file that is used to keep track of which slot to use next when the Monitor runes. This file must be writable by the User used to launch the Engine.

Note: When writing Synthetic Monitoring Components for IE there are many Alert Pop-Ups you will need to dismiss. This code snippet can handle them. log.info is optional.

JAVA
    //Close Authentication pop-up
    log.info("***** Waiting for Authentication Alert");
    Alert alert = wait.until(ExpectedConditions.alertIsPresent());
    log.info("***** Closing Alert");
    alert.dismiss();
Option 2: Go wide

You can avoid scenario / windows focus conflicts by having a separate engine on a separate Windows User or host system (for the Engine) for each Scenario.

If you are on a separate user or system, there will be no cross talk between IE instances, and there will be no focus problems.

Note: This can require a lot of resources


On the Component, must set driver option for Clean Session

If the option isn’t added to the Component, the session settings and cookies will persist between sessions and cause unpredictable and uncontrollable behavior.

To prevent this, add ie.ensureCleanSession=true


Handle "Enhanced Security Configuration"

If IE is set to “Enhanced Security Configuration”, it will add complexity to managing your Synthetic Scenarios.

If you cannot disable it, you will need to clear any alerts that may happen manually(and make sure they do not re-occur).

If you get these alert, check the box to not show them again.

You will also need to Manually perform the scenario and add all involved domains/URLs to Trusted Sites.

If you see this, click “Add…”. Leave the box checked, or it will be much harder to figure out what to add to trusted sites.

Click Add again. Then close the dialogs.

Internet Options: All Security Zone must have the same “Protected Mode” setting

Open “Internet Options” → “Security”

  1. Go to each Zone

  1. Check up uncheck the “Protected Mode” option.

(All zones must be the same)

Internet Options: Must allow Scripting

Most modern sites cannot function without scripting. Verify that Active Scripting is Enabled in these zones:

  • Internet

  • Local Intranet

  • Trusted Sites

(Security --> [appropriate zone] --> Custom Level... --> Scripting --> Active Scripting --> Enable)

Launching/Relaunching the Dedicated Engine for IE Synthetic Monitoring

If the Engine with a Desktop Session is interrupted, but being logged out or from a Windows Server Restart, you will need to launch it again. Here are the details.

For convenience I recommend having a few things available.

  1. A shortcut to launch PowerShell as an Administrator

    1. See Section “Create an Admin PowerShell Shortcut”

  2. A stop script to easily shutdown the engine if you need to make changes on the user. (The IE Driver will get in the way)

stop-active-engine.ps1 (Click to Expand)
POWERSHELL
### Make sure we are administrator
#Requires -RunAsAdministrator

### Clean up related engine & manager
$nodes=@(Get-CimInstance Win32_Process -Filter "name = 'Java.exe'" | Where-Object {$_.CommandLine -like "*apmname=ie_syntheticnode*"})
$nodes | ForEach-Object { Stop-Process -ID $_.processID }
Start-Sleep -s 5
$nodes=@(Get-CimInstance Win32_Process -Filter "name = 'Java.exe'" | Where-Object {$_.CommandLine -like "*apmname=ie_syntheticnode*"})
$nodes | ForEach-Object { Stop-Process -Force -ID $_.processID }
$engns=@(Get-CimInstance Win32_Process -Filter "name = 'Java.exe'" | Where-Object {$_.CommandLine -like "*apmname=ie_syntheticengine*"})
$engns | ForEach-Object { Stop-Process -Force -ID $_.processID }

### clean up iedriver and iexplore processes
Get-Process iedriverserver -ErrorAction SilentlyContinue | stop-process
Get-Process iexplore -ErrorAction SilentlyContinue | stop-process

$null = Read-Host -Prompt "Stop Complete. Press Enter to continue..."

Steps:

  1. RDP to the Host VM as the user you run the Dedicated IE Synthetic Monitoring Engine on

  2. Start an Administrator PowerShell Console (Using the link you created earlier)

  3. Run the PowerShell Script from section “IE cannot be run “headless””

    1. Example name was start-active-engine.ps1

  4. You will be disconnected shortly after running the script (This is good)

  5. Verify components are running Error free in the Engine Log file.

  6. Verify New data is showing up in the drillthroughs on your portlets after one cycle has completed (Slots * Monitor Interval)

Create an Admin PowerShell Shortcut

Follow the steps in the screenshots below for creating an Admin PowerShell Shortcut

Rename the Shortcut created to “Admin PowerShell”

Setting a different port for Engine Manager

Select your Engine Manager / Node in Germain State

Alter the “State Store URL” and the “State Store Server Port” to use an unused port on the Host System

If you are having any difficulty, please contact us.

JavaScript errors detected

Please note, these errors can depend on your browser setup.

If this problem persists, please contact our support.