一、HAProxy Lua运行上下文
lua 代码在haproxy中以两种模式执行,第一种是initialisation mode 第二种是runtime mode
1、在initialisation mode 中,可以执行dns解析,但是不能执行socket i/o,在这个模式中当lua脚本执行时haproxy将会blocked
2、在runtime mode中,不能执行dns解析,但是可以使用socket,执行lua脚本是和请求线程一致。
lua 代码可以在一个或者多个文件中导入,这些文件包括主要的代码和函数,lua有6个执行上下文:
1、body context,它在当haproxy global中load时执行,这个主要用于配置lua绑定到haproxy中。
2、init context,在这个上下文中haproxy中的环境变量已经初始化,在执行检查配置时很有用,或初始化socket连接或任务。这些方法在body context中用core.register_init()声明,方法的属性是没有返回值和没有参数的简单函数,like:function fun()
3、task context,他是一个lua方法,在启动haproxy调度后执行,它使用core.register_task()声明,
4、action context,它是使用core.register_action()声明的lua函数,它接受class TXN参数,
5、sample-fetch context,这个方法接受txn对象并且返回字符串,它使用core
haproxy lua hello world
haproxy 配置文件:
global
lua-load hello_world.lua
listen proxy
bind 127.0.0.1:10000
tcp-request inspect-delay 1s
tcp-request content use-service lua.hello_world
hello_world.lua
core.register_service("hello_world","tcp",function(applet)
applet:send("hello world\n")
end)
class core()
这个core对象包含了所有的haproxy核心函数,这些函数包括控制执行,注册钩子,处理全局映射或acl等
这个core是静态的,不用创建一个新的对象
core.emerg
return: integer
这个属性是一个整数,它包含日志级别"emergency"的值0
core.alert
returns:integer
它包含日志级别“alert”的值1
core.crit
return :integer
它包含日志级别“critical”的值2
core.err
return :integer 3
core.warning
return :integer 4
core.notice
return: integer 5
core.info
return: integer 6
core.debug
return:integer 7
core.proxies
context:task,action,sample-fetch,convert
这个属性是一张table声明了frontend和backend proxies,每一个代理给出它的listeners和serviers列表,这个表使用proxy name作为index,
core.backends
context:task,action,sample-fetch,convert
返回一张表,backend name作为index
core.frontends
context:task,action,sample-fetch,convert
返回一张表,frontend name做为index
core.log(loglevel,msg)
context:body,init,task,action,sample-fetch,convert
记录日志,根据haproxy的日志配置
core.Debug(msg)
context:body,init,action,sample-fetch,converter
和core.log(core.debug,msg) 同等
core.Info(msg)
core.Warning(msg)
core.Alert(msg)
core.add_acl(filename,key)
context:init,task,action,sample-fetch,converter
向file中的acls添加acl key
core.del_acl(filename,key)
context:init,task,action,sample-fetch,converter
core,del_map(filename,key)
context:init,task,action,sample-fetch,converter
core.get_info()
context:body,init,task,action,sample-fetch,converter
返回haproxy的信息,可以得到:uptime,pid,memory pool usage,tasks number 等。
core.now()
context:body,init,task,action
返回当前时间。
core.http_date(date)
context:body,init,task,action
这个函数将一个string转换为date,
core.imf_date(date)
context:body,init,task,action
参数imf格式日期
core.rfc850_date(date)
context:body,init,task,action
参数:RFC859格式的日期
core.asctime_date(date)
context:body,init,task,action
参数:http-date格式
core.msleep(milliseconds)
context:body,init,task,action
暂停多少时间
core.register_action(name,actions,func[,nb_args])
context:body
注册lua函数作为action,所有注册的action可以在haproxy中使用通过“lua.”来调用,function使用txn作为输入
like:function(txn,args)
txn:表示当前的请求或tcp流
example:
core.register_action("hello",{
"tcp-req","http-req"},function(txn) txn:Info("hello")
end)
haproxy配置:
frontend tcp_frt
mode tcp
tcp-request content lua.hello
frontend http-frt
mode http
http-request lua.hello
带参数:
function hello(txn,arg)
txn:Info("hello"..arg)
end
core.register_action("hello",{
"tcp-req","http-req"},hello,2)
配置文件:
frontend tcpfrt
mode tcp
tcp-request content lua.hello everybody
core.register_converters(name,func)
context:body
注册lua函数为converter,注册后可在haproxy中使用“lua.”来进行调用。
function(str,[p1[,p2[,…][,p5]]])
str:输入值自动转化为string
p1.。。p5:string类型的列表,在haproxy 配置中声明,最多5个参数,
core.register_fetches(name,func)
context:body
注册lua函数为fetch,注册后可在haproxy中使用“lua.”来进行调用。返回字符串
string function(txn,[p1[,p2[,…][,p5]]])
txn:表示当前请求对象
example:
core.register_fetches("hello",function(txn)
return "hello"
end)
配置文件:
frontend example
http-request redirect location /%[lua.hello]
core.register_service(name,mode,func)
context:body
注册lua函数为service,注册后使用“lua.”来进行调用。service使用mode作为输入对象。
mode:只能是tcp或者http
function(applet)
applet:将会是applettcp class 或者applethttp class它取决于注册的applet
example:
core.register_service("hello","http",function(applet)
local response ="hello world"
applet:set_status(200)
applet:add_header("content-length",string.len(response))
applet:add_response("content-type","text/plain")
applet:start_reponse()
applet:send(response)
end)
配置文件:
frontend example
http-request use-service lua.hello
core.register_init(func)
context:body
注册一个函数在配置检查后启动,这在检查参数的时候很有用
function()
它没有输入和输出
core.register_task(func)
context:body,init,task,action,sample-fetch,converter
注册并启动一个独立的任务,这个任务在haproxy主进程启动后就启动,这个任务可用与复杂的健康检查
core.register_cli([path],usage,func)
context:body
作用等同于register_task
function(applettcp,[args])
example:
core.register_cli({
"show","ssl","stats"},"display ssl stats...",function(applet,arg1,arg2,arg3,arg4,arg5)
end)
arg1…arg3将对应show,ssl,stats,arg4表示all,arg5表示nil
core.set_nice(nice)
context:task,action,sample-fetch,converter
改变当前任务获取session的nice
nice:是一个数值,它位于1-1024之间
core.set_map(filename,key,value)
context:init,task,action,sample-fetch,converter
设置filename中对应key的值
core.sleep(int seconds)
context:body,init,task,actin
暂停执行
core.tcp()
context :init,task,action
返回一个新的socket对象
core.concat()
context:body,init,task,action,sample-fetch,converter
返回concat对象
core.done(data)
context:body,init,task,action,sample-fetch,converter
立即停止当前lua脚本的执行,并返回给调用方,它可以是一个fetch,converter ,oraction。它在lua进程完成了它的工作并且想要将控制权交还给haproxy,它相当于return
core.yield()
context:task,action,sample-fetch,converter
将控制权交还给haproxy,它在lua进程需要大量的时间的时候很有用
core.parse_addr(address)
context:body,init,task,action,sample-fetch,converter
core.match_addr(addr1,addr2)
context:body,init,task,action,sample-fetch,converter
当两个地址相当时返回true,or false
core.tokenize(str,separators[,noblank])
context:body,init,task,action,sample-fetch,converter
这个函数在tokenizing entry,分隔信息,str参数将会被分隔,separators包含分隔符的列表,noblank:忽略空输入,返回 array
example:
local array=core.tokenize("this function is useful,for tokenizing an entry.",".,",true)
print_r(array)
class Proxy()
这个类提供了操作proxy的通道,并且可以得到统计信息
Proxy.name
包含proxy的name
Proxy.uuid
包含proxy的唯一id
Proxy.servers
包含一张server表,server name 作为表的index,每一个server是server class 对象
Proxy.stktable
包含proxy的固定表
Proxy.listeners
包含listener的表
Proxy.pause(px)
暂停proxy,
Proxy.resume(px)
恢复proxy
Proxy.stop(px)
停止proxy
Proxy.shut_bcksess(px)
kill session to backup server
Proxy.get_cap(px)
返回proxy的描述信息
Proxy.get_mode(px)
返回proxy的mode
Proxy.get_stats(px)
返回proxy统计的表
class Server()
这个类提供可以操作servers的方法,
Server.name
包含server name
Server.puid
包含server所属的proxy uuid
Server.is_draining(sv)
如果当前服务处于连接状态返回true
Server.set_maxconn(sv,maxconn)
动态改变服务的最大连接,
Server.get_maxconn(sv)
返回服务的最大连接数
Server.set_weight(sv,weight)
动态设置服务的权重
Server.get_weight(sv)
获取权重
Server.set_addr(sv,addr)
动态改变服务地址
Server.get_addr(sv)
返回服务地址
Server.get_stats(sv)
返回服务statistics
Server.shut_sess(sv)
关闭服务的所有连接
Server.set_drain(sv)
Server.set_maint(sv)
设置为maintenance mode
Server.set_ready(sv)
设置为nomal mode
Server.check_enable(sv)
enable 健康检查
Server.check_disable(sv)
disabel 健康检查
Server.check_force_up(sv)
强制启用健康检查
Server.check_force_nolb(sv)
强制健康检查 nolb模式
Server.check_force_down(sv)
强制不使用健康检查
Server.agent_enable(sv)
启用agent检查
Server.agent_disable(sv)
不启用agent检查
Server.agent_force_up(sv)
强制启用agent
Server.agent_force_down(sv)
强制关闭agent
Listener.get_stats(ls)
返回server 状态信息
class Concat()
这个类提供了快速的将string 连接,原生的lua连接… 因为一些原因比较慢
example:
for j =1,100 do
c=core.concat()
for i =1,20000 do
c:add("####")
end
end
Concat.add(concat,string)
将string拼接到concat中。
Concat.dump(concat)
返回concat的string
class Fetches()
这个类包含很多的haproxy内部的fetches。
txn.f
txn.fc
fetches 在一下情况比较实用:
example:
function action(txn)
local clientip = txn.f:src
end
class Converters()
这个类包含了很多的haproxy内部的转换器,
txn.c
txn.sc
converter 可用于:
class Channel()
haproxy使用两个buffer在requests的请求中,第一个用于request data(client to server)。第二个用于response data(server to client)
没个buffer都包含两个类型的数据。第一个类型是等待处理的incoming data,第二是已处理的outgoing data。
接下来的方法提供了工具去处理这些buffer中的数据
Channel.dup(channel)
返回整个buffer的数据,这些数据并没有从buffer中删除。
Channel.get(channel)
返回整个buffer的数据,从buffer中消费数据
Channel.getline(channel)
返回第一行数据,从buffer中消费数据
Channel.set(channel,string)
替换buffer内容,
Channel.append(channel,string)
将string添加到buffer content中,
Channel.send(channel,string)
这个函数需要立即发送数据,除非连接关闭,
Channel.get_in_length(channel)
从input buffer中获取长度
Channel.get_out_length(channel)
返回out buffer 长度
Channel.forward(channel,int)
转换为bytes从input到output
Channel.is_full(channel)
class HTTP()
这个类包含了所有的http操作函数
HTTP.req_get_headers(http)
返回所有请求头
HTTP:req_get_headers()['header-name']['header-index']="header-value"
local hdr=HTTP:req_get_headers()
hdr["host"][0]="www.example.com"
HTTP.res_get_headers(http)
返回响应头信息
HTTP.req_add_header(http,name,value)
添加请求头部信息
HTTP.res_add_header(http,name,value)
添加响应头部信息
HTTP.req_del_header(http,name)
删除请求头
HTTP.res_del_header(http,name)
删除响应头
HTTP.req_set_header(http,name,value)
如果头存在则替换
example:
function fcn(txn)
TXN.http:req_del_header("header")
TXN.http:req_add_header("header","value")
end
HTTP.res_set_header(http,name,value)
替换响应头
HTTP.req_rep_header(http,name,regex,replace)
根据正则匹配头,然后使用replace进行替换,
HTTP.req_rep_header(http,name,regex,replace)
根据正则匹配头,然后使用replace进行替换,
HTTP.req_set_method(http,method)
重写请求方法
HTTP.req_set_query(http,query)
重写查询参数
HTTP.req_set_uri(http,uri)
重写uri
HTTP.res_set_status(http,status [,reason])
重写响应ma
class TXN()
txn 包含了所有的方法去解析http或tcp请求
这个类允许去解析请求数据并改变或转发
TXN.c
returns : an converters class
这个属性包含转化实例
TXN.sc
return : an converters class
这个属性包含转化实例,这个实例的方法总是返回string
TXN.f
return: an fetches class
这个属性包含fetches 实例
TXN.sf
return: an fetches class
这个属性包含fetches 实例,这个实例的方法总是返回string
TXN.req
return :an channel class
这个属性包含请求buffer 的channel 实例
TXN.res
return: an channel class
这个属性包含响应buffer 的channel 实例
TXN.http
return : an http class
这个属性包含http实例,仅当mode为http时有效
TXN.log(TXN,loglevel,msg)
该函数发送log
TXN.log(TXN,msg)
发送默认loglevel
TXN.Debug(txn,msg)
TXN.Info(txn,msg)
TXN.Warning(txn,msg)
TXN.Alert(txn,msg)
TXN.get_priv(txn)
返回当前transaction存储的lua数据,如果没有,则返回nil
TXN.set_priv(txn,data)
存储数据到当前transaction。
TXN.set_var(txn,var,value)
将lua type转换为haproxy type并存储在variable
TXN.unset_var(txn,var)
unset 变量
TXN.get_var(txn,var)
返回存储的var,并转化为lua 类型
TXN.done(txn)
终止进程,
TXN.set_loglevel(txn,loglevel)
改变当前请求的日志级别
TXN.set_tos(txn,tos)
它被用于设置tos或dscp
TXN.set_mark(txn,mark)
他被用于设置netfilter mark
TXN.set_priority_class(txn,prio)
设置transaction的优先级,取值范围:-2047-2047
TXN.set_priority_offset(txn,prio)
class Socket()
这个类必须与lua socket 一起使用,
Socket.close(socket)
关闭socket,
Socket.connect(socket,address [,port])
网络连接
如果出错则返回nil,正确返回1
Socket.connetc_ssl(socket,address,port)
和connet()一直,只是使用ssl
Socket.getpeername(socket)
返回远程终端信息,
Socket.getsockname(socket)
返回local ip和port
Socket.receive(socket[,pattern[,prefix]])
读取信息,根据pattern,pattern是lua 文件i/o的格式
Socket.send(socket,data[,start[,end]])
发送信息
Socket.setoption(socket,option[,value])
Socket.settimeout(socket,value[,mode])
设置超时时间
这个类允许使用haproxy 的正则,因为lua并不提供正则。
example:
st,regex=Regex.new("needle (..)(...)",true)
if st == false then
print "error:" .. regex
end
print(regex:exec("Looking for a needle in the"))--true
print(regex:exec("lookin for a cat in the"))--false
st,list=regex:match("looking for a needle in the")
print(st)--true
print(list[1])--needle in the
print(list[2])--in
print(list[3])--the
Regex.new(regex,case_sensitive)
创建正则匹配
returns:boolean status and Regex class or 失败原因
Regex.exec(regex,str)
进行正则匹配
如果匹配返回true else false
Regex.match(regex,str)
执行正则匹配,并返回匹配
return:boolean status 和匹配的table
这个类可以在haproxy maps中查找,
default=usa
geo=Map.new('geo.map',Map._ip)
core.register_fetches("country",function(txn)
local src
local loc
src = txn.f:fhdr("x-forwared-for")
if (src == nil) then
src=txc.f:src()
if (src == nil) then
return default
end
end
loc = geo:lookup(src)
if (loc == nil) then
return default
end
return loc
end)
Map._int
Map._ip
Map._str
Map._beg
Map._sub
Map._dir
Map._dom
Map._end
Map._reg
Map.new(file,method)
创建并导入map
Map.lookup(map,str)
执行lookup在map中
Map.slookup(map,str)
这个类用于使用http 模式的applet,http applet能够使用core.register_service()方法注册,它被用于像haproxy后端服务一样处理http 请求。
example:
core.register_service("hello","http",function(applet)
local response="hello"
applet:set_status(200)
applet:add_header("content-length",string.len(response))
applet:start_response()
applet:send(response)
end)
applethttp.c
applethttp.sc
applethttp.f
applethttp.sf
applethttp.method
返回http方法
applethttp.version
返回http请求版本
applethttp.path
返回请求path
applethttp.qs
返回请求query string
applethttp.length
返回请求body长度
applethttp.headers
返回请求头
applethttp.set_status(applet,code[,reason])
设置响应代码,code范围100-599
applethttp.add_header(applet,name,value)
添加响应头,
applethttp.start_response(applet)
这个方法启用http engine 来处理和发送响应头,在这个函数后不能调用 add_header(),send()函数需要在此函数调用后使用。
applethttp.getline(applet)
这个函数返回一行http body内容,
applethttp.receive(applet[,size])
从http body中读取内容,根据size,如果没有设置size则读取全部内容。
applethttp.send(applet,msg)
发送数据到http request body
applethttp.get_priv(applet)
返回存储在当前transaction中的数据,如果没有则返回nil
applethttp.set_priv(applet,data)
存储数据到当前haproxy transaction
applethttp.set_var(applet,var,value)
转换lua 类型为haproxy类型,并存储到var
applethttp.unset_var(applet,var,value)
applethttp.get_var(applet,var,value)
这个类用于tcp mode的applet。
applettcp.c
applettcp.sc
applettcp.f
applettcp.sf
applettcp.getline(applet)
applettcp.receive(applet[,size])
applettcp.send(applet,msg)
applettcp.get_priv(applet)
applettcp.set_priv(applet,data)
applettcp.set_var(applet,var,value)
applettcp.unset_var(applet,var)
applettcp.get_var(applet,var)