-- ======================
-- Description
-- ======================
--
-- Logika umożliwiająca aktualizację ibpakietu
--
-- ======================
-- Parameters
-- ======================
--
-- setting.script.type - typ skryptu
--
-- "check_online_01" - zostanie wygenerowany skrypt, który będzie sprawdzał połączenie z serwerem zdefiniowanym w setting.script.param.1 (http na porcie 80)
-- do counter.result zostanie wpisana informacja tekstowa o czasie uruchomienia skryptu i stanie połączenia
-- przykładowy rezultat "datetime=2022-06-19 18:26:46;status=online"
--
-- setting.script.param.1 - parametry 1 dla skryptu
--
-- setting.run.time - czas co jaki będzie uruchamiany skrypt [s]
--
-- setting.run.timeout - czas oczekiwania na wykonanie skryptu po tym czasie zostanie porzucone oczekiwanie na wykonanie skryptu [s]
--
-- counter.result - zwrócona informacja ze skryptu
--
-- counter.run.downcounter - licznik powiązany z setting.run.counter
--
-- counter.run.timeout.downcounter - licznik powiązany z setting.run.timeout
--
-- counter.os - identyfikator systemu operacyjnego
--
-- Logic uses lua language to implement own behaviour
--
-- ======================
-- mandatory variables
-- ======================
--
-- Logic expects following mandatory variables:
--
-- reload.trigger - causes reloading lua script
--
-- memcnt - current amount of memory used by lua in bytes
--
-- Logic expects following kv settings:
--
-- LuaScriptPath - path to the lua script - must be absolute
--
-- ======================
-- ChangeLog
-- ======================
--
-- 2022-05-28 ver 1.0.0
-- # First release
--
--
-- user can use some functions provided by ibmanager.
-- ibmanager provides following functions to use:
--
-- function returns value of required ibmanager variable
-- @param fullName - string - variable name - name of variable of which value must be returned, for example "rs.0.id.255.input.t.0.value"
-- @return - string or integer - variable value or "nil" if variable not exist or is not readable
--
-- getValue(fullName)
-- function set value of given ibmanager variable
-- @param fullName - string - variable name - name of variable of which value we want to set, for example "rs.0.id.255.input.t.0.value"
-- @param value - string, int or boolean - value to set
-- @return - nothing
--
-- setValue(fullName, value)
-- function returns value of required ibmanager variable
-- @param key - placed in xml logic configuration file:
-- * as attribute: Name, in Var, RemoteVar and ImportVar elements in the case of stand alone variables
-- * as concatenation of two attributes: ListName.Postfix in VarListItem, RemoteVarListItem and ImportVarListItem elements
-- in the case of variables that are placed in lists
-- @return - string or integer - variable value or "nil" if variable not exist or is not readable
--
-- getLogicValue(key)
-- function set value of given ibmanager variable
-- @param key - placed in xml logic configuration file:
-- * as attribute: Name, in Var, RemoteVar and ImportVar elements in the case of stand alone variables
-- * as concatenation of two attributes: ListName.Postfix in VarListItem, RemoteVarListItem and ImportVarListItem elements
-- in the case of variables that are placed in lists
-- @param value - string, int or boolean - value to set
-- @return - nothing
--
-- setLogicValue(key, value)
-- function returns two sections of kvsettings from xml configuration file
-- returned value is two element table, each of these elements is table too.
-- indices of returned table are strings and equal "instance" and "global"
-- values of returned tables are tables and contain KVsettings for applicable section.
-- nested tables have form key = value, where key is index in nested table and value is value.
-- example: {"instance" = {"ikey1" = "ivalue1", "ikey2" = "gvalue2"}, "global" = {"gkey1" = "gvalue1", "gkey2" = "gvalue2", "gkey3" = "gvalue3"}}
-- @return - two dimensional array - kvsettings for global and instance sections
-- getKvSettings()
-- function schedules alert to send.
-- rules are defined in separated alert configuration files and are described in ibmanager instruction manual
-- @param id - alert identifier - must be defined in current logic configuration file in section: <Alert Id="any_identifier" ...
-- scheduleAlert(id)
-- function cancels alert sending, if was previously scheduled. if not then only wakes up alerts handling thread, so if there is no need to call this function, then do not call it.
-- rules are defined in separated alert configuration files and are described in ibmanager instruction manual
-- @param id - alert identifier - must be defined in current logic configuration file in section: <Alert Id="any_identifier" ...
-- cancelAlert(name)
-- function logs message to logfile
-- @param logLevel - loglevel avaliable values:
-- * LogLevel.TraceLo
-- * LogLevel.Trace
-- * LogLevel.TraceHi
-- * LogLevel.DebugLo
-- * LogLevel.Debug
-- * LogLevel.DebugHi
-- * LogLevel.Info
-- * LogLevel.Notice
-- * LogLevel.Warning
-- * LogLevel.Error
-- * LogLevel.Critical
-- @param value - string - message to log
-- @return -
--
-- log(logLevel, logMessage)
-- getVarList(listName)
-- ibmanager provide following global variables:
-- logic type, (in this case it will always be "Lua") - the same as in logic configuration file in section: <Logic Type="Lua" ...
-- LOGIC_TYPE
-- logic version, the same as in logic configuration file in section: <Logic ... Version="x.y.z" ...
-- LOGIC_VERSION
-- logic sub-type, the same as in logic configuration file in section: <Logic ... SubType="Hysteresis" ...
-- LOGIC_SUBTYPE
-- logic sub-version, the same as in logic configuration file in section: <Logic ... SubVersion="x.y.z" ...
-- LOGIC_SUBVERSION
-- logic instance name - the same as in logic configuration file, in section: <Instance Name="0">
-- LOGIC_INSTANCE_NAME
-- add script directory to package path
package.path = package.path .. ";./logic/scripts/utils/?.lua";
-- use script - without .lua extension - delta class
require("State");
require("DownCounter");
SUPPORTED_SUBLOGIC_TYPE = "RunScript";
SUPPORTED_SUBLOGIC_VERSION = "1.0.0";
g_versionChecked = false;
-- entry point to the logic
-- @param firstCall - tells if logic is called first time
-- @return - nothing
-- jaki os: https://gist.github.com/soulik/82e9d02a818ce12498d1
-- get_os_name(), funtion to return current OS name and architecture
-- Copyright Philippe Fremy 2017
-- This code is based on the following Gist from Soulik (https://gist.github.com/soulik)
-- https://gist.github.com/soulik/82e9d02a818ce12498d1
-- Initial license was unspecified so I am assuming public domain
local function getOS()
-- Return two strings describing the OS name and OS architecture.
-- For Windows, the OS identification is based on environment variables
-- On unix, a call to uname is used.
--
-- OS possible values: Windows, Linux, Mac, BSD, Solaris
-- Arch possible values: x86, x86864, powerpc, arm, mips
--
-- On Windows, detection based on environment variable is limited
-- to what Windows is willing to tell through environement variables. In particular
-- 64bits is not always indicated so do not rely hardly on this value.
local raw_os_name, raw_arch_name = '', ''
-- LuaJIT shortcut
if jit and jit.os and jit.arch then
raw_os_name = jit.os
raw_arch_name = jit.arch
-- print( ("Debug jit name: %q %q"):format( raw_os_name, raw_arch_name ) )
else
if package.config:sub(1,1) == '\\' then
-- Windows
local env_OS = os.getenv('OS')
local env_ARCH = os.getenv('PROCESSOR_ARCHITECTURE')
-- print( ("Debug: %q %q"):format( env_OS, env_ARCH ) )
if env_OS and env_ARCH then
raw_os_name, raw_arch_name = env_OS, env_ARCH
end
else
-- other platform, assume uname support and popen support
raw_os_name = io.popen('uname -s','r'):read('*l')
raw_arch_name = io.popen('uname -m','r'):read('*l')
end
end
raw_os_name = (raw_os_name):lower()
raw_arch_name = (raw_arch_name):lower()
-- print( ("Debug: %q %q"):format( raw_os_name, raw_arch_name) )
local os_patterns = {
['windows'] = 'Windows',
['linux'] = 'linux',
['osx'] = 'Mac',
['mac'] = 'Mac',
['darwin'] = 'Mac',
['^mingw'] = 'Windows',
['^cygwin'] = 'Windows',
['bsd$'] = 'BSD',
['sunos'] = 'Solaris',
}
local arch_patterns = {
['^x86$'] = 'x86',
['i[%d]86'] = 'x86',
['amd64'] = 'x86_64',
['x86_64'] = 'x86_64',
['x64'] = 'x86_64',
['power macintosh'] = 'powerpc',
['^arm'] = 'arm',
['^mips'] = 'mips',
['i86pc'] = 'x86',
}
local os_name, arch_name = 'unknown', 'unknown'
for pattern, name in pairs(os_patterns) do
if raw_os_name:match(pattern) then
os_name = name
break
end
end
for pattern, name in pairs(arch_patterns) do
if raw_arch_name:match(pattern) then
arch_name = name
break
end
end
--return os_name, arch_name
return os_name .. "-" .. arch_name
end
g_runDowncounterTimer = nil;
g_runTimeoutTimer = nil;
g_os_name = nil;
function fileExists(name)
local f=io.open(name,"r")
if f~=nil then io.close(f) return true else return false end
end
function lunixArm_runScript()
local settingScriptType = getLogicValue("setting.script.type");
local settingScriptParam1 = getLogicValue("setting.script.param.1");
local content = "";
if (settingScriptType == "check_online_01") then
content =
[[
#!/bin/bash
echo -e "GET ]] .. settingScriptParam1 .. [[ HTTP/1.0\n\n" | nc ]] .. settingScriptParam1 .. [[ 80 > /dev/null 2>&1
if [ $? -eq 0 ]; then
echo "datetime="$(date +%F' '%T)";status=online"
else
echo "datetime="$(date +%F' '%T)";status=offline"
fi
echo "EOF"
]]
else
log(LogLevel.Error, "unsupported script type: " .. g_os_name)
end
if (content ~= "") then
local dirName = "/ibsystem-tmp/tmp/runscript/" .. LOGIC_INSTANCE_NAME .. "_script";
local fileName = dirName .. "/script.sh";
local outputFileName = dirName .. "/script.out";
os.execute("mkdir -p " .. dirName)
os.execute("rm -rf " .. dirName .. "/*")
os.execute("touch " .. fileName)
os.execute("chmod 755 " .. fileName)
local file = io.open(fileName, "w")
file:write(content)
file:close()
os.execute(fileName .. " > " .. outputFileName .. " 2>&1 &")
local res = "";
repeat
local resFile = io.popen([[sed 's/\r/\n/g' < ]] .. outputFileName .. [[ | tail -n 1]])
res = assert(resFile:read(_VERSION <= "Lua 5.2" and "*a" or "a"))
resFile:close()
-- obsługuje timeouta z logiki
if g_runTimeoutTimer:elapsed() then
log(LogLevel.Error, "run script timeout!")
return;
end
until res == "EOF\n"
resFile = io.input (outputFileName)
res = ""
for line in resFile:lines () do
res = line
break
--print (line)
end
resFile:close ()
--print (res)
-- send logic variables to ibmanager
setLogicValue("counter.result", res);
end
end
function onLogicCall(firstCall)
if not g_versionChecked then
-- checking sublogic type and sublogic version
if LOGIC_SUBTYPE ~= SUPPORTED_SUBLOGIC_TYPE then
error("Wrong logic sub-type. expected " .. SUPPORTED_SUBLOGIC_TYPE .. " but used " .. LOGIC_SUBTYPE);
end
local versionWithoutBuild = string.match(LOGIC_SUBVERSION, "[0-9]+%.[0-9]+%.[0-9]+");
if versionWithoutBuild ~= SUPPORTED_SUBLOGIC_VERSION then
error("Wrong logic sub-version. expected " .. SUPPORTED_SUBLOGIC_VERSION .. " but used " .. LOGIC_SUBVERSION);
end
g_versionChecked = true;
end
local settingRunTime = getLogicValue("setting.run.time");
local settingRunTimeout = getLogicValue("setting.run.timeout");
local runDowncounter = 0;
-- timers
if g_runDowncounterTimer == nil or firstCall then
g_runDowncounterTimer = DownCounter.create();
end
g_runDowncounterTimer:updateParams(settingRunTime * 1000);
if g_runTimeoutTimer == nil or firstCall then
g_runTimeoutTimer = DownCounter.create();
end
g_runTimeoutTimer:updateParams(settingRunTimeout * 1000);
if g_os_name == nil or firstCall then
g_os_name = getOS()
end
if g_runDowncounterTimer:elapsed() then
if (g_os_name == 'linux-arm') then
g_runTimeoutTimer:reset();
lunixArm_runScript();
g_runDowncounterTimer:reset();
else
log(LogLevel.Error, "unsupported OS: " .. g_os_name)
end
g_runDowncounterTimer:reset();
end
runDowncounter = g_runDowncounterTimer:timeTo0() / 1000;
runDowncounter = (runDowncounter < 0) and 0 or runDowncounter;
-- send logic variables to ibmanager
setLogicValue("counter.run.downcounter", runDowncounter);
setLogicValue("counter.os", g_os_name);
end