30. Скрипты

ПАК “Фортикс” позволяет автоматизировать действия администратора с помощью сценариев (скриптов) на языке программирования Lua.

Для интеграции скриптов в систему команд необходимо:

  • (опционально) создать директории для хранения файлов-скриптов в диретории /system/scripts/;

  • загрузить файлы-скрипты в подкаталоги;

  • запустить скрипт в командной строке с помощью команды @ режима администрирования.

Иерархия директорий в /system/scripts доступна как параметр команды @.

Для выполнения скрипта, находящегося в созданной директории, применяется команда:

> @ <directory> <script>

где

  • <directory> – имя директории относительно директории /system/scripts/;

  • <script> – имя скрипта.

Например, для выполнение скрипта enable_all.lua из каталога /system/scripts/iface применяется команда:

> @ iface enable_all.lua

Для команд-скриптов применимо автодополнение по клавише <Tab>.

Для создания скриптов непосредственно в командной строке необходимо:

  1. Запустить текстовый редактор для файла-скрипта:

> edit <file-path>

где <file-path> – полное имя файла-скрипта или имя файла относительно домашней директории пользователя.

  1. В текстовом редакторе непосредственно записать текст скрипта.

  2. Использовать комбинацию клавиш <C> + <O> для сохранения файла и <C> + <X> для выхода из текстового редактора.

Пример создания скрипта непосредственно на ПАК “Фортикс”:

Запуск текстового редактора для файла-скрипта:

> edit /system/scripts/hello.lua

Запись скрипта в текстовом редакторе:

print "Hello, Fortics!"

Сохранение файла-скрипта: <C> + <O>.

Выход из текстового редактора: <C> + <X>.

Запуск созданного скрипта:

> @ hello.lua
Hello, Fortics!

30.1. Дескрипторы

Для использования параметров, указываемых после имени скрипта при его запуске, применяются описатели параметров (дескрипторы) или массив ARGS, в который помещаются параметры.

Пример текста скрипта без дескрипторов:

print("Hello, ",ARGS[1])

Запуск скрипта из примера:

@ hello.lua world
Hello, world

Дескрипторы представляют собой строки заголовка скрипта, начинающиеся с --@. Данные строки воспринимаются окружением Lua как комментарии. Для описания параметров предусмотрены следующие дескрипторы:

  • @help <Help> – текстовое описание скрипта, которое выводится по горячей клавише <?> перед набором имени скрипта;

  • @arg <id>:<value> <Help> – обязательный параметр, где <id> – идентификатор параметра, <value> – тип параметра в формате строки, <Help> – текстовое описание параметра;

  • @arg* <id>:<value> – массив обязательных параметров (1 или более), где <id> – идентификатор параметра, <value> – тип параметра в формате строки;

  • @opt <id>:<value> – необязательный параметр, где <id> – идентификатор параметра, <value> – тип параметра в формате строки или списка (см. ниже);

  • @opt* <id>:<value> – массив необязательных параметров, где <id> – идентификатор параметра, <value> – тип параметра в формате строки.

В окружении Lua любые задаваемые параметры являются строками независимо от значения в <value>, которое задаётся только для отображения в справке.

В качестве <value> допустимо указание списка из возможных вариантов строк, например:

--@arg op:set|del Operation

В данном примере параметр op принимает только значения set или del.

Для описания специфики выполнения скрипта предусмотрены следующие дескрипторы:

  • @timeout – максимальный интервал выполнения скрипта, запущенного не интерактивно (в фоновом режиме), по истечении которого выполнение скрипта останавливается, где <sec> – число секунд, по умолчанию – 30;

  • @noerror – отключение режима остановки выполнения скрипта по ошибке (по умолчанию скрипт останавливается при любой ошибке).

Пример текста скрипта с дескрипторами:

--@help Example
--@arg msg:string Message string
print("Hello,",ARGS.msg)

При запуске указанного скрипта отображаются подсказки по горячей клавише <?> и осуществляется проверка на корректность всех значений параметров.

30.2. Функции

