

#
# monitor one single system variable
#
# tests extending this test are expected to set
#
#    set domain <the variable's domain>;
#    set variable <name of the variable>;
#    set variable_name <name of the performance variable sent to the server>;
#    set variable_text <some clear text string describing the variable (appears in status texts);
#
# if set, the variable's value is checked against the following limits:
#
#    upper_red_limit: status is red if value is > upper_red_limit
#    upper_yellow_limit: status is yellow if value is > upper_yellow_limit
#    lower_red_limit: status is red if value is < lower_red_limit
#    lower_yellow_limit: status is yellow if value is < lower_yellow_limit
#
test single_value {
    # the module we get our configuration from
    static set domain snmp;

    set discover_refresh 60*24;
    set discover_retry 60;
    set frequency 5;
    # report as item "disk"
    pernode set report_item "cpu";
    set host "set by uxmon";
    set alias "set by uxmon";
    # do not send perf variables by default
    set perf_frequency 0;

    set variable none_set_yet;
    set variable_name "some_variable";
    set variable_text "some variable";
    set lower_yellow_limit;
    set lower_red_limit;
    set upper_yellow_limit;
    set upper_red_limit;
    set export_domain "single";

    init {
        pernode import item report_item;
	instance import perf perf_frequency;
		instance set firstpass 1;
    }

    monitor {
        get ${domain}.${variable};
	instance set former_value ${value};
	instance set value ${${domain}.${variable}};
	instance set monvalue ${value};
    }

    report {
	set text "${variable_text} = ${monvalue}";
		status clear null( ${monvalue} ) && ${firstpass} "&clear ${variable_text} status not known (yet)";
		status purple null( ${monvalue} ) && not( ${firstpass} ) "&purple ${variable_text} status not known";
        status red not( null( ${upper_red_limit} ) ) && (${monvalue} > ${upper_red_limit}) && not( null( ${monvalue} ) ) "&red (>>) " ${text};
        status red not( null( ${lower_red_limit} ) ) && ( ${monvalue} < ${lower_red_limit} ) && not( null( ${monvalue} ) )"&red (<<) " ${text};
        status yellow not( null( ${upper_yellow_limit} ) ) && ( ${monvalue} > ${upper_yellow_limit} ) && not( null( ${monvalue} ) )"&yellow (>) " ${text};
        status yellow not( null( ${lower_yellow_limit} ) ) && ( ${monvalue} < ${lower_yellow_limit} ) && not( null( ${monvalue} ) )"&yellow (<) " ${text};
	status green not( null( ${monvalue} ) ) "&green " ${text};
		instance set firstpass 0;
    }

    perf {
        export always ${export_domain}.${variable_name} , ${monvalue};
	export sometimes ${export_domain}.${variable_name}.description,  ${variable_text};
    }
}



#
# like single_value monitor one single system variable, but the value
# is handled as a differential counter and divided by the time between two samples
# 
test single_value_persecond extends single_value {
    pernode monitor {
        pernode set monvalue ( ${value} - ${former_value} ) / ( when( ${value} ) - when( ${former_value} ) );
    }
}




