Skip to content

Commit

Permalink
rgw/lua: allow setting metadata via lua
Browse files Browse the repository at this point in the history
Signed-off-by: Yuval Lifshitz <[email protected]>
  • Loading branch information
yuvalif committed Oct 30, 2020
1 parent d162c00 commit eaf48d1
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 8 deletions.
22 changes: 20 additions & 2 deletions doc/radosgw/lua-scripting.rst
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ Request Fields
+----------------------------------------------------+----------+--------------------------------------------------------------+----------+-----------+----------+
| ``Request.HTTP.Resources`` | table | string to string resource map | yes | no | no |
+----------------------------------------------------+----------+--------------------------------------------------------------+----------+-----------+----------+
| ``Request.HTTP.Metadata`` | table | string to string metadata map | yes | no | no |
| ``Request.HTTP.Metadata`` | table | string to string metadata map | yes | yes | no |
+----------------------------------------------------+----------+--------------------------------------------------------------+----------+-----------+----------+
| ``Request.HTTP.Host`` | string | host name | no | no | no |
+----------------------------------------------------+----------+--------------------------------------------------------------+----------+-----------+----------+
Expand Down Expand Up @@ -290,7 +290,6 @@ Lua Code Samples
- Use of operations log only in case of errors:

.. code-block:: lua
if Request.Response.HTTPStatusCode ~= 200 then
RGWDebugLog("request is bad, use ops log")
Expand All @@ -306,3 +305,22 @@ Lua Code Samples
Request.Response.Message = "<Message> something bad happened :-( </Message>"
end
- Add metadata to objects that was not originally sent by the client:

In the `preRequest` context we should add:

.. code-block:: lua
if Request.RGWOp == 'put_obj' then
Request.HTTP.Metadata["x-amz-meta-mydata"] = "my value"
end
In the `postRequest` context we look at the metadata:

.. code-block:: lua
RGWDebugLog("number of metadata entries is: " .. #Request.HTTP.Metadata)
for k, v in pairs(Request.HTTP.Metadata) do
RGWDebugLog("key=" .. k .. ", " .. "value=" .. v)
end
25 changes: 22 additions & 3 deletions src/rgw/rgw_lua_request.cc
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ struct ResponseMetaTable : public EmptyMetaTable {
} else {
throw_unknown_field(index, TableName());
}
return ONE_RETURNVAL;
return NO_RETURNVAL;
}
};

Expand Down Expand Up @@ -244,7 +244,22 @@ struct ObjectMetaTable : public EmptyMetaTable {
}
};

template<typename MapType=std::map<std::string, std::string>>
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)));

ceph_assert(lua_isstring(L, -1));
ceph_assert(lua_isstring(L, -2));
const char* value = lua_tostring(L, -1);
const char* index = lua_tostring(L, -2);
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";}
Expand All @@ -265,6 +280,10 @@ struct StringMapMetaTable : public EmptyMetaTable {
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);
Expand Down Expand Up @@ -628,7 +647,7 @@ struct HTTPMetaTable : public EmptyMetaTable {
create_metatable<StringMapMetaTable<>>(L, false,
const_cast<std::map<std::string, std::string>*>(&(info->args.get_sub_resources())));
} else if (strcasecmp(index, "Metadata") == 0) {
create_metatable<StringMapMetaTable<meta_map_t>>(L, false, &(info->x_meta_map));
create_metatable<StringMapMetaTable<meta_map_t, StringMapWriteableNewIndex<meta_map_t>>>(L, false, &(info->x_meta_map));
} else if (strcasecmp(index, "Host") == 0) {
pushstring(L, info->host);
} else if (strcasecmp(index, "Method") == 0) {
Expand Down
7 changes: 4 additions & 3 deletions src/rgw/rgw_lua_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ constexpr auto THREE_UPVALS = 3;
constexpr auto FOUR_UPVALS = 4;
constexpr auto FIVE_UPVALS = 5;

constexpr auto NO_RETURNVAL = 0;
constexpr auto ONE_RETURNVAL = 1;
constexpr auto TWO_RETURNVALS = 2;
constexpr auto THREE_RETURNVALS = 3;
Expand Down Expand Up @@ -143,21 +144,21 @@ struct EmptyMetaTable {
// to change, overload this function in the derived
static int NewIndexClosure(lua_State* L) {
throw std::runtime_error("trying to write to readonly field");
return 1;
return NO_RETURNVAL;
}

// by default nothing is iterable
// to change, overload this function in the derived
static int PairsClosure(lua_State* L) {
throw std::runtime_error("trying to iterate over non-iterable field");
return 1;
return ONE_RETURNVAL;
}

// by default nothing is iterable
// to change, overload this function in the derived
static int LenClosure(lua_State* L) {
throw std::runtime_error("trying to get length of non-iterable field");
return 1;
return ONE_RETURNVAL;
}

static void throw_unknown_field(const std::string& index, const std::string& table) {
Expand Down
42 changes: 42 additions & 0 deletions src/test/rgw/test_rgw_lua.cc
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,48 @@ TEST(TestRGWLua, Tags)
ASSERT_EQ(rc, 0);
}

TEST(TestRGWLua, TagsNotWriteable)
{
const std::string script = R"(
Request.Tags["hello"] = "goodbye"
)";

DEFINE_REQ_STATE;
s.tagset.add_tag("hello", "world");

const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, "put_obj", script);
ASSERT_NE(rc, 0);
}

TEST(TestRGWLua, Metadata)
{
const std::string script = R"(
print("number of metadata entries is: " .. #Request.HTTP.Metadata)
for k, v in pairs(Request.HTTP.Metadata) do
print("key=" .. k .. ", " .. "value=" .. v)
end
print("value of 'hello' is:")
print(Request.HTTP.Metadata["hello"])
print("value of 'kaboom' is:")
print(Request.HTTP.Metadata["kaboom"])
Request.HTTP.Metadata["hello"] = "goodbye"
Request.HTTP.Metadata["kaboom"] = "boom"
print("new number of metadata entries is: " .. #Request.HTTP.Metadata)
print("new value of 'hello' is:")
print(Request.HTTP.Metadata["hello"])
print("new value of 'kaboom' is:")
print(Request.HTTP.Metadata["kaboom"])
)";

DEFINE_REQ_STATE;
s.info.x_meta_map["hello"] = "world";
s.info.x_meta_map["foo"] = "bar";
s.info.x_meta_map["ka"] = "boom";

const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, "put_obj", script);
ASSERT_EQ(rc, 0);
}

TEST(TestRGWLua, Acl)
{
const std::string script = R"(
Expand Down

0 comments on commit eaf48d1

Please sign in to comment.