Скрипты выполняются в ограниченном окружении Lua, в котором доступны следующие стандартные функции:

  • dofile;

  • ipairs;

  • pairs.

  • print;

  • tonumber;

  • tostring;

  • type.

В ПАК “Фортикс” предусмотрены специфичные для данной среды исполнения функции.

30.2.1. Функции set_config() и del_config()

Функции set_config() и del_config() позволяют устанавливать и удалять узлы в конфигурации candidate. Предусмотрено два способа работы с функциями:

  • непосредственное указание пути к узлу конфигурации в формате командной строки для операций;

  • использование специального объекта (применим при генерации пути к узлу конфигурации в формате командной строки для операций).

Пример применения функции set_config() с непосредственным указанием пути к узлу конфигурации в формате командной стркои для операций:

set_config [[interface ether en0 description "en0"
interface ether en0 description "en1"
interface ether en0 description "en2"
interface ether en0 description "en3"]]

Пример использования специального объекта:

cfg = set_config()
for i = 0, 3 do
  cfg:printf('interface ether en%d description "en%d"\n', i, i)
end
cfg:apply()

Предупреждение

Функции set_config() и del_config() оптимизированы для выполнения групп операций. Данные функции работают значительно быстрее, чем последовательные вызовы для выполнения каждой операции по отдельности. Например, выполнение следующих последовательных операций:

set_config 'interface ether en0 description "en0"'
set_config 'interface ether en0 description "en1"'
set_config 'interface ether en0 description "en2"'
set_config 'interface ether en0 description "en3"'

значительно медленнее, чем выполнение следующей группы операций:

set_config [[interface ether en0 description "en0"
interface ether en0 description "en1"
interface ether en0 description "en2"
interface ether en0 description "en3"]]

Предупреждение

Данные функции изменяют конфигурацию candidate. Для применения указанных изменений к конфигурации running необходимо выполнить команду commit.

30.2.2. Функция load_config()

Функция load_config() позволяет дополнять конфигурацию candidate фрагментами конфигурации. Данная функция изменяет конфигурацию candidate.

Пример применения функции load_config():

load_config [[interface {
  ether en0 {
    description "en0"
    enable
  }
}]]

В указанном примере добавляются/изменяются параметры enable и description, при этом другие параметры конфигурации остаются неизменными.

Для замены конфигурации интерфейса целиком перед применением рассматриваемой функции выполняется функция del_config():

del_config "interface ether en0"
load_config [[interface {
  ether en0 {
    description "en0"
    enable
  }
}]]

30.2.3. Функция commit()

Функция commit() осуществляет фиксацию конфигурации с помощью команды commit.

Применение функции commit():

commit()

Пример применения функции commit():

set_config 'interface ether en0 description "en0"'
commit()

Применение функции commit() для указанного узла конфигурации:

commit 'path'

где path – путь к узлу конфигурации в формате командной строки.

Пример применения функции commit() для указанного узла конфигурации:

set_config 'interface ether en0 description "en0"'
commit 'interface ether en0'

30.2.4. Функция revert()

Функция revert() отменяет изменения в конфигурации candidate.

Применение функции:

revert()

Для применения revert() для указанного узла конфигурации используется конструкция:

revert 'path'

где path – путь к узлу конфигурации в формате командной строки.

30.2.5. Функция exit()

Функция exit() соответствует стандартной функции Lua os.exit().

Применение функции:

exit(true)

30.2.6. Функция command()

Функция command() позволяет выполнять последовательность команд режима администрирования.

Применение функции command():

command('<command-adm>')

где <command-adm> – команда режима администрирования.

Пример применения функции command():

command('show version')

По умолчанию вывод команды на экран подавляется и возвращается в виде двух таблиц stdout и stderr, например:

out = command 'show version'
print(out[2]) -- Показать версию (вторая строка вывода)

Для стандартного выполнения команды и получения её вывода в качестве второго параметра задается true.

Применение функции с указанием второго параметра true:

command('<command>', true)

где <command> – команда режима администрирования.

Пример применения функции с указанием второго параметра true:

command('show version', true)

