From 57d2d955f33cbbe82c0e97d501e2ef9d0682ab60 Mon Sep 17 00:00:00 2001 From: DigiDaz Date: Thu, 4 Aug 2016 18:40:36 +0100 Subject: [PATCH] Fixed scripts to get multiserver memcache working (#1795) --- resources/classes/cache.php | 10 +- resources/install/scripts/ha_monitor.lua | 183 ++++++++++++++++++ .../scripts/resources/functions/cache.lua | 2 +- 3 files changed, 189 insertions(+), 6 deletions(-) create mode 100644 resources/install/scripts/ha_monitor.lua diff --git a/resources/classes/cache.php b/resources/classes/cache.php index de1e8e44d5..fd4788e782 100644 --- a/resources/classes/cache.php +++ b/resources/classes/cache.php @@ -89,8 +89,8 @@ class cache { //send a custom event $event = "sendevent CUSTOM\n"; - $event .= "Event-Name: MEMCACHE\n"; - $event .= "Event-Subclass: delete\n"; + $event .= "Event-Name: CUSTOM\n"; + $event .= "Event-Subclass: fusion::memcache\n"; $event .= "API-Command: memcache\n"; $event .= "API-Command-Argument: delete ".$key."\n"; event_socket_request($fp, $event); @@ -118,8 +118,8 @@ class cache { //send a custom event $event = "sendevent CUSTOM\n"; - $event .= "Event-Name: MEMCACHE\n"; - $event .= "Event-Subclass: flush\n"; + $event .= "Event-Name: CUSTOM\n"; + $event .= "Event-Subclass: fusion::memcache\n"; $event .= "API-Command: memcache\n"; $event .= "API-Command-Argument: flush\n"; event_socket_request($fp, $event); @@ -136,4 +136,4 @@ class cache { } } -?> \ No newline at end of file +?> diff --git a/resources/install/scripts/ha_monitor.lua b/resources/install/scripts/ha_monitor.lua new file mode 100644 index 0000000000..0ce91b4104 --- /dev/null +++ b/resources/install/scripts/ha_monitor.lua @@ -0,0 +1,183 @@ +--! @todo move `servers` table to `local.lua` file + +servers = {} +servers[#servers + 1] = { + method = 'curl'; + username = "aaa"; + password = "***"; + hostname = "127.0.0.1"; + port = "8080"; +} +servers[#servers + 1] = { + method = 'ssh'; + username = "aaa"; + password = "***"; + hostname = "127.0.0.2"; + port = "8080"; +} + +require "resources.functions.config" + +local log = require "resources.functions.log".ha_monitor +local EventConsumer = require "resources.functions.event_consumer" +local api = require "resources.functions.api" + +local service_name = 'ha_monitor' +local pid_file = scripts_dir .. '/run/' .. service_name .. '.tmp' +local method = 'curl' -- default method + +local function trim(s) + return s and (string.gsub(s, "^%s*(.-)%s*$", "%1")) +end + +local function urlencode(s) + s = string.gsub(s, "([^%w])",function(c) + return string.format("%%%02X", string.byte(c)) + end) + return s +end + +local function emit(new_event_name) + return function(self, name, event) + self:emit(new_event_name, event) + end +end + +-- execute command on remote FS using mod_xml_rpc +local function curl(server, command, args) + local url = 'http://' + if server.username then + url = url .. server.username .. ':' .. server.password .. '@' + end + + url = url .. server.hostname + + if server.port then + url = url .. ':' .. server.port + end + + url = url .. '/webapi/' .. command + + if args then + url = url .. '?' .. urlencode(args) + end + + -- log.noticef('curl %s', url) + + local response, err = api:execute('curl', url) + + if err then log.warningf('[curl %s] error [%s]', url, err) + else log.noticef('[curl %s] pass [%s]', url, response) end +end + +-- execute command on remote FS using SSH access +local function ssh(server, command, args) + local cmd = 'ssh '..server.username..'@'..server.hostname + if server.port then + cmd = cmd .. ':' .. server.port + end + cmd = cmd .. [[ "fs_cli -x ']] .. command + if args then + --! todo escape args + cmd = cmd .. ' ' .. args + end + cmd = cmd .. [['"]] + + -- log.notice(cmd) + + local status = os.execute(cmd) + + if status ~= 0 then log.warningf('[%s] fail [%d]', cmd, status) + else log.noticef('[%s] pass', cmd) end +end + +local remote_execute_methods = {curl = curl; ssh = ssh} +local default_remote_execute = assert(remote_execute_methods[servers.method or method], 'Unknown execute method') + +local function remote_execute(server, command, args) + local exec = default_remote_execute + if server.method then + exec = assert(remote_execute_methods[server.method], 'Unknown execute method') + end + return exec(server, command, args) +end + +-- execute command on all remotes FS +local function remote_execute_all(...) + for _, server in ipairs(servers) do + remote_execute(server, ...) + end +end + +local events = EventConsumer.new(pid_file) + +-- FS shutdown +events:bind('SHUTDOWN', function(self, name, event) + log.notice('shutdown') + return self:stop() +end) + +-- Control commands from FusionPBX +events:bind("CUSTOM::fusion::service::control", function(self, name, event) + if service_name ~= event:getHeader('service-name') then return end + + local command = event:getHeader('service-command') + if command == "stop" then + log.notice("get stop command") + return self:stop() + end + + log.warningf('Unknown service command: %s', command or '') +end) + +-- Lua code can not generate 'MEMCACHE' event so we use `CUSTOM::fusion::memcache` +-- and forwart MEMCACHE to it for backward compatability +events:bind('MEMCACHE', emit'CUSTOM::fusion::memcache') + +-- Memcache event +events:bind('CUSTOM::fusion::memcache', function(self, name, event) + -- log.noticef('event: %s\n%s', name, event:serialize('xml')) + + local api_command = trim(event:getHeader('API-Command')) + if api_command ~= 'memcache' then return end + + local api_command_argument = trim(event:getHeader('API-Command-Argument')) + + local memcache_updated = api_command_argument and ( + (api_command_argument == 'flush') + or (api_command_argument:sub(1, 6) == 'delete') + ) + + if memcache_updated then + remote_execute_all(api_command, api_command_argument) + end +end) + +-- start gateway +events:bind('CUSTOM::sofia::gateway_add', function(self, name, event) + -- log.noticef('event: %s\n%s', name, event:serialize('xml')) + + local profile = event:getHeader('profile-name') + local gateway = event:getHeader('Gateway') + + local cmd = 'profile ' .. profile .. ' start ' .. gateway + remote_execute_all('sofia', cmd) +end) + +-- stop gateway +events:bind('CUSTOM::sofia::gateway_delete', function(self, name, event) + -- log.noticef('event: %s\n%s', name, event:serialize('xml')) + + local profile = event:getHeader('profile-name') + local gateway = event:getHeader('Gateway') + + local cmd = 'profile ' .. profile .. ' killgw ' .. gateway + remote_execute_all('sofia', cmd) +end) + +log.notice('start') + +events:run() + +log.notice('stop') + diff --git a/resources/install/scripts/resources/functions/cache.lua b/resources/install/scripts/resources/functions/cache.lua index fa88078bae..45aebf48fd 100644 --- a/resources/install/scripts/resources/functions/cache.lua +++ b/resources/install/scripts/resources/functions/cache.lua @@ -21,7 +21,7 @@ if not api then end local function send_event(action, key) - local event = freeswitch.Event("MEMCACHE"); + local event = freeswitch.Event("CUSTOM", "fusion::memcache"); event:addHeader("API-Command", "memcache"); event:addHeader("API-Command-Argument", action .. " " .. key); event:fire()