注意
本文档适用于 Ceph 开发版本。
Lua 脚本
Pacific版本中的新功能。
此功能允许用户为Lua脚本分配执行上下文。支持的上下文有:
prerequest
将在每次操作执行前执行脚本
postrequest
将在每次操作执行后执行脚本
background
将在指定的时间间隔内执行脚本
getdata
当对象被下载时,将在对象的数据上执行脚本
putdata
当对象被上传时,将在对象的数据上执行脚本
请求(预或后)或数据(获取或上传)上下文脚本可以限制为属于特定租户的用户的所有操作。全局RGW表。全局RGW表。rgw_lua_max_memory_per_state
配置参数。请注意,Lua及其标准库的基本开销约为32K字节。要禁用此限制,请使用零。rgw_lua_max_runtime_per_state
配置参数更改。如果Lua脚本超过此运行时间,它将被终止。要禁用运行时限制,请使用零。
警告
修改内存限制时要小心。如果当前内存使用量超过新设置的限制,背景状态中之前存储的所有数据都将丢失。
警告
禁用运行时限制可能导致无限制的脚本执行,这可能导致过度资源消耗,并可能影响RADOS网关的可用性。
默认情况下,所有Lua标准库在脚本中都是可用的,但是,为了允许在脚本中使用额外的Lua模块,我们支持将软件包添加到允许列表:
确保在现有集群的每个主机上都有
luarocks
如果主机上安装了将Lua软件包添加到允许列表,或从其中删除软件包不会安装或删除它。要使更改生效,应调用“重新加载”命令。
此外,所有允许列表中的软件包都使用luarocks软件包管理器在radosgw重新启动时重新安装。
要添加包含需要编译的C源代码的软件包,请使用
--allow-compilation
标志。在这种情况下,主机上需要提供C编译器Lua软件包安装在radosgw的本地目录中,并从中使用。这意味着允许列表中的Lua软件包与主机上可用的任何Lua软件包是分开的。
/tmp/luarocks/<entity name>
。其前缀部分(/tmp/luarocks/
)可以通过rgw_luarocks_location
配置参数设置为不同的位置。$HOME/.luarocks
,/usr/lib64/lua
,/usr/share/lua
).
通过CLI管理脚本
要上传脚本:
# radosgw-admin script put --infile={lua-file-path} --context={prerequest|postrequest|background|getdata|putdata} [--tenant={tenant-name}]
当使用
background
上下文上传脚本时,不应指定租户名称。
# cephadm shell radosgw-admin script put --infile=/rootfs/{lua-file-path} --context={prerequest|postrequest|background|getdata|putdata} [--tenant={tenant-name}]
要将脚本内容打印到标准输出:
# radosgw-admin script get --context={preRequest|postRequest|background|getdata|putdata} [--tenant={tenant-name}]
要删除脚本:
# radosgw-admin script rm --context={preRequest|postRequest|background|getdata|putdata} [--tenant={tenant-name}]
通过CLI管理软件包
要将软件包添加到允许列表:
# radosgw-admin script-package add --package={package name} [--allow-compilation]
要将特定版本的软件包添加到允许列表:
# radosgw-admin script-package add --package='{package name} {package version}' [--allow-compilation]
当向列表中添加已存在的软件包的不同版本时,新添加的版本将覆盖现有的版本。
当添加未指定版本的软件包时,将添加软件包的最新版本。
要从允许列表中删除软件包:
# radosgw-admin script-package rm --package={package name}
要从允许列表中删除特定版本的软件包:
# radosgw-admin script-package rm --package='{package name} {package version}'
当删除未指定版本的软件包时,将删除软件包的任何现有版本。
要打印允许列表中的软件包列表:
# radosgw-admin script-package list
要将允许列表中的更改应用到所有RGWs:
# radosgw-admin script-package reload
无上下文函数
调试日志
The RGWDebugLog()
function接受一个字符串并将其以优先级20打印到调试日志。Lua INFO:
前缀。此函数没有返回值。
请求字段
警告
此功能是实验性的。字段可能在将来被删除或重命名。
Note
虽然Lua是一种区分大小写的语言,但radosgw提供的字段名是不区分大小写的。函数名仍然区分大小写。
标记为“可选”的字段可以有nil值。
标记为“可迭代”的字段可以使用pairs()函数和#长度运算符。
所有表字段都可以使用括号运算符
[]
.time
字段是具有以下格式的字符串:%Y-%m-%d %H:%M:%S
.
字段 |
类型 |
描述 |
可迭代 |
可写 |
可选 |
---|---|---|---|---|---|
|
string |
radosgw操作 |
no |
no |
no |
|
string |
解码的URI |
no |
no |
no |
|
整数 |
请求的大小 |
no |
no |
no |
|
表 |
字符串到字符串通用属性映射 |
是 |
no |
no |
|
表 |
对请求的响应 |
no |
no |
no |
|
整数 |
HTTP状态码 |
no |
是 |
no |
|
string |
HTTP状态文本 |
no |
是 |
no |
|
整数 |
radosgw错误码 |
no |
是 |
no |
|
string |
响应消息 |
no |
是 |
no |
|
string |
swift账户名称 |
no |
no |
是 |
|
表 |
桶的信息 |
no |
no |
no |
|
string |
桶的租户 |
no |
no |
是 |
|
string |
桶名称(仅在 |
no |
是 |
no |
|
string |
桶标记(初始ID) |
no |
no |
是 |
|
string |
桶ID |
no |
no |
是 |
|
string |
桶的区域组 |
no |
no |
是 |
|
时间 |
桶的创建时间 |
no |
no |
是 |
|
时间 |
桶的修改时间 |
no |
no |
是 |
|
表 |
桶配额 |
no |
no |
是 |
|
整数 |
桶配额最大大小 |
no |
no |
no |
|
整数 |
桶配额最大对象数 |
no |
no |
no |
|
布尔值 |
桶配额已启用 |
no |
no |
no |
|
布尔值 |
桶配额四舍五入到4K |
no |
no |
no |
|
表 |
桶放置规则 |
no |
no |
是 |
|
string |
桶放置规则名称 |
no |
no |
no |
|
string |
桶放置规则存储类 |
no |
no |
no |
|
string |
所有者用户/账户ID |
no |
no |
是 |
|
表 |
对象的信息 |
no |
no |
是 |
|
string |
对象名称 |
no |
no |
no |
|
string |
对象版本 |
no |
no |
no |
|
string |
对象ID |
no |
no |
no |
|
整数 |
对象大小 |
no |
no |
no |
|
时间 |
对象mtime |
no |
no |
no |
|
表 |
复制操作的信息 |
no |
no |
是 |
|
string |
从哪个对象复制租户 |
no |
no |
no |
|
string |
从哪个桶复制对象 |
no |
no |
no |
|
表 |
从哪个对象复制。参见: |
no |
no |
是 |
|
表 |
对象所有者 |
no |
no |
no |
|
string |
对象所有者显示名称 |
no |
no |
no |
|
string |
所有者用户/账户ID。参见: |
no |
no |
是 |
|
string |
区域组的名称 |
no |
no |
no |
|
string |
区域组的端点 |
no |
no |
no |
|
表 |
用户ACL |
no |
no |
no |
|
表 |
用户ACL所有者。参见: |
no |
no |
no |
|
表 |
用户ACL从字符串到授权的映射 |
是 |
no |
no |
|
表 |
用户ACL授权 |
no |
no |
no |
|
整数 |
用户ACL授权类型 |
no |
no |
no |
|
string |
用户ACL授权用户/账户ID |
no |
no |
no |
|
整数 |
用户ACL授权组类型 |
no |
no |
是 |
|
string |
用户ACL授权引用者 |
no |
no |
是 |
|
表 |
桶ACL。参见: |
no |
no |
no |
|
表 |
对象ACL。参见: |
no |
no |
no |
|
表 |
字符串到字符串环境映射 |
是 |
no |
no |
|
表 |
策略 |
no |
no |
是 |
|
string |
策略文本 |
no |
no |
no |
|
string |
策略ID |
no |
no |
是 |
|
表 |
字符串语句列表 |
是 |
no |
no |
|
表 |
用户策略列表 |
是 |
no |
no |
|
表 |
用户策略。参见: |
no |
no |
no |
|
string |
radosgw主机ID: |
no |
no |
no |
|
表 |
HTTP头 |
no |
no |
no |
|
表 |
字符串到字符串参数映射 |
是 |
no |
no |
|
表 |
字符串到字符串资源映射 |
是 |
no |
no |
|
表 |
字符串到字符串元数据映射 |
是 |
是 |
no |
|
string |
存储类 |
no |
是 |
是 |
|
string |
主机名 |
no |
no |
no |
|
string |
HTTP方法 |
no |
no |
no |
|
string |
URI |
no |
no |
no |
|
string |
HTTP查询字符串 |
no |
no |
no |
|
string |
域名 |
no |
no |
no |
|
时间 |
请求时间 |
no |
no |
no |
|
string |
“S3”或“Swift” |
no |
no |
no |
|
string |
请求ID |
no |
no |
no |
|
string |
事务ID |
no |
no |
no |
|
表 |
对象标签映射 |
是 |
no |
no |
|
表 |
触发请求的用户 |
no |
no |
no |
|
string |
触发用户的租户 |
no |
no |
no |
|
string |
触发用户ID |
no |
no |
no |
|
表 |
跟踪信息 |
no |
no |
no |
|
布尔值 |
跟踪已启用 |
no |
是 |
no |
请求函数
操作日志
The Request.Log()
function将请求打印到操作日志中。此函数没有参数。如果成功,它返回0,如果失败,则返回错误代码。
跟踪
跟踪函数只能在postrequest
上下文中使用。
Request.Trace.SetAttribute(<key>, <value>)
- 设置请求跟踪的属性。key
,应该是字符串,第二个是value
,可以是字符串或数字(整数或双精度数)。Request.Trace.AddEvent(<name>, <attributes>)
- 向请求跟踪的第一个跨度添加事件name
的字符串应该是第一个参数,然后是可选的事件attributes
,对于没有属性的事件。
背景上下文
The background
上下文可用于分析、监控、为其他上下文执行缓存数据等目的。
数据上下文
双getdata
和putdata
上下文具有以下字段:Data
读取-only且可迭代(字节逐字节)。如果对象在多个块中上传或检索,则Data
字段将一次包含一个块的数据。Offset
包含块在整个对象中的偏移量。Request
字段和背景RGW
表也可用。
全局RGW表
The RGW
Lua表可以从所有上下文中访问,并在执行期间保存写入它的数据,以便稍后在同一上下文或不同上下文中读取和使用。RGW
Lua表,当守护进程重新启动时它会丢失。请注意,background
上下文脚本将在每个实例上运行。RGW
Lua表使用字符串索引,可以存储以下类型的值:字符串、整数、双精度数和布尔值
增减函数
由于RGW
表中的条目可能同时从多个位置访问,我们需要一种原子方式来增减其中的数值。为此,应使用以下函数:RGW.increment(<key>, [value])
将key
的值减少value
(如果提供值)或1(如果不提供)RGW.decrement(<key>, [value])
将key
的值减少value
(如果提供值)或1(如果不提供)key
的值不是数字,脚本执行将失败
Lua代码示例
在复制的情况下打印源和目标对象的信息:
function print_object(object)
RGWDebugLog(" Name: " .. object.Name)
RGWDebugLog(" Instance: " .. object.Instance)
RGWDebugLog(" Id: " .. object.Id)
RGWDebugLog(" Size: " .. object.Size)
RGWDebugLog(" MTime: " .. object.MTime)
end
if Request.CopyFrom and Request.Object and Request.CopyFrom.Object then
RGWDebugLog("copy from object:")
print_object(Request.CopyFrom.Object)
RGWDebugLog("to object:")
print_object(Request.Object)
end
通过“通用函数”打印ACL:
function print_owner(owner)
RGWDebugLog("Owner:")
RGWDebugLog(" Display Name: " .. owner.DisplayName)
RGWDebugLog(" Id: " .. owner.User.Id)
RGWDebugLog(" Tenant: " .. owner.User.Tenant)
end
function print_acl(acl_type)
index = acl_type .. "ACL"
acl = Request[index]
if acl then
RGWDebugLog(acl_type .. "ACL Owner")
print_owner(acl.Owner)
RGWDebugLog(" there are " .. #acl.Grants .. " grant for owner")
for k,v in pairs(acl.Grants) do
RGWDebugLog(" Grant Key: " .. k)
RGWDebugLog(" Grant Type: " .. v.Type)
RGWDebugLog(" Grant Group Type: " .. v.GroupType)
RGWDebugLog(" Grant Referer: " .. v.Referer)
RGWDebugLog(" Grant User Tenant: " .. v.User.Tenant)
RGWDebugLog(" Grant User Id: " .. v.User.Id)
end
else
RGWDebugLog("no " .. acl_type .. " ACL in request: " .. Request.Id)
end
end
print_acl("User")
print_acl("Bucket")
print_acl("Object")
仅在错误情况下使用操作日志:
if Request.Response.HTTPStatusCode ~= 200 then
RGWDebugLog("request is bad, use ops log")
rc = Request.Log()
RGWDebugLog("ops log return code: " .. rc)
end
将值设置到错误消息中:
if Request.Response.HTTPStatusCode == 500 then
Request.Response.Message = "<Message> something bad happened :-( </Message>"
end
向对象添加客户端未原始发送的元数据:
在prerequest
在
if Request.RGWOp == 'put_obj' then
Request.HTTP.Metadata["x-amz-meta-mydata"] = "my value"
end
在postrequest
在我们查看元数据时,上下文为:
RGWDebugLog("number of metadata entries is: " .. #Request.HTTP.Metadata)
for k, v in pairs(Request.HTTP.Metadata) do
RGWDebugLog("key=" .. k .. ", " .. "value=" .. v)
end
使用模块创建基于Unix套接字的JSON编码“访问日志”:
首先,我们应该将以下软件包添加到允许列表:
# radosgw-admin script-package add --package=lua-cjson --allow-compilation
# radosgw-admin script-package add --package=luasocket --allow-compilation
然后,运行一个服务器来监听Unix套接字。例如,使用“netcat”:
# rm -f /tmp/socket
# nc -vklU /tmp/socket
最后,重新启动radosgw并上传以下脚本到postrequest
上下文:
if Request.RGWOp == "get_obj" then
local json = require("cjson")
local socket = require("socket")
local unix = require("socket.unix")
local s = assert(unix())
E = {}
msg = {bucket = (Request.Bucket or (Request.CopyFrom or E).Bucket).Name,
time = Request.Time,
operation = Request.RGWOp,
http_status = Request.Response.HTTPStatusCode,
error_code = Request.Response.HTTPStatus,
object_size = Request.Object.Size,
trans_id = Request.TransactionId}
assert(s:connect("/tmp/socket"))
assert(s:send(json.encode(msg).."\n"))
assert(s:close())
end
仅跟踪特定桶的请求
跟踪默认情况下是禁用的,因此我们应该为此特定桶启用跟踪
if Request.Bucket.Name == "my-bucket" then
Request.Trace.Enable = true
end
如果跟踪已启用在RGW上,Request.Trace.Enable的值为true,因此我们应该禁用与桶名称不匹配的所有其他请求的跟踪。prerequest
上下文:
if Request.Bucket.Name ~= "my-bucket" then
Request.Trace.Enable = false
end
注意,更改Request.Trace.Enable
不会改变跟踪器的状态,但会禁用或启用仅针对请求的跟踪。
为请求跟踪添加信息
in postrequest
在
Request.Trace.AddEvent("lua script execution started")
Request.Trace.SetAttribute("HTTPStatusCode", Request.Response.HTTPStatusCode)
event_attrs = {}
for k,v in pairs(Request.GenericAttributes) do
event_attrs[k] = v
end
Request.Trace.AddEvent("second event", event_attrs)
对象的熵值可用于检测对象是否加密。
。Cephadm 还支持使用putdata
上下文中,添加以下脚本
function object_entropy()
local byte_hist = {}
local byte_hist_size = 256
for i = 1,byte_hist_size do
byte_hist[i] = 0
end
local total = 0
for i, c in pairs(Data) do
local byte = c:byte() + 1
byte_hist[byte] = byte_hist[byte] + 1
total = total + 1
end
entropy = 0
for _, count in ipairs(byte_hist) do
if count ~= 0 then
local p = 1.0 * count / total
entropy = entropy - (p * math.log(p)/math.log(byte_hist_size))
end
end
return entropy
end
local full_name = Request.Bucket.Name.."\\"..Request.Object.Name
RGWDebugLog("entropy of chunk of: " .. full_name .. " at offset:" .. tostring(Offset) .. " is: " .. tostring(object_entropy()))
RGWDebugLog("payload size of chunk of: " .. full_name .. " is: " .. #Data)
由 Ceph 基金会带给您
Ceph 文档是一个社区资源,由非盈利的 Ceph 基金会资助和托管Ceph Foundation. 如果您想支持这一点和我们的其他工作,请考虑加入现在加入.