Данная функция не возвращает таблицы с stdout и stderr.

Пример выполнения последовательности команд:

command([[show version
show system software]], true)

30.2.7. Функция file()

Функция file() позволяет получать содержимое файлов или создавать текстовые файлы.

Пример применения функции file():

file("hello.txt", "Hello, World!")
command("cat hello.txt", true)
txt = file 'hello.txt'
txt = txt:gsub('World', 'Fortics')
file("hello2.txt", txt)
command("cat hello2.txt", true)

30.2.8. Функция sleep()

Функция sleep() позволяет скрипту переходить в режим сна на указанное время.

Пример применения функции sleep():

sleep(1)

30.2.9. Функция getenv()

Функция getenv() соответствует стандартной функции Lua os.getenv и позволяет получать переменные окружения. Некоторые службы ПАК “Фортикс”, которые могут быть интегрированы со скриптами, передают информацию о событиях с помощью переменных окружения.

30.2.10. Функция stop_on_error()

По умолчанию любая ошибка останавливает выполнение скрипта. Для изменения режима обработки ошибок предусмотрено:

  • применение дескриптора @noerror – выключает режим остановки выполнения скрипта по ошибке полностью;

  • применение функции stop_on_error(true|false) – включает (true) или выключает (false) режим остановки по ошибке.

Функция stop_on_error() возвращает предыдущее значение режима.

Применение функции stop_on_error():

stop_on_error(true|false)

Пример применения функции stop_on_error():

old_mode = stop_on_error(false)
print(io.file("hello.txt"))
stop_on_error(true)

Функции noerror() и check_error() меняют поведение обработки ошибок для указанных вызовов функций.

30.2.11. Функция noerror()

Функция noerror() позволяет отключать режим остановки выполнения скрипта по ошибке для указанной функции.

Пример применения функции noerror():

-- проверить, существует ли файл
if noerror(file)("test") then
  print "test is exist"
else
  print "test is not exist"
end

30.2.12. Функция check_error()

Функция check_error() позволяет включать режим остановки выполнения скрипта по ошибке для указанной функции.

Пример применения функции check_error():

--@noerror
del_config "interface ether en1 enable"
check_error(commit)()
print "Commit done!"

30.2.13. Функции time() и date()

Функции time() и date() соответствуют стандартным функциям Lua os.time() и os.date().

30.2.14. Функция send_smtp

Функция send_smtp позволяет отправлять e-mail сообщения на некоторый сервер.

Применение функции send_smtp:

send_smtp(<opt>, <message>)

где

  • <opt> – lua-таблица, ключами которой являются опции, а значениями – значения опций;

  • <message> – строка сообщения, которая может содержать получателей и отправителя (см. пример ниже).

Доступны следующие опции для таблицы <opt>:

  • recipients – получатели, значение опции – адреса, указанные через “;”, в кавычках;

  • password – пароль для аутентификации на почтом сервере отправителя, значение опции – строка в кавычках;

  • user – имя пользователя для аутентификации на почтовом сервере, значение опции – строка в кавычках;

  • host – адрес почтового сервера, значение опции – строка в кавычках;

  • from – отправитель письма, значение опции – строка в кавычках;

  • tls – включение/отключение TLS для связи с почтовым сервером (все необходимые для проверки сертификаты сервера должны находиться в каталоге /system/ssl/certs, если проверка сертификата не отключена), значение опции – “on”/“off”;

  • auth – включение/отключение аутентификации при связи с сервером, значение опции – “on”/“off”, при значении “on” данной опции значения опций user и password должны быть определены;

  • tls-certcheck – включение/отключение проверки сертификата почтового сервера при включенном tls, значение опции – “on”/“off”.

Если опции recipients и/или from не указаны, их значения извлекаются из строки сообщения.

Пример определения значений опций recipients и from в строке сообщения:

local message = "From: best_programmer@zts.ru\n To: test@zts.ru\n Hello!\n"

Пример применения функции send_smtp:

