I have lua block in nginx config, which checks for redis-server connection and if 4 java-processes are up, and then returns 200 or 500 status accordingly to this checks.
location = /healthcheck {
content_by_lua_block {
local redis = require "resty.redis"
local red = redis:new()
red:set_timeout(1000)
local ok, err = red:connect("127.0.0.1", 6379)
if not ok then
ngx.status = 500
return
end
local ps = io.popen("/bin/ps aux |grep -c '[j]ava.*63'")
local output = tostring(ps:read('*a'))
ps:close()
if string.match(output, '4') then
ngx.status = 200
else
ngx.status = 500
end
}
}
But periodically output variable takes nil value, while it shouldn't. Just can't get why it happens.
Thanks in advance, comrades.
UPD:
Using tonumber fails on
bad argument #2 to 'tonumber' (number expected, got string)
Updated location config:
location = /healthcheck {
content_by_lua_block {
local redis = require "resty.redis"
local red = redis:new()
red:set_timeout(1000)
local ok, err = red:connect("127.0.0.1", 6379)
if not ok then
ngx.status = 500
return
end
local ps = io.popen("/bin/ps aux |grep -c '[j]ava.*63'")
local output = tonumber(ps:read())
ps:close()
if (output == 4) then
ngx.status = 200
else
ngx.status = 500
end
}
}
UPD2:
Logging to nginx error (with tostring) prints next:
grep: write error: Broken pipe
2016/04/19 17:54:48 [error] 301#0: *5 [lua] content_by_lua(healthcheck.conf:33):20: OUTPUT:nil
UPD3:
Using command grep -c '[j]ava.*63' <(/bin/ps aux) to avoid the use of pipe:
local ps = io.popen("grep -c '[j]ava.*63' <(/bin/ps aux)")
getting next error:
sh: -c: line 0: syntax error near unexpected token `('
sh: -c: line 0: `grep -c '[j]ava.*63' <(/bin/ps aux)'
According to this answer and some testing next config do the job:
location = /healthcheck {
content_by_lua_block {
local redis = require "resty.redis"
local red = redis:new()
red:set_timeout(1000)
local ok, err = red:connect("127.0.0.1", 6379)
if not ok then
ngx.status = 500
return
end
local ps = io.popen("/bin/ps aux >/tmp/ps.out", "w")
ps:close()
local ps = io.popen("grep -c '[j]ava.*63' /tmp/ps.out")
local output = tostring(ps:read())
ps:close()
if string.match(output, '4') then
ngx.status = 200
else
ngx.status = 500
end
}
}
Related
I have a unix domain socket file and it is working with with nc command. Now I want to access it via nginx but it does not work. Am I missing something?
test with nc => it works
$ echo '{ "method" : "getinfo", "params" : [], "id" : "1" }' | nc -U /home/zono/.lightning/lightning-rpc
{ "jsonrpc": "2.0", "id" : "1", "result" :
{
"id": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
}
test via nginx => it does not work
// /etc/nginx/sites-enabled/default
upstream nginx-internal-sock {
server unix:/home/zono/.lightning/lightning-rpc;
}
server {
listen 80;
location / {
proxy_pass http://nginx-internal-sock;
}
}
$ curl -H "content-type: application/json" -X POST --data '{ "method" : "getinfo", "params" : [], "id" : "1" }' http://127.0.0.1
2019-03-20T04:25:52.551Z lightningd(30143):jcon fd 32: Invalid token in json input: 'POST / HTTP/1.0??Host: nginx-internal-sock??Connection: close??C'
Update 1
There's been a development. However I can't get whole data.
// install nginx-extras
apt-get install nginx-extras
// /etc/nginx/sites-enabled/default
server {
listen 80;
location / {
content_by_lua '
ngx.req.read_body()
local body_data = ngx.req.get_body_data()
local sock = ngx.socket.tcp()
local ok, err = sock:connect("unix:/home/zono/.lightning/lightning-rpc")
local bytes = sock:send(body_data)
local line, err = sock:receive("*a")
ngx.say(line)
ok, err = sock:close()
';
}
}
// Response is nil
$ curl -X POST --data '{ "method" : "getinfo", "params" : [], "id" : "1" }' http://127.0.0.1
nil
// /var/log/nginx/error.log
2019/03/20 07:43:39 [error] 4926#4926: *35 lua tcp socket read timed out, client: 127.0.0.1, server: , request: "POST / HTTP/1.1", host: "127.0.0.1"
// When I set "sock:receive("*l")" the response is the part of the data.
$ curl -X POST --data '{ "method" : "getinfo", "params" : [], "id" : "1" }' http://127.0.0.1
{ "jsonrpc": "2.0", "id" : "1", "result" :
I'm checking the reference now. http://w3.impa.br/~diego/software/luasocket/tcp.html
'*a': reads from the socket until the connection is closed. No end-of-line translation is performed;
'*l': reads a line of text from the socket. The line is terminated by a LF character (ASCII 10), optionally preceded by a CR character (ASCII 13). The CR and LF characters are not included in the returned line. In fact, all CR characters are ignored by the pattern. This is the default pattern;
number: causes the method to read a specified number of bytes from the socket.
I found out the answer.
// install nginx-extras
apt-get install nginx-extras
// /etc/nginx/sites-enabled/default
server {
listen 80;
location / {
content_by_lua '
ngx.req.read_body()
local body_data = ngx.req.get_body_data()
local sock = ngx.socket.tcp()
local ok, err = sock:connect("unix:/home/zono/.lightning/lightning-rpc")
local bytes = sock:send(body_data)
local readline = sock:receiveuntil("\\n\\n")
local line, err, part = readline()
if line then
ngx.say(line)
end
ok, err = sock:close()
';
}
}
// curl
$ curl -X POST --data '{ "method" : "getinfo", "params" : [], "id" : "1" }' http://127.0.0.1
I have next nginx location with Lua code (used with nginx lua-resty-redis):
location = /healthcheck {
content_by_lua_block {
local red = redis:new()
used_mem_limit = 536870912
-- connect to redis
ok, err = red:connect(ngx.var.redis_host, 6379)
if not ok then
ngx.log(ngx.ERR, "Redis connection error: ", err)
ngx.status = 500
return
end
-- setting connection timeout
red:set_timeout(1000)
-- getting redis used_memory_rss
memory = red:info('memory')
red_used_memory = ...
-- set response code
if (red_used_memory >= used_mem_limit) then
http_code = 500
elseif (red_used_memory < used_mem_limit)
http_code = 200
else
http_code = 500
end
ngx.status = http_code
}
}
memory variable should be like this:
# Memory
used_memory:105157968
used_memory_human:100.29M
used_memory_rss:110387200
used_memory_rss_human:105.27M
used_memory_peak:105219456
used_memory_peak_human:100.35M
used_memory_peak_perc:99.94%
used_memory_overhead:32290608
used_memory_startup:487168
used_memory_dataset:72867360
used_memory_dataset_perc:69.62%
total_system_memory:1044770816
I need to get used_memory_rss value, so then I can compare it with used_mem_limit. So, I don't know, how to complete red_used_memory = ... line.
There seems to be only digits in possible value so use a simple regexp and then convert resulting string to number:
red_used_memory = tonumber(memory:match('used_memory_rss:(%d+)'))
Line breaks are irrelevant.
I am using openresty with lua. When I was loading torch without cutorch,cunn(GPU) it was working fine. But it is unable to load cutorch module.
Here is my nginx.conf
error_log stderr notice;
daemon off;
events{}
http {
lua_code_cache on;
#lua_package_cpath '/usr/local/cuda/include/?.so;;';
init_by_lua_file 'evaluate.lua';
server {
listen 6788;
lua_code_cache on;
lua_need_request_body on;
client_body_buffer_size 10M;
client_max_body_size 10M;
location /ff {
# only permit POST requests
if ($request_method !~ ^(POST)$ ) {
return 403;
}
content_by_lua '
local body = ngx.req.get_body_data()
if body == nil then
ngx.say("empty body")
else
local resp =FeedForward(body)
ngx.say(cjson.encode({result=resp}))
end
';
}
}
}
Here is my evaluate.lua code
-- load the required lua models
torch = require("torch")
nn = require("nn")
gm = require("image")
cutorch = require "cutorch"
cunn = require "cunn"
cjson = require("cjson")
-- model
modelPath='./model.t7'
ninputs = 3
model = nn.Sequential()
model:add(nn.Linear(ninputs,2))
-- let’s save a dummy model
-- to demonstrate the functionality
torch.save(modelPath, model)
-- load a pretrained model
net = torch.load(modelPath)
net:cuda()
net:evaluate()
-- our end point function
-- this function is called by the ngx server
-- accepts a json body
function FeedForward(json)
print("starting")
-- decode and extract field x
local data = cjson.decode(json)
local input = torch.Tensor(data.x)
local response = {}
-- example checks
if input == nil then
print("No input given")
elseif input:size(1) ~=ninputs then
print("Wrong input size")
else
-- evaluat the input and create a response
local output = net:forward(input:cuda()):float()
-- from tensor to table
for i=1,output:size(1) do
response[i] = output[i]
end
end
-- return response
return response
end
I am trying to run the model using following commands
/usr/local/openresty/nginx/sbin/nginx -p "$(pwd)" -c "nginx.conf"
It's starting up fine but when I am sending curl request like
curl -H "Content-Type: application/json" -X POST -d '{"x":[1,2,3]}' http://localhost:6788/ff
I am getting following error.
2016/09/29 12:59:59 [notice] 10355#0: *1 [lua] evaluate.lua:28: FeedForward(): starting, client: 127.0.0.1, server: , request: "POST /ff HTTP/1.1", host: "localhost:6788"
THCudaCheck FAIL file=/tmp/luarocks_cutorch-scm-1-700/cutorch/lib/THC/generic/THCStorage.cu line=40 error=3 : initialization error
2016/09/29 12:59:59 [error] 10355#0: *1 lua entry thread aborted: runtime error: unknown reason
stack traceback:
coroutine 0:
[C]: in function 'resize'
/home/ubuntu/torch/install/share/lua/5.1/cutorch/Tensor.lua:14: in function 'cuda'
/rootpath/evaluate.lua:41: in function 'FeedForward'
content_by_lua(nginx.conf:31):7: in function <content_by_lua(nginx.conf:31):1>, client: 127.0.0.1, server: , request: "POST /ff HTTP/1.1", host: "localhost:6788"
Without cutorch the model is running fine like If I remove
net:cuda()
and replace line
local output = net:forward(input:cuda()):float()
by
local output = net:forward(input):float()
It's working fine. Also I tried to run evaluate.lua using th and it's working fine there with cutorch and cunn packages.
I have compiled nginx with Lua. and i am facing a problem .
When i hit localhost i get an error in nginx error logs
2015/05/29 07:41:32 [error] 112#0: *1 lua entry thread aborted: runtime error: /opt/hello.lua:11: bad argument #1 to 'getNewSessionID' (string expected, got nil)
stack traceback:
coroutine 0:
[C]: in function 'getNewSessionID'
Nginx configurations are
location / {
default_type 'text/html';
content_by_lua_file /opt/hello.lua;
}
And my hello.lua look like
package.path = package.path ..';/opt/?.lua'
JSON = (loadfile "/opt/JSON.lua")()
local proxyFunctions = require("proxyCode")
coherenceNGIXLocation = "/coherence"
local coherenceCookie = proxyFunctions.getExistingSessionID()
-- To Create a coherance Session if not present
if (not coherenceCookie or coherenceCookie == '') then
-- ngx.log(ngx.INFO,"No Coherence Session Exists, Creating New")
local uidCookieValueEncoded = proxyFunctions.base64Encode(str,proxyFunctions.getNewSessionID())
local sessCreateResponse = proxyFunctions.coherencePut('{"sessionToken":"'..uidCookieValueEncoded..'"}')
local parsedJSON= JSON:decode(sessCreateResponse.body)
ngx.log(ngx.INFO, "Coherence Session Create")
ngx.log(ngx.INFO, "\n\n\n=============Coherence Res==============\n\n\n"..sessCreateResponse.body.."\n\n\n=============Coherence Res==============\n\n\n")
end
local client_cookie = ngx.req.get_headers()["cookie"]
-- To Create a coherance Session if not present
ngx.log(ngx.DEBUG, "\n\n\n=============REQ==============\n\n\n"..proxyFunctions.deepPrint(ngx.req.get_headers()).."\n\n\n=============REQ==============\n\n\n")
-- Set the cookie for the legacy request
ngx.req.set_header('cookie', client_cookie)
ngx.log(ngx.INFO, "\n\n\n=============REQ URI==============\n\n\n"..ngx.var.request_uri.."\n\n\n=============REQ URI==============\n\n\n")
local legacy_res = ngx.location.capture("/app"..ngx.var.request_uri, { share_all_vars = true })
ngx.log(ngx.DEBUG, "\n\n\n=============APP Res==============\n\n\n"..proxyFunctions.deepPrint(legacy_res.header).."\n\n\n=============APP Res==============\n\n\n")
if (legacy_res.status == 302) then
ngx.redirect(legacy_res.header.Location )
else
ngx.log(ngx.INFO, "Passing the Page/Layout to Maken")
local dev_res_encoded = legacy_res.body
dev_res_encoded = ngx.escape_uri(dev_res_encoded)
-- ngx.req.set_header('Cookie', ngx.req.get_headers()["cookie"])
-- ngx.req.set_header("Content-Type", "text/html") -- application/x-www-form-urlencoded -- 'page='..dev_res_encoded
ngx.req.set_header('cookie', client_cookie) -- maken/render
-- legacy_res.header('Content-Length', legacy_res.header['Content-Length']);
local maken_res = ngx.location.capture("/maken/", {method = ngx.HTTP_POST, body = legacy_res.body, share_all_vars = true} )
ngx.header['Set-Cookie'] = legacy_res.header["Set-Cookie"]
ngx.log(ngx.INFO, "Sending Back Maken Response to Client/Browser with Cookies from lagacy")
ngx.say(maken_res.body)
end
My proxyCode.lua looks like
function _M.getNewSessionID()
-- strip the sessionID length 11 cookie name before putting into the session
-- return string.sub(ngx.var.uid_set,11)
return _M.removeCookieSessionPrefixname(ngx.var.uid_set,11)
end
function _M.removeCookieSessionPrefixname(cookieName)
return string.sub(cookieName,11)
end
function _M.getIncomingAuthToken()
local cookie = ngx.req.get_headers()["Cookie"]
if (cookie ~=nil) then
local str = string.match(cookie,"AuthToken=(.*)$")
if (str ~= nil) then
return string.sub(str,11)
end
end
return nil
end
Can someone help me why i am getting this error ? i am new to Lua programming. and trying to run legacy application on my laptop.
Having trouble with file output in Nginx + Lua. I chosen LUA, because nginx logic is pretty complicated, based on referrer or subdomains, etc.
Having request like /img/am1/s/1.jpg I need to check if file exists in /somepath/am1/1.jpg. If it exists, then output it, otherwise proxy request to backend.
Ok, found it
content_by_lua '
local file = "/path..."
local f = io.open(file, "rb")
local content = f:read("*all")
f:close()
ngx.print(content)
';
If someone need to know how to output last n lines from file:
location /service-man/log {
default_type 'text/plain';
content_by_lua '
local log_path = "/path/to/log.log"
-- Opens a file in read
file = io.open(log_path, "r")
if file==nil
then
ngx.say(log_path .. " can\'t read or does not exists")
return
end
-- sets the default input file
io.input(file)
local lines = {}
-- read the lines in table lines
for line in io.lines() do
table.insert(lines, line)
end
io.close(file)
log_limit = 10
if #lines < log_limit then
log_start = 0
else
log_len = #lines
log_start = log_len - log_limit
end
local one_line = ""
for i, line in ipairs(lines) do
if i > log_start then
one_line = one_line .. line .. "\\n"
end
end
ngx.say(one_line)
';
}
Should be compatible with nginx/1.6.2 and Lua 5.3.
Please share if you know how to make it in more optimal way.