За последний год на Хабре появилось несколько статей про использование диалплана lua в asterisk (раз, два, три, четыре). Это достаточно интересный способ написания гибких и мощных диалпланов. Но чтобы попробовать такой способ написания диалпланов надо потратить некоторое количество времени: установить нужные библиотеки, пересобрать с необходимыми опциям астериск.
Вдобавок у многих пользователей asterisk'а разный уровень подготовки: кто-то ближе к системному администрированию или даже к традиционной телефонии, чем к программированию. Плюс специфика телефонии — лучше лишний раз незнакомыми экспериментами не нагружать работающие системы, а проводить тесты и эксперименты на своем ноутбуке — приходится захламлять систему. В общем, есть немало причин «отложить на потом».
В данной статье я хочу показать всем желающим и работающим с астериском, как, используя docker, можно быстро ощутить вкус гибких сценариев lua. А уж затем решить стоит этим пользоваться дальше на практике или нет. (Кому неинтересно читать, а интересно смотреть и слушать — в конце текста 6-минутное видео с основными моментами и результатом.)
В рамках работы над несколькими своими проектами, следуя современной тенденции упаковки всего в контейнеры, я подготовил образ astolua (asterisk + lua). В Dockerfile приведены команды для установки asterisk 11, lua 5.1, luarocks (пакетный менеджер для lua), luamongo (драйвер для доступа к mongodb), некоторые пакеты lua rocks. Вы можете в дальнейшем в репозитории docker-astolua взять только полезное для себя и собрать свою рабочую лошадку.
Безусловно плюсом докера является возможность скачать образ, провести пробы-эксперименты-тесты, а затем удалить образы, оставив свою операционную систему в чистоте и привычном порядке.
На основе образа astolua мы создадим свой рабочий образ, в котором будем использовать тестовые файлы конфигурации астериска и диалплан на lua.
Нам потребуется docker. Если у вас он не установлен, то, пожалуйста, установите сначала docker (официальная документация, статья на Хабре).
Также нам потребуется git (установка git)
Также сразу отмечу, что моей рабочей системой является Ubuntu 14.04. Если вы используете иной Linux, то отличия в командах по идее быть не должно, но нюансы не исключены.
Затягиваем образ (внимание, будет скачан образ с репозитория hub.docker.com размером ~600Мб).
Клонируем docker-astolua-sample — это заранее заготовленный набор файлов для этой статьи.
Теперь давайте остановимся на sample и посмотрим содержимое директории.
Файл Dockerfile
Файл для сборки нашего рабочего образа. В нем мы указываем, что берем за основу astolua. Затем добавляем скрипт автозагрузки after_start.sh, который будет выполнен при старте контейнера. В консоль, где мы запустим контейнер, будт выводиться лог консоли астериска.
Файл build
Внутри файла команда докера на построение образа sample из нашего Dockerfile.
Файл run
Внутри файла команда докера на запуск контейнера на основе образа sample с конфигурированием необходимых ему ресурсов.
Папка store
Папка store содержит конфигурационные файлы астериска (те, которые обычно лежат в /etc/asterisk) и папки для логов и голосовых меню.
Команда run наиболее интересна, т.к. здесь указываются необходимые ресурсы для контейнера. Например, опцией -v $(pwd)/store/etc/asterisk:/etc/asterisk мы указываем, что конфигурационные файлы из нашей папки store должны оказаться внутри контейнера на своем месте в /etc/asterisk.
Почему команды в файлах? Удобно редактировать команды в файлах, т.к. это ускоряет время на протестировать изменения в командах с разными опциями, а также все изменения лягут под контроль версий. И еще удобно потом перенести опции в docker-compose, если образ будет использоваться совместно с другими.
Вернемся к консоли.
Сделаем образ astolua:sample (в директории, куда мы склонировали docker-astolua-sample)
Запускаем asterisk (если у вас уже запущен на машине астериск или иной сервис, занимающий порт 5060, то его лучше предварительно остановить)
В консоль должен повалиться лог загрузки астериска. Можно протестировать связь.
В конфигурационном файле астериска sip.conf указаны два абонента 101 и 102 (пароль 1234), а в файле queues.conf очередь 1234, в которую добавлены эти два абонента. Настройте свой софтфон или хардфон на 101 абонента и попробуйте совершить звонок на абонента 102. (Транков для подключения к внешним voip-сервисам или настроек какого-либо железа нет, поэтому диалплан мы потестируем на локальных звонках). Информация о звонке между абонентами должна появиться в консоли астериска.
Абоненты работают, звонки проходят? Ок, значит астериск в докер-контейнере работает как надо.
Диалплан lua находится в файле extensions.lua. В конфигурационных файлах астериска в папке store/etc/asterisk есть пример работающего диалплана lua.
В этом файле должны быть правильно описаны переменные extensions и hints (в терминологии lua — это «таблицы»).
В таблице extensions содержатся контексты и соответствующие extensions. Все как в традиционном диалплане. Но каждый extension обрабатывается своей функцией, в которой вы уже можете делать все, что угодно на lua, при этом взаимодействуя с астериском через таблицы app и channel.
Самый простой пример
Видно, что через app доступно приложение диалплана Dial, оно принимает все те же параметры, что и в традиционном диалплане. Через app доступны все приложения диалплана.
Переменная channel дает доступ к канальным переменным. Вот так, например, получаем dialstatus.
Вы можете изменить extensions.lua, а затем командой в CLI астериска module reload pbx_lua.so перечитать extensions.lua. Астериск проверит синтаксис lua, и если все ок, то загрузит его для выполнения — можно тестировать изменения.
А что еще можно делать в диалплане lua?
Например, гибко обработать dialstatus, который будет возвращен функцией Dial диалплана. Не надо больше изобретать эти Goto(s-${DIALSTATUS},1), теперь можно по-человечески написать проверку статуса
В примерe extensions.lua есть пример простого ivr: позвонив на номер 200, вы услышите запись из файла /var/menu/demo и сможете перейти дальше, нажав 1 или 2.
Для человека, написавшего пару десятков строк традиционного диалплана, здесь должно быть все знакомо. Плюс появляется вся мощь lua и пакетов luarocks. Надеюсь очевидно, что здесь же в диалплане вы можете отправить смс, емейл, положить данные в бд, взять данные из бд, а бд может быть любая: mysql, mongodb, redis и т.п., сделать вызов команды, инициировать еще один звонок, сделать крутой роутинг звонка по транкам и т.д., не забывая, конечно, что это все работает в рамках астериска, и все «тяжелые» задачи лучше все-таки решать отдельно.
Предлагаю:
Надеюсь, данная статья будет полезна для быстрого старта, и вы найдете один свободный зимний вечер и попробуете такой способ написания диалпланов.
Ошибки? Опечятки? Вопросы? Пожалуйста, пишите.
Вдобавок у многих пользователей asterisk'а разный уровень подготовки: кто-то ближе к системному администрированию или даже к традиционной телефонии, чем к программированию. Плюс специфика телефонии — лучше лишний раз незнакомыми экспериментами не нагружать работающие системы, а проводить тесты и эксперименты на своем ноутбуке — приходится захламлять систему. В общем, есть немало причин «отложить на потом».
В данной статье я хочу показать всем желающим и работающим с астериском, как, используя docker, можно быстро ощутить вкус гибких сценариев lua. А уж затем решить стоит этим пользоваться дальше на практике или нет. (Кому неинтересно читать, а интересно смотреть и слушать — в конце текста 6-минутное видео с основными моментами и результатом.)
Вводное слово
В рамках работы над несколькими своими проектами, следуя современной тенденции упаковки всего в контейнеры, я подготовил образ astolua (asterisk + lua). В Dockerfile приведены команды для установки asterisk 11, lua 5.1, luarocks (пакетный менеджер для lua), luamongo (драйвер для доступа к mongodb), некоторые пакеты lua rocks. Вы можете в дальнейшем в репозитории docker-astolua взять только полезное для себя и собрать свою рабочую лошадку.
Безусловно плюсом докера является возможность скачать образ, провести пробы-эксперименты-тесты, а затем удалить образы, оставив свою операционную систему в чистоте и привычном порядке.
На основе образа astolua мы создадим свой рабочий образ, в котором будем использовать тестовые файлы конфигурации астериска и диалплан на lua.
Подготовка
Нам потребуется docker. Если у вас он не установлен, то, пожалуйста, установите сначала docker (официальная документация, статья на Хабре).
Также нам потребуется git (установка git)
Также сразу отмечу, что моей рабочей системой является Ubuntu 14.04. Если вы используете иной Linux, то отличия в командах по идее быть не должно, но нюансы не исключены.
Загрузка образа astolua
Затягиваем образ (внимание, будет скачан образ с репозитория hub.docker.com размером ~600Мб).
docker pull antirek/astolua
Sample
Клонируем docker-astolua-sample — это заранее заготовленный набор файлов для этой статьи.
git clone https://github.com/antirek/docker-astolua-sample.git
cd docker-astolua-sample
Теперь давайте остановимся на sample и посмотрим содержимое директории.
Файл Dockerfile
Файл для сборки нашего рабочего образа. В нем мы указываем, что берем за основу astolua. Затем добавляем скрипт автозагрузки after_start.sh, который будет выполнен при старте контейнера. В консоль, где мы запустим контейнер, будт выводиться лог консоли астериска.
Файл build
Внутри файла команда докера на построение образа sample из нашего Dockerfile.
docker build -t "astolua:sample" .
Файл run
Внутри файла команда докера на запуск контейнера на основе образа sample с конфигурированием необходимых ему ресурсов.
docker run -v /etc/localtime:/etc/localtime:ro -v $(pwd)/store/etc/asterisk:/etc/asterisk -v $(pwd)/store/var/log/asterisk:/var/log/asterisk -v $(pwd)/store/var/menu:/var/menu/ --net=host -i -t "astolua:sample"
Папка store
Папка store содержит конфигурационные файлы астериска (те, которые обычно лежат в /etc/asterisk) и папки для логов и голосовых меню.
Команда run наиболее интересна, т.к. здесь указываются необходимые ресурсы для контейнера. Например, опцией -v $(pwd)/store/etc/asterisk:/etc/asterisk мы указываем, что конфигурационные файлы из нашей папки store должны оказаться внутри контейнера на своем месте в /etc/asterisk.
Почему команды в файлах? Удобно редактировать команды в файлах, т.к. это ускоряет время на протестировать изменения в командах с разными опциями, а также все изменения лягут под контроль версий. И еще удобно потом перенести опции в docker-compose, если образ будет использоваться совместно с другими.
Вернемся к консоли.
Сделаем образ astolua:sample (в директории, куда мы склонировали docker-astolua-sample)
./build
Запускаем asterisk (если у вас уже запущен на машине астериск или иной сервис, занимающий порт 5060, то его лучше предварительно остановить)
./run
В консоль должен повалиться лог загрузки астериска. Можно протестировать связь.
В конфигурационном файле астериска sip.conf указаны два абонента 101 и 102 (пароль 1234), а в файле queues.conf очередь 1234, в которую добавлены эти два абонента. Настройте свой софтфон или хардфон на 101 абонента и попробуйте совершить звонок на абонента 102. (Транков для подключения к внешним voip-сервисам или настроек какого-либо железа нет, поэтому диалплан мы потестируем на локальных звонках). Информация о звонке между абонентами должна появиться в консоли астериска.
Абоненты работают, звонки проходят? Ок, значит астериск в докер-контейнере работает как надо.
Диалплан lua
Диалплан lua находится в файле extensions.lua. В конфигурационных файлах астериска в папке store/etc/asterisk есть пример работающего диалплана lua.
В этом файле должны быть правильно описаны переменные extensions и hints (в терминологии lua — это «таблицы»).
В таблице extensions содержатся контексты и соответствующие extensions. Все как в традиционном диалплане. Но каждый extension обрабатывается своей функцией, в которой вы уже можете делать все, что угодно на lua, при этом взаимодействуя с астериском через таблицы app и channel.
Самый простой пример
extensions = {
["internal"] = {
["_1XX"] = function (context, extension)
-- do something --
app.dial('SIP/'..extension);
-- do something again
end;
}
}
Видно, что через app доступно приложение диалплана Dial, оно принимает все те же параметры, что и в традиционном диалплане. Через app доступны все приложения диалплана.
Переменная channel дает доступ к канальным переменным. Вот так, например, получаем dialstatus.
extensions = {
["internal"] = {
["_1XX"] = function (context, extension)
-- do something --
app.dial('SIP/'..extension);
local dialstatus = channel["DIALSTATUS"]:get();
app.noop('dialstatus: '..dialstatus);
end;
}
}
Вы можете изменить extensions.lua, а затем командой в CLI астериска module reload pbx_lua.so перечитать extensions.lua. Астериск проверит синтаксис lua, и если все ок, то загрузит его для выполнения — можно тестировать изменения.
А что еще можно делать в диалплане lua?
Например, гибко обработать dialstatus, который будет возвращен функцией Dial диалплана. Не надо больше изобретать эти Goto(s-${DIALSTATUS},1), теперь можно по-человечески написать проверку статуса
extensions = {
["internal"] = {
["_1XX"] = function (context, extension)
app.dial('SIP/'..extension);
local dialstatus = channel["DIALSTATUS"]:get();
if dialstatus == 'BUSY' then
-- do something
elseif dialstatus == 'CHANUNAVAIL' then
-- do another thing
end;
end;
}
}
В примерe extensions.lua есть пример простого ivr: позвонив на номер 200, вы услышите запись из файла /var/menu/demo и сможете перейти дальше, нажав 1 или 2.
local ivr = function (context, extension)
app.read("IVR_CHOOSE", "/var/menu/demo", 1, nil, 2, 3);
local choose = channel["IVR_CHOOSE"]:get();
if choose == '1' then
app.queue('1234');
elseif choose == '2' then
dial('internal', '101');
else
app.hangup();
end;
end;
Для человека, написавшего пару десятков строк традиционного диалплана, здесь должно быть все знакомо. Плюс появляется вся мощь lua и пакетов luarocks. Надеюсь очевидно, что здесь же в диалплане вы можете отправить смс, емейл, положить данные в бд, взять данные из бд, а бд может быть любая: mysql, mongodb, redis и т.п., сделать вызов команды, инициировать еще один звонок, сделать крутой роутинг звонка по транкам и т.д., не забывая, конечно, что это все работает в рамках астериска, и все «тяжелые» задачи лучше все-таки решать отдельно.
Что дальше?
Предлагаю:
- посмотреть официальную документацию Asterisk и LUA — достаточно примеров и сравнений, чтобы разобраться с основами
- прочитать еще раз статьи на Хабре от Sayman_Nsk и ovoshlook: диалплан на lua, AMI в диалплане, обновление DEF-кодов, создание IVR
- посмотреть пример диалплана на lua от Игмара, где реализована большая часть функционала АТС: звонки абонентам, регистрация/отрегистрация операторов очередей, webhook'и при входящих звонках, маршрутизация в зависимости от дня недели и времени дня.
- «запилить» что-то свое: )
Надеюсь, данная статья будет полезна для быстрого старта, и вы найдете один свободный зимний вечер и попробуете такой способ написания диалпланов.
Ошибки? Опечятки? Вопросы? Пожалуйста, пишите.