Essentially, the goal was to allow storage of commonly used configurations so they could be easily deployed later. Rather than constantly setting up the same monitor, and possibly making mistakes; Discrete configurations are given a name and can be recalled at the properties page. And By separating the Configuration from the script entity we can also make use of more generic scripts that have multiple uses.
The Script itself preforms a SNMP Walk over an OID and verify that the value return is contained in an acceptance list. This can be useful in monitoring of things such as Raid Arrays which have a status variable( Online, Degraded, Rebuilding). The script allows you to specify a list of acceptable states, and alarms if an instances return value was not found in the list.
Uses:
*Disk/Array Status
*Cooling unit Fan States
*Switch Port Statuses
*Any SNMP OID that returns a status. ( I'd be interested to hear of others uses people find)
The addition of the Profile manager will allow a single script to be extended to work across multiple vendors and devices with out necessarily making it hard to use. Ex: RAID State Monitoring for DELL, HP, IBM can use the same script with separate profiles(No need to remember which OIDs to use.)
As usual the code is as is and no promises are made. Hope it helps.
Comments and Criticism Welcome.
Thanks,
JAzz Alyxzander
CODE
--[[
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE
--]]
ScriptName= "SnmpWalkEnumWithProfile-RC2.lua"
date= "May 24, 2009"
Author = "Jazz Alyxzander Turner-Baggs"
VersionMaj = 1
VersionMin = 10
Description = "The Script preforms an SNMP Walk and ensures all values are contained in a specified Accept-Set. If not Found the the ErrorCount is incremented and total number of errors are returned with the fail_string "
-----------------------------------------------------------------
--
-- The Logic for the Monitor is fairly Straight forward
-- - define a List acceptable states
-- - preform a SNMPWalk
-- - Alarm if there are any states were not found in the list of acceptable return values.
--
-- The Configuration Profiles are a New addition to the template
-- Instead of having to manually specify configurations they are stored in the script and enumerated on configuration. Once Configured it can easily
-- be deployed across numerous hosts.
-- Parameters that are variable such as SNMP Community in this case are passed as normal,
-- however Configuration details which are not specific to a host, can be migrated to the profile manager
--
-- Goals:
-- Reduce Probability of Configuration Errors
-- Provide single location for mass-updating
-- Allow for greater code reuse, via templating.
--
-- Structure:
-- Profile Manager : LUA Table that contains a Series of profiles( Dictionary )
-- Enumerater: Allows Selection of Profile on Configure
-- Profile Loader: Loads Profile Values into Local Variables
-- Notes:
--
-- -Inorder to maintain persistant configurations the Profiles are stored in the script and currently manually entered. To the SRC.
--
-- -In this revison there is an option to allow manual Configurations by altering the boolean value. By Selecting teh manual Profile it will
-- Skip the profile table and pull results from the Standard arguments. It has Not been Tested.
--
-- -Currently the 3.X branch of the LUA IDE does not support Alternative usage values for teh Enum Object. With this said using the 3.3 IDE
-- will result in Fatal Errors. The script runs fine in intellipool. See OLD_IDE_HACK
-- -SNMP Community is not passed from the object properties and must be entered at the monitor level.
-----------------------------------------------------------------
AllowManualConfigurations = false -- Controls Whether to allow manual Configuraitons at the monitor page
OLD_IDE_HACK = false -- Disables Enumation of profile names as work around ( See Notes)
-- Profile Table
profile_manager = {
-- DELL Disk Status Profile : Detects Physical Disk Errors via Insight
{ name="DELL ArrayDisk State - Detects Failed Disks in RaidArray",
accept={3},
oid="1.3.6.1.4.1.674.10893.1.20.130.4.1.4",
success_string="All Disks Online",
error_string="Failed Drives have been Detected: Bad Drives = "
} ,
-- IBM ServeRaidPhysDiskState: Detects Physical Disk Errors that are not Online or ready
{ name="IBM ServeRaidPhysDiskState - Detects Physical Disk Errors that are not Online or ready",
accept={2,6},
oid="1.3.6.1.4.1.2.6.167.2.1.2.2.1.6",
success_string="No Disk Errors Detected",
error_string="Failed Drives have been Detected: Bad Drives = "
} ,
-- Switch Port Status Profile : Detects Switch ports that are not operational
{ name="Switch Port Status - Detects Non-operational Switch ports",
accept={"1"},
oid="1.3.6.1.2.1.2.2.1.8",
success_string="All Ports Up",
error_string="Not all Ports online: "
}
}
-- End Profile Table
function OnEnumerate(sFieldToEnum)
Enum = LuaScriptEnumResult()
-- Enumerator
if sFieldToEnum == "Profile" then
if not IsIDE() then
for index,profile in pairs(profile_manager) do Enum:Add( profile["name"], index) end
if AllowManualConfigurations then
Enum:Add( "Manual Configuration", 0);
end
elseif OLD_IDE_HACK then
for index,profile in pairs(profile_manager) do Enum:Add(index) end
if AllowManualConfigurations then
Enum:Add( "Manual Configuration", 0);
end
end
end
-- End Enumerator
return Enum
end
function OnConfigure()
Config = LuaScriptConfigurator()
Config:SetAuthor(Author)
Config:SetDescription(Description)
Config:SetMinBuildVersion(0)
Config:SetScriptVersion(VersionMaj, VersionMin )
Config:AddArgument("Community Name", "Display results of this ",LuaScriptConfigurator.CHECK_NOT_EMPTY)
Config:AddArgument("Profile", "Display results of this ",LuaScriptConfigurator.CHECK_NOT_EMPTY + LuaScriptConfigurator.ENUM_AVAIL)
if AllowManualConfigurations then
Config:AddArgument("Acceptable State", "List of Acceptable states sepearted by commas\nEx: 5,3,Down,Unknown,2 ",LuaScriptConfigurator.CHECK_NOTHING)
Config:AddArgument("OID", "OID to Walk",LuaScriptConfigurator.CHECK_NOTHING)
Config:AddArgument("Success String", "Return String when no errors exist",LuaScriptConfigurator.CHECK_NOTHING)
Config:AddArgument("Error String", "Return String when error is detected",LuaScriptConfigurator.CHECK_NOTHING)
end
Config:SetEntryPoint("main")
return Config
end
function split(s)
t = {}
while string.find(s,",") ~= nil do
_, _, s, m = string.find(s, "(.+),(.+)")
table.insert(t,tostring(m))
end
table.insert(t,tostring(s))
return t
end
---------------------------------------------------------
function main()
--// ===========================================================================
--// Variables
--// ===========================================================================
--// Script Vars
iErrorCount = 0
iTotalCount = 0
accept_list = {}
sSuccess = ""
sError = ""
--// SNMP vars
SNMP = TLuaSNMP()
sCommunity = ""
sOID = ""
--// ===========================================================================
--// Initialize Script
--// ===========================================================================
sCommunity = GetArgument(0)
sProfileID = GetArgument(1)
profile = {}
if sProfileID == "0" then
sList = GetArgument(2)
profile["accept"] = split(sList)
profile["oid"] = GetArgument(3)
profile["success_string"] = GetArgument(4)
profile["error_string"] = GetArgument(5)
else
profile = profile_manager[tonumber(sProfileID)]
end
--// ===========================================================================
--// Profile Loader
--// ===========================================================================
sOID = profile["oid"]
accept_list = profile["accept"]
sSuccess = profile["success_string"]
sError = profile["error_string"]
--// ===========================================================================
--// SNMP Query
--// ===========================================================================
-- Ensure all return values are present in the Accept-list
SNMP:Open(sCommunity);
snmpResult = TLuaSNMPResult();
SNMP:BeginWalk(sOID);
repeat
snmpResult = SNMP:Walk(sOID);
sOID = snmpResult.m_sOID;
if snmpResult.m_sData ~= "" then
bAcceptable = false
iTotalCount = iTotalCount + 1
for k,v in pairs(accept_list) do
if IsIDE() then print( snmpResult.m_sData,v) end
if snmpResult.m_sData == v then
bAcceptable = true
end
end
if not bAcceptable then
iErrorCount = iErrorCount + 1
end
end
until snmpResult.m_sOID == "";
--// ===========================================================================
--// Compare
--// ===========================================================================
if iTotalCount == 0 then
SetExitStatus("Error - No instances found", false)
elseif iErrorCount > 0 then
SetExitStatus(sError .." - (Instances Failed :" .. iErrorCount .. ")", false)
else
SetExitStatus(sSuccess, true)
end
--// ===========================================================================
--// ~~
--// ===========================================================================
end
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE
--]]
ScriptName= "SnmpWalkEnumWithProfile-RC2.lua"
date= "May 24, 2009"
Author = "Jazz Alyxzander Turner-Baggs"
VersionMaj = 1
VersionMin = 10
Description = "The Script preforms an SNMP Walk and ensures all values are contained in a specified Accept-Set. If not Found the the ErrorCount is incremented and total number of errors are returned with the fail_string "
-----------------------------------------------------------------
--
-- The Logic for the Monitor is fairly Straight forward
-- - define a List acceptable states
-- - preform a SNMPWalk
-- - Alarm if there are any states were not found in the list of acceptable return values.
--
-- The Configuration Profiles are a New addition to the template
-- Instead of having to manually specify configurations they are stored in the script and enumerated on configuration. Once Configured it can easily
-- be deployed across numerous hosts.
-- Parameters that are variable such as SNMP Community in this case are passed as normal,
-- however Configuration details which are not specific to a host, can be migrated to the profile manager
--
-- Goals:
-- Reduce Probability of Configuration Errors
-- Provide single location for mass-updating
-- Allow for greater code reuse, via templating.
--
-- Structure:
-- Profile Manager : LUA Table that contains a Series of profiles( Dictionary )
-- Enumerater: Allows Selection of Profile on Configure
-- Profile Loader: Loads Profile Values into Local Variables
-- Notes:
--
-- -Inorder to maintain persistant configurations the Profiles are stored in the script and currently manually entered. To the SRC.
--
-- -In this revison there is an option to allow manual Configurations by altering the boolean value. By Selecting teh manual Profile it will
-- Skip the profile table and pull results from the Standard arguments. It has Not been Tested.
--
-- -Currently the 3.X branch of the LUA IDE does not support Alternative usage values for teh Enum Object. With this said using the 3.3 IDE
-- will result in Fatal Errors. The script runs fine in intellipool. See OLD_IDE_HACK
-- -SNMP Community is not passed from the object properties and must be entered at the monitor level.
-----------------------------------------------------------------
AllowManualConfigurations = false -- Controls Whether to allow manual Configuraitons at the monitor page
OLD_IDE_HACK = false -- Disables Enumation of profile names as work around ( See Notes)
-- Profile Table
profile_manager = {
-- DELL Disk Status Profile : Detects Physical Disk Errors via Insight
{ name="DELL ArrayDisk State - Detects Failed Disks in RaidArray",
accept={3},
oid="1.3.6.1.4.1.674.10893.1.20.130.4.1.4",
success_string="All Disks Online",
error_string="Failed Drives have been Detected: Bad Drives = "
} ,
-- IBM ServeRaidPhysDiskState: Detects Physical Disk Errors that are not Online or ready
{ name="IBM ServeRaidPhysDiskState - Detects Physical Disk Errors that are not Online or ready",
accept={2,6},
oid="1.3.6.1.4.1.2.6.167.2.1.2.2.1.6",
success_string="No Disk Errors Detected",
error_string="Failed Drives have been Detected: Bad Drives = "
} ,
-- Switch Port Status Profile : Detects Switch ports that are not operational
{ name="Switch Port Status - Detects Non-operational Switch ports",
accept={"1"},
oid="1.3.6.1.2.1.2.2.1.8",
success_string="All Ports Up",
error_string="Not all Ports online: "
}
}
-- End Profile Table
function OnEnumerate(sFieldToEnum)
Enum = LuaScriptEnumResult()
-- Enumerator
if sFieldToEnum == "Profile" then
if not IsIDE() then
for index,profile in pairs(profile_manager) do Enum:Add( profile["name"], index) end
if AllowManualConfigurations then
Enum:Add( "Manual Configuration", 0);
end
elseif OLD_IDE_HACK then
for index,profile in pairs(profile_manager) do Enum:Add(index) end
if AllowManualConfigurations then
Enum:Add( "Manual Configuration", 0);
end
end
end
-- End Enumerator
return Enum
end
function OnConfigure()
Config = LuaScriptConfigurator()
Config:SetAuthor(Author)
Config:SetDescription(Description)
Config:SetMinBuildVersion(0)
Config:SetScriptVersion(VersionMaj, VersionMin )
Config:AddArgument("Community Name", "Display results of this ",LuaScriptConfigurator.CHECK_NOT_EMPTY)
Config:AddArgument("Profile", "Display results of this ",LuaScriptConfigurator.CHECK_NOT_EMPTY + LuaScriptConfigurator.ENUM_AVAIL)
if AllowManualConfigurations then
Config:AddArgument("Acceptable State", "List of Acceptable states sepearted by commas\nEx: 5,3,Down,Unknown,2 ",LuaScriptConfigurator.CHECK_NOTHING)
Config:AddArgument("OID", "OID to Walk",LuaScriptConfigurator.CHECK_NOTHING)
Config:AddArgument("Success String", "Return String when no errors exist",LuaScriptConfigurator.CHECK_NOTHING)
Config:AddArgument("Error String", "Return String when error is detected",LuaScriptConfigurator.CHECK_NOTHING)
end
Config:SetEntryPoint("main")
return Config
end
function split(s)
t = {}
while string.find(s,",") ~= nil do
_, _, s, m = string.find(s, "(.+),(.+)")
table.insert(t,tostring(m))
end
table.insert(t,tostring(s))
return t
end
---------------------------------------------------------
function main()
--// ===========================================================================
--// Variables
--// ===========================================================================
--// Script Vars
iErrorCount = 0
iTotalCount = 0
accept_list = {}
sSuccess = ""
sError = ""
--// SNMP vars
SNMP = TLuaSNMP()
sCommunity = ""
sOID = ""
--// ===========================================================================
--// Initialize Script
--// ===========================================================================
sCommunity = GetArgument(0)
sProfileID = GetArgument(1)
profile = {}
if sProfileID == "0" then
sList = GetArgument(2)
profile["accept"] = split(sList)
profile["oid"] = GetArgument(3)
profile["success_string"] = GetArgument(4)
profile["error_string"] = GetArgument(5)
else
profile = profile_manager[tonumber(sProfileID)]
end
--// ===========================================================================
--// Profile Loader
--// ===========================================================================
sOID = profile["oid"]
accept_list = profile["accept"]
sSuccess = profile["success_string"]
sError = profile["error_string"]
--// ===========================================================================
--// SNMP Query
--// ===========================================================================
-- Ensure all return values are present in the Accept-list
SNMP:Open(sCommunity);
snmpResult = TLuaSNMPResult();
SNMP:BeginWalk(sOID);
repeat
snmpResult = SNMP:Walk(sOID);
sOID = snmpResult.m_sOID;
if snmpResult.m_sData ~= "" then
bAcceptable = false
iTotalCount = iTotalCount + 1
for k,v in pairs(accept_list) do
if IsIDE() then print( snmpResult.m_sData,v) end
if snmpResult.m_sData == v then
bAcceptable = true
end
end
if not bAcceptable then
iErrorCount = iErrorCount + 1
end
end
until snmpResult.m_sOID == "";
--// ===========================================================================
--// Compare
--// ===========================================================================
if iTotalCount == 0 then
SetExitStatus("Error - No instances found", false)
elseif iErrorCount > 0 then
SetExitStatus(sError .." - (Instances Failed :" .. iErrorCount .. ")", false)
else
SetExitStatus(sSuccess, true)
end
--// ===========================================================================
--// ~~
--// ===========================================================================
end