#include "rgw_lua.h"
#include "rgw_common.h"
#include "rgw_log.h"
-#include "rgw_process.h"
+#include "rgw_op.h"
+#include "rgw_process_env.h"
#include "rgw_zone.h"
#include "rgw_acl.h"
#include "rgw_sal_rados.h"
+#include "rgw_lua_background.h"
+#include "rgw_perf_counters.h"
#define dout_subsys ceph_subsys_rgw
int RequestLog(lua_State* L)
{
- const auto rest = reinterpret_cast<RGWREST*>(lua_touserdata(L, lua_upvalueindex(1)));
- const auto olog = reinterpret_cast<OpsLogSink*>(lua_touserdata(L, lua_upvalueindex(2)));
- const auto s = reinterpret_cast<req_state*>(lua_touserdata(L, lua_upvalueindex(3)));
- const auto op(reinterpret_cast<RGWOp*>(lua_touserdata(L, lua_upvalueindex(4))));
+ const auto rest = reinterpret_cast<RGWREST*>(lua_touserdata(L, lua_upvalueindex(FIRST_UPVAL)));
+ const auto olog = reinterpret_cast<OpsLogSink*>(lua_touserdata(L, lua_upvalueindex(SECOND_UPVAL)));
+ const auto s = reinterpret_cast<req_state*>(lua_touserdata(L, lua_upvalueindex(THIRD_UPVAL)));
+ const auto op(reinterpret_cast<RGWOp*>(lua_touserdata(L, lua_upvalueindex(FOURTH_UPVAL))));
if (s) {
const auto rc = rgw_log_op(rest, s, op, olog);
lua_pushinteger(L, rc);
return ONE_RETURNVAL;
}
+int SetAttribute(lua_State* L) {
+ auto s = reinterpret_cast<req_state*>(lua_touserdata(L, lua_upvalueindex(1)));
+
+ if (!s->trace || !s->trace->IsRecording()) {
+ return 0;
+ }
+
+ auto key = luaL_checkstring(L, 1);
+ int value_type = lua_type(L, 2);
+
+ switch (value_type) {
+ case LUA_TSTRING:
+ s->trace->SetAttribute(key, lua_tostring(L, 2));
+ break;
+
+ case LUA_TNUMBER:
+ if (lua_isinteger(L, 2)) {
+ s->trace->SetAttribute(key, static_cast<int64_t>(lua_tointeger(L, 2)));
+ } else {
+ s->trace->SetAttribute(key, static_cast<double>(lua_tonumber(L, 2)));
+ }
+ break;
+
+ default:
+ luaL_error(L, "unsupported value type for SetAttribute");
+ }
+ return 0;
+}
+
+int AddEvent(lua_State* L) {
+ auto s = reinterpret_cast<req_state*>(lua_touserdata(L, lua_upvalueindex(1)));
+
+ if (!s->trace || !s->trace->IsRecording()) {
+ return 0;
+ }
+
+ int args = lua_gettop(L);
+ if (args == 1) {
+ auto log = luaL_checkstring(L, 1);
+ s->trace->AddEvent(log);
+ } else if(args == 2) {
+ auto event_name = luaL_checkstring(L, 1);
+ std::unordered_map<const char*, jspan_attribute> event_values;
+ lua_pushnil(L);
+ while (lua_next(L, 2) != 0) {
+ if (lua_type(L, -2) != LUA_TSTRING) {
+ // skip pair if key is not a string
+ lua_pop(L, 1);
+ continue;
+ }
+
+ auto key = luaL_checkstring(L, -2);
+ int value_type = lua_type(L, -1);
+ switch (value_type) {
+ case LUA_TSTRING:
+ event_values.emplace(key, lua_tostring(L, -1));
+ break;
+
+ case LUA_TNUMBER:
+ if (lua_isinteger(L, -1)) {
+ event_values.emplace(key, static_cast<int64_t>(lua_tointeger(L, -1)));
+ } else {
+ event_values.emplace(key, static_cast<double>(lua_tonumber(L, -1)));
+ }
+ break;
+ }
+ lua_pop(L, 1);
+ }
+ lua_pop(L, 1);
+ s->trace->AddEvent(event_name, event_values);
+ }
+ return 0;
+}
+
struct ResponseMetaTable : public EmptyMetaTable {
static std::string TableName() {return "Response";}
static std::string Name() {return TableName() + "Meta";}
static int IndexClosure(lua_State* L) {
- const auto err = reinterpret_cast<const rgw_err*>(lua_touserdata(L, lua_upvalueindex(1)));
+ const auto err = reinterpret_cast<const rgw_err*>(lua_touserdata(L, lua_upvalueindex(FIRST_UPVAL)));
const char* index = luaL_checkstring(L, 2);
}
static int NewIndexClosure(lua_State* L) {
- auto err = reinterpret_cast<rgw_err*>(lua_touserdata(L, lua_upvalueindex(1)));
+ auto err = reinterpret_cast<rgw_err*>(lua_touserdata(L, lua_upvalueindex(FIRST_UPVAL)));
const char* index = luaL_checkstring(L, 2);
static std::string Name() {return TableName() + "Meta";}
static int IndexClosure(lua_State* L) {
- const auto info = reinterpret_cast<RGWQuotaInfo*>(lua_touserdata(L, lua_upvalueindex(1)));
+ const auto info = reinterpret_cast<RGWQuotaInfo*>(lua_touserdata(L, lua_upvalueindex(FIRST_UPVAL)));
const char* index = luaL_checkstring(L, 2);
static std::string Name() {return TableName() + "Meta";}
static int IndexClosure(lua_State* L) {
- const auto rule = reinterpret_cast<rgw_placement_rule*>(lua_touserdata(L, lua_upvalueindex(1)));
+ const auto rule = reinterpret_cast<rgw_placement_rule*>(lua_touserdata(L, lua_upvalueindex(FIRST_UPVAL)));
const char* index = luaL_checkstring(L, 2);
static std::string Name() {return TableName() + "Meta";}
static int IndexClosure(lua_State* L) {
- const auto user = reinterpret_cast<const rgw_user*>(lua_touserdata(L, lua_upvalueindex(1)));
+ const auto user = reinterpret_cast<const rgw_user*>(lua_touserdata(L, lua_upvalueindex(FIRST_UPVAL)));
const char* index = luaL_checkstring(L, 2);
}
};
+struct TraceMetaTable : public EmptyMetaTable {
+ static std::string TableName() {return "Trace";}
+ static std::string Name() {return TableName() + "Meta";}
+
+ static int IndexClosure(lua_State* L) {
+ const auto s = reinterpret_cast<req_state*>(lua_touserdata(L, lua_upvalueindex(FIRST_UPVAL)));
+
+ const char* index = luaL_checkstring(L, 2);
+
+ if (strcasecmp(index, "Enable") == 0) {
+ lua_pushboolean(L, s->trace_enabled);
+ } else if(strcasecmp(index, "SetAttribute") == 0) {
+ lua_pushlightuserdata(L, s);
+ lua_pushcclosure(L, SetAttribute, ONE_UPVAL);
+ } else if(strcasecmp(index, "AddEvent") == 0) {
+ lua_pushlightuserdata(L, s);
+ lua_pushcclosure(L, AddEvent, ONE_UPVAL);
+ } else {
+ return error_unknown_field(L, index, TableName());
+ }
+ return ONE_RETURNVAL;
+ }
+
+ static int NewIndexClosure(lua_State* L) {
+ const auto s = reinterpret_cast<req_state*>(lua_touserdata(L, lua_upvalueindex(FIRST_UPVAL)));
+
+ const char* index = luaL_checkstring(L, 2);
+
+ if (strcasecmp(index, "Enable") == 0) {
+ s->trace_enabled = lua_toboolean(L, 3);
+ } else {
+ return error_unknown_field(L, index, TableName());
+ }
+ return NO_RETURNVAL;
+ }
+};
+
struct OwnerMetaTable : public EmptyMetaTable {
static std::string TableName() {return "Owner";}
static std::string Name() {return TableName() + "Meta";}
static int IndexClosure(lua_State* L) {
- const auto owner = reinterpret_cast<ACLOwner*>(lua_touserdata(L, lua_upvalueindex(1)));
+ const auto owner = reinterpret_cast<ACLOwner*>(lua_touserdata(L, lua_upvalueindex(FIRST_UPVAL)));
const char* index = luaL_checkstring(L, 2);
static std::string TableName() {return "Bucket";}
static std::string Name() {return TableName() + "Meta";}
- using Type = rgw::sal::Bucket;
-
static int IndexClosure(lua_State* L) {
- const auto bucket = reinterpret_cast<Type*>(lua_touserdata(L, lua_upvalueindex(1)));
+ const auto s = reinterpret_cast<req_state*>(lua_touserdata(L, lua_upvalueindex(FIRST_UPVAL)));
+ const auto bucket = s->bucket.get();
const char* index = luaL_checkstring(L, 2);
- if (strcasecmp(index, "Tenant") == 0) {
+ if (rgw::sal::Bucket::empty(bucket)) {
+ if (strcasecmp(index, "Name") == 0) {
+ pushstring(L, s->init_state.url_bucket);
+ } else {
+ lua_pushnil(L);
+ }
+ } else if (strcasecmp(index, "Tenant") == 0) {
pushstring(L, bucket->get_tenant());
} else if (strcasecmp(index, "Name") == 0) {
pushstring(L, bucket->get_name());
}
return ONE_RETURNVAL;
}
+
+ static int NewIndexClosure(lua_State* L) {
+ const auto s = reinterpret_cast<req_state*>(lua_touserdata(L, lua_upvalueindex(FIRST_UPVAL)));
+ const auto bucket = s->bucket.get();
+
+ const char* index = luaL_checkstring(L, 2);
+
+ if (rgw::sal::Bucket::empty(bucket)) {
+ if (strcasecmp(index, "Name") == 0) {
+ s->init_state.url_bucket = luaL_checkstring(L, 3);
+ return NO_RETURNVAL;
+ }
+ }
+ return error_unknown_field(L, index, TableName());
+ }
};
struct ObjectMetaTable : public EmptyMetaTable {
using Type = rgw::sal::Object;
static int IndexClosure(lua_State* L) {
- const auto obj = reinterpret_cast<const Type*>(lua_touserdata(L, lua_upvalueindex(1)));
+ const auto obj = reinterpret_cast<const Type*>(lua_touserdata(L, lua_upvalueindex(FIRST_UPVAL)));
const char* index = luaL_checkstring(L, 2);
}
};
-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";}
static int IndexClosure(lua_State* L) {
- const auto grant = reinterpret_cast<ACLGrant*>(lua_touserdata(L, lua_upvalueindex(1)));
+ const auto grant = reinterpret_cast<ACLGrant*>(lua_touserdata(L, lua_upvalueindex(FIRST_UPVAL)));
const char* index = luaL_checkstring(L, 2);
static std::string Name() {return TableName() + "Meta";}
static int IndexClosure(lua_State* L) {
- const auto map = reinterpret_cast<ACLGrantMap*>(lua_touserdata(L, lua_upvalueindex(1)));
+ const auto map = reinterpret_cast<ACLGrantMap*>(lua_touserdata(L, lua_upvalueindex(FIRST_UPVAL)));
const char* index = luaL_checkstring(L, 2);
}
static int PairsClosure(lua_State* L) {
- auto map = reinterpret_cast<ACLGrantMap*>(lua_touserdata(L, lua_upvalueindex(1)));
+ auto map = reinterpret_cast<ACLGrantMap*>(lua_touserdata(L, lua_upvalueindex(FIRST_UPVAL)));
ceph_assert(map);
lua_pushlightuserdata(L, map);
lua_pushcclosure(L, stateless_iter, ONE_UPVAL); // push the stateless iterator function
static int stateless_iter(lua_State* L) {
// based on: http://lua-users.org/wiki/GeneralizedPairsAndIpairs
- auto map = reinterpret_cast<ACLGrantMap*>(lua_touserdata(L, lua_upvalueindex(1)));
+ auto map = reinterpret_cast<ACLGrantMap*>(lua_touserdata(L, lua_upvalueindex(FIRST_UPVAL)));
ACLGrantMap::iterator next_it;
if (lua_isnil(L, -1)) {
next_it = map->begin();
}
static int LenClosure(lua_State* L) {
- const auto map = reinterpret_cast<ACLGrantMap*>(lua_touserdata(L, lua_upvalueindex(1)));
+ const auto map = reinterpret_cast<ACLGrantMap*>(lua_touserdata(L, lua_upvalueindex(FIRST_UPVAL)));
lua_pushinteger(L, map->size());
using Type = RGWAccessControlPolicy;
static int IndexClosure(lua_State* L) {
- const auto acl = reinterpret_cast<Type*>(lua_touserdata(L, lua_upvalueindex(1)));
+ const auto acl = reinterpret_cast<Type*>(lua_touserdata(L, lua_upvalueindex(FIRST_UPVAL)));
const char* index = luaL_checkstring(L, 2);
}
static int IndexClosure(lua_State* L) {
- const auto statements = reinterpret_cast<Type*>(lua_touserdata(L, lua_upvalueindex(1)));
+ const auto statements = reinterpret_cast<Type*>(lua_touserdata(L, lua_upvalueindex(FIRST_UPVAL)));
const auto index = luaL_checkinteger(L, 2);
}
static int PairsClosure(lua_State* L) {
- auto statements = reinterpret_cast<Type*>(lua_touserdata(L, lua_upvalueindex(1)));
+ auto statements = reinterpret_cast<Type*>(lua_touserdata(L, lua_upvalueindex(FIRST_UPVAL)));
ceph_assert(statements);
lua_pushlightuserdata(L, statements);
lua_pushcclosure(L, stateless_iter, ONE_UPVAL); // push the stateless iterator function
}
static int stateless_iter(lua_State* L) {
- auto statements = reinterpret_cast<Type*>(lua_touserdata(L, lua_upvalueindex(1)));
+ auto statements = reinterpret_cast<Type*>(lua_touserdata(L, lua_upvalueindex(FIRST_UPVAL)));
size_t next_it;
if (lua_isnil(L, -1)) {
next_it = 0;
}
static int LenClosure(lua_State* L) {
- const auto statements = reinterpret_cast<Type*>(lua_touserdata(L, lua_upvalueindex(1)));
+ const auto statements = reinterpret_cast<Type*>(lua_touserdata(L, lua_upvalueindex(FIRST_UPVAL)));
lua_pushinteger(L, statements->size());
static std::string Name() {return TableName() + "Meta";}
static int IndexClosure(lua_State* L) {
- const auto policy = reinterpret_cast<rgw::IAM::Policy*>(lua_touserdata(L, lua_upvalueindex(1)));
+ const auto policy = reinterpret_cast<rgw::IAM::Policy*>(lua_touserdata(L, lua_upvalueindex(FIRST_UPVAL)));
const char* index = luaL_checkstring(L, 2);
pushstring(L, policy->id.get());
}
} else if (strcasecmp(index, "Statements") == 0) {
- create_metatable<StatementsMetaTable>(L, &(policy->statements));
+ create_metatable<StatementsMetaTable>(L, false, &(policy->statements));
} else {
return error_unknown_field(L, index, TableName());
}
using Type = std::vector<rgw::IAM::Policy>;
static int IndexClosure(lua_State* L) {
- const auto policies = reinterpret_cast<Type*>(lua_touserdata(L, lua_upvalueindex(1)));
+ const auto policies = reinterpret_cast<Type*>(lua_touserdata(L, lua_upvalueindex(FIRST_UPVAL)));
const auto index = luaL_checkinteger(L, 2);
}
static int PairsClosure(lua_State* L) {
- auto policies = reinterpret_cast<Type*>(lua_touserdata(L, lua_upvalueindex(1)));
+ auto policies = reinterpret_cast<Type*>(lua_touserdata(L, lua_upvalueindex(FIRST_UPVAL)));
ceph_assert(policies);
lua_pushlightuserdata(L, policies);
lua_pushcclosure(L, stateless_iter, ONE_UPVAL); // push the stateless iterator function
}
static int stateless_iter(lua_State* L) {
- auto policies = reinterpret_cast<Type*>(lua_touserdata(L, lua_upvalueindex(1)));
+ auto policies = reinterpret_cast<Type*>(lua_touserdata(L, lua_upvalueindex(FIRST_UPVAL)));
size_t next_it;
if (lua_isnil(L, -1)) {
next_it = 0;
}
static int LenClosure(lua_State* L) {
- const auto policies = reinterpret_cast<Type*>(lua_touserdata(L, lua_upvalueindex(1)));
+ const auto policies = reinterpret_cast<Type*>(lua_touserdata(L, lua_upvalueindex(FIRST_UPVAL)));
lua_pushinteger(L, policies->size());
static std::string Name() {return TableName() + "Meta";}
static int IndexClosure(lua_State* L) {
- const auto info = reinterpret_cast<req_info*>(lua_touserdata(L, lua_upvalueindex(1)));
+ const auto info = reinterpret_cast<req_info*>(lua_touserdata(L, lua_upvalueindex(FIRST_UPVAL)));
const char* index = luaL_checkstring(L, 2);
}
static int NewIndexClosure(lua_State* L) {
- auto info = reinterpret_cast<req_info*>(lua_touserdata(L, lua_upvalueindex(1)));
+ auto info = reinterpret_cast<req_info*>(lua_touserdata(L, lua_upvalueindex(FIRST_UPVAL)));
const char* index = luaL_checkstring(L, 2);
static std::string Name() {return TableName() + "Meta";}
static int IndexClosure(lua_State* L) {
- const auto s = reinterpret_cast<req_state*>(lua_touserdata(L, lua_upvalueindex(1)));
+ const auto s = reinterpret_cast<req_state*>(lua_touserdata(L, lua_upvalueindex(FIRST_UPVAL)));
const char* index = luaL_checkstring(L, 2);
static std::string Name() {return TableName() + "Meta";}
static int IndexClosure(lua_State* L) {
- const auto s = reinterpret_cast<req_state*>(lua_touserdata(L, lua_upvalueindex(1)));
+ const auto s = reinterpret_cast<req_state*>(lua_touserdata(L, lua_upvalueindex(FIRST_UPVAL)));
const char* index = luaL_checkstring(L, 2);
// __index closure that expect req_state to be captured
static int IndexClosure(lua_State* L) {
- const auto s = reinterpret_cast<req_state*>(lua_touserdata(L, lua_upvalueindex(1)));
- const auto op_name = reinterpret_cast<const char*>(lua_touserdata(L, lua_upvalueindex(2)));
+ const auto s = reinterpret_cast<req_state*>(lua_touserdata(L, lua_upvalueindex(FIRST_UPVAL)));
+ const auto op_name = reinterpret_cast<const char*>(lua_touserdata(L, lua_upvalueindex(SECOND_UPVAL)));
const char* index = luaL_checkstring(L, 2);
lua_pushnil(L);
}
} else if (strcasecmp(index, "Bucket") == 0) {
- create_metatable<BucketMetaTable>(L, false, s->bucket);
+ create_metatable<BucketMetaTable>(L, false, s);
} else if (strcasecmp(index, "Object") == 0) {
create_metatable<ObjectMetaTable>(L, false, s->object);
} else if (strcasecmp(index, "CopyFrom") == 0) {
} else {
create_metatable<UserMetaTable>(L, false, const_cast<rgw_user*>(&(s->user->get_id())));
}
+ } else if (strcasecmp(index, "Trace") == 0) {
+ create_metatable<TraceMetaTable>(L, false, s);
} else {
return error_unknown_field(L, index, TableName());
}
}
};
+void create_top_metatable(lua_State* L, req_state* s, const char* op_name) {
+ create_metatable<RequestMetaTable>(L, true, s, const_cast<char*>(op_name));
+ lua_getglobal(L, RequestMetaTable::TableName().c_str());
+ ceph_assert(lua_istable(L, -1));
+}
+
int execute(
- rgw::sal::Store* store,
+ rgw::sal::Driver* driver,
RGWREST* rest,
OpsLogSink* olog,
req_state* s,
lua_state_guard lguard(L);
open_standard_libs(L);
- set_package_path(L, store ?
- store->get_luarocks_path() :
- "");
+ set_package_path(L, s->penv.lua.luarocks_path);
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);
lua_pushlightuserdata(L, op);
lua_pushcclosure(L, RequestLog, FOUR_UPVALS);
lua_rawset(L, -3);
+
+ if (s->penv.lua.background) {
+ s->penv.lua.background->create_background_metatable(L);
+ lua_getglobal(L, rgw::lua::RGWTable::TableName().c_str());
+ ceph_assert(lua_istable(L, -1));
+ }
+ int rc = 0;
try {
// execute the lua script
if (luaL_dostring(L, script.c_str()) != LUA_OK) {
const std::string err(lua_tostring(L, -1));
ldpp_dout(s, 1) << "Lua ERROR: " << err << dendl;
- return -1;
+ rc = -1;
}
} catch (const std::runtime_error& e) {
ldpp_dout(s, 1) << "Lua ERROR: " << e.what() << dendl;
- return -1;
+ rc = -1;
+ }
+ if (perfcounter) {
+ perfcounter->inc((rc == -1 ? l_rgw_lua_script_fail : l_rgw_lua_script_ok), 1);
}
- return 0;
+ return rc;
}
-}
+} // namespace rgw::lua::request
+