Subnet monitoring script interface - User Guide - Micetro - 25.2.0

Micetro Admin Guide

ft:locale
en-US
Product name
Micetro
Version
25.2.0

The XML schema for a subnet monitoring script is as follows:

<?xml version="1.0" encoding="ISO-8859-1"?>
<xs:schema targetNamespace="http://tempuri.org/XMLSchema.xsd" elementFormDefault="qualified" xmlns="http://tempuri.org/XMLSchema.xsd" xmlns:mstns="http://tempuri.org/XMLSchema.xsd" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="scopeMonitor">
<xs:complexType>
<xs:sequence>
<xs:element name="scope" type="xs:string" minOccurs="0" maxOccurs="1" />
<xs:element name="server" type="xs:string" minOccurs="0" maxOccurs="1" />
<xs:element name="superscope" type="xs:string" minOccurs="0" maxOccurs="1" />
<xs:element name="threshold" type="xs:integer" minOccurs="1" maxOccurs="1" />
<xs:element name="available" type="xs:integer" minOccurs="1" maxOccurs="1" />
<xs:element name="fixed" type="xs:boolean" minOccurs="1" maxOccurs="1" />
<xs:element name="thresholdType" type="xs:string" minOccurs="1" maxOccurs="1" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>

The value of the thresholdType element will be either static or dynamic, depending on whether the threshold being crossed is one of the dynamically allocatable addresses (that is, available addresses in address pools) or a threshold set for static addresses (that is, available addresses outside of address pools).

Note: The global subnet monitor, set through the system settings, is the only one that takes superscopes into account. When the global subnet monitoring actions are performed, due to the conditions being met for a superscope, the XML generated will contain a <server> tag and a <superscope> tag.

An example XML structure for a subnet monitoring script for a scope might look like this:

<?xml version="1.0" encoding="ISO-8859-1"?>
<scopeMonitor>
<scope>123.45.67.0/24</scope>
<threshold>20</threshold>
<available>8</available>
<fixed>0</fixed>
<thresholdType>dynamic</thresholdType>
<customFields>
<customField customFieldID="1" customFieldName="Title" objectID="526" objectType="6" value="Your subnet title"></customField>
<customField customFieldID="2" customFieldName="Description" objectID="526" objectType="6" value="You subnet description"></customField>
<customFields>
</scopeMonitor>

The XML structure differs slightly if a superscope (MS DHCP) or a shared-network (ISC DHCP) configuration is used. An example XML structure for a scope monitoring script for a superscope/shared-network configuration might look like this:

<?xml version="1.0" encoding="ISO-8859-1"?>
<scopeMonitor>
<server>dhcp1.corp.net.</server>
<superscope>office</superscope>
<threshold>20</threshold>
<available>22</available>
<fixed>1</fixed>
<thresholdType>dynamic</thresholdType>
</scopeMonitor>

A subnet monitoring script does not have any return value.

Example PowerShell script

Note: PowerShell scripts (.ps1 extension) are run natively by Micetro on Windows with powershell. The script can then read the stdin with [Console]::In.ReadToEnd().

Instructions:

  1. Copy the ScopeMonScript.ps1 to the scripts folder: C:\\ProgramData\\Men and Mice\\Central\scripts.
  2. In the Web Application, navigate to Admin > Configuration > Event hooks, and under Subnet monitoring events select Set defaults.
  3. Select ScopeMonScript.ps1 in the Script to invoke field.
  4. Configure a dynamic threshold.

The monitor will be executed every ten minutes during the DHCP synchronization interval.

param([Parameter(Mandatory=$false,ValueFromPipeLine=$false)]$UserName = "",
[Parameter(Mandatory=$false,ValueFromPipeLine=$false)]$Password = "",
[Parameter(Mandatory=$false,ValueFromPipeLine=$false)]$xmlFileName = "")
$strInput = get-content $xmlFileName
#$strInput = $args
# write output for troubleshooting in file:
#Add-Content -Path .\monitoroutput.xml $strInput

