mirror of
https://github.com/ceph/ceph
synced 2025-02-24 03:27:10 +00:00
rgw: Lua scripting global map feature
Adding a lua background class. This class aims to allow to run a background Lua script and bind a shared Lua table with a cpp map. Signed-off-by: Matan Breizman <Matan.Brz@gmail.com>
This commit is contained in:
parent
74e57a6ab2
commit
4856c7d514
@ -6,9 +6,10 @@ Lua Scripting
|
||||
|
||||
.. contents::
|
||||
|
||||
This feature allows users to upload Lua scripts to different context in the radosgw. The two supported context are "preRequest" that will execute a script before the
|
||||
operation was taken, and "postRequest" that will execute after each operation is taken. Script may be uploaded to address requests for users of a specific tenant.
|
||||
The script can access fields in the request and modify some fields. All Lua language features can be used in the script.
|
||||
This feature allows users to upload Lua scripts to different context in the radosgw. The three supported contexts are "preRequest" that will execute a script before the
|
||||
operation was taken, "postRequest" that will execute after each operation is taken and "background" that will execute a script in a given time interval.
|
||||
Request context script may be uploaded to address requests for users of a specific tenant.
|
||||
The request context script can also access fields in the request and modify some fields. All Lua language features can be used in the script.
|
||||
|
||||
By default, all lua standard libraries are available in the script, however, in order to allow for other lua modules to be used in the script, we support adding packages to an allowlist:
|
||||
|
||||
@ -28,23 +29,27 @@ Script Management via CLI
|
||||
|
||||
To upload a script:
|
||||
|
||||
|
||||
::
|
||||
|
||||
# radosgw-admin script put --infile={lua-file} --context={preRequest|postRequest} [--tenant={tenant-name}]
|
||||
# radosgw-admin script put --infile={lua-file} --context={preRequest|postRequest|background} [--tenant={tenant-name}]
|
||||
|
||||
|
||||
* When uploading a script in background context, tenant name could not be specified.
|
||||
|
||||
|
||||
To print the content of the script to standard output:
|
||||
|
||||
::
|
||||
|
||||
# radosgw-admin script get --context={preRequest|postRequest} [--tenant={tenant-name}]
|
||||
# radosgw-admin script get --context={preRequest|postRequest|background} [--tenant={tenant-name}]
|
||||
|
||||
|
||||
To remove the script:
|
||||
|
||||
::
|
||||
|
||||
# radosgw-admin script rm --context={preRequest|postRequest} [--tenant={tenant-name}]
|
||||
# radosgw-admin script rm --context={preRequest|postRequest|background} [--tenant={tenant-name}]
|
||||
|
||||
|
||||
Package Management via CLI
|
||||
@ -297,6 +302,23 @@ Operations Log
|
||||
~~~~~~~~~~~~~~
|
||||
The ``Request.Log()`` function prints the requests into the operations log. This function has no parameters. It returns 0 for success and an error code if it fails.
|
||||
|
||||
Background Context
|
||||
--------------------
|
||||
The background context may be used for various need such as analytics, monitoring and
|
||||
caching data from other context executions.
|
||||
|
||||
The ``RGW`` Lua table which is accesible from any context saves the data written into it
|
||||
while execution and this data could be read and used later in any other execution.
|
||||
|
||||
- Background script execution default interval is 5 seconds.
|
||||
|
||||
- Each RGW instance has its own ``RGW`` Lua table, while the Background Context script
|
||||
will run on every instance.
|
||||
|
||||
- The maximum number of entries in the table is 100,000. Each entry has a key and string value
|
||||
of no more than 1KB (together). Lua script will abort with an error if the
|
||||
number of entries or entry size exceeds their limits.
|
||||
|
||||
Lua Code Samples
|
||||
----------------
|
||||
- Print information on source and destination objects in case of copy:
|
||||
|
@ -162,7 +162,8 @@ set(librgw_common_srcs
|
||||
rgw_lua_utils.cc
|
||||
rgw_lua.cc
|
||||
rgw_bucket_encryption.cc
|
||||
rgw_tracer.cc)
|
||||
rgw_tracer.cc
|
||||
rgw_lua_background.cc)
|
||||
|
||||
if(WITH_RADOSGW_AMQP_ENDPOINT)
|
||||
list(APPEND librgw_common_srcs rgw_amqp.cc)
|
||||
@ -357,7 +358,10 @@ add_library(radosgw SHARED
|
||||
target_compile_definitions(radosgw PUBLIC "-DCLS_CLIENT_HIDE_IOCTX")
|
||||
target_include_directories(radosgw
|
||||
PUBLIC "${CMAKE_SOURCE_DIR}/src/dmclock/support/src"
|
||||
PRIVATE "${CMAKE_SOURCE_DIR}/src/libkmip")
|
||||
PRIVATE "${CMAKE_SOURCE_DIR}/src/libkmip"
|
||||
PUBLIC "${CMAKE_SOURCE_DIR}/src/rgw"
|
||||
PRIVATE "${LUA_INCLUDE_DIR}")
|
||||
|
||||
target_include_directories(radosgw SYSTEM PUBLIC "../rapidjson/include")
|
||||
|
||||
target_link_libraries(radosgw
|
||||
|
@ -454,7 +454,7 @@ void usage()
|
||||
cout << " --subscription pubsub subscription name\n";
|
||||
cout << " --event-id event id in a pubsub subscription\n";
|
||||
cout << "\nScript options:\n";
|
||||
cout << " --context context in which the script runs. one of: preRequest, postRequest\n";
|
||||
cout << " --context context in which the script runs. one of: preRequest, postRequest, background\n";
|
||||
cout << " --package name of the lua package that should be added/removed to/from the allowlist\n";
|
||||
cout << " --allow-compilation package is allowed to compile C code as part of its installation\n";
|
||||
cout << "\nradoslist options:\n";
|
||||
@ -10037,7 +10037,11 @@ next:
|
||||
}
|
||||
const rgw::lua::context script_ctx = rgw::lua::to_context(*str_script_ctx);
|
||||
if (script_ctx == rgw::lua::context::none) {
|
||||
cerr << "ERROR: invalid script context: " << *str_script_ctx << ". must be one of: preRequest, postRequest" << std::endl;
|
||||
cerr << "ERROR: invalid script context: " << *str_script_ctx << ". must be one of: preRequest, postRequest, background" << std::endl;
|
||||
return EINVAL;
|
||||
}
|
||||
if (script_ctx == rgw::lua::context::background && !tenant.empty()) {
|
||||
cerr << "ERROR: cannot specify tenant in background context" << std::endl;
|
||||
return EINVAL;
|
||||
}
|
||||
rc = rgw::lua::write_script(dpp(), store, tenant, null_yield, script_ctx, script);
|
||||
@ -10054,7 +10058,7 @@ next:
|
||||
}
|
||||
const rgw::lua::context script_ctx = rgw::lua::to_context(*str_script_ctx);
|
||||
if (script_ctx == rgw::lua::context::none) {
|
||||
cerr << "ERROR: invalid script context: " << *str_script_ctx << ". must be one of: preRequest, postRequest" << std::endl;
|
||||
cerr << "ERROR: invalid script context: " << *str_script_ctx << ". must be one of: preRequest, postRequest, background" << std::endl;
|
||||
return EINVAL;
|
||||
}
|
||||
std::string script;
|
||||
@ -10077,7 +10081,7 @@ next:
|
||||
}
|
||||
const rgw::lua::context script_ctx = rgw::lua::to_context(*str_script_ctx);
|
||||
if (script_ctx == rgw::lua::context::none) {
|
||||
cerr << "ERROR: invalid script context: " << *str_script_ctx << ". must be one of: preRequest, postRequest" << std::endl;
|
||||
cerr << "ERROR: invalid script context: " << *str_script_ctx << ". must be one of: preRequest, postRequest, background" << std::endl;
|
||||
return EINVAL;
|
||||
}
|
||||
const auto rc = rgw::lua::delete_script(dpp(), store, tenant, null_yield, script_ctx);
|
||||
|
@ -269,7 +269,7 @@ void handle_connection(boost::asio::io_context& context,
|
||||
*env.auth_registry, &client, env.olog, y,
|
||||
scheduler, &user, &latency,
|
||||
env.ratelimiting->get_active(),
|
||||
&http_ret);
|
||||
&http_ret, env.lua_background);
|
||||
|
||||
if (cct->_conf->subsys.should_gather(dout_subsys, 1)) {
|
||||
// access log line elements begin per Apache Combined Log Format with additions following
|
||||
|
@ -137,7 +137,7 @@ void RGWLoadGenProcess::handle_request(const DoutPrefixProvider *dpp, RGWRequest
|
||||
int ret = process_request(store, rest, req, uri_prefix,
|
||||
*auth_registry, &client_io, olog,
|
||||
null_yield, nullptr, nullptr, nullptr,
|
||||
ratelimit.get_active());
|
||||
ratelimit.get_active(), nullptr);
|
||||
if (ret < 0) {
|
||||
/* we don't really care about return code */
|
||||
dout(20) << "process_request() returned " << ret << dendl;
|
||||
|
@ -23,6 +23,9 @@ context to_context(const std::string& s)
|
||||
if (strcasecmp(s.c_str(), "postrequest") == 0) {
|
||||
return context::postRequest;
|
||||
}
|
||||
if (strcasecmp(s.c_str(), "background") == 0) {
|
||||
return context::background;
|
||||
}
|
||||
return context::none;
|
||||
}
|
||||
|
||||
@ -33,6 +36,8 @@ std::string to_string(context ctx)
|
||||
return "prerequest";
|
||||
case context::postRequest:
|
||||
return "postrequest";
|
||||
case context::background:
|
||||
return "background";
|
||||
case context::none:
|
||||
break;
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ namespace rgw::lua {
|
||||
enum class context {
|
||||
preRequest,
|
||||
postRequest,
|
||||
background,
|
||||
none
|
||||
};
|
||||
|
||||
|
56
src/rgw/rgw_lua_background.cc
Normal file
56
src/rgw/rgw_lua_background.cc
Normal file
@ -0,0 +1,56 @@
|
||||
#include "rgw_lua_background.h"
|
||||
#include "rgw_lua.h"
|
||||
#include "rgw_lua_utils.h"
|
||||
#include "include/ceph_assert.h"
|
||||
#include <lua.hpp>
|
||||
|
||||
namespace rgw::lua {
|
||||
|
||||
void Background::shutdown(){
|
||||
this->stop();
|
||||
runner.join();
|
||||
}
|
||||
void Background::stop(){
|
||||
stopped = true;
|
||||
}
|
||||
|
||||
//(1) Loads the script from the object
|
||||
//(2) Executes the script
|
||||
//(3) Sleep (configurable)
|
||||
void Background::run() {
|
||||
lua_State* const L = luaL_newstate();
|
||||
rgw::lua::lua_state_guard lguard(L);
|
||||
open_standard_libs(L);
|
||||
set_package_path(L, luarocks_path);
|
||||
create_debug_action(L, cct->get());
|
||||
create_background_metatable(L);
|
||||
|
||||
while (!stopped) {
|
||||
|
||||
std::string tenant;
|
||||
auto rc = rgw::lua::read_script(dpp, store, tenant, null_yield, rgw::lua::context::background, rgw_script);
|
||||
if (rc == -ENOENT) {
|
||||
// no script, nothing to do
|
||||
} else if (rc < 0) {
|
||||
ldpp_dout(dpp, 1) << "WARNING: failed to read background script. error " << rc << dendl;
|
||||
} else {
|
||||
try {
|
||||
//execute the background lua script
|
||||
if (luaL_dostring(L, rgw_script.c_str()) != LUA_OK) {
|
||||
const std::string err(lua_tostring(L, -1));
|
||||
ldpp_dout(dpp, 1) << "Lua ERROR: " << err << dendl;
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
ldpp_dout(dpp, 1) << "Lua ERROR: " << e.what() << dendl;
|
||||
}
|
||||
}
|
||||
std::this_thread::sleep_for(std::chrono::seconds(execute_interval));
|
||||
}
|
||||
}
|
||||
|
||||
void Background::create_background_metatable(lua_State* L) {
|
||||
create_metatable<rgw::lua::RGWTable>(L, true, &rgw_map, &m_mutex);
|
||||
}
|
||||
|
||||
} //namespace lua
|
||||
|
73
src/rgw/rgw_lua_background.h
Normal file
73
src/rgw/rgw_lua_background.h
Normal file
@ -0,0 +1,73 @@
|
||||
#pragma once
|
||||
#include "common/dout.h"
|
||||
#include "rgw_common.h"
|
||||
#include <string>
|
||||
#include "rgw_lua_utils.h"
|
||||
|
||||
namespace rgw::lua {
|
||||
|
||||
//Interval between each execution of the script is set to 5 seconds
|
||||
constexpr const int INIT_EXECUTE_INTERVAL = 5;
|
||||
|
||||
//Writeable meta table named RGW with mutex protection
|
||||
using BackgroundMap = std::unordered_map<std::string, std::string>;
|
||||
struct RGWTable : StringMapMetaTable<BackgroundMap,
|
||||
StringMapWriteableNewIndex<BackgroundMap>> {
|
||||
static std::string TableName() {return "RGW";}
|
||||
static std::string Name() {return TableName() + "Meta";}
|
||||
static int IndexClosure(lua_State* L) {
|
||||
auto& mtx = *reinterpret_cast<std::mutex*>(lua_touserdata(L, lua_upvalueindex(2)));
|
||||
std::lock_guard l(mtx);
|
||||
return StringMapMetaTable::IndexClosure(L);
|
||||
}
|
||||
static int LenClosure(lua_State* L) {
|
||||
auto& mtx = *reinterpret_cast<std::mutex*>(lua_touserdata(L, lua_upvalueindex(2)));
|
||||
std::lock_guard l(mtx);
|
||||
return StringMapMetaTable::LenClosure(L);
|
||||
}
|
||||
static int NewIndexClosure(lua_State* L) {
|
||||
auto& mtx = *reinterpret_cast<std::mutex*>(lua_touserdata(L, lua_upvalueindex(2)));
|
||||
std::lock_guard l(mtx);
|
||||
return StringMapMetaTable::NewIndexClosure(L);
|
||||
}
|
||||
};
|
||||
|
||||
class Background {
|
||||
|
||||
private:
|
||||
BackgroundMap rgw_map;
|
||||
std::string rgw_script;
|
||||
bool stopped = false;
|
||||
int execute_interval = INIT_EXECUTE_INTERVAL;
|
||||
const DoutPrefixProvider* const dpp;
|
||||
rgw::sal::Store* const store;
|
||||
CephContext* const cct;
|
||||
std::string luarocks_path;
|
||||
std::thread runner;
|
||||
std::mutex m_mutex;
|
||||
|
||||
void run();
|
||||
|
||||
public:
|
||||
Background(const DoutPrefixProvider* dpp,
|
||||
rgw::sal::Store* store,
|
||||
CephContext* cct,
|
||||
const std::string& luarocks_path) :
|
||||
dpp(dpp),
|
||||
store(store),
|
||||
cct(cct),
|
||||
luarocks_path(luarocks_path),
|
||||
runner(std::thread(&Background::run, this)) {
|
||||
const auto rc = ceph_pthread_setname(runner.native_handle(),
|
||||
"lua_background");
|
||||
ceph_assert(rc == 0);
|
||||
}
|
||||
|
||||
~Background() = default;
|
||||
void stop();
|
||||
void shutdown();
|
||||
void create_background_metatable(lua_State* L);
|
||||
};
|
||||
|
||||
} //namepsace lua
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "rgw_zone.h"
|
||||
#include "rgw_acl.h"
|
||||
#include "rgw_sal_rados.h"
|
||||
#include "rgw_lua_background.h"
|
||||
|
||||
#define dout_subsys ceph_subsys_rgw
|
||||
|
||||
@ -241,90 +242,6 @@ struct ObjectMetaTable : public EmptyMetaTable {
|
||||
}
|
||||
};
|
||||
|
||||
typedef int MetaTableClosure(lua_State* L);
|
||||
|
||||
template<typename MapType>
|
||||
int StringMapWriteableNewIndex(lua_State* L) {
|
||||
const auto map = reinterpret_cast<MapType*>(lua_touserdata(L, lua_upvalueindex(1)));
|
||||
|
||||
const char* index = luaL_checkstring(L, 2);
|
||||
const char* value = luaL_checkstring(L, 3);
|
||||
map->insert_or_assign(index, value);
|
||||
return NO_RETURNVAL;
|
||||
}
|
||||
|
||||
template<typename MapType=std::map<std::string, std::string>,
|
||||
MetaTableClosure NewIndex=EmptyMetaTable::NewIndexClosure>
|
||||
struct StringMapMetaTable : public EmptyMetaTable {
|
||||
|
||||
static std::string TableName() {return "StringMap";}
|
||||
static std::string Name() {return TableName() + "Meta";}
|
||||
|
||||
static int IndexClosure(lua_State* L) {
|
||||
const auto map = reinterpret_cast<MapType*>(lua_touserdata(L, lua_upvalueindex(1)));
|
||||
|
||||
const char* index = luaL_checkstring(L, 2);
|
||||
|
||||
const auto it = map->find(std::string(index));
|
||||
if (it == map->end()) {
|
||||
lua_pushnil(L);
|
||||
} else {
|
||||
pushstring(L, it->second);
|
||||
}
|
||||
return ONE_RETURNVAL;
|
||||
}
|
||||
|
||||
static int NewIndexClosure(lua_State* L) {
|
||||
return NewIndex(L);
|
||||
}
|
||||
|
||||
static int PairsClosure(lua_State* L) {
|
||||
auto map = reinterpret_cast<MapType*>(lua_touserdata(L, lua_upvalueindex(1)));
|
||||
ceph_assert(map);
|
||||
lua_pushlightuserdata(L, map);
|
||||
lua_pushcclosure(L, stateless_iter, ONE_UPVAL); // push the stateless iterator function
|
||||
lua_pushnil(L); // indicate this is the first call
|
||||
// return stateless_iter, nil
|
||||
|
||||
return TWO_RETURNVALS;
|
||||
}
|
||||
|
||||
static int stateless_iter(lua_State* L) {
|
||||
// based on: http://lua-users.org/wiki/GeneralizedPairsAndIpairs
|
||||
auto map = reinterpret_cast<MapType*>(lua_touserdata(L, lua_upvalueindex(1)));
|
||||
typename MapType::const_iterator next_it;
|
||||
if (lua_isnil(L, -1)) {
|
||||
next_it = map->begin();
|
||||
} else {
|
||||
const char* index = luaL_checkstring(L, 2);
|
||||
const auto it = map->find(std::string(index));
|
||||
ceph_assert(it != map->end());
|
||||
next_it = std::next(it);
|
||||
}
|
||||
|
||||
if (next_it == map->end()) {
|
||||
// index of the last element was provided
|
||||
lua_pushnil(L);
|
||||
lua_pushnil(L);
|
||||
// return nil, nil
|
||||
} else {
|
||||
pushstring(L, next_it->first);
|
||||
pushstring(L, next_it->second);
|
||||
// return key, value
|
||||
}
|
||||
|
||||
return TWO_RETURNVALS;
|
||||
}
|
||||
|
||||
static int LenClosure(lua_State* L) {
|
||||
const auto map = reinterpret_cast<MapType*>(lua_touserdata(L, lua_upvalueindex(1)));
|
||||
|
||||
lua_pushinteger(L, map->size());
|
||||
|
||||
return ONE_RETURNVAL;
|
||||
}
|
||||
};
|
||||
|
||||
struct GrantMetaTable : public EmptyMetaTable {
|
||||
static std::string TableName() {return "Grant";}
|
||||
static std::string Name() {return TableName() + "Meta";}
|
||||
@ -799,7 +716,8 @@ int execute(
|
||||
OpsLogSink* olog,
|
||||
req_state* s,
|
||||
const char* op_name,
|
||||
const std::string& script)
|
||||
const std::string& script,
|
||||
rgw::lua::Background* background)
|
||||
|
||||
{
|
||||
auto L = luaL_newstate();
|
||||
@ -811,12 +729,13 @@ int execute(
|
||||
"");
|
||||
|
||||
create_debug_action(L, s->cct);
|
||||
|
||||
create_metatable<RequestMetaTable>(L, true, s, const_cast<char*>(op_name));
|
||||
|
||||
// add the ops log action
|
||||
create_metatable<RequestMetaTable>(L, true, s, const_cast<char*>(op_name));
|
||||
|
||||
lua_getglobal(L, RequestMetaTable::TableName().c_str());
|
||||
ceph_assert(lua_istable(L, -1));
|
||||
|
||||
// add the ops log action
|
||||
pushstring(L, RequestLogAction);
|
||||
lua_pushlightuserdata(L, rest);
|
||||
lua_pushlightuserdata(L, olog);
|
||||
@ -824,6 +743,12 @@ int execute(
|
||||
lua_pushlightuserdata(L, const_cast<char*>(op_name));
|
||||
lua_pushcclosure(L, RequestLog, FOUR_UPVALS);
|
||||
lua_rawset(L, -3);
|
||||
|
||||
if (background) {
|
||||
background->create_background_metatable(L);
|
||||
lua_getglobal(L, rgw::lua::RGWTable::TableName().c_str());
|
||||
ceph_assert(lua_istable(L, -1));
|
||||
}
|
||||
|
||||
try {
|
||||
// execute the lua script
|
||||
|
@ -9,6 +9,9 @@ class OpsLogSink;
|
||||
namespace rgw::sal {
|
||||
class Store;
|
||||
}
|
||||
namespace rgw::lua {
|
||||
class Background;
|
||||
}
|
||||
|
||||
namespace rgw::lua::request {
|
||||
|
||||
@ -19,7 +22,8 @@ int execute(
|
||||
OpsLogSink* olog,
|
||||
req_state *s,
|
||||
const char* op_name,
|
||||
const std::string& script);
|
||||
const std::string& script,
|
||||
rgw::lua::Background* background = nullptr);
|
||||
|
||||
}
|
||||
|
||||
|
@ -43,6 +43,9 @@ public:
|
||||
void reset(lua_State* _l=nullptr) {l = _l;}
|
||||
};
|
||||
|
||||
constexpr const int MAX_LUA_VALUE_SIZE = 1000;
|
||||
constexpr const int MAX_LUA_KEY_ENTRIES = 100000;
|
||||
|
||||
constexpr auto ONE_UPVAL = 1;
|
||||
constexpr auto TWO_UPVALS = 2;
|
||||
constexpr auto THREE_UPVALS = 3;
|
||||
@ -193,5 +196,101 @@ void set_package_path(lua_State* L, const std::string& install_dir);
|
||||
// and the "debug" library
|
||||
void open_standard_libs(lua_State* L);
|
||||
|
||||
typedef int MetaTableClosure(lua_State* L);
|
||||
|
||||
template<typename MapType>
|
||||
int StringMapWriteableNewIndex(lua_State* L) {
|
||||
const auto map = reinterpret_cast<MapType*>(lua_touserdata(L, lua_upvalueindex(1)));
|
||||
|
||||
const char* index = luaL_checkstring(L, 2);
|
||||
|
||||
if (lua_isnil(L, 3) == 0) {
|
||||
const char* value = luaL_checkstring(L, 3);
|
||||
if (strnlen(value, MAX_LUA_VALUE_SIZE) + strnlen(index, MAX_LUA_VALUE_SIZE)
|
||||
> MAX_LUA_VALUE_SIZE) {
|
||||
return luaL_error(L, "Lua maximum size of entry limit exceeded");
|
||||
} else if (map->size() > MAX_LUA_KEY_ENTRIES) {
|
||||
return luaL_error(L, "Lua max number of entries limit exceeded");
|
||||
} else {
|
||||
map->insert_or_assign(index, value);
|
||||
}
|
||||
} else {
|
||||
map->erase(std::string(index));
|
||||
}
|
||||
|
||||
return NO_RETURNVAL;
|
||||
}
|
||||
|
||||
template<typename MapType=std::map<std::string, std::string>,
|
||||
MetaTableClosure NewIndex=EmptyMetaTable::NewIndexClosure>
|
||||
struct StringMapMetaTable : public EmptyMetaTable {
|
||||
|
||||
static std::string TableName() {return "StringMap";}
|
||||
static std::string Name() {return TableName() + "Meta";}
|
||||
|
||||
static int IndexClosure(lua_State* L) {
|
||||
const auto map = reinterpret_cast<MapType*>(lua_touserdata(L, lua_upvalueindex(1)));
|
||||
|
||||
const char* index = luaL_checkstring(L, 2);
|
||||
|
||||
const auto it = map->find(std::string(index));
|
||||
if (it == map->end()) {
|
||||
lua_pushnil(L);
|
||||
} else {
|
||||
pushstring(L, it->second);
|
||||
}
|
||||
return ONE_RETURNVAL;
|
||||
}
|
||||
|
||||
static int NewIndexClosure(lua_State* L) {
|
||||
return NewIndex(L);
|
||||
}
|
||||
|
||||
static int PairsClosure(lua_State* L) {
|
||||
auto map = reinterpret_cast<MapType*>(lua_touserdata(L, lua_upvalueindex(1)));
|
||||
ceph_assert(map);
|
||||
lua_pushlightuserdata(L, map);
|
||||
lua_pushcclosure(L, stateless_iter, ONE_UPVAL); // push the stateless iterator function
|
||||
lua_pushnil(L); // indicate this is the first call
|
||||
// return stateless_iter, nil
|
||||
|
||||
return TWO_RETURNVALS;
|
||||
}
|
||||
|
||||
static int stateless_iter(lua_State* L) {
|
||||
// based on: http://lua-users.org/wiki/GeneralizedPairsAndIpairs
|
||||
auto map = reinterpret_cast<MapType*>(lua_touserdata(L, lua_upvalueindex(1)));
|
||||
typename MapType::const_iterator next_it;
|
||||
if (lua_isnil(L, -1)) {
|
||||
next_it = map->begin();
|
||||
} else {
|
||||
const char* index = luaL_checkstring(L, 2);
|
||||
const auto it = map->find(std::string(index));
|
||||
ceph_assert(it != map->end());
|
||||
next_it = std::next(it);
|
||||
}
|
||||
|
||||
if (next_it == map->end()) {
|
||||
// index of the last element was provided
|
||||
lua_pushnil(L);
|
||||
lua_pushnil(L);
|
||||
// return nil, nil
|
||||
} else {
|
||||
pushstring(L, next_it->first);
|
||||
pushstring(L, next_it->second);
|
||||
// return key, value
|
||||
}
|
||||
|
||||
return TWO_RETURNVALS;
|
||||
}
|
||||
|
||||
static int LenClosure(lua_State* L) {
|
||||
const auto map = reinterpret_cast<MapType*>(lua_touserdata(L, lua_upvalueindex(1)));
|
||||
|
||||
lua_pushinteger(L, map->size());
|
||||
|
||||
return ONE_RETURNVAL;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -58,6 +58,7 @@
|
||||
#ifdef WITH_RADOSGW_DBSTORE
|
||||
#include "rgw_sal_dbstore.h"
|
||||
#endif
|
||||
#include "rgw_lua_background.h"
|
||||
|
||||
#include "services/svc_zone.h"
|
||||
|
||||
@ -605,6 +606,8 @@ int radosgw_Main(int argc, const char **argv)
|
||||
|
||||
int fe_count = 0;
|
||||
|
||||
rgw::lua::Background lua_background(&dp, store, cct.get(), store->get_luarocks_path());
|
||||
|
||||
for (multimap<string, RGWFrontendConfig *>::iterator fiter = fe_map.begin();
|
||||
fiter != fe_map.end(); ++fiter, ++fe_count) {
|
||||
RGWFrontendConfig *config = fiter->second;
|
||||
@ -623,7 +626,8 @@ int radosgw_Main(int argc, const char **argv)
|
||||
std::string uri_prefix;
|
||||
config->get_val("prefix", "", &uri_prefix);
|
||||
|
||||
RGWProcessEnv env = { store, &rest, olog, port, uri_prefix, auth_registry, &ratelimiting };
|
||||
RGWProcessEnv env = { store, &rest, olog, port, uri_prefix,
|
||||
auth_registry, &ratelimiting, &lua_background};
|
||||
|
||||
fe = new RGWLoadGenFrontend(env, config);
|
||||
}
|
||||
@ -632,7 +636,8 @@ int radosgw_Main(int argc, const char **argv)
|
||||
config->get_val("port", 80, &port);
|
||||
std::string uri_prefix;
|
||||
config->get_val("prefix", "", &uri_prefix);
|
||||
RGWProcessEnv env{ store, &rest, olog, port, uri_prefix, auth_registry, &ratelimiting };
|
||||
RGWProcessEnv env{ store, &rest, olog, port, uri_prefix,
|
||||
auth_registry, &ratelimiting, &lua_background};
|
||||
fe = new RGWAsioFrontend(env, config, sched_ctx);
|
||||
}
|
||||
|
||||
@ -740,6 +745,8 @@ int radosgw_Main(int argc, const char **argv)
|
||||
rgw::kafka::shutdown();
|
||||
#endif
|
||||
|
||||
lua_background.shutdown();
|
||||
|
||||
rgw_perf_stop(g_ceph_context);
|
||||
|
||||
dout(1) << "final shutdown" << dendl;
|
||||
|
@ -273,10 +273,10 @@ int process_request(rgw::sal::Store* const store,
|
||||
string* user,
|
||||
ceph::coarse_real_clock::duration* latency,
|
||||
std::shared_ptr<RateLimiter> ratelimit,
|
||||
int* http_ret)
|
||||
int* http_ret,
|
||||
rgw::lua::Background* lua_background)
|
||||
{
|
||||
int ret = client_io->init(g_ceph_context);
|
||||
|
||||
dout(1) << "====== starting new request req=" << hex << req << dec
|
||||
<< " =====" << dendl;
|
||||
perfcounter->inc(l_rgw_req);
|
||||
@ -335,7 +335,7 @@ int process_request(rgw::sal::Store* const store,
|
||||
} else if (rc < 0) {
|
||||
ldpp_dout(op, 5) << "WARNING: failed to read pre request script. error: " << rc << dendl;
|
||||
} else {
|
||||
rc = rgw::lua::request::execute(store, rest, olog, s, op->name(), script);
|
||||
rc = rgw::lua::request::execute(store, rest, olog, s, op->name(), script, lua_background);
|
||||
if (rc < 0) {
|
||||
ldpp_dout(op, 5) << "WARNING: failed to execute pre request script. error: " << rc << dendl;
|
||||
}
|
||||
@ -417,7 +417,7 @@ done:
|
||||
} else if (rc < 0) {
|
||||
ldpp_dout(op, 5) << "WARNING: failed to read post request script. error: " << rc << dendl;
|
||||
} else {
|
||||
rc = rgw::lua::request::execute(store, rest, olog, s, op->name(), script);
|
||||
rc = rgw::lua::request::execute(store, rest, olog, s, op->name(), script, lua_background);
|
||||
if (rc < 0) {
|
||||
ldpp_dout(op, 5) << "WARNING: failed to execute post request script. error: " << rc << dendl;
|
||||
}
|
||||
|
@ -30,6 +30,9 @@ extern void signal_shutdown();
|
||||
namespace rgw::dmclock {
|
||||
class Scheduler;
|
||||
}
|
||||
namespace rgw::lua {
|
||||
class Background;
|
||||
}
|
||||
|
||||
struct RGWProcessEnv {
|
||||
rgw::sal::Store* store;
|
||||
@ -40,6 +43,7 @@ struct RGWProcessEnv {
|
||||
std::shared_ptr<rgw::auth::StrategyRegistry> auth_registry;
|
||||
//maybe there is a better place to store the rate limit data structure
|
||||
ActiveRateLimiter* ratelimiting;
|
||||
rgw::lua::Background* lua_background;
|
||||
};
|
||||
|
||||
class RGWFrontendConfig;
|
||||
@ -58,6 +62,7 @@ protected:
|
||||
RGWFrontendConfig* conf;
|
||||
int sock_fd;
|
||||
std::string uri_prefix;
|
||||
rgw::lua::Background* lua_background;
|
||||
|
||||
struct RGWWQ : public DoutPrefixProvider, public ThreadPool::WorkQueue<RGWRequest> {
|
||||
RGWProcess* process;
|
||||
@ -109,6 +114,7 @@ public:
|
||||
conf(conf),
|
||||
sock_fd(-1),
|
||||
uri_prefix(pe->uri_prefix),
|
||||
lua_background(pe->lua_background),
|
||||
req_wq(this,
|
||||
ceph::make_timespan(g_conf()->rgw_op_thread_timeout),
|
||||
ceph::make_timespan(g_conf()->rgw_op_thread_suicide_timeout),
|
||||
@ -177,7 +183,8 @@ extern int process_request(rgw::sal::Store* store,
|
||||
std::string* user,
|
||||
ceph::coarse_real_clock::duration* latency,
|
||||
std::shared_ptr<RateLimiter> ratelimit,
|
||||
int* http_ret = nullptr);
|
||||
int* http_ret = nullptr,
|
||||
rgw::lua::Background* lua_background = nullptr);
|
||||
|
||||
extern int rgw_process_authenticated(RGWHandler_REST* handler,
|
||||
RGWOp*& op,
|
||||
|
@ -356,7 +356,7 @@
|
||||
--event-id event id in a pubsub subscription
|
||||
|
||||
Script options:
|
||||
--context context in which the script runs. one of: preRequest, postRequest
|
||||
--context context in which the script runs. one of: preRequest, postRequest, background
|
||||
--package name of the lua package that should be added/removed to/from the allowlist
|
||||
--allow-compilation package is allowed to compile C code as part of its installation
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user