local opts = {
  password = "Aqwl;vxcjk123",
  user = "test@inbox.ru",
  tls = "off",
  host = "smtp.mail.ru",
  auth = "on",
}
local message = "From:test@inbox.ru\n Hello world!\n"

local ret, err = send_smtp(opts, message)

Допустимо указание значения nil строки сообщения. В этом случае отправляется пустое сообщение, при этом определение значений опций from и recipients обязательно.

30.2.15. Функция send_snmp

Функция send_snmp позволяет отправлять SNMP-сообщения trap/inform на удалённый сервер с помощью протокола SNMP второй и третьей версии.

Применение функции send_snmp:

send_snmp(<opt>, <message>)

где

  • <opt> – lua-таблица, ключами которой являются опции, а значениями – значения опций;

  • <message> – набор таблиц.

Доступны следующие опции для таблицы <opt>:

  • snmtype – тип посылаемого сообщения, значение опции – “trap” или “inform”, по умолчанию – “trap”;

  • version – версия сообщения, значение опции – “2” или “3”, по умолчанию – “2”;

  • addr – адрес приёмника, значение опции – адрес хоста, для указания порта добавляется :<port>, где <port> – число от 1 до 65535;

  • uptime – (опционально) время работы системы (по умолчанию указывается время работы после загрузки системы), значение опции – число секунд в кавычках;

  • user – (только для v3) имя пользователя для аутентификации на сервере, значение опции – строка в кавычках;

  • sec_engine_id – (только для v3) engineID, используемое при включённой аутентификации на принимающей стороне, значение опции – hex-значение в кавычках;

  • auth_alg – (только для v3) алгоритм аутентификации, значение опции – “MD5”/“SHA”;

  • auth_key – (только для v3) ключ аутентификации, значение опции – строка в кавычках;

  • privacy_alg – (только для v3) алгоритм шифрования, значение опции – “DES”/“AES”;

  • privacy_key – (только для v3) закрытый ключ, используемый для шифрования, значение опции – строка в кавычках;

  • context_engine_id – (только для v3) engineID для контекста, значение опции – hex-значение в кавычках;

  • community – (только для v2) идентификатор отправителя, значение опции – строка в кавычках.

Сообщение – это набор таблиц, где в начале указывается oid события и далее дополнительный oid. Каждая таблица в начале содержит базовый oid/mib, далее опциональное значение, которое является строкой или числом. Данное значение отправляется с типом ASN1_INTEGER или ASN1_STRING в зависимости от переданного значения.

Пример сообщения:

{"1.2.3.4", "2"}

{"1.2.3.4", 2}

В первом случае сообщение отправится как ASN1_STRING, во втором – как ASN1_INTEGER.

Примеры:

local conf1 = {
  snmptype = "trap",
  version = "3",
  addr = "192.168.56.1:12345",
  sec_engine_id = "0x8000123acd1ab43abbfff000fa",
  user = "test",
  auth_alg = "MD5",
  auth_key = "testsnmp",
  privacy_alg = "DES",
  privacy_key = "testSNMP",
}
send_snmp(conf1, {"SNMPv2-MIB::coldStart"}, {"iso.3.6.1.6.3.1.1.6.2", 2},
{"SNMPv2-MIB::sysName.0", "My Device"}) --Send snmpv3 trap with auth and privacy. uptime from system

local conf2 = {
 version = "3",
 addr = "192.168.56.1:12345",
 user = "test2",
}
send_snmp(conf2, {"SNMPv2-MIB::coldStart"}, {"iso.3.6.1.6.3.1.1.6.2", 2},
{"SNMPv2-MIB::sysName.0", "My Device"}) -- --Send snmpv3 trap without auth and privacy, uptime from system

local conf3 = {
  addr = "192.168.56.1:12345",
  community = "public",
}
send_snmp(conf2, {"SNMPv2-MIB::coldStart"}, {"iso.3.6.1.6.3.1.1.6.2", 2},
{"SNMPv2-MIB::sysName.0", "My Device"}) -- --Send snmpv2 trap

30.2.16. Функция journal

Функция journal позволяет отправлять сообщения в системный журнал.