test storage {
    # these are defaults describing some test parameters

    # re-discover every 60 minutes
    set discover_refresh 120;
    # after a discover failure retry every 5 minutes
    set discover_retry 10;
    # monitor every 5 minutes by default
    set frequency 5;
    # report as item "disk"
    pernode set report_item "disk";
    set host "set by uxmon";
    set alias "set by uxmon";
    # do not send perf variables by default
    set perf_frequency 0;

    # the module we get our configuration from
    static set domain snmp;

    # we will only scan for disks with this OID
    set storagetypes snmp.hrStorageFixedDisk;
    # if partition contains a list of partitions we will only monitor those
    set partition;
    # report yellow if free space goes below warn level
    set warn "10%";
    # report red if free space goes below fail level
    set fail "5%";
    # the snmp community
    set community "public";
    # partition names which are not reported
    static set avoid_partitions;
    # the sub-id (storage.<id>) we send perf variables as
    static set storageid "disk";

    # just declare a few variables here
    set thismonitor;

    pernode set optional_info;

    pernode set storage.description;
    pernode set storage.storagetype;
    pernode set storage.size;
    pernode set storage.used.size;
    pernode set storage.used.percent;
    pernode set storage.free.percent;
    pernode set storage.free.size;
    pernode set storage.device;
    pernode set storage.fstype;
    pernode set allocunits;
    pernode set monitored;
    pernode set formerly_monitored;
    pernode set former_description;

    static set arguments
	"fail:kbsize|percentage:Fail level - Big Sister panics (red) if free space goes below this level"
	"warn:kbsize|percentage:Warn level - Big Sister warns (yellow) if free space goes below this level"
	"partition:@pattern:A list of resource (partition/volume/drive) names"
	"community:string:The SNMP get community"
        "storagetypes:@oid:The object IDs of the resource(s) to be monitored"
	"perf:int:report perf data every perf minutes"
	"item:string:Item as which to report.";

    # import configuration from uxmon-net
    init {
        instance import storagetypes;
	instance import partition;
	instance import warn;
	instance import fail;
	instance import community;
	instance import perf perf_frequency;
	pernode import item report_item;

	set warn input_kbsize( ${warn} );
	set fail input_kbsize( ${fail} );

	debug 6 "storage types:" ${storagetypes} ", partition:" ${partition} ", warn:" ${warn} ", fail:" ${fail} ", domain:" ${domain};
    }

    # walk the relevant data structures and do some pre-processing
    pernode discover {
	get @${domain}.hrStorageIndex @${domain}.hrStorageDescr @${domain}.hrStorageSize 
	    @${domain}.hrStorageType @${domain}.hrStorageAllocationUnits
	    ${optional_data};
	set storage.description ${${domain}.hrStorageDescr};
	set storage.storagetype ${${domain}.hrStorageType};
	set allocunits ${${domain}.hrStorageAllocationUnits};
	set index ${${domain}.hrStorageSize};
	select storagesize index true;
	for storage.size storagesize
	    ${${domain}.hrStorageSize[${i}]} * (${allocunits[${i}]} / 1024);
	set storage.device;
	for storage.device storagesize
            if( ${${domain}.hrStorageDevice[${i}]}, ${${domain}.hrStorageDevice[${i}]}, "N/A" );
        set storage.fstype ${${domain}.hrStorageFSType};
    }

    # select the entities this instance will monitor
    discover {
	set oldmonitor ${thismonitor};
	set monitored remove( ${monitored}, ${oldmonitor} );

	set index ${storage.description};
	select thismonitor index
	    ( null( ${partition} ) || contains_pattern( ${partition}, ${storage.description[${i}]} ) )
	    && ( null( ${fstype} ) || contains_pattern( ${fstype}, ${storage.fstype[${i}]} ) )
	    && (contains( ${storagetypes}, ${storage.storagetype[${i}]} ) 
	       && not( contains( ${monitored}, ${i} ) ) )
	       && not( contains_pattern( ${avoid_partitions}, ${storage.description[${i}]} ) );

	set monitored ${monitored} ${thismonitor};
    };

    pernode postdiscover {
	debug 3 "currently monitored:" ${monitored};
	set notmonitored_anymore unmonitored( ${formerly_monitored}, ${monitored}, ${former_description} );
	set newly_monitored nowmonitored( ${formerly_monitored}, ${monitored}, ${storage.description} );
	event "notice" ${notmonitored_anymore};
	event "notice" ${newly_monitored};
	pernode set formerly_monitored ${monitored};
	pernode set former_description ${storage.description};
    }

    pernode monitor {
	# clear variables
        set storage.used.size;
	set storage.used.percent;
	set storage.free.size;
	set storage.free.percent;
    }

    monitor {
	debug 6 getting ${thismonitor} for domain ${domain};
	debug 3 getting ${thismonitor} for domain ${domain} ${domain}.hrStorageUsed[${thismonitor}];
	get ${domain}.hrStorageUsed[${thismonitor}];
	debug 3 got ${${domain}.hrStorageUsed};
	for storage.used.size thismonitor ${${domain}.hrStorageUsed[${i}]} * ( ${allocunits[${i}]} / 1024 );
	for storage.used.percent thismonitor percentage( ${storage.used.size[${i}]}, ${storage.size[${i}]} );
	for storage.free.size thismonitor ${storage.size[${i}]} - ${storage.used.size[${i}]};
	for storage.free.percent thismonitor percentage( ${storage.free.size[${i}]}, ${storage.size[${i}]} );
    };

    pernode report {
	debug 3 monitored items are ${monitored};
	set text;
	for text monitored pad( ${storage.device[${i}]}, 20, "l" )
		pad( format_kbsize( ${storage.size[${i}]} ), 10, "r" )
		pad( format_kbsize( ${storage.used.size[${i}]} ), 10, "r" )
		pad( format_kbsize( ${storage.free.size[${i}]} ), 10, "r" )
		pad( format_percentage( ${storage.used.percent[${i}]} ), 5, "r" ) 
		" " ${storage.description[${i}]} "\n";
	debug 3 ${text};
	set head pad( "Filesystem", 20, "l" )
		pad( "Size", 10, "r" )
		pad( "Used", 10, "r" )
		pad( "Available", 10, "r" )
		pad( "Use%", 5, "r" )
		" Resource name\n\n";
	status purple null( ${monitored} ) "no file systems monitored";
	comment "html" "<HR></HR><PRE><strong>" ${head} </strong> ${text} "</PRE>";
    };

    report {
	instance for message thismonitor 
	  ${storage.description[${i}]} " " format_kbsize( ${storage.free.size[${i}]} ) " ("
	  format_percentage( ${storage.free.percent[${i}]} ) ") free";
    }

    report for thismonitor {
	status red in_range( 0, ${fail}, ${storage.free.size[${p}]}, ${storage.free.percent[${p}]} )
	    "&red" " " ${message[${p}]};
	status yellow in_range( 0, ${warn}, ${storage.free.size[${p}]}, ${storage.free.percent[${p}]} )
	    "&yellow" " " ${message[${p}]};
	status purple null( ${storage.free.size[${p}]} )
	    "&purple " ${storage.description[${p}]} " no info available";
	status green 1
	    "&green" " " ${message[${p}]};
    };

    perf {
	export sometimes storage.${storageid}.description, ${storage.description[${thismonitor}]};
	export sometimes storage.${storageid}.device, ${storage.device[${thismonitor}]};
	export always storage.${storageid}.used.size, ${storage.used.size[${thismonitor}]};
	export always storage.${storageid}.used.percent, ${storage.used.percent[${thismonitor}]}; 
	export always storage.${storageid}.free.size, ${storage.free.size[${thismonitor}]};
	export always storage.${storageid}.free.percent, ${storage.free.percent[${thismonitor}]};
    };

    pernode unconfigure {
	pernode set monitored;
	pernode set storage.description;
	pernode set storage.storagetype;
	pernode set storage.size;
	pernode set storage.used.size;
	pernode set storage.used.percent;
	pernode set storage.free.percent;
	pernode set storage.free.size;
	pernode set storage.device;
	pernode set storage.fstype;
	pernode set allocunits;
	pernode set monitored;
    }
}



