Other LogicModules

Creating PropertySources

PropertySources auto-assign properties at the device level based on the output of a Groovy or PowerShell script. Automating property assignments has a wide range of benefits for improved inventory tracking and reporting; troubleshooting; and dynamically grouping devices based on their shared properties.

At a high level, PropertySources work as follows:

  1. Your script interacts with a device to identify designated system information (for example, serial number, port speed, or firmware version)
  2. Establishes this information as a key-value pair (for example, port.number=443)
  3. Then assigns this key-value pair as a property on the device

Once established, PropertySources will run:

  • Every time the PropertySource is updated
  • Every time Active Discovery is manually executed (from Manage | Device)
  • Automatically once a day

Note: In order for PropertySources to work properly for cloud resources, you'll need to first enable monitoring via a local Collector.

In this support article, we will cover the following topics:

Configuring PropertySources

To create a new PropertySource, select Settings | PropertySources | Add | PropertySource. On the Create New PropertySource page, you will need to configure the settings shown below.

Name

As a best practice, give your PropertySource a descriptive name. Specifiy the platform or application and, if necessary, a specific component of the platform.

 

Description

As a best practice, if the PropertySource name does not sufficiently describe what the PropertySource is collecting, the Description field should provide enough additional detail so that someone viewing the name and description will easily recognize the PropertySource's purpose.

 

Group

In the Group field, specify the PropertySource group to which the PropertySource will be added. If this field is left empty, the PropertySource will not be added to a group.  If you enter text that does not match an existing PropertySource group, a new group will be created on the fly.

 

Applies To

The Applies To field defines which devices will be associated with this PropertySource. The expression entered into this field must follow AppliesTo Scripting Language syntax.

Click the Test AppliesTo button to display a list of all devices for which the new PropertySource will be applied, based on the current AppliesTo script.

PropertySource Script

PropertySource scripts may be written in a Groovy or PowerShell.

Let's take a look at how we would create a PropertySource that collects information from PureStorage arrays. This PropertySource will identify the array name, ID, revision, and version number and store this information as properties on the device.

To do this, we would employ the following Groovy script format:

  1. Import the Java Helper classes as well as the JsonSlurper class (used to parse JSON text into Groovy data structures legible for our script).
    import java.net.*;
    import java.io.*;
    import java.util.*;
    import java.text.*;
    import groovy.json.JsonSlurper;
  2. GET the array's hostname and API token, which should be set as properties on the device. Establish these responses as the values for the "hostName" and "apitoken" variables, respectively.
    hostName = hostProps.get("system.hostname");
    apitoken = hostProps.get("purestorage.apitoken.pass");
  3. Initiate the API URL to prepare to make the request.
    base_url           = "https://" + hostName;
    arrayInfo_commmand = "/api/1.4/array";
    api_url            = new URL(base_url + arrayInfo_commmand);
  4. GET session based on API authentication parameters defined in previous step.
    cookie = getSession();
  5. Open an HTTP connection and issue the arrayInfo request.
    connection   = api_url.openConnection();
    connection.setRequestMethod("GET");
    connection.setDoOutput(true);
    connection.setRequestProperty("Content-Type", "application/json");
    connection.setRequestProperty("Cookie", cookie); 
  6. Verify whether we received a valid response from our API endpoint.
    if (connection.getResponseCode() != 200)
    {
        // no -- return an error code that indicates failure
        return(2);
    }
  7. Collect the payload and parse the JSON into a map object.
    jsonslurper  = new JsonSlurper();
    arrayInfo_map = jsonslurper.parseText(connection.content.text);
  8. Iterate over the resultant map.
    arrayInfo_map.each
    {  key, value ->
        // print out each key and value
        println "$key=$value";
    }

Based on the format of the above script, we would expect an output resembling the following.

array_name=MY-PURE-001
id=93f00dad-b1aa-1234-5678-ec55f5ba55d6
revision=201609291808+e9e9b09
version=4.7.6

These four key-value pairs will be automatically stored as properties on your device. In the event that a value changes, the property will be updated during the next Active Discovery iteration.

To test your script's ability to properly assign the designated properties to a device, click the Test Script button and select a device to test the script against. Only devices that match the Applies To expression can be selected.

PropertySource Script Examples

For your convenience, we've provided several working, real-world PropertySource scripts to give you a starting point for common scenarios:

SNMP OID for NetApp Devices

Description:
Returns a list of OIDs related to all NetApp devices. Applies productVersion, productModel, productFirmwareVersion, productSerialNumber, ProductPartnerSerialNumber, and productMachineType as properties in key-value pair format on their respective devices.