Предусмотрены следующие уровни отправляемых в журнал сообщений:

  • alert – оповещение, требующее немедленной реакции администратора;

  • err – ошибка;

  • warning – предупреждение;

  • info – информационное сообщение.

Пример применения функции journal:

journal("alert", "No free space available!")

Пример использования форматной строки в функции journal:

journal("info", "%d days left", days)

30.2.17. Функции get, get_data, get_xpath

Функции get, get_data и get_xpath позволяют выполнять выборку из конфигурации running, возвращая lua-таблицу с данными. Функции get и get_data получают в качестве параметра путь к узлу конфигурации в формате командной строки. Функция get_xpath получает в качестве параметра путь в виде yang xpath-запроса.

Функция get возвращает узел. Функции get_data и get_xpath возвращают поддерево от корня конфигурации до узла. Функция get не может быть использована в тех случаях, когда под выборку попадает несколько элементов.

Для анализа структур применяется функция table.dump().

Пример применения функций get, get_data, get_xpath, table.dump():

local addr = get_data "interface ether en0 ipv4 address"
if not addr then
  exit()
end

printf("data: %s\n\n", table.dump(addr, true))
for _, v in ipairs(addr[1][1][2]) do
  print(v[1].val)
end
print(addr:dump())

local enable = get "interface ether en0 enable"
printf("data: %s\n\n", table.dump(enable, true))
printf("enabled: %s\n", enable and enable[1] and true)

30.3. Библиотеки

В ПАК “Фортикс” поддерживаются следующие стандартные библиотеки Lua:

  • table;

  • string;

  • math.

В ПАК “Фортикс” поддерживаются следующие нестандартные библиотеки:

  • ipnet;

  • rex.

30.4. Расширение стандартных библиотек

В ПАК “Фортикс” для удобства решения типовых задач стандартные библиотеки Lua расширены дополнительными функциями.

30.4.1. Расширение библиотеки string

  • string.empty(<string>) – проверить, что строка состоит из пробелов и табуляций, где <string> – строка;

  • string.strip(<string>,[набор символов]) – убрать разделители в конце строки, где <string> – строка;

  • string.split(<string>, [макс. разбиений], [separator]) – разбить строку на массив строк, где <string> – строка, [separator] – разделитель;

  • string.startswith(<string>, <prefix>) – проверить, что строка начинается с указанного префикса, где <string> – строка, <prefix> – префикс строки;

  • string.endswith(<string>, <postfix>) – проверить, что строка заканчивается на указанный постфикс, где <string> – строка, <postfix> – постфикс строки;

  • string.lines(<text>) – построчный итератор.

30.4.2. Расширение библиотеки table

  • table.append(<dst>, <src>) – добавить элементы таблицы <src> в таблицу <dst>, где <dst> – lua-таблица, <src> – lua-таблица;

  • table.clone(<src>) – клонировать таблицу, где <src> – lua-таблица;

  • table.merge(<dst>, <src>) – внести в таблицу элементы таблицы без изменений, где <dst> – lua-таблица, <src> – lua-таблица;

  • table.empty(<src>) – проверить, что таблица пуста, где <src> – lua-таблица;

  • table.unpack(<src>) – распаковать таблицу в список значений, где <src> – lua-таблица;

  • table.iter(<src>) – аналогична стандартной функции ipairs, при этом индекс не возвращается, где <src> – lua-таблица.

30.5. Пример скрипта

Пример скрипта, выполняющего команды для группы параметров:

--@help For iterator
--@arg start:int Start value
--@arg stop:int End value
--@arg op:set|del Command
--@arg* arg:path Path

local start = tonumber(ARGS.start)
local stop = tonumber(ARGS.stop)
local cmd = ''
for _, v in ipairs(ARGS.arg) do
  cmd = cmd .. string.quote(v) .. ' '
end
local cfg = ARGS.op == 'del' and del_config() or set_config()
for i=start, stop do
  cfg:printf(cmd..'\n', i)
end
cfg:apply()

Применение скрипта из примера:

@ for 0 10 set interface ether en%d enable