$strXML = [string]::Join(" ", $strInput)
$objXML = [xml]$strXML
$subnetMonitor = (Select-Xml -XML $objXML -XPath "/subnetMonitor").Node

# Check if it's an alert or fixed message
# The script only cares about alerts
if ($subnetMonitor.fixed -eq "0")
{
    $strAlert = "Alert:  The following scope or subnet has fewer IPs available than the configured threshold."

    # We could send here an email or generate a trap or...
    #Send-MailMessage -SmtpServer "smpt.example.com" -From "subnetmonitor@example.com" -To "alert1@example.com;alert2@example.net" -Subject "Subnet Monitor Message" -Body $strOutput

    # First handle the superscopes
    if ($subnetMonitor.superscope -ne $null -and $subnetMonitor.superscope -ne "")
    {
    $strOutput = @"

    $strAlert
    Superscope: $($subnetMonitor.superscope)
    Alert Date:    $(Get-Date -Format G)
    Server:        $($subnetMonitor.server)
    Threshold:    $($subnetMonitor.threshold)
    IPs Available:    $($subnetMonitor.available)
    Subnet Type:    $($subnetMonitor.thresholdType)
    "@
        New-EventLog -Source SubnetMonitor -LogName Application
        Write-EventLog -LogName Application -Source SubnetMonitor -EventID 1063 -EntryType Warning -message "$strOutput"
        #Add-Content -Path .\superscopemonitor_msg.txt $strOutput
        }
    else
    {
    # then in the else clause the normal scopes

    $strOutput = @"

    $strAlert
      Alert Date:    $(Get-Date -Format G)
      Scope:        $($subnetMonitor.subnet)
      Threshold:    $($subnetMonitor.threshold)
      IPs Available:    $($subnetMonitor.available)
      Subnet Type:    $($subnetMonitor.thresholdType)
      "@
        New-EventLog -Source SubnetMonitor -LogName Application
        Write-EventLog -LogName Application -Source SubnetMonitor -EventID 1064 -EntryType Warning -message "$strOutput"
        #Add-Content -Path .\scopemonitor_msg.txt $strOutput
    }
  }
  else
  {
  # possible issue fixed message
  }

Example Python script

The following example script, written in Python, shows how a script could return different values depending on the input of custom fields. The script is called when an object property changes, and it queries for country and city using a location code. The intended use is to mark the locations of servers.
import sys
import xml.etree.ElementTree as ET

def get_custom_field_element(custom_fields, name):
 element = custom_fields.find(f"./customField[@customFieldName='{name}']")
 if element is None:
     raise KeyError(f"Custom property '{name}' was not found.")
 return element

def get_result(root):
 # username variable is not used but this is how to get the username
 username = root.get('userName')
 custom_fields = root.find("./customFields")

 result = ET.Element("result", {"success": "0"})
 try:
     location_element = get_custom_field_element(custom_fields, 'Location')
     country_element = get_custom_field_element(custom_fields, 'Country')
     city_element = get_custom_field_element(custom_fields, 'City')
 except KeyError as e:
     ET.SubElement(result, "error", {"code": "1", "message": str(e)})
     return result
 location = location_element.get('value')

 # A database could be queried instead here
 LOCATION_MAP = {
     'l1': ('USA', 'Washington'),
     'l2': ('UK', 'London')
 }
 if location not in LOCATION_MAP:
     ET.SubElement(result, "error", {"code": "1", "message": "Unknown location."})
     return result

 result.set("success", "1")
 country, city = LOCATION_MAP[location]
 country_element.set('value', country)
 city_element.set('value', city)
 result.append(custom_fields)
 return result

# Read all input and parse as XML
root = ET.fromstring(sys.stdin.read())
result = get_result(root)

print('<?xml version="1.0"?>')
# This will write the generated result xml to standard output
ET.dump(result)