#==================== disk size ========================================

#
# The unix disk monitor using the "df" command
test unix_dfdisk extends storage {
    static set name "disk";
    static set device computer;
    static set features unix local;
    static set description "Monitor a disks free space using the 'df' command";

    # domain "df" is the requester using "df" command
    static set domain df;
    # "df" returns some additional useful information
    pernode set optional_data @${domain}.hrStorageDevice @${domain}.hrStorageFSType;

    set storagetypes 1.3.6.1.2.1.25.2.1.4;

    static set arguments ${arguments}
	"fstype:@pattern:FS type (works only if OS supports it)"
        "df:string:The 'df' command to be used";

    init {
	# if "df=" argument is set then interpret it as the df command to be executed
	# otherwise the "df" requester just tries to guess which is suitable
        import df dfcommand;
	instance import fstype;
    }
}


#
# The Solaris disk monitor
test solaris_dfdisk extends unix_dfdisk {
    static set features local unix sysv solaris;
    pernode set dfcommand "df -k -t";
    set avoid_partitions "~^/cdrom/";
}

#
# The AIX disk monitor
test aix_dfdisk extends unix_dfdisk {
    static set features local unix sysv aix;
    pernode set dfcommand "df -k -I";
    set avoid_partitions "~^/cdrom/";
}


#
# The generic SNMP disk monitor -- works for all devices returning hrStorageFixedDisk as the disk type
test generic_snmpdisk extends storage {
    static set name "disk";
    static set features remote;
    static set domain snmp;
    set storagetypes 1.3.6.1.2.1.25.2.1.4;
    static set description "Monitor a disks free space using SNMP and Host-MIB";
}


#
# The unix SNMP disk monitor -- avoids common "trash"
test unix_snmpdisk extends generic_snmpdisk {
    static set features remote unix;
    static set avoid_partitions /proc/bus/usb /dev/pts;
    static set description "Monitor a disks free space using SNMP and Host-MIB";
}


#===================== memory usage ======================================

#
# Free page memory using SNMP
test snmp_virtualmemory extends generic_snmpdisk {
    static set name "memory";
    static set storageid "memory";
    set storagetypes 1.3.6.1.2.1.25.2.1.3;
    pernode set report_item "cpu";
    static set description "Monitor virtual memory usage using SNMP and Host-MIB";
}


#
# Free page memory using linux /proc/meminfo
test linux_virtualmemory extends storage {
    static set name "memory";
    static set features local unix linux;
    pernode set report_item "cpu";
    static set storageid "memory.swap";
    static set description "Monitor virtual memory usage using Linux /proc/meminfo file";

    pernode precheck {
        set test_available domain_available( procMeminfo );
    }

    overrides pernode discover {
	get procMeminfo.SwapTotal[0];
	set storage.description "Swap Space";
	set allocunits 1024;
	set storage.size ${procMeminfo.SwapTotal[0]};
	set storage.device "N/A";
    }

    # select the entities this instance will monitor
    overrides discover {
	set monitored remove( ${monitored}, ${thismonitor} );
	select thismonitor storage.description true;
	set monitored ${monitored} ${thismonitor};
    };

    overrides monitor {
        get procMeminfo.SwapFree[0];
	set storage.free.size ${procMeminfo.SwapFree[0]};
	set storage.free.percent percentage( ${storage.free.size[0]}, ${storage.size[0]} );
	set storage.used.size ${storage.size} - ${storage.free.size};
	set storage.used.percent percentage( ${storage.used.size[0]}, ${storage.size[0]} );
    }
}



#===================== logged in users ======================================

#
# retrieve the number of logged on users via SNMP -- netware servers
test netware_numusers extends single_value {
    static set name "users";
    static set features remote netware;
    static set domain snmp;
    set variable nwLoginCount[0];
    set variable_name "NumUsers";
    set variable_text "logged on users";
    static set description "Monitor the number of logged on users on a netware server";
    static set arguments
        "yellow:int:The test goes yellow if the number of logged in users goes above this level (default: #licenses-10%)"
        "red:int:The test goes red if the number of logged in users goes above this level (default: #licenses-1)"
	"perf:int:report perf data every perf minutes"
	"item:string:Item as which to report.";

    discover {
        get ${domain}.nwMaxLogins[0];
	set maxLogins ${${domain}.nwMaxLogins[0]};
    }

    postdiscover {
	set variable_text "logged on users (Max. " ${${domain}.nwMaxLogins[0]} " )";
	set upper_red_limit ${maxLogins} - 1;
	set upper_yellow_limit ${maxLogins} - ${maxLogins} / 10;
	# configured limits will override
        instance import yellow upper_yellow_limit;
	instance import red upper_red_limit;
    }
}


#
# retrieve the number of logged on users via SNMP
test snmphost_numusers extends single_value {
    static set name "users";
    static set features remote;
    static set domain snmp;
    set variable hrSystemNumUsers[0];
    set variable_name "NumUsers";
    set variable_text "logged on users";
    static set description "Monitor the number of logged on users on a SNMP aware device (Host-MIB)";
    static set arguments
        "yellow:int:The test goes yellow if the number of logged in users goes above this level (default: no limit)"
        "red:int:The test goes red if the number of logged in users goes above this level (default: no limit)"
	"perf:int:report perf data every perf minutes"
	"item:string:Item as which to report.";

    init {
        instance import yellow upper_yellow_limit;
	instance import red upper_red_limit;
    }
}


#
# retrieve the number of logged on users via 'who' command
test who_numusers extends snmphost_numusers {
    static set features local unix;
    static set domain who;
    static set description "Monitor the number of logged on users on a Unix machine (who command)";

    monitor {
        get ${domain}.hrSystemDistinctUsers[0];
	pernode set distinctusers ${${domain}.hrSystemDistinctUsers[0]};
    }

    perf {
        export always single.NumDistinctUsers, ${distinctusers};
        export sometimes single.NumDistinctUsers.description, "distinct logged on users";
    }
}



#
# Monitoring any SNMP variable. Depends on "single_value" in etc/tests.cfg.
#

test snmp_anyvar extends single_value {
    debug 8 "Entering snmpvar_anyvar.";
    static set name "snmpvar";
    static set features remote;
    static set domain snmp;

    static set description "Monitor a given SNMP variable and create alerts if a given threshold is reached.";
    static set arguments
                "upper-yellow:int:Yellow alarm is raised if value raises above this value and is still below upper-red."
                "upper-red:int:Red alarm if value raises beyond this value."
		"lower-yellow:int:Yellow alarm is raised if value raises below this value and is still above lower-red."
		"lower-red:int:Red alarm if value drops below this value."
		"perf:int:report perf data every perf minutes"
		"item:string:Item as which to report."
		"variable:string:SNMP variable to query (cf. etc/mibs.txt file).";

    init {
	instance import item report_item;
	instance import variable;
        instance import upper-yellow upper_yellow_limit;
        instance import upper-red upper_red_limit;
	instance import lower-yellow lower_yellow_limit;
	instance import lower-red lower_red_limit;
	set variable_name ${variable};
	set variable_text ${variable};
    }

}


#
# Include all the *.cfg files in etc/testdef
#
include etc/testdef/*.cfg