Applies to:
isNetApp()

Groovy script:

import com.santaba.agent.groovyapi.snmp.Snmp;
// get the snmp host from the device properties
def host = hostProps.get('system.hostname');
// define a list of product oids
def netapp_product_mib =
[
productVersion          : '.1.3.6.1.4.1.789.1.1.3.0',
productModel            : '.1.3.6.1.4.1.789.1.1.7.0',
productFirmwareVersion  : '.1.3.6.1.4.1.789.1.1.11.0',
productSerialNum        : '.1.3.6.1.4.1.789.1.1.14.0',
productPartnerSerialNum : '.1.3.6.1.4.1.789.1.1.15.0',
productMachineType      : '.1.3.6.1.4.1.789.1.1.16.0',
];
// iterate over each oid entry
netapp_product_mib.each
{ key, oid ->
    // retrieve the oid and print the value
    value = Snmp.get(host, oid);
    println "auto." + key + "=" + value;
}
return(0);

SNMP Basic Information

Description:
Sets ‘location=something’, ‘contact=something’, and so on that it gets from SNMP values under the common branch 1.3.6.1.2.1.1.

Applies to:
hasCategory(“SNMP”)

Groovy script:

def hostname = hostProps.get("system.hostname") 
import com.santaba.agent.groovyapi.snmp.Snmp; //for SNMP get 
def OID_model = "1.3.6.1.2.1.1.1.0" // the OID we want 
def model = Snmp.get(hostname, OID_model); 
println "model=" + model //show on screen 
def OID_uptime = "1.3.6.1.2.1.1.3.0" // the OID we want 
def uptime = Snmp.get(hostname, OID_uptime); 
println "uptime=" + uptime 
def OID_contact = "1.3.6.1.2.1.1.4.0" // the OID we want 
def contact = Snmp.get(hostname, OID_contact); 
println "contact=" + contact 
def OID_system_name = "1.3.6.1.2.1.1.5.0" // the OID we want 
def system_name = Snmp.get(hostname, OID_system_name); 
println "system_name=" + system_name 
def OID_location = "1.3.6.1.2.1.1.6.0" // the OID we want 
def location = Snmp.get(hostname, OID_location); 
println "location=" + location 
return 0

Serial Number and BIOS from Windows

Description:
Set ‘serial_number=something’ and ‘BIOS_version=something’ using WMI (useful if you run Windows on bare-metal (not a hypervisor).

Applies to:
system.model !~ “Virtual” && system.model !~ “domU” && isWindows()
(For efficiency, narrow to only Windows on bare metal–not virtual)

Groovy script:

hostname=hostProps.get("system.hostname"); 
my_query="Select * from Win32_BIOS" 
namespace="CIMv2" 
import com.santaba.agent.groovyapi.win32.WMI; 
import com.santaba.agent.groovyapi.win32.WMISession; 
def session = WMI.open(hostname); 
def obj = session.queryFirst(namespace, my_query, 10); 
println "serial_number=" + obj.SERIALNUMBER 
println "bios_version=" + obj.SMBIOSBIOSVERSION 
return 0

Is Postgres Database Running

Description:
Set ‘postgres=yes’  by checking to see if a specific TCP port is open (useful for detecting lots of applications, e.g. Oracle uses port 1521, Postgres=5432, etc.)

Applies to:
Servers()
(For efficiency, narrow to only servers–not switches)

Groovy script:

def hostname = hostProps.get("system.hostname")
def port_number = 5432
try {
 new Socket(hostname, port_number).close(); // Socket try to open a REMOTE port
 println "postgres=yes" // remote port can be opened
 } catch(Exception e) {
 println "connection on port " + port_number + " failed"
 }
return 0

Hyper-V

Description:
Set ‘hyper-v=yes’, detects Microsoft Hyper-V by detecting if the service named VMMS (Hyper-V Virtual Machine Management) is running.

Applies to:
system.model !~ “Virtual” && system.model !~ “domU” && isWindows()
(For efficiency, narrow to only Windows on bare metal)

Groovy script:

hostname=hostProps.get("system.hostname") 
my_query="Select name,state from Win32_Service Where Name ='vmms'" 
import com.santaba.agent.groovyapi.win32.WMI; 
import com.santaba.agent.groovyapi.win32.WMISession; 
def session = WMI.open(hostname); 
def obj = session.queryFirst("CIMv2", my_query, 10); 
if (obj.STATE == "Running") { 
 println "hyper-v=yes" 
} else { 
 println "hyper-v=no" 
} 
return 0

Web_server

Description:
Set ‘Web_server=something’ property by retrieving the web page and grabbing the text next to “SERVER:” (e.g. Microsoft-IIS/8.5).

Applies to:
isWindows()
(For efficiency, narrow to only Windows)

Groovy script:

import com.santaba.agent.groovyapi.http.*; // needed for http.get 
def hostname=hostProps.get("system.hostname"); 
def my_url="http://" + hostname 
my_input_string = HTTP.get(my_url) 
def my_regex = /(?i)server: (.*)/ 
def my_matcher = (my_input_string =~ my_regex) 
my_stuff = my_matcher[0][1] 
println "web_server=" + my_stuff 
return 0;

Description:
Set ‘domain_controller=yes’ property if the service ‘NTDS’ (i.e. Active Directory Domain Services) is running.

Applies to:
isWindows()
(For efficiency, narrow to only Windows)

Groovy script:

hostname=hostProps.get("system.hostname"); 
my_query="Select name,state from Win32_Service Where Name ='NTDS'" 
import com.santaba.agent.groovyapi.win32.WMI; 
import com.santaba.agent.groovyapi.win32.WMISession; 
def session = WMI.open(hostname); 
def result = session.queryFirst("CIMv2", my_query, 10); 
if (result.STATE == "Running") { 
println "active_directory=yes" 
} else { 
println "active_directory=no" } 
return 0;

Exchange

Description:
Set ‘exchange=yes’ property if the service ‘MSExchangeADTopology’ (i.e. Microsoft Exchange Active Directory Topology) is running.

Applies to:
isWindows()
(For efficiency, narrow to only Windows)

Groovy script:

hostname=hostProps.get("system.hostname"); 
my_query="Select name,state from Win32_Service Where Name ='MSExchangeADTopology'" 
import com.santaba.agent.groovyapi.win32.WMI; 
import com.santaba.agent.groovyapi.win32.WMISession; 
def session = WMI.open(hostname); 
def result = session.queryFirst("CIMv2", my_query, 10); 
if (result.STATE == "Running") { 
println "exchange=yes" 
} else { 
println "exchange=no" } 
return 0

MS_SQL

Description:
Set ‘MS_SQL=yes’ if the service named MSSQLSERVER is running.

Applies to:
isWindows()
(For efficiency, narrow to only Windows)

Groovy script:

hostname=hostProps.get("system.hostname"); 
my_query="Select name,state from Win32_Service Where Name ='MSSQLSERVER'" 
import com.santaba.agent.groovyapi.win32.WMI; 
import com.santaba.agent.groovyapi.win32.WMISession; 
def session = WMI.open(hostname); 
def obj = session.queryFirst("CIMv2", my_query, 10); 
if (obj.STATE == "Running") { 
 println "MS_SQL=yes" 
} else { 
 println "MS_SQL=no" 
} 
return 0

MS_SQL_version

Description:
Set ‘MS_SQL_version=something’. Uses SQL query. Uses Windows auth but can be changed to use SQL auth.

Applies to:
system.db.mssql
(For efficiency,(narrow to only MS SQL computers)

Groovy script:

def hostname = hostProps.get("system.hostname"); 
import groovy.sql.Sql // needed for SQL connection and query 
def url = "jdbc:sqlserver://" + hostname + ";databaseName=master;integratedSecurity=true"; 
def driver = "com.microsoft.sqlserver.jdbc.SQLServerDriver";  
sql = Sql.newInstance(url, driver) // connects to SQL server 
def query_result = sql.firstRow("SELECT @@version as info") 
full_version_info = query_result.info 
sql.close() // Close connection 
input_string_1 = full_version_info 
def regex_1 = /(?<=SQL Server)(.*)(?=-)/; //capture between 'SQL Server' until '-' 
def matcher_1 = (input_string_1 =~ regex_1) 
version = matcher_1[0][1].trim() 
input_string_2 = full_version_info 
def regex_2 = /(?<=\n)(.*)(?=Edition)/; //capture between line break until 'Edition' 
def matcher_2 = (input_string_2 =~ regex_2) 
edition = matcher_2[0][1].trim() 
println "ms_sql_version=" + version +" "+ edition 
return 0;
 

Managing PropertySources

Once you have created a PropertySource, you are able to view and edit it from Settings | LogicModules | PropertySources. Additionally, from the header of the PropertySource settings page (shown next), you can click the More button to perform one of the following actions:

  • Force device match. Manually run the AppliesTo code to ensure all applicable devices are captured and associated with this PropertySource.
  • Show associated devices. Display a table containing all the devices impacted by this PropertySource.
  • Export. Export your PropertySource as a JSON file.