diff --git a/.gitignore b/.gitignore index d4ae6fdf..df001675 100644 --- a/.gitignore +++ b/.gitignore @@ -19,7 +19,7 @@ luac.out # luarocks build files *.src.rock *.zip -*.tar.gz +#*.tar.gz # Object files *.o diff --git a/dashboard/model/node.lua b/dashboard/model/node.lua index 9b39a009..f03747e2 100644 --- a/dashboard/model/node.lua +++ b/dashboard/model/node.lua @@ -1,33 +1,23 @@ -local DB = require("dashboard.model.db") local json = require("orange.utils.json") +local store = context.store return function(config) + local store_type = config.store local node_model = {} - local mysql_config = config.store_mysql - local db = DB:new(mysql_config) - local table_name = 'cluster_node' local stat_table_name = 'cluster_node_stat' function node_model:new(name, ip, port, api_username, api_password) - return db:query("insert into " .. table_name .. "(name,ip,port,api_username,api_password) values(?,?,?,?,?)", - { name, ip, port, api_username, api_password }) + return store:node_new(name, ip, port, api_username, api_password) end function node_model:query_all() - local result, err = db:query("select * from " .. table_name .. " order by ip asc") - - if not result or err or type(result) ~= "table" or #result < 1 then - return nil, err - else - return result, err - end + return store:node_query_all() end function node_model:get_stat(limit) - - local result, err = db:query("select op_time,sum(request_2xx) as request_2xx,sum(request_3xx) as request_3xx," .. +--[[ local result, err = db:query("select op_time,sum(request_2xx) as request_2xx,sum(request_3xx) as request_3xx," .. " sum(request_4xx) as request_4xx," .. " sum(request_5xx) as request_5xx," .. " sum(total_request_count) as total_request_count," .. @@ -43,84 +33,86 @@ return function(config) return nil, err else return result, err - end + end]] end function node_model:get_stat_by_ip(ip, limit) - - local result, err = db:query("select * from " .. stat_table_name .. " where ip = ? order by op_time asc limit ?", { ip, limit }) +--[[ local result, err = db:query("select * from " .. stat_table_name .. " where ip = ? order by op_time asc limit ?", { ip, limit }) if not result or err or type(result) ~= "table" or #result < 1 then return nil, err else return result, err - end + end]] end function node_model:query_by_id(id) - local result, err = db:query("select * from " .. table_name .. " where id=?", { tonumber(id) }) +--[[ local result, err = db:query("select * from " .. table_name .. " where id=?", { tonumber(id) }) if not result or err or type(result) ~= "table" or #result ~= 1 then return nil, err else return result[1], err - end + end]] end - function node_model:query_by_ip(ip) - local result, err = db:query("select * from " .. table_name .. " where ip=?", { ip }) + function node_model:query_by_ip(ip, port) + return store:node_query_by_ip(ip, port) +--[[ local result, err = db:query("select * from " .. table_name .. " where ip=?", { ip }) if not result or err or type(result) ~= "table" or #result ~= 1 then return nil, err else return result[1], err - end + end]] end function node_model:update_node(id, name, ip, port, api_username, api_password) - local res, err = db:query("update " .. table_name .. " set name=?,ip=?,port=?,api_username=?,api_password=? where id=?", { name, ip, port, api_username, api_password, tonumber(id) }) + return store:node_update_node(id, name, ip, port, api_username, api_password) +--[[ local res, err = db:query("update " .. table_name .. " set name=?,ip=?,port=?,api_username=?,api_password=? where id=?", { name, ip, port, api_username, api_password, tonumber(id) }) if not res or err then return false else return true - end + end]] end function node_model:update_node_status(id, status) - local res, err = db:query("update " .. table_name .. " set sync_status=? where id=?", { status, tonumber(id) }) +--[[ local res, err = db:query("update " .. table_name .. " set sync_status=? where id=?", { status, tonumber(id) }) if not res or err then return false else return true - end + end]] end function node_model:delete(id) - local res, err = db:query("delete from " .. table_name .. " where id=?", { tonumber(id) }) + return store:node_delete(id) +--[[ local res, err = db:query("delete from " .. table_name .. " where id=?", { tonumber(id) }) if not res or err then return false else return true - end + end]] end function node_model:remove_error_nodes() - local res, err = db:query("delete from " .. table_name .. " where sync_status=? ", { json.encode({ ERROR = false }) }) +--[[ local res, err = db:query("delete from " .. table_name .. " where sync_status=? ", { json.encode({ ERROR = false }) }) if not res or err then return false else return true - end + end]] end function node_model:registry(ip, port, credentials) - local local_node = self:query_by_ip(ip) +--[[ local local_node = self:query_by_ip(ip) if not local_node then self:new(ip, ip, port, credentials.username, credentials.password) local_node = self.query_by_ip(ip) end - return local_node + return local_node]] end return node_model diff --git a/dashboard/model/user.lua b/dashboard/model/user.lua index d53e4083..917796fa 100644 --- a/dashboard/model/user.lua +++ b/dashboard/model/user.lua @@ -1,32 +1,22 @@ -local DB = require("dashboard.model.db") - +local store = context.store return function(config) local user_model = {} - local mysql_config = config.store_mysql - local db = DB:new(mysql_config) - function user_model:new(username, password, enable) - return db:query("insert into dashboard_user(username, password, enable) values(?,?,?)", - {username, password, enable}) + return store:user_new(username, password, enable) end function user_model:query(username, password) - local res, err = db:query("select * from dashboard_user where username=? and password=?", {username, password}) - return res, err + return store:user_query(username, password) end function user_model:query_all() - local result, err = db:query("select id, username, is_admin, create_time, enable from dashboard_user order by id asc") - if not result or err or type(result) ~= "table" or #result < 1 then - return nil, err - else - return result, err - end + return store:user_query_all() end + --@unused function user_model:query_by_id(id) - local result, err = db:query("select * from dashboard_user where id=?", {tonumber(id)}) + local result, err = self.db:query("select * from dashboard_user where id=?", {tonumber(id)}) if not result or err or type(result) ~= "table" or #result ~=1 then return nil, err else @@ -36,39 +26,19 @@ return function(config) -- return user, err function user_model:query_by_username(username) - local res, err = db:query("select * from dashboard_user where username=? limit 1", {username}) - if not res or err or type(res) ~= "table" or #res ~=1 then - return nil, err or "error" - end - - return res[1], err + return store:user_query_by_username(username) end - function user_model:update_enable(userid, enable) - local res, err = db:query("update dashboard_user set enable=? where id=?", {tonumber(enable), tonumber(userid)}) - if not res or err then - return false - else - return true - end + function user_model:update_enable(username, enable) + return store:user_update_enable(username, enable) end - function user_model:update_pwd_and_enable(userid, pwd, enable) - local res, err = db:query("update dashboard_user set password=?, enable=? where id=?", {pwd, tonumber(enable), tonumber(userid)}) - if not res or err then - return false - else - return true - end + function user_model:update_pwd_and_enable(username, pwd, enable) + return store:user_update_pwd_and_enable(username, pwd, enable) end - function user_model:delete(userid) - local res, err = db:query("delete from dashboard_user where id=?", {tonumber(userid)}) - if not res or err then - return false - else - return true - end + function user_model:delete(username) + store:user_delete(username) end return user_model diff --git a/dashboard/routes/auth.lua b/dashboard/routes/auth.lua index eb85cd4d..c4badae3 100644 --- a/dashboard/routes/auth.lua +++ b/dashboard/routes/auth.lua @@ -39,18 +39,18 @@ return function(config, store) end local isExist = false - local userid = 0 + local userid = 1 password = encode(password .. "#" .. pwd_secret) --ngx.say(username.. "#" ..password) - local result, err = user_model:query(username, password) + local result, err = user_model:query_by_username(username) local user = {} if result and not err then - if result and #result == 1 then + if result and type(result) == "table" then isExist = true - user = result[1] - userid = user.id + user = result + --userid = user.id end else isExist = false @@ -58,19 +58,22 @@ return function(config, store) if isExist == true then local is_admin = false - if user.is_admin == 1 then + if user.is_admin == "1" then ngx.log(ngx.INFO, "管理员[", user.username, "]登录") is_admin = true else ngx.log(ngx.INFO, "普通用户[", user.username, "]登录") end - req.session.set("user", { + local session = { username = username, is_admin = is_admin, - userid = userid, - create_time = user.create_time or "" - }) + userid = userid + } + + --ngx.log(ngx.ERR, session.create_time) + + req.session.set("user", session) return res:json({ success = true, msg = "登录成功." diff --git a/dashboard/routes/node.lua b/dashboard/routes/node.lua index 071c2098..06e35378 100644 --- a/dashboard/routes/node.lua +++ b/dashboard/routes/node.lua @@ -8,7 +8,7 @@ local string_format = string.format local lor = require("lor.index") local socket = require("socket") local orange_db = require("orange.store.orange_db") - +local ip_utils = require "lua_ip" return function(config, store) @@ -16,29 +16,9 @@ return function(config, store) local node_model = require("dashboard.model.node")(config) local function get_nodes() - local nodes = node_model:query_all() - - if nodes then - for _, node in pairs(nodes) do - -- 格式化成 json 数据 - node.sync_status = json.decode(node.sync_status) - end - end - - return nodes + return node_model:query_all() end - -- 获取 IP - local function get_ip_by_hostname(hostname) - local ip, resolved = socket.dns.toip(hostname) - local ListTab = {} - for k, v in ipairs(resolved.ip) do - table.insert(ListTab, v) - end - return unpack(ListTab) - end - - -- 节点同步 local function sync_nodes(nodes, plugins) @@ -85,7 +65,7 @@ return function(config, store) end function node_router:register() - local local_ip = get_ip_by_hostname(socket.dns.gethostname()) + local local_ip = ip_utils.get_ipv4() node_model:registry(local_ip, 7777, config.api.credentials[1]) end diff --git a/install/etcd_default_data/etcd_v2_backup.tar.gz b/install/etcd_default_data/etcd_v2_backup.tar.gz new file mode 100644 index 00000000..41acb598 Binary files /dev/null and b/install/etcd_default_data/etcd_v2_backup.tar.gz differ diff --git a/install/orange_install_quick_view.txt b/install/orange_install_quick_view.txt new file mode 100644 index 00000000..d97e0174 --- /dev/null +++ b/install/orange_install_quick_view.txt @@ -0,0 +1,27 @@ +cd /opt/ +wget https://openresty.org/download/openresty-1.15.8.2.tar.gz +tar zxvf openresty-1.15.8.2.tar.gz +cd openresty-1.15.8.2 +./configure --prefix=/usr/local/openresty --with-luajit --with-pcre-jit --with-http_iconv_module --with-http_realip_module --with-http_stub_status_module --with-http_ssl_module --with-http_v2_module --with-stream --with-stream_ssl_module +gmake && gmake install + +wget https://luarocks.org/releases/luarocks-2.4.3.tar.gz +tar zxvf luarocks-2.4.3.tar.gz +./configure --prefix=/usr/local/openresty/luajit --with-lua=/usr/local/openresty/luajit/ --lua-suffix=jit --with-lua-include=/usr/local/openresty/luajit/include/luajit-2.1 +make build && make install +/usr/local/openresty/luajit/bin/luarocks install luafilesystem +/usr/local/openresty/luajit/bin/luarocks install lrandom +/usr/local/openresty/luajit/bin/luarocks install https://luarocks.org/manifests/kong/lua_ip-0.1-2.rockspec +/usr/local/openresty/luajit/bin/luarocks install https://luarocks.org/manifests/membphis/lua-typeof-0.1-0.rockspec +/usr/local/openresty/luajit/bin/luarocks install penlight +/usr/local/openresty/luajit/bin/luarocks install https://luarocks.org/manifests/kong/lua-resty-dns-client-2.2.0-1.rockspec +/usr/local/openresty/luajit/bin/luarocks install luasocket + +cd /opt +git clone https://github.com/dangdangdotcom/orange.git +cd orange +cd /usr/local/orange +/usr/local/openresty/bin/opm --install-dir=./ get zhangbao0325/orangelib +/usr/local/openresty/bin/opm install sumory/lor +make install +sh start.sh diff --git a/orange/lib/etcd.lua b/orange/lib/etcd.lua new file mode 100644 index 00000000..96603f64 --- /dev/null +++ b/orange/lib/etcd.lua @@ -0,0 +1,536 @@ +-- https://github.com/ledgetech/lua-resty-http +local http = require "resty.http" +local typeof = require "typeof" +local encode_args = ngx.encode_args +local setmetatable = setmetatable +local decode_json, encode_json +do + local cjson = require "cjson.safe" + decode_json = cjson.decode + encode_json = cjson.encode +end +local clear_tab = require "table.clear" +--local tab_nkeys = require "table.nkeys" +local split = require "ngx.re" .split +local concat_tab = table.concat +local tostring = tostring +local select = select +local ipairs = ipairs +local type = type +local error = error +local ERR = ngx.ERR + +local _M = {} +local mt = { __index = _M } +local ops = {} + +local normalize +do + local items = {} + local function concat(sep, ...) + local argc = select('#', ...) + clear_tab(items) + local len = 0 + + for i = 1, argc do + local v = select(i, ...) + if v ~= nil then + len = len + 1 + items[len] = tostring(v) + end + end + + return concat_tab(items, sep); + end + + local segs = {} + function normalize(...) + local path = concat('/', ...) + local names = {} + local err + + segs, err = split(path, [[/]], "jo", nil, nil, segs) + if not segs then + return nil, err + end + + local len = 0 + for _, seg in ipairs(segs) do + if seg == '..' then + if len > 0 then + len = len - 1 + end + + elseif seg == '' or seg == '/' and names[len] == '/' then + -- do nothing + + elseif seg ~= '.' then + len = len + 1 + names[len] = seg + end + end + + return '/' .. concat_tab(names, '/', 1, len); + end +end +_M.normalize = normalize + +local function init_configurations(opts) + if opts == nil then + opts = {} + + elseif not typeof.table(opts) then + return nil, 'opts must be table' + end + + local timeout = opts.timeout or 5000 -- 5 sec + --ngx.log(ERR, opts.host) + local http_host = opts.host or "http://127.0.0.1:2379" + local ttl = opts.ttl or -1 + local prefix = opts.prefix or "/v2/keys" + + if not typeof.uint(timeout) then + return nil, 'opts.timeout must be unsigned integer' + end + + if not typeof.string(http_host) then + return nil, 'opts.host must be string' + end + + if not typeof.int(ttl) then + return nil, 'opts.ttl must be integer' + end + + if not typeof.string(prefix) then + return nil, 'opts.prefix must be string' + end + ops = { + timeout = timeout, + ttl = ttl, + endpoints = { + full_prefix = http_host .. normalize(prefix), + http_host = http_host, + prefix = prefix, + version = http_host .. '/version', + stats_leader = http_host .. '/v2/stats/leader', + stats_self = http_host .. '/v2/stats/self', + stats_store = http_host .. '/v2/stats/store', + keys = http_host .. '/v2/keys', + } + } +end + +function _M.new(opts) + if opts == nil then + opts = {} + + elseif not typeof.table(opts) then + return nil, 'opts must be table' + end + + local timeout = opts.timeout or 5000 -- 5 sec + --ngx.log(ERR, opts.host) + local http_host = opts.host or "http://127.0.0.1:2379" + local ttl = opts.ttl or -1 + local prefix = opts.prefix or "/v2/keys" + + if not typeof.uint(timeout) then + return nil, 'opts.timeout must be unsigned integer' + end + + if not typeof.string(http_host) then + return nil, 'opts.host must be string' + end + + if not typeof.int(ttl) then + return nil, 'opts.ttl must be integer' + end + + if not typeof.string(prefix) then + return nil, 'opts.prefix must be string' + end + local res = setmetatable({ + timeout = timeout, + ttl = ttl, + endpoints = { + full_prefix = http_host .. normalize(prefix), + http_host = http_host, + prefix = prefix, + version = http_host .. '/version', + stats_leader = http_host .. '/v2/stats/leader', + stats_self = http_host .. '/v2/stats/self', + stats_store = http_host .. '/v2/stats/store', + keys = http_host .. '/v2/keys', + } + }, + mt) + ngx.log(ERR, http_host) + return res +end + +local content_type = { + ["Content-Type"] = "application/x-www-form-urlencoded", +} + +local function _request(method, uri, opts, timeout) + local body + --ngx.log(ERR, "METHOD ==================+++++++++++++++++=====================" .. method) + --if opts and opts.body and tab_nkeys(opts.body) > 0 then + if opts and opts.body then + body = encode_args(opts.body) + end + + --if opts and opts.query and tab_nkeys(opts.query) > 0 then + if opts and opts.query then + uri = uri .. '?' .. encode_args(opts.query) + end + --ngx.log(ERR, "URI***************************" .. uri) + local http_cli, err = http.new() + if err then + return nil, err + end + + if timeout then + http_cli:set_timeout(timeout * 1000) + end + + local res + res, err = http_cli:request_uri(uri, { + method = method, + body = body, + headers = content_type, + }) + + if err then + return nil, err + end + + if res.status >= 500 then + return nil, "invalid response code: " .. res.status + end + + if not typeof.string(res.body) then + return res + end + + res.body = decode_json(res.body) + return res +end + +local function set(key, val, attr) + local err + val, err = encode_json(val) + if not val then + return nil, err + end + + local prev_exist + if attr.prev_exist ~= nil then + prev_exist = attr.prev_exist and 'true' or 'false' + end + + local dir + if attr.dir then + dir = attr.dir and 'true' or 'false' + end + + local opts = { + body = { + ttl = attr.ttl, + value = val, + dir = dir, + }, + query = { + prevExist = prev_exist, + prevIndex = attr.prev_index, + } + } + + -- todo: check arguments + + -- verify key + key = normalize(key) + if key == '/' then + return nil, "key should not be a slash" + end + + local res + res, err = _request(attr.in_order and 'POST' or 'PUT', + ops.endpoints.full_prefix .. key, + opts, ops.timeout) + if err then + return nil, err + end + + -- get + if res.status < 300 and res.body.node and + not res.body.node.dir then + res.body.node.value, err = decode_json(res.body.node.value) + if err then + return nil, err + end + end + + return res +end + +local function decode_dir_value(body_node) + if not body_node.dir then + return false + end + + if type(body_node.nodes) ~= "table" then + return false + end + + local err + for _, node in ipairs(body_node.nodes) do + local val = node.value + if type(val) == "string" then + node.value, err = decode_json(val) + if err then + error("failed to decode info|" .. val) + end + end + + decode_dir_value(node) + end + + return true +end + +local function get(key, attr) + local opts + if attr then + local attr_wait + if attr.wait ~= nil then + attr_wait = attr.wait and 'true' or 'false' + end + + local attr_recursive + if attr.recursive then + attr_recursive = attr.recursive and 'true' or 'false' + end + + opts = { + query = { + wait = attr_wait, + waitIndex = attr.wait_index, + recursive = attr_recursive, + consistent = attr.consistent, -- todo + } + } + end + local res, err = _request("GET", + ops.endpoints.full_prefix .. normalize(key), + opts, attr and attr.timeout or ops.timeout) + if err then + return nil, err + end + --for key, val in pairs(res) do + -- ngx.log(ERR, "key==============================" .. key) + -- ngx.log(ERR, "val==============================" .. type(val)) + --end + + -- readdir + if attr and attr.dir then + if res.status == 200 and res.body.node and + not res.body.node.dir then + res.body.node.dir = false + end + end + + if res.status == 200 and res.body.node then + if not decode_dir_value(res.body.node) then + local val = res.body.node.value + if type(val) == "string" then + res.body.node.value, err = decode_json(val) + if err then + ngx.log(ERR, "failed to pass json, err:" .. err) + return nil, err + end + end + end + end + return res +end + +local function delete(key, attr) + local val, err = attr.prev_value + if val ~= nil and type(val) ~= "number" then + val, err = encode_json(val) + if not val then + return nil, err + end + end + + local attr_dir + if attr.dir then + attr_dir = attr.dir and 'true' or 'false' + end + + local attr_recursive + if attr.recursive then + attr_recursive = attr.recursive and 'true' or 'false' + end + + local opts = { + query = { + dir = attr_dir, + prevIndex = attr.prev_index, + recursive = attr_recursive, + prevValue = val, + }, + } + + -- todo: check arguments + return _request("DELETE", + ops.endpoints.full_prefix .. normalize(key), + opts, ops.timeout) +end + +do + + function _M.get(ops, key) + init_configurations(ops) + if not typeof.string(key) then + return nil, 'key must be string' + end + return get(key) + end + + local attr = {} + function _M.wait(self, key, modified_index, timeout) + clear_tab(attr) + attr.wait = true + attr.wait_index = modified_index + attr.timeout = timeout + + return get(self, key, attr) + end + + function _M.readdir(self, key, recursive) + clear_tab(attr) + attr.dir = true + attr.recursive = recursive + + return get(self, key, attr) + end + + -- wait with recursive + function _M.waitdir(self, key, modified_index, timeout) + clear_tab(attr) + attr.wait = true + attr.dir = true + attr.recursive = true + attr.wait_index = modified_index + attr.timeout = timeout + + return get(self, key, attr) + end + + -- /version + function _M.version(self) + return _request('GET', ops.endpoints.version, nil, ops.timeout) + end + + -- /stats + function _M.stats_leader(self) + return _request('GET', ops.endpoints.stats_leader, nil, ops.timeout) + end + + function _M.stats_self(self) + return _request('GET', ops.endpoints.stats_self, nil, ops.timeout) + end + + function _M.stats_store(self) + return _request('GET', ops.endpoints.stats_store, nil, ops.timeout) + end + +end -- do + + +do + local attr = {} + function _M.delete(ops, key, prev_val, modified_index) + init_configurations(ops) + clear_tab(attr) + attr.prev_value = prev_val + attr.prev_index = modified_index + + return delete(key, attr) + end + + function _M.rmdir(ops, key, recursive) + init_configurations(ops) + clear_tab(attr) + attr.dir = true + attr.recursive = recursive + + return delete(key, attr) + end + + function _M.set(ops, key, val, ttl) + init_configurations(ops) + clear_tab(attr) + attr.ttl = ttl + return set(key, val, attr) + end + + -- set key-val and ttl if key does not exists (atomic create) + function _M.setnx(self, key, val, ttl) + clear_tab(attr) + attr.ttl = ttl + attr.prev_exist = false + + return set(self, key, val, attr) + end + + -- set key-val and ttl if key is exists (update) + function _M.setx(self, key, val, ttl, modified_index) + clear_tab(attr) + attr.ttl = ttl + attr.prev_exist = true + attr.prev_index = modified_index + + return set(self, key, val, attr) + end + + -- dir + function _M.mkdir(self, key, ttl) + clear_tab(attr) + attr.ttl = ttl + attr.dir = true + + return set(self, key, nil, attr) + end + + -- mkdir if not exists + function _M.mkdirnx(self, key, ttl) + clear_tab(attr) + attr.ttl = ttl + attr.dir = true + attr.prev_exist = false + + return set(self, key, nil, attr) + end + + -- in-order keys + function _M.push(self, key, val, ttl) + clear_tab(attr) + attr.ttl = ttl + attr.in_order = true + + return set(self, key, val, attr) + end + +end -- do + + +do + local attr = {} + +end -- do + + +return _M diff --git a/orange/orange.lua b/orange/orange.lua index 42f0c43f..912cca3f 100644 --- a/orange/orange.lua +++ b/orange/orange.lua @@ -9,6 +9,7 @@ local utils = require("orange.utils.utils") local config_loader = require("orange.utils.config_loader") local dao = require("orange.store.dao") local dns_client = require("resty.dns.client") +local ERR = ngx.ERR local HEADERS = { PROXY_LATENCY = "X-Orange-Proxy-Latency", @@ -64,15 +65,18 @@ function Orange.init(options) local status, err = pcall(function() local conf_file_path = options.config config = config_loader.load(conf_file_path) - store = require("orange.store.mysql_store")(config.store_mysql) - + local store_type = config.store + local modname = "orange.store." .. store_type .. ".store" + local data_source_key = "store_" .. store_type + ngx.log(ERR, "loading from data source:" .. data_source_key) + store = require(modname)(config[data_source_key]) loaded_plugins = load_node_plugins(config, store) ngx.update_time() config.orange_start_at = ngx.now() end) if not status or err then - ngx.log(ngx.ERR, "Startup error: " .. err) + ngx.log(ERR, "Startup error: " .. err) os.exit(1) end @@ -94,29 +98,57 @@ function Orange.init_worker() -- 仅在 init_worker 阶段调用,初始化随机因子,仅允许调用一次 math.randomseed() -- 初始化定时器,清理计数器等 - if Orange.data and Orange.data.store and Orange.data.config.store == "mysql" then - local ok, err = ngx.timer.at(0, function(premature, store, config) - local available_plugins = config.plugins - for _, v in ipairs(available_plugins) do - local load_success = dao.load_data_by_mysql(store, v) - if not load_success then - os.exit(1) - end - - if v == "consul_balancer" then - for ii,p in ipairs(loaded_plugins) do - if v == p.name then - p.handler.db_ready() - end + if Orange.data and Orange.data.store then + local ok, err = ngx.timer.at(0, function(premature, store, config) + local available_plugins = config.plugins + for _, v in ipairs(available_plugins) do + local load_success = dao.load_data(store, v) + if not load_success then + os.exit(1) + end + + if v == "consul_balancer" then + for ii,p in ipairs(loaded_plugins) do + if v == p.name then + p.handler.db_ready() end end end - end, Orange.data.store, Orange.data.config) + end + if Orange.data.config.store == "etcd" then + local register_rotate_time = Orange.data.config.store_etcd.register.register_rotate_time + local ok , err = dao.register_node(store, config, register_rotate_time) + if not ok then + ngx.log(ERR, "failed to register mysql to etcd. err:" .. err) + os.exit(1) + end + if Orange.data.config.store == "etcd" then + local register_rotate_time = Orange.data.config.store_etcd.register.register_rotate_time + local handler + handler = function (premature, store, config) + if premature then + return + end - if not ok then - ngx.log(ngx.ERR, "failed to create the timer: ", err) - return os.exit(1) + local ok , err = dao.register_node(store, config, register_rotate_time) + if not ok then + return + end + end + local ok, err = ngx.timer.every(register_rotate_time, handler, Orange.data.store, + Orange.data.config) + if not ok then + ngx.log(ERR, "failed to create the timer: ", err) + return + end + end end + end, Orange.data.store, Orange.data.config) + + if not ok then + ngx.log(ERR, "failed to create the timer: ", err) + return os.exit(1) + end end for _, plugin in ipairs(loaded_plugins) do diff --git a/orange/plugins/common_api.lua b/orange/plugins/common_api.lua index 10a1fb05..09f65ffc 100644 --- a/orange/plugins/common_api.lua +++ b/orange/plugins/common_api.lua @@ -146,7 +146,7 @@ return function(plugin) }) end - local current_selector = json.decode(selector.value) + local current_selector = selector.value if not current_selector then return res:json({ success = false, @@ -273,7 +273,7 @@ return function(plugin) }) end - local current_selector = json.decode(selector.value) + local current_selector = selector.value if not current_selector then return res:json({ success = false, @@ -376,7 +376,7 @@ return function(plugin) msg = "error to find selector when resorting rules of it" }) else - local new_selector = json.decode(selector.value) or {} + local new_selector = selector.value or {} new_selector.rules = rules update_selector_result = dao.update_selector(plugin, store, new_selector) if update_selector_result then @@ -443,7 +443,7 @@ return function(plugin) end -- delete rules of it - local to_del_selector = json.decode(selector.value) + local to_del_selector = selector.value if not to_del_selector then return res:json({ success = false, @@ -461,7 +461,7 @@ return function(plugin) -- update meta local meta = dao.get_meta(plugin, store) - local current_meta = json.decode(meta.value) + local current_meta = meta if not meta or not current_meta then return res:json({ success = false, @@ -525,7 +525,7 @@ return function(plugin) -- update meta local meta = dao.get_meta(plugin, store) - local current_meta = json.decode(meta and meta.value or "{}") + local current_meta = meta if not meta or not current_meta then return res:json({ success = false, @@ -552,7 +552,7 @@ return function(plugin) tag = nil }) end - + local update_local_meta_result = dao.update_local_meta(plugin, store) local update_local_selectors_result = dao.update_local_selectors(plugin, store) if update_local_meta_result and update_local_selectors_result then @@ -590,7 +590,8 @@ return function(plugin) }) end - old_selector = json.decode(old_selector.value) + --old_selector = json.decode(old_selector.value) + old_selector = old_selector.value if not old_selector then return res:json({ success = false, @@ -661,14 +662,14 @@ return function(plugin) local update_meta_result, update_local_meta_result local meta = dao.get_meta(plugin, store) - if not meta or not meta.value then + if not meta then ngx.log(ngx.ERR, "error to find meta when resorting selectors") return res:json({ success = true, msg = "error to find meta when resorting selectors" }) else - local new_meta = json.decode(meta.value) or {} + local new_meta = meta.value or {} new_meta.selectors = selectors update_meta_result = dao.update_meta(plugin, store, new_meta) if update_meta_result then diff --git a/orange/store/dao.lua b/orange/store/dao.lua index 79a634e6..33bc49f7 100644 --- a/orange/store/dao.lua +++ b/orange/store/dao.lua @@ -5,7 +5,14 @@ local type = type local xpcall = xpcall local json = require("orange.utils.json") local orange_db = require("orange.store.orange_db") - +local ERR = ngx.ERR +local utils = require("orange.utils.utils") +local decode_json, encode_json +do + local cjson = require "cjson.safe" + decode_json = cjson.decode + encode_json = cjson.encode +end local _M = { desc = "store access & local cache manage" @@ -15,49 +22,29 @@ function _M.get_selector(plugin, store, selector_id) if not selector_id or selector_id == "" or type(selector_id) ~= "string" then return nil end - - local selector, err = store:query({ - sql = "select * from " .. plugin .. " where `key` = ? and `type` = ? limit 1", - params = { selector_id, "selector" } - }) - - if not err and selector and type(selector) == "table" and #selector > 0 then - return selector[1] + local res, err = store:get_selector(plugin, selector_id) + if err then + ngx.log(ERR, "error to find meta from storage when initializing plugin[" .. plugin .. "] local meta, err:", err) + return false end - - return nil + return res end -function _M.get_rules_of_selector(plugin, store, rule_ids) - if not rule_ids or type(rule_ids) ~= "table" or #rule_ids == 0 then - return {} - end - - local to_concat = {} - for _, r in ipairs(rule_ids) do - table_insert(to_concat, "'" .. r .. "'") - end - local to_get_rules_ids = table_concat(to_concat, ",") - if not to_get_rules_ids or to_get_rules_ids == "" then +function _M.get_rules_of_selector(plugin, store, selector, all_rules) + if not (selector and selector.id) then + ngx.log(ERR, "error: selector or selector_id is nil") return {} end - - local rules, err = store:query({ - sql = "select * from " .. plugin .. " where `key` in ( " .. to_get_rules_ids .. ") and `type`=?", - params = {"rule" } - }) - if err then - ngx.log(ngx.ERR, "error to get rules of selector, err:", err) + local rule_ids = selector.rules + if not rule_ids or type(rule_ids) ~= "table" or #rule_ids == 0 then return {} end - - if rules and type(rules) == "table" and #rules > 0 then + if all_rules and type(all_rules) == "table" and #all_rules > 0 then local format_rules = {} - -- reorder the rules as the order stored in selector for _, rule_id in ipairs(rule_ids) do - for _, r in ipairs(rules) do - local tmp = json.decode(r.value) + for _, r in ipairs(all_rules) do + local tmp = r.value if tmp and tmp.id == rule_id then table_insert(format_rules, tmp) end @@ -73,24 +60,11 @@ function _M.delete_rules_of_selector(plugin, store, rule_ids) if not rule_ids or rule_ids == "" or type(rule_ids) ~= "table" then return true end - - local to_concat = {} - for _, r in ipairs(rule_ids) do - table_insert(to_concat, "'" .. r .. "'") - end - local to_delete_rules_ids = table_concat(to_concat, ",") - if not to_delete_rules_ids or to_delete_rules_ids == "" then - return true - end - - local delete_result = store:delete({ - sql = "delete from " .. plugin .. " where `key` in (" .. to_delete_rules_ids .. ") and `type`=?", - params = { "rule" } - }) - if delete_result then + local res = store:delete_rules_of_selector(plugin, rule_ids) + if res then return true else - ngx.log(ngx.ERR, "delete rules of selector err, ", rule_ids) + ngx.log(ERR, "delete rules of selector err, ", rule_ids) return false end end @@ -99,29 +73,21 @@ function _M.delete_selector(plugin, store, selector_id) if not selector_id or selector_id == "" or type(selector_id) ~= "string" then return true end - - local delete_result = store:delete({ - sql = "delete from " .. plugin .. " where `key` = ? and `type` = ?", - params = { selector_id, "selector" } - }) + local delete_result, err = store:delete_selector(plugin, selector_id) if delete_result then return true else - ngx.log(ngx.ERR, "delete selector err, ", selector_id) + ngx.log(ERR, "delete selector err, ", selector_id) return false end end function _M.get_meta(plugin, store) - local meta, err = store:query({ - sql = "select * from " .. plugin .. " where `type` = ? limit 1", - params = {"meta"} - }) - - if not err and meta and type(meta) == "table" and #meta > 0 then - return meta[1] + local meta, err = store:get_meta(plugin) + if not err and meta and type(meta) == "table" then + return meta else - ngx.log(ngx.ERR, "[FATAL ERROR]meta not found while it must exist.") + ngx.log(ERR, "[FATAL ERROR]meta not found while it must exist.") return nil end end @@ -130,392 +96,305 @@ function _M.update_meta(plugin, store, meta) if not meta or type(meta) ~= "table" then return false end - local meta_json_str = json.encode(meta) if not meta_json_str then - ngx.log(ngx.ERR, "encode error: meta to save is not json format.") + ngx.log(ERR, "encode error: meta to save is not json format.") return false end - - local result = store:update({ - sql = "update " .. plugin .. " set `value` = ? where `type` = ?", - params = {meta_json_str, "meta"} - }) - - return result + local res, err = store:update_meta(plugin, meta) + if err then + ngx.log(ERR, "failed to update meta, err:", err) + return false + end + return res end function _M.update_selector(plugin, store, selector) if not selector or type(selector) ~= "table" then return false end - - local selector_json_str = json.encode(selector) - if not selector_json_str then - ngx.log(ngx.ERR, "encode error: selector to save is not json format.") - return false - end - - local result = store:update({ - sql = "update " .. plugin .. " set `value` = ? where `key`=? and `type` = ?", - params = {selector_json_str, selector.id, "selector"} - }) - + local result = store:update_selector(plugin, selector) return result end function _M.update_local_meta(plugin, store) - local meta, err = store:query({ - sql = "select * from " .. plugin .. " where `type` = ? limit 1", - params = {"meta"} - }) - - if err then - ngx.log(ngx.ERR, "error to find meta from storage when updating local meta, err:", err) - return false - end - - if meta and type(meta) == "table" and #meta > 0 then - local success, err, forcible = orange_db.set(plugin .. ".meta", meta[1].value or '{}') + local meta = _M.get_meta(plugin, store) + if meta and type(meta) == "table" then + local success, err, forcible = orange_db.set(plugin .. ".meta", encode_json(meta or {})) if err or not success then - ngx.log(ngx.ERR, "update local plugin's meta error, err:", err) + ngx.log(ERR, "update local plugin's meta error, err:", err) return false end else - ngx.log(ngx.ERR, "can not find meta from storage when updating local meta") + ngx.log(ERR, "can not find meta from storage when updating local meta") end - return true end function _M.update_local_selectors(plugin, store) - local selectors, err = store:query({ - sql = "select * from " .. plugin .. " where `type` = ?", - params = {"selector"} - }) - - if err then - ngx.log(ngx.ERR, "error to find selectors from storage when updating local selectors, err:", err) - return false - end - + local selectors = store:get_selectors(plugin) local to_update_selectors = {} - if selectors and type(selectors) == "table" then - for _, s in ipairs(selectors) do - to_update_selectors[s.key] = json.decode(s.value or "{}") + if selectors then + for _, _node in ipairs(selectors) do + local selector_id = _node.value.id + to_update_selectors[selector_id] = _node.value or {} end local success, err, forcible = orange_db.set_json(plugin .. ".selectors", to_update_selectors) if err or not success then - ngx.log(ngx.ERR, "update local plugin's selectors error, err:", err) + ngx.log(ERR, "update local plugin's selectors error, err:", err) return false end else - ngx.log(ngx.ERR, "the size of selectors from storage is 0 when updating local selectors") + ngx.log(ERR, "the size of selectors from storage is 0 when updating local selectors") local success, err, forcible = orange_db.set_json(plugin .. ".selectors", {}) if err or not success then - ngx.log(ngx.ERR, "update local plugin's selectors error, err:", err) + ngx.log(ERR, "update local plugin's selectors error, err:", err) return false end end - return true end function _M.update_local_selector_rules(plugin, store, selector_id) if not selector_id then - ngx.log(ngx.ERR, "error to find selector from storage when updating local selector rules, selector_id is nil") + ngx.log(ERR, "error to find selector from storage when updating local selector rules, selector_id is nil") return false end local selector = _M.get_selector(plugin, store, selector_id) if not selector or not selector.value then - ngx.log(ngx.ERR, "error to find selector from storage when updating local selector rules, selector_id:", selector_id) + ngx.log(ERR, "error to find selector from storage when updating local selector rules, selector_id:", + selector_id) return false end - selector = json.decode(selector.value) - local rules_ids = selector.rules or {} - local rules = _M.get_rules_of_selector(plugin, store, rules_ids) - + selector = selector.value + -- read all rules + local rules_res, err = store:get_rules(plugin) + local rules = _M.get_rules_of_selector(plugin, store, selector, rules_res) local success, err, forcible = orange_db.set_json(plugin .. ".selector." .. selector_id .. ".rules", rules) if err or not success then - ngx.log(ngx.ERR, "update local rules of selector error, err:", err) + ngx.log(ERR, "update local rules of selector error, err:", err) return false end - return true end function _M.create_selector(plugin, store, selector) - return store:insert({ - sql = "insert into " .. plugin .. "(`key`, `value`, `type`, `op_time`) values(?,?,?,?)", - params = { selector.id, json.encode(selector), "selector", selector.time } - }) + return store:create_selector(plugin, selector) end function _M.update_rule(plugin, store, rule) - return store:update({ - sql = "update " .. plugin .. " set `value`=?,`op_time`=? where `key`=? and `type`=?", - params = { json.encode(rule), rule.time, rule.id, "rule" } - }) + local res, err = store:update_rule(plugin, rule) + if err then + ngx.log(ERR, "update rule failed, err:", err) + return false + end + return res end function _M.create_rule(plugin, store, rule) - return store:insert({ - sql = "insert into " .. plugin .. "(`key`, `value`, `op_time`, `type`) values(?,?,?,?)", - params = { rule.id, json.encode(rule), rule.time, "rule" } - }) -end - -function _M.get_enable(plugin, store) - return store:query({ - sql = "select `value` from meta where `key`=?", - params = { plugin .. ".enable" } - }) + local res, err = store:create_rule(plugin, rule) + if not res and err then + ngx.log(ERR, "failed to create rule, err:" .. err) + return false + end + return true end function _M.update_enable(plugin, store, enable) - return store:update({ - sql = "replace into meta SET `key`=?, `value`=?", - params = { plugin .. ".enable", enable } - }) + return store:update_enable(plugin, enable) end - -- ########################### local cache init start ############################# -function _M.init_rules_of_selector(plugin, store, selector_id) - if not selector_id then - ngx.log(ngx.ERR, "error: selector_id is nil") - return false - end - - local selector = _M.get_selector(plugin, store, selector_id) - if not selector or not selector.value then - ngx.log(ngx.ERR, "error to find selector from storage when initializing plugin[" .. plugin .. "] local selector rules, selector_id:", selector_id) +function _M.init_rules_of_selector(plugin, store, selector, all_rules) + if not (selector and selector.id) then + ngx.log(ERR, "error: selector or selector_id is nil") return false end - selector = json.decode(selector.value) local rules_ids = selector.rules or {} - local rules = _M.get_rules_of_selector(plugin, store, rules_ids) - - local success, err, forcible = orange_db.set_json(plugin .. ".selector." .. selector_id .. ".rules", rules) + local rules = {} + -- reorder the rules as the order stored in selector + for _, rule_id in ipairs(rules_ids) do + for _, r in ipairs(all_rules) do + local tmp = r.value + --local tmp = json.decode(r.value) + if tmp and tmp.id == rule_id then + table_insert(rules, tmp) + end + end + end + local success, err, forcible = orange_db.set_json(plugin .. ".selector." .. selector.id .. ".rules", rules) if err or not success then - ngx.log(ngx.ERR, "init plugin[" .. plugin .. "] local rules of selector error, err:", err) + ngx.log(ERR, "init plugin[" .. plugin .. "] local rules of selector error, err:", err) return false end - return true end -function _M.init_enable_of_plugin(plugin, store) +function _M.init_enable_of_plugin(plugin, store, config) -- 查找enable - local enables, err = store:query({ - sql = "select `key`, `value` from meta where `key`=?", - params = {plugin .. ".enable"} - }) - - if err then - ngx.log(ngx.ERR, "Load `enable` of plugin[" .. plugin .. "], error: ", err) - return false - end - - if enables and type(enables) == "table" and #enables > 0 then - orange_db.set(plugin .. ".enable", enables[1].value == "1") - else - orange_db.set(plugin .. ".enable", false) - end - + local enable = store:get_enable(plugin) + orange_db.set(plugin .. ".enable", enable) return true end -function _M.init_meta_of_plugin(plugin, store) - local meta, err = store:query({ - sql = "select * from " .. plugin .. " where `type` = ? limit 1", - params = {"meta"} - }) - +function _M.init_meta_of_plugin(plugin, store, config) + -- 查找enable + local meta, err = store:get_meta(plugin) if err then - ngx.log(ngx.ERR, "error to find meta from storage when initializing plugin[" .. plugin .. "] local meta, err:", err) + ngx.log(ERR, "error to find meta from storage when initializing plugin[" .. + plugin .. "] local meta, err:", err) return false end - if meta and type(meta) == "table" and #meta > 0 then - local success, err, forcible = orange_db.set(plugin .. ".meta", meta[1].value or '{}') + if meta and type(meta) == "table" then + --ngx.log(ERR, "init_meta_of_plugin DATA ======================== " .. type(meta.body.node.value)) table + local success, err, forcible = orange_db.set(plugin .. ".meta", encode_json(meta or {})) if err or not success then - ngx.log(ngx.ERR, "init local plugin[" .. plugin .. "] meta error, err:", err) + ngx.log(ERR, "init local plugin[" .. plugin .. "] meta error, err:", err) return false end else - ngx.log(ngx.ERR, "can not find meta from storage when initializing plugin[" .. plugin .. "] local meta") + ngx.log(ERR, "can not find meta from storage when initializing plugin[" .. plugin .. "] local meta") end return true end -function _M.init_selectors_of_plugin(plugin, store) - local selectors, err = store:query({ - sql = "select * from " .. plugin .. " where `type` = ?", - params = {"selector"} - }) - - if err then - ngx.log(ngx.ERR, "error to find selectors from storage when initializing plugin[" .. plugin .. "], err:", err) - return false - end - +function _M.init_selectors_of_plugin(plugin, store, config) + local selectors = store:get_selectors(plugin) local to_update_selectors = {} - if selectors and type(selectors) == "table" then - for _, s in ipairs(selectors) do - to_update_selectors[s.key] = json.decode(s.value or "{}") - - -- init this selector's rules local cache - local init_rules_of_it = _M.init_rules_of_selector(plugin, store, s.key) + if selectors then + -- read all rules + local rules, err = store:get_rules(plugin) + if err then + ngx.log(ERR, "init local plugin[" .. plugin .. "] selectors error, err:", err) + return false + end + --local rules = rules_res.body.node.nodes + for _, _node in ipairs(selectors) do + local selector_id = _node.value.id + to_update_selectors[selector_id] = _node.value or {} + local init_rules_of_it = _M.init_rules_of_selector(plugin, store, _node.value, rules) if not init_rules_of_it then return false end end - local success, err, forcible = orange_db.set_json(plugin .. ".selectors", to_update_selectors) if err or not success then - ngx.log(ngx.ERR, "init local plugin[" .. plugin .. "] selectors error, err:", err) + ngx.log(ERR, "init local plugin[" .. plugin .. "] selectors error, err:", err) return false end else - ngx.log(ngx.ERR, "the size of selectors from storage is 0 when initializing plugin[" .. plugin .. "] local selectors") + ngx.log(ERR, "the size of selectors from storage is 0 when initializing plugin[" .. plugin .. "] local selectors") local success, err, forcible = orange_db.set_json(plugin .. ".selectors", {}) if err or not success then - ngx.log(ngx.ERR, "init local plugin[" .. plugin .. "] selectors error, err:", err) + ngx.log(ERR, "init local plugin[" .. plugin .. "] selectors error, err:", err) return false end end - return true end -- ########################### local cache init end ############################# - -- ########################### for data(configurations in storage) preview ############################# +local function get_selectors_and_rules(store, plugin, data) + local selectors, err = store:get_selectors(plugin) + if err then + ngx.log(ERR, "error to find selectors from storage when fetching data of plugin[" .. + plugin .. "], err:", err) + return false + end + if selectors then + -- read all rules + local rules, err = store:get_rules(plugin) + local to_update_selectors = {} + for _, _node in ipairs(selectors) do + local selector_id = _node.value.id + -- init this selector's rules local cache + if not selector_id then + ngx.log(ERR, "error: selector_id is nil") + return false + end + to_update_selectors[selector_id] = _node.value or {} + + -- init this selector's rules local cache + local rules = _M.get_rules_of_selector(plugin, store, _node.value, rules) + data[plugin .. ".selector." .. selector_id .. ".rules"] = rules + end + data[plugin .. ".selectors"]= to_update_selectors + else + ngx.log(ERR, "the size of selectors from storage is 0 when fetching data of plugin[" .. + plugin .. "] selectors") + data[plugin .. ".selectors"] = {} + end + return nil +end function _M.compose_plugin_data(store, plugin) local data = {} local ok, e ok = xpcall(function() -- get enable - local enables, err = store:query({ - sql = "select `key`, `value` from meta where `key`=?", - params = {plugin .. ".enable"} - }) - - if err then - ngx.log(ngx.ERR, "Load `enable` of plugin[" .. plugin .. "], error: ", err) - return false - end - - if enables and type(enables) == "table" and #enables > 0 then - data[plugin .. ".enable"] = (enables[1].value == "1") - else - data[plugin .. ".enable"] = false - end - + local enable = store:get_enable(plugin) + data[plugin .. ".enable"] = enable -- get meta - local meta, err = store:query({ - sql = "select * from " .. plugin .. " where `type` = ? limit 1", - params = {"meta"} - }) - + local meta, err = store:get_meta(plugin) if err then - ngx.log(ngx.ERR, "error to find meta from storage when fetching data of plugin[" .. plugin .. "], err:", err) + ngx.log(ERR, "error to find meta from storage when fetching data of plugin[" .. plugin .. "], err:", err) return false end - - if meta and type(meta) == "table" and #meta > 0 then - data[plugin .. ".meta"] = json.decode(meta[1].value) or {} + if meta and type(meta) == "table" then + data[plugin .. ".meta"] = meta or {} else - ngx.log(ngx.ERR, "can not find meta from storage when fetching data of plugin[" .. plugin .. "]") + ngx.log(ERR, "can not find meta from storage when fetching data of plugin[" .. plugin .. "]") return false end - -- get selectors and its rules - local selectors, err = store:query({ - sql = "select * from " .. plugin .. " where `type` = ?", - params = {"selector"} - }) - - if err then - ngx.log(ngx.ERR, "error to find selectors from storage when fetching data of plugin[" .. plugin .. "], err:", err) - return false + local res = get_selectors_and_rules(store, plugin, data) + if res ~= nil then + return res end - - local to_update_selectors = {} - if selectors and type(selectors) == "table" then - for _, s in ipairs(selectors) do - to_update_selectors[s.key] = json.decode(s.value or "{}") - - -- init this selector's rules local cache - local selector_id = s.key - if not selector_id then - ngx.log(ngx.ERR, "error: selector_id is nil") - return false - end - - local selector = _M.get_selector(plugin, store, selector_id) - if not selector or not selector.value then - ngx.log(ngx.ERR, "error to find selector from storage when fetch plugin[" .. plugin .. "] selector rules, selector_id:", selector_id) - return false - end - - selector = json.decode(selector.value) - local rules_ids = selector.rules or {} - local rules = _M.get_rules_of_selector(plugin, store, rules_ids) - data[plugin .. ".selector." .. selector_id .. ".rules"] = rules - end - - data[plugin .. ".selectors"]= to_update_selectors - else - ngx.log(ngx.ERR, "the size of selectors from storage is 0 when fetching data of plugin[" .. plugin .. "] selectors") - data[plugin .. ".selectors"] = {} - end - return true, data end, function() e = debug.traceback() end) - if not ok or e then - ngx.log(ngx.ERR, "[fetch plugin's data error], plugin:", plugin, " error:", e) + ngx.log(ERR, "[fetch plugin's data error], plugin:", plugin, " error:", e) return false end - return true, data end --- ########################### init cache when starting orange ############################# -function _M.load_data_by_mysql(store, plugin) +-- ########################### init cache when starting gateway ############################# +function _M.load_data(store, plugin, config) local ok, e ok = xpcall(function() local v = plugin if not v or v == "" then - ngx.log(ngx.ERR, "params error, the `plugin` is nil") + ngx.log(ERR, "params error, the `plugin` is nil") return false end - if v == "stat" then + if v == "stat" or v == "prometheus" then return elseif v == "kvstore" then - local init_enable = _M.init_enable_of_plugin(v, store) + local init_enable = _M.init_enable_of_plugin(v, store, config) if not init_enable then - ngx.log(ngx.ERR, "load data of plugin[" .. v .. "] error, init_enable:", init_enable) + ngx.log(ERR, "load data of plugin[" .. v .. "] error, init_enable:", init_enable) return false else ngx.log(ngx.INFO, "load data of plugin[" .. v .. "] success") end else -- ignore `stat` and `kvstore` - local init_enable = _M.init_enable_of_plugin(v, store) - local init_meta = _M.init_meta_of_plugin(v, store) - local init_selectors_and_rules = _M.init_selectors_of_plugin(v, store) + local init_enable = _M.init_enable_of_plugin(v, store, config) + local init_meta = _M.init_meta_of_plugin(v, store, config) + local init_selectors_and_rules = _M.init_selectors_of_plugin(v, store, config) if not init_enable or not init_meta or not init_selectors_and_rules then - ngx.log(ngx.ERR, "load data of plugin[" .. v .. "] error, init_enable:", init_enable, " init_meta:", init_meta, " init_selectors_and_rules:", init_selectors_and_rules) + ngx.log(ERR, "load data of plugin[" .. v .. "] error, init_enable:", init_enable, " init_meta:", + init_meta, " init_selectors_and_rules:", init_selectors_and_rules) return false else ngx.log(ngx.INFO, "load data of plugin[" .. v .. "] success") @@ -526,11 +405,39 @@ function _M.load_data_by_mysql(store, plugin) end) if not ok or e then - ngx.log(ngx.ERR, "[load plugin's data error], plugin:", plugin, " error:", e) + ngx.log(ERR, "[load plugin's data error], plugin:", plugin, " error:", e) return false end return true end +-- only ETCD need to use +function _M.register_node(store, config, delay) + local username, password + local credentials = config.api.credentials + for _, credential in ipairs(credentials) do + username = credential.username + password = credential.password + end + local ip = utils.get_ipv4() + local port = config.store_etcd.register.port + local val = { + id = utils.new_id(), + name = utils.get_hostname(), + ip = ip, + port = port, + api_username = username, + api_password = password + } + local store_etcd = config.store_etcd + local key_prefix = store_etcd.default_path .. "node/nodes/" + local key = key_prefix .. ip .. ":" .. port + local res, err = store.insert(store, key, val, delay * 3) + if err ~= nil then + ngx.log(ERR, "failed to register myself to etcd. err:" .. err) + end + return res, err +end + return _M diff --git a/orange/store/etcd/store.lua b/orange/store/etcd/store.lua new file mode 100644 index 00000000..b8269df8 --- /dev/null +++ b/orange/store/etcd/store.lua @@ -0,0 +1,333 @@ +local ERR = ngx.ERR +local etcd = require("orange.lib.etcd") +local Store = require("orange.store.base") +local EtcdStore = Store:extend() +local table_insert = table.insert + +function EtcdStore:new(options) + local name = options.name or "etcd-store" + self.super.new(self, name) + self.store_type = "etcd" + local config = options.connect_config + local ops = { + host = "http://" .. config.host .. ":" .. config.port, + timeout = config.timeout + } + self.ops = ops +end + +----------------- user manage start --------------------------- +function EtcdStore:user_new(username, password, enable) + local key = context.config.store_etcd.default_path .. "user/" .. username + local val = { + password = password, + enable = enable + } + return EtcdStore.insert(self, key, val) +end + +function EtcdStore:user_query(username, password) + local key = context.config.store_etcd.default_path .. "user/" .. username + return EtcdStore.query(self, key) +end + +function EtcdStore:user_query_all() + local key = context.config.store_etcd.default_path .. "user/" + local result, err = EtcdStore.query(self, key) + if not result or err or type(result) ~= "table" then + return nil, err + else + return result, err + end +end + +function EtcdStore:user_query_by_username(username) + local key = context.config.store_etcd.default_path .. "user/" .. username + local result, err = EtcdStore.query(self, key) + if not result or err or type(result) ~= "table" then + return nil, err + else + if result.body.node then + return result.body.node.value + end + return nil, err + end +end + +function EtcdStore:user_update_enable(username, enable) + local key = context.config.store_etcd.default_path .. "user/" .. username + local user_info, err = self:user_query_by_username(username) + if err ~= nil then + ngx.log(ERR, "Failed to get user, username=" .. username) + return false + end + user_info.enable = enable + local res, err = EtcdStore.update(self, key, user_info) + if not res or err then + return false + else + return true + end +end + +function EtcdStore:user_update_pwd_and_enable(username, pwd, enable) + local key = context.config.store_etcd.default_path .. "user/" .. username + local val = { + password = pwd, + enable = enable + } + local res, err = EtcdStore.update(self, key, val) + if not res or err then + return false + else + return true + end +end + +function EtcdStore:user_delete(username) + local key = context.config.store_etcd.default_path .. "user/" .. username + local res, err = EtcdStore.delete(self, key) + if not res or err then + return false + else + return true + end +end +----------------- user manage end --------------------------- + +----------------- node manage start --------------------------- +function EtcdStore:node_new(name, ip, port, api_username, api_password) + local val = { + id = utils.new_id(), + name = name, + ip = ip, + port = port, + api_username = api_username, + api_password = api_password + } + local key = context.config.store_etcd.default_path .. "node/nodes/" .. val.id + return EtcdStore.insert(self, key, val) +end + +function EtcdStore:node_query_all() + local key = context.config.store_etcd.default_path .. "node/nodes" + local result, err = EtcdStore.query(self, key) + if not result or err or type(result) ~= "table" or result.status ~= 200 then + return nil, err + else + if result.body.node.nodes then + local nodes = result.body.node.nodes + local res = {} + for _, node in ipairs(nodes) do + table_insert(res, node.value) + end + return res + end + return nil, err + end +end + +function EtcdStore:node_update_node(id, name, ip, port, api_username, api_password) + local key = context.config.store_etcd.default_path .. "node/nodes/" .. id + local val = { + id = id, + name = name, + ip = ip, + port = port, + api_username = api_username, + api_password = api_password + } + local res, err = EtcdStore.update( self, key, val) + if not res or err then + return false + else + return true + end +end + +function EtcdStore:node_delete(id) + local key = context.config.store_etcd.default_path .. "node/nodes/" .. id + local res, err = EtcdStore.delete(self, key) + if not res or err then + return false + else + return true + end +end + +function EtcdStore:node_query_by_ip(ip, port) + local key = context.config.store_etcd.default_path .. "node/nodes/" .. ip .. "-" .. port + local res, err = EtcdStore.query(self, key) + if not res or err then + return false + else + return true + end +end +----------------- node manage end --------------------------- +function EtcdStore:get_selectors(plugin) + local config = context.config + local key = config.store_etcd.default_path .. plugin .. "/selectors" + local res, err = EtcdStore.query(self, key) + if res and res.status == 200 then + return res.body.node.nodes or {} + end + return nil, err +end + +function EtcdStore:delete_selector(plugin, selector_id) + local key = context.config.store_etcd.default_path .. plugin .. "/selectors/" .. selector_id + local delete_result, err = EtcdStore.delete(self, key) + if delete_result then + return true + else + ngx.log(ERR, "delete selector err, ", selector_id) + return false + end +end + +function EtcdStore:create_selector(plugin, selector) + local key = context.config.store_etcd.default_path .. plugin .. "/selectors/" .. selector.id + return EtcdStore.insert(self, key, selector) +end + +function EtcdStore:get_selector(plugin, selector_id) + local config = context.config + local key = config.store_etcd.default_path .. plugin .. "/selectors/" .. selector_id + local res, err = EtcdStore.query(self, key) + if res and res.status == 200 then + return res.body.node or {} + end + return nil, err +end + +function EtcdStore:update_selector(plugin, selector) + local key = context.config.store_etcd.default_path .. plugin .. "/selectors/" .. selector.id + local result = EtcdStore.update(self, key, selector) + return result +end + +function EtcdStore:get_rules(plugin) + local key = context.config.store_etcd.default_path .. plugin .. "/rules" + local rules_res, err = EtcdStore.query(self, key) + if err then + return false, err + end + local rules = rules_res.body.node.nodes or {} + return rules, err +end + +function EtcdStore:delete_rules_of_selector(plugin, rule_ids) + local config = context.config + local keys = {} + for _, rule_id in ipairs(rule_ids) do + local key = config.store_etcd.default_path .. plugin .. "/rules/" .. rule_id + table_insert(keys, key) + end + return EtcdStore.delete_keys(self, keys) +end + +function EtcdStore:delete_rule(plugin, rule_id) + if not rule_id or rule_id == "" then + return true + end + local config = context.config + local key = config.store_etcd.default_path .. plugin .. "/rules/" .. rule_id + return EtcdStore.delete(self, key) +end + +function EtcdStore:update_rule(plugin, rule) + local config = context.config + local key = config.store_etcd.default_path .. plugin .. "/rules/" .. rule.id + return EtcdStore.update(self, key, rule) +end + +function EtcdStore:create_rule(plugin, rule) + local key = context.config.store_etcd.default_path .. plugin .. "/rules/" .. rule.id + return EtcdStore.insert(self, key, rule) +end + +function EtcdStore:get_meta(plugin) + local config = context.config + local key = config.store_etcd.default_path .. plugin .. "/meta" + local res, err = EtcdStore.query(self, key) + if err then + return nil, err + end + return res.body.node.value or {} +end + +function EtcdStore:update_meta(plugin, meta) + local config = context.config + local key = config.store_etcd.default_path .. plugin .. "/meta" + return EtcdStore.update(self, key, meta) +end + +function EtcdStore:update_enable(plugin, enable) + local enable_values = { + enable = enable + } + local config = context.config + local key = config.store_etcd.default_path .. plugin .. "/enable" + return EtcdStore.update(self, key, enable_values) +end + +function EtcdStore:get_enable(plugin) + local config = context.config + local key = config.store_etcd.default_path .. plugin .. "/enable" + local res, err = EtcdStore.query(self, key) + if err then + ngx.log(ERR, "Failed to query, key=" .. key) + return nil, err + end + if res.body.node then + return res.body.node.value.enable + end + return false +end + +function EtcdStore:query(key) + return etcd.get(self.ops, key) +end + +function EtcdStore:insert(key, val, ttl) + local res, err = etcd.set(self.ops, key, val, ttl) + if err then + ngx.log(ERR, "failed to do insert, err: " , err) + return false + end + return true +end + +function EtcdStore:delete(key) + local res, err = etcd.delete(self.ops, key) + if res and not err then + return true + else + ngx.log(ERR, "EtcdStore:delete error:", err) + return false + end +end + +function EtcdStore:delete_keys(keys) + for _, key in ipairs(keys) do + local res, err = etcd.delete(self.ops, key) + if err then + ngx.log(ERR, "EtcdStore:delete error:", err) + return false + end + end + return true +end + +function EtcdStore:update(key, val, ttl) + local res, err = etcd.set(self.ops, key, val, ttl) + if res and res.status == 200 and not err then + return true + else + ngx.log(ERR, "EtcdStore:update error:", err) + return false + end +end + +return EtcdStore diff --git a/orange/store/mysql_db.lua b/orange/store/mysql/mysql_db.lua similarity index 100% rename from orange/store/mysql_db.lua rename to orange/store/mysql/mysql_db.lua diff --git a/orange/store/mysql/store.lua b/orange/store/mysql/store.lua new file mode 100644 index 00000000..b3cb10ea --- /dev/null +++ b/orange/store/mysql/store.lua @@ -0,0 +1,398 @@ +local type = type +local mysql_db = require("orange.store.mysql.mysql_db") +local Store = require("orange.store.base") +local json = require("orange.utils.json") +local table_insert = table.insert +local table_concat = table.concat + +local MySQLStore = Store:extend() + +function MySQLStore:new(options) + local name = options.name or "mysql-store" + self.super.new(self, name) + self.store_type = "mysql" + local connect_config = options.connect_config + self.mysql_addr = connect_config.host .. ":" .. connect_config.port + self.data = {} + self.db = mysql_db(options) +end + +function MySQLStore:query(opts) + if not opts or opts == "" then return nil end + local param_type = type(opts) + local res, err, sql, params + if param_type == "string" then + sql = opts + elseif param_type == "table" then + sql = opts.sql + params = opts.params + end + + res, err = self.db:query(sql, params) + if err then + ngx.log(ngx.ERR, "MySQLStore:query, error:", err, " sql:", sql) + return nil + end + + if res and type(res) == "table" and #res <= 0 then + ngx.log(ngx.WARN, "MySQLStore:query empty, sql:", sql) + end + + return res +end + +function MySQLStore:insert(opts) + if not opts or opts == "" then return false end + + local param_type = type(opts) + local res, err + if param_type == "string" then + res, err = self.db:query(opts) + elseif param_type == "table" then + res, err = self.db:query(opts.sql, opts.params or {}) + end + + if res and not err then + return true + else + ngx.log(ngx.ERR, "MySQLStore:insert error:", err) + return false + end +end + +function MySQLStore:delete(opts) + if not opts or opts == "" then return false end + local param_type = type(opts) + local res, err + if param_type == "string" then + res, err = self.db:query(opts) + elseif param_type == "table" then + res, err = self.db:query(opts.sql, opts.params or {}) + end + + if res and not err then + return true + else + ngx.log(ngx.ERR, "MySQLStore:delete error:", err) + return false + end +end + +function MySQLStore:update(opts) + if not opts or opts == "" then return false end + local param_type = type(opts) + local res, err + if param_type == "string" then + res, err = self.db:query(opts) + elseif param_type == "table" then + res, err = self.db:query(opts.sql, opts.params or {}) + end + + if res and not err then + return true + else + ngx.log(ngx.ERR, "MySQLStore:update error:", err) + return false + end +end + +function MySQLStore:user_new(username, password, enable) + return self.db:query("insert into dashboard_user(username, password, enable) values(?,?,?)", + {username, password, enable}) +end + +function MySQLStore:user_query(username, password) + local res, err = self.db:query("select * from dashboard_user where username=? and password=?", {username, password}) + return res, err +end + +function MySQLStore:user_query_all() + local result, err = self.db:query("select id, username, is_admin, create_time, enable from dashboard_user order by id asc") + if not result or err or type(result) ~= "table" or #result < 1 then + return nil, err + else + return result, err + end +end + +function MySQLStore:user_query_by_username(username) + local res, err = self.db:query("select * from dashboard_user where username=? limit 1", {username}) + if not res or err or type(res) ~= "table" or #res ~=1 then + return nil, err or "error" + end + return res[1], err +end + +function MySQLStore:user_update_enable(username, enable) + local res, err = self.db:query("update dashboard_user set enable=? where id=?", {tonumber(enable), tonumber(userid)}) + if not res or err then + return false + else + return true + end + res, err = self.db:query("select * from dashboard_user where username=? limit 1", {username}) + if not res or err or type(res) ~= "table" or #res ~=1 then + return nil, err or "error" + end + return res[1], err +end + +function MySQLStore:user_update_pwd_and_enable(username, pwd, enable) + local res, err = self.db:query("update dashboard_user set password=?, enable=? where username=?", {pwd, tonumber(enable), username}) + if not res or err then + return false + else + return true + end +end + +function MySQLStore:user_delete(username) + local res, err = self.db:query("delete from dashboard_user where id=?", { username }) + if not res or err then + return false + else + return true + end +end + +function MySQLStore:node_new(name, ip, port, api_username, api_password) + return self.db:query("insert into cluster_node (name,ip,port,api_username,api_password) values(?,?,?,?,?)", + { name, ip, port, api_username, api_password }) +end + +function MySQLStore:node_query_all() + local result, err = self.db:query("select * from cluster_node order by ip asc") + + if not result or err or type(result) ~= "table" or #result < 1 then + return nil, err + else + return result, err + end +end + +function MySQLStore:node_update_node(id, name, ip, port, api_username, api_password) + local res, err = self.db:query("update cluster_node set name=?,ip=?,port=?,api_username=?,api_password=? where id=?", { name, ip, port, api_username, api_password, tonumber(id) }) + if not res or err then + return false + else + return true + end +end + +function MySQLStore:node_delete(id) + local res, err = self.db:query("delete from cluster_node where id=?", { tonumber(id) }) + if not res or err then + return false + else + return true + end +end + +function MySQLStore:node_query_by_ip(ip, port) + local result, err = self.db:query("select * from cluster_node where ip=?", { ip }) + if not result or err or type(result) ~= "table" or #result ~= 1 then + return nil, err + else + return result[1], err + end +end + +function MySQLStore:get_selectors(plugin) + local options = { + sql = "select * from " .. plugin .. " where `type` = ?", + params = {"selector"} + } + local res = MySQLStore.query(self, options) + if res and type(res) == "table" then + for _, s in ipairs(res) do + s.value = json.decode(s.value or "{}") + end + end + return res +end + +function MySQLStore:delete_selector(plugin, selector_id) + local options = { + sql = "delete from " .. plugin .. " where `key` = ? and `type` = ?", + params = { selector_id, "selector" } + } + local delete_result, err = MySQLStore.delete(self, options) + if delete_result then + return true + else + ngx.log(ngx.ERR, "delete selector err, ", selector_id) + return false + end +end + +function MySQLStore:create_selector(plugin, selector) + local options = { + sql = "insert into " .. plugin .. "(`key`, `value`, `type`, `op_time`) values(?,?,?,?)", + params = { selector.id, json.encode(selector), "selector", selector.time } + } + return MySQLStore.insert(self, options) +end + +function MySQLStore:get_selector(plugin, selector_id) + local options = { + sql = "select * from " .. plugin .. " where `key` = ? and `type` = ? limit 1", + params = { selector_id, "selector" } + } + local selector, err = MySQLStore.query(self, options) + if not err and selector and type(selector) == "table" and #selector > 0 then + selector[1].value = json.decode(selector[1].value or "{}") + return selector[1] + end + return nil, err +end + +function MySQLStore:update_selector(plugin, selector) + local selector_json_str = json.encode(selector) + if not selector_json_str then + ngx.log(ngx.ERR, "encode error: selector to save is not json format.") + return false + end + local options = { + sql = "update " .. plugin .. " set `value` = ? where `key`=? and `type` = ?", + params = {selector_json_str, selector.id, "selector"} + } + local result = MySQLStore.update(self, options) + return result +end + +function MySQLStore:get_rules(plugin, rule_ids) + local options = { + sql = "select * from " .. plugin .. " where `type`=?", + params = {"rule" } + } + if rule_ids and type(rule_ids) == "table" and #rule_ids > 0 then + local to_concat = {} + for _, r in ipairs(rule_ids) do + table_insert(to_concat, "'" .. r .. "'") + end + local to_get_rules_ids = table_concat(to_concat, ",") + if not to_get_rules_ids or to_get_rules_ids == "" then + return {} + end + options = { + sql = "select * from " .. plugin .. " where `key` in ( " .. to_get_rules_ids .. ") and `type`=?", + params = {"rule" } + } + end + local res, err = MySQLStore.query(self, options) + if res then + for _, r in ipairs(res) do + r.value = json.decode(r.value or "{}") + end + end + return res, err +end + +function MySQLStore:delete_rule(plugin, rule_id) + if not rule_id or rule_id == "" then + return true + end + local options = { + sql = "delete from " .. plugin .. " where `key` in ('" .. rule_id .. "') and `type`=?", + params = { "rule" } + } + local delete_result, err = MySQLStore.delete(self, options) + if delete_result then + return true + else + ngx.log(ngx.ERR, "delete rules of selector err, ", err) + return false + end +end + +function MySQLStore:delete_rules_of_selector(plugin, rule_ids) + local to_concat = {} + for _, r in ipairs(rule_ids) do + table_insert(to_concat, "'" .. r .. "'") + end + local to_delete_rules_ids = table_concat(to_concat, ",") + if not to_delete_rules_ids or to_delete_rules_ids == "" then + return true + end + local options = { + sql = "delete from " .. plugin .. " where `key` in (" .. to_delete_rules_ids .. ") and `type`=?", + params = { "rule" } + } + local delete_result = MySQLStore.delete(self, options) + if delete_result then + return true + else + ngx.log(ngx.ERR, "delete rules of selector err, ", rule_ids) + return false + end +end + +function MySQLStore:update_rule(plugin, rule) + local options = { + sql = "update " .. plugin .. " set `value`=?,`op_time`=? where `key`=? and `type`=?", + params = { json.encode(rule), rule.time, rule.id, "rule" } + } + return MySQLStore.update(self, options, rule) +end + +function MySQLStore:create_rule(plugin, rule) + local options = { + sql = "insert into " .. plugin .. "(`key`, `value`, `op_time`, `type`) values(?,?,?,?)", + params = { rule.id, json.encode(rule), rule.time, "rule" } + } + return MySQLStore.insert(self, options) +end + +function MySQLStore:get_meta(plugin) + local options = { + sql = "select * from " .. plugin .. " where `type` = ? limit 1", + params = {"meta"} + } + local meta, err = MySQLStore.query(self, options) + if not err and meta and type(meta) == "table" and #meta > 0 then + if meta[1] then + return json.decode(meta[1].value or "{}") + end + return nil + else + ngx.log(ngx.ERR, "[FATAL ERROR]meta not found while it must exist.") + return nil + end +end + +function MySQLStore:update_meta(plugin, meta) + local meta_json_str = json.encode(meta) + if not meta_json_str then + ngx.log(ngx.ERR, "encode error: meta to save is not json format.") + return false + end + local options = { + sql = "update " .. plugin .. " set `value` = ? where `type` = ?", + params = {meta_json_str, "meta"} + } + return MySQLStore.update(self, options) +end + +function MySQLStore:update_enable(plugin, enable) + local plugin_enable = "0" + if enable then plugin_enable = "1" end + local options = { + sql = "replace into meta SET `key`=?, `value`=?", + params = { plugin .. ".enable", plugin_enable } + } + return MySQLStore.update(self,options) +end + +function MySQLStore:get_enable(plugin) + local options = { + sql = "select `value` from meta where `key`=?", + params = { plugin .. ".enable" } + } + local enable = MySQLStore.query(self, options) + if enable and type(enable) == "table" and #enable > 0 then + return enable[1].value == "1" + end + return false +end + +return MySQLStore diff --git a/orange/store/mysql_store.lua b/orange/store/mysql_store.lua deleted file mode 100644 index d0fd93d3..00000000 --- a/orange/store/mysql_store.lua +++ /dev/null @@ -1,96 +0,0 @@ -local type = type -local mysql_db = require("orange.store.mysql_db") -local Store = require("orange.store.base") - -local MySQLStore = Store:extend() - -function MySQLStore:new(options) - local name = options.name or "mysql-store" - self.super.new(self, name) - self.store_type = "mysql" - local connect_config = options.connect_config - self.mysql_addr = connect_config.host .. ":" .. connect_config.port - self.data = {} - self.db = mysql_db(options) -end - -function MySQLStore:query(opts) - if not opts or opts == "" then return nil end - local param_type = type(opts) - local res, err, sql, params - if param_type == "string" then - sql = opts - elseif param_type == "table" then - sql = opts.sql - params = opts.params - end - - res, err = self.db:query(sql, params) - if err then - ngx.log(ngx.ERR, "MySQLStore:query, error:", err, " sql:", sql) - return nil - end - - if res and type(res) == "table" and #res <= 0 then - ngx.log(ngx.WARN, "MySQLStore:query empty, sql:", sql) - end - - return res -end - -function MySQLStore:insert(opts) - if not opts or opts == "" then return false end - - local param_type = type(opts) - local res, err - if param_type == "string" then - res, err = self.db:query(opts) - elseif param_type == "table" then - res, err = self.db:query(opts.sql, opts.params or {}) - end - - if res and not err then - return true - else - ngx.log(ngx.ERR, "MySQLStore:insert error:", err) - return false - end -end - -function MySQLStore:delete(opts) - if not opts or opts == "" then return false end - local param_type = type(opts) - local res, err - if param_type == "string" then - res, err = self.db:query(opts) - elseif param_type == "table" then - res, err = self.db:query(opts.sql, opts.params or {}) - end - - if res and not err then - return true - else - ngx.log(ngx.ERR, "MySQLStore:delete error:", err) - return false - end -end - -function MySQLStore:update(opts) - if not opts or opts == "" then return false end - local param_type = type(opts) - local res, err - if param_type == "string" then - res, err = self.db:query(opts) - elseif param_type == "table" then - res, err = self.db:query(opts.sql, opts.params or {}) - end - - if res and not err then - return true - else - ngx.log(ngx.ERR, "MySQLStore:update error:", err) - return false - end -end - -return MySQLStore diff --git a/orange/utils/utils.lua b/orange/utils/utils.lua index 067f9a01..1fc35383 100644 --- a/orange/utils/utils.lua +++ b/orange/utils/utils.lua @@ -15,6 +15,7 @@ local ffi_typeof = ffi.typeof local ffi_new = ffi.new local ffi_str = ffi.string local C = ffi.C +local ip_utils = require "lua_ip" ffi_cdef[[ typedef unsigned char u_char; @@ -92,6 +93,10 @@ function _M.get_hostname() return hostname end +function _M.get_ipv4() + return ip_utils.get_ipv4() +end + --- Generates a random unique string -- @return string The random string (a uuid without hyphens) function _M.random_string()