Page Sequence Monitor (PSM) Setup
Subscribe

From OpenNMS

Jump to: navigation, search

PSM

PSM stands for "Page Sequence Monitor". The PSM allows to monitor beyond the complexity of only requesting a single url.

A typical use case for this is:

  • You want to login to a certain application
  • Execute an action while being logged in
  • Log off again

If this is all working ok, your application works. If there's an error somewhere, your application will need attention.

Before the PSM, it was necessary to implement this using a Plugin. By the means of the GPPlugin you had to call a script to execute the queries and give feedback to OpenNMS about the result. Webinject is to be mentioned here.

With the PSM you can now run "simple" sequences from within OpenNMS without calling an external script. This has some advantages (better resource allocation, higher reliability, configuration for the full process in one place).

"Simple" sequences because they must be programmable in a sequence. A forward (30x Response) for example is right now not supported.


Service Detection

You can use the regular HTTP or HTTPS detector to detect a webapp.

PSM-http-detector.png

Poller

To configure a service using the PSM, the poller must be configured to know what page sequence it should use. With this monitor, the page sequence is defined as an XML element within a parameter! The parameter key attribute is required to be "page-sequence" and the value attribute is not specified. The value is actually an XML page-sequence element itself and is embedded within the definition of this special parameter.

(Note: this was done so that the page-sequence monitor could be used in the distributed monitor for the distributed monitor doesn't have access to the configuration files on the filesystem of the server. With the page-sequence configuration in-lined, it can be serialized and passed to the remote poller through the RMI interface)"

   <service name="OpenNMSLogin" interval="30000" user-defined="true" status="on">
        <parameter key="retry" value="1"/>
        <parameter key="timeout" value="5000"/>
        <parameter key="rrd-repository" value="/opt/opennms/share/rrd/response"/>
        <parameter key="ds-name" value="opennmslogin"/>
        <parameter key="page-sequence">
          <page-sequence>
            <page path="/opennms" port="8980" successMatch="Password" />
            <page path="/opennms/j_spring_security_check"  port="8980" method="POST">
              <parameter key="j_username" value="admin"/>
              <parameter key="j_password" value="admin"/>
            </page>
            <page path="/opennms/index.jsp" port="8980" successMatch="Log out" />
            <page path="/opennms/event/index.jsp" port="8980" successMatch="Event Queries" />
            <page path="/opennms/j_spring_security_logout" port="8980" successMatch="logged out" />
          </page-sequence>
        </parameter>
    </service>
        ...


        <monitor service="OpenNMSLogin" class-name="org.opennms.netmgt.poller.monitors.PageSequenceMonitor"/>

(Note: The XML definition of a page follows the same design as the HTTP Collector's URL in that it has the same attributes and child elements. See the HTTP Collector URL page fragment to learn about all these attributes)

(Note: In 1.8.7+, changes were made to how redirect behavior is handled. See NMS-3827 Page Sequence Monitor uses configured method instead of GET when following redirects for more detail.)

Page sequences work by attempting to retrieve each page defined in the sequence and verifying that it meets the specified expectations. If any page fails, then the entire sequence fails and the monitor returns 'UNAVAILABLE' with a reason code indicating the reason for failure. If all of the pages succeed, then the monitor returns 'AVAILABLE' with a response time indicating the time it takes to run the entire sequence.

The above page sequence works as follows:

  1. First do an HTTP GET of ${ipaddr}/opennms (following redirects as a browser would) and then checks to ensure that the resulting page has the phrase 'Password' on it. Each page is checked to ensure it HTTP response code fits into the response-range which defaults 100-399. This is done before any sucess or failure matches occur and out of range indicated a failing page.
  2. Next a login is attempted.
    1. The URL specified in the path attribute, is the relative URL used for submitting form data. The parameters for the page indicate the form's data and values to be submitted. In this example, the monitor will be sending the user and password as values for the form's j_username and j_password parameters.
    2. After getting the resulting page, first the expression specified in the page's failureMatch attribute is verified. If the failure match expression is found anywhere on the page, then page has failed. In this example, it indicates that the login failed. The failureMessage is then used to construct the reason code. ${n} values are used to pull information from matching groups in the failureMatch regular expression.
    3. If the failureMatch expression is not found in the resulting page, then the expression specified in the page's successMatch attribute is next checked to ensure it matches the resulting page. If successMatch expression is not found on the page, then the page fails. Both the failureMatch and the successMatch attributes are optional.
  3. If the monitor was able to successfully login, then the next page is processed. In this example, the monitor navicates to Event page to ensure that the text "Event Queries" is found on the page.
  4. The final page in the sequence is a logout page.

Another Example Using HTTP and HTTPS mixed

                <page-sequence>
                    <page scheme="http" host="ecomm.example.com" port="80"
                        path="/ecomm/jsp/Login.jsp"
                        virtual-host="ecomm.example.com"
                        successMatch="eComm Login" timeout="10000" http-version="1.1"/>
                    <page scheme="https" method="POST"
                        host="ecomm.example.com" port="443"
                        path="/ecomm/controller"
                        virtual-host="ecomm.example.com"
                        successMatch="requesttab_select.gif"
                        failureMessage="Login failed: ${1}"
                        timeout="10000" http-version="1.1">
                        <parameter key="action_name" value="XbtnLogin"/>
                        <parameter key="session_timeout" value=""/>
                        <parameter key="userid" value="EXAMPLE"/>                        
                        <parameter key="password" value="econ"/>
                    </page>                    
                    <page scheme="http" host="ecomm.example.com" port="80"
                        path="/econsult/controller"                        
                        virtual-host="ecomm.example.com"
                        successMatch="You have successfully logged out of eComm"
                        timeout="10000" http-version="1.1">
                        <parameter key="action_name" value="XbtnLogout"/>
                    </page>
                </page-sequence>

Session Variables

From OpenNMS 1.6.10 onward, the PSM supports session variables. This facility allows the assignment of strings from a retrieved page to variables that can be used in page parameters later in the same sequence. This example shows how to log in to the web UI of demo.opennms.org without knowing ahead of time what username and password to use.

    <page-sequence name="opennms-login-seq-dynamic-credentials">
      <page path="/opennms" port="80" virtual-host="demo.opennms.org"
            successMatch="(?s)User:.*<strong>(.*?)</strong>.*?Password:.*?<strong>(.*?)</strong>">
        <session-variable name="username" match-group="1" />
        <session-variable name="password" match-group="2" />
      </page>
      <page path="/opennms/j_acegi_security_check"  port="80" virtual-host="demo.opennms.org" method="POST"
            failureMatch="(?s)Your log-in attempt failed.*Reason: ([^<]*)" failureMessage="Login Failed: ${1}"
            successMatch="Log out">"
        <parameter key="j_username" value="${username}" />
        <parameter key="j_password" value="${password}" />
      </page>
      <page path="/opennms/event/index.jsp" port="80" virtual-host="demo.opennms.org" successMatch="Event Queries" />
      <page path="/opennms/j_acegi_logout" port="80" virtual-host="demo.opennms.org" successMatch="logged off" />
    </page-sequence>

The <session-variable> tags tell the PSM to assign match groups 1 and 2 from the successMatch regular expression of the first page to the variables username and password, respectively. The match groups correspond to the parenthesized sub-expressions in the expression, highlighted here:

(?s)User:.*&lt;strong&gt;(.*?)&lt;/strong&gt;.*?Password:.*?&lt;strong&gt;(.*?)&lt;/strong&gt;

(Note that the (?s) at the beginning of the regular expression is a modifier and not a subexpression.)

The variables are referenced in <parameter> child tags of the second page using the ${varName} convention:

<parameter key="j_username" value="${username}" />
<parameter key="j_password" value="${password}" />

Per-Page Response Times

From OpenNMS 1.6.10 onwards, the PSM can store the response times for individual pages in a sequence. To use this functionality, just add a ds-name attribute to each page whose load time you want to record. For example:

<page path="/opennms/event/index.jsp" ds-name="event-page" successMatch="Event Queries" />

The response time for each such page will be stored in the same RRD file specified for the service via the rrd-base-name parameter under the specified datasource name. Note that you will need to delete existing RRD files and let them be recreated with the new list of datasources when you add a ds-name attribute to a page in a sequence that is already storing response time data.

Per-Page Response Graph Configuration

Graph configuration for per-page response collection isn't entirely intuitive. RRD data of total session and each page is stored within a single file. Given the following poller configuration (removed unrelated bits):

    <service name="OpenNMSLogin" interval="300000" user-defined="false" status="on">
       <parameter key="rrd-repository" value="/opt/opennms/share/rrd/response"/>
       <parameter key="rrd-base-name" value="opennmslogin"/>
       <parameter key="ds-name" value="opennmslogin"/>
       <parameter key="page-sequence">
           <page path="/opennms/acegilogin.jsp" port="8980" ds-name="login-page" successMatch="Login" />
           <page path="/opennms/event/index.jsp" port="8980" ds-name="event-page" successMatch="Event Queries" />
         </page-sequence>
       </parameter>
   </service>

Graph definition (response-graph.properties) would end up as:

report.opennmslogin.name=OpenNMS Login
report.opennmslogin.columns=opennmslogin
report.opennmslogin.type=responseTime, distributedStatus
report.opennmslogin.command=--title="OpenNMS Login Response" \
 --vertical-label="Seconds" \
 DEF:totalrtMills={rrd1}:opennmslogin:AVERAGE \
 DEF:totalminRtMills={rrd1}:opennmslogin:MIN \
 DEF:totalmaxRtMills={rrd1}:opennmslogin:MAX \
 DEF:page1rtMills={rrd1}:login-page:AVERAGE \
 DEF:page1minRtMills={rrd1}:login-page:MIN \
 DEF:page1maxRtMills={rrd1}:login-page:MAX \
 DEF:page2rtMills={rrd1}:event-page:AVERAGE \
 DEF:page2minRtMills={rrd1}:event-page:MIN \
 DEF:page2maxRtMills={rrd1}:event-page:MAX \
 CDEF:totalrt=totalrtMills,1000,/ \
 CDEF:totalminRt=totalminRtMills,1000,/ \
 CDEF:totalmaxRt=totalmaxRtMills,1000,/ \
 CDEF:page1rt=page1rtMills,1000,/ \
 CDEF:page1minRt=page1minRtMills,1000,/ \
 CDEF:page1maxRt=page1maxRtMills,1000,/ \
 CDEF:page2rt=page2rtMills,1000,/ \
 CDEF:page2minRt=page2minRtMills,1000,/ \
 CDEF:page2maxRt=page2maxRtMills,1000,/ \
 LINE2:totalrt#00ff00:"Total Session" \
 GPRINT:totalrt:AVERAGE:" Avg\\: %6.2lf %s" \
 GPRINT:totalrt:MIN:"Min\\: %6.2lf %s" \
 GPRINT:totalrt:MAX:"Max\\: %6.2lf %s\\n" \
 AREA:page1rt#0000ff:"Login Page   " \
 GPRINT:page1rt:AVERAGE:" Avg\\: %6.2lf %s" \
 GPRINT:page1rt:MIN:"Min\\: %6.2lf %s" \
 GPRINT:page1rt:MAX:"Max\\: %6.2lf %s\\n" \
 STACK:page2rt#ff00ff:"Event Page   " \
 GPRINT:page2rt:AVERAGE:" Avg\\: %6.2lf %s" \
 GPRINT:page2rt:MIN:"Min\\: %6.2lf %s" \
 GPRINT:page2rt:MAX:"Max\\: %6.2lf %s\\n"

Importing a custom SSL-certificate

To import a SSL-certificate into the default keystore used by Java you should perform the following steps.

Obtain a Copy of the SSL Certificate

First, copy the SSL certificate to a file, preferably in PKCS#7 format. You can do this easily by using openssl:

$ openssl s_client -connect www.opennms.com:443

Then copy the certificate (the text in between "-----BEGIN CERTIFICATE---" and "-----END CERTIFICATE-----", including those tags) into a text file. This block of text is the PKCS#7-formatted certificate data.

You can also save the certificate using Firefox. In Firefox, visit the desired URL. Click on the SSL lock icon on the status bar once you reach the page. Click "View Certificate", then go to the "Details" tab, then click "Export...". This will allow you to export the certificate (or the entire certificate chain) in PKCS#7 format.

Another option is to simply contact the administrator of the service and have them give you a copy of the certificate file.

Note that the certificate file does not contain confidential or cryptographically insecure data: it is the public portion of the encrypted content. You are not compromising the security of the server by copying its certificate file.

Import the Certificate into the Keystore Using Java Keytool

Run the following command. If the JAVA_HOME environment variable is undefined, replace it with the full path where your Java Developer Kit (JDK) is installed.

$JAVA_HOME/bin/keytool -import -keystore $JAVA_HOME/jre/lib/security/cacerts -file <pkcs7_filename>

Debugging

Logs are kept in a couple files. There are some standard poller-type entries and a verbose http page log. They are enabled by setting appropriate DEBUG levels in the logging properties file. A restart is NOT needed.

etc/log4j.properties

# Pollers
log4j.category.OpenNMS.Poller=DEBUG, POLLERS
# Miscellaneous
...
log4j.category.httpclient=DEBUG, MISC


Version History/Availability