From: Emin Sunacoglu Date: Thu, 11 Dec 2025 08:27:11 +0000 (+0100) Subject: rgw: Add Bucket tags attribute for Lua scripts X-Git-Tag: v21.0.1~510^2 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=6e09062fcc4a623ab8ac9f1f0e8ec78456f7fe28;p=ceph.git rgw: Add Bucket tags attribute for Lua scripts Expose bucket tags (from RGW_ATTR_TAGS) to the RGW Lua Request.Bucket.Tags table, allowing lua scripts to read these tags. Fixes: https://tracker.ceph.com/issues/74756 Signed-off-by: Emin Sunacoglu Apply suggestion from @yuvalif Co-authored-by: Yuval Lifshitz Signed-off-by: Emin Mert Sunacoglu <33792101+mertsunacoglu@users.noreply.github.com> --- diff --git a/doc/radosgw/lua-scripting.rst b/doc/radosgw/lua-scripting.rst index 62bf004e4b7..5d7d6d1ed67 100644 --- a/doc/radosgw/lua-scripting.rst +++ b/doc/radosgw/lua-scripting.rst @@ -198,6 +198,8 @@ Request Fields +----------------------------------------------------+----------+--------------------------------------------------------------+----------+-----------+----------+ | ``Request.Bucket.Quota.Rounded`` | boolean | bucket quota is rounded to 4K | no | no | no | +----------------------------------------------------+----------+--------------------------------------------------------------+----------+-----------+----------+ +| ``Request.Bucket.Tags`` | table | bucket tags | no | no | yes | ++----------------------------------------------------+----------+--------------------------------------------------------------+----------+-----------+----------+ | ``Request.Bucket.PlacementRule`` | table | bucket placement rule | no | no | yes | +----------------------------------------------------+----------+--------------------------------------------------------------+----------+-----------+----------+ | ``Request.Bucket.PlacementRule.Name`` | string | bucket placement rule name | no | no | no | diff --git a/src/rgw/rgw_lua_request.cc b/src/rgw/rgw_lua_request.cc index 6f65a4c7ff0..8c02b35fbc4 100644 --- a/src/rgw/rgw_lua_request.cc +++ b/src/rgw/rgw_lua_request.cc @@ -272,6 +272,46 @@ struct OwnerMetaTable : public EmptyMetaTable { } }; +struct BucketTagsTable : public EmptyMetaTable { + static int IndexClosure(lua_State* L) { + const auto bl = reinterpret_cast(lua_touserdata(L, lua_upvalueindex(SECOND_UPVAL))); + const char* key = luaL_checkstring(L, 2); + try { + RGWObjTags tags; + auto bl_it = bl->cbegin(); + tags.decode(bl_it); + + const auto& tag_map = tags.get_tags(); + auto tag_it = tag_map.find(key); + + if (tag_it != tag_map.end()) { + pushstring(L, tag_it->second); + return ONE_RETURNVAL; + } + } catch (const buffer::error& err) { + lua_pushnil(L); + return ONE_RETURNVAL; + } + lua_pushnil(L); + return ONE_RETURNVAL; + } + + static int LenClosure(lua_State* L) { + const auto bl = reinterpret_cast(lua_touserdata(L, lua_upvalueindex(FIRST_UPVAL))); + + try { + RGWObjTags tags; + auto bl_it = bl->cbegin(); + tags.decode(bl_it); + lua_pushinteger(L, tags.get_tags().size()); + return ONE_RETURNVAL; + } catch (const buffer::error& err) { + lua_pushinteger(L, 0); + return ONE_RETURNVAL; + } + } +}; + struct BucketMetaTable : public EmptyMetaTable { static int IndexClosure(lua_State* L) { const auto name = table_name_upvalue(L); @@ -300,6 +340,13 @@ struct BucketMetaTable : public EmptyMetaTable { pushtime(L, bucket->get_creation_time()); } else if (strcasecmp(index, "MTime") == 0) { pushtime(L, bucket->get_modification_time()); + } else if (strcasecmp(index, "Tags") == 0) { + auto it = s->bucket_attrs.find(RGW_ATTR_TAGS); + if (it != s->bucket_attrs.end()) { + create_metatable(L, name, index, false, &(it->second)); + } else { + lua_pushnil(L); + } } else if (strcasecmp(index, "Quota") == 0) { create_metatable(L, name, index, false, &(bucket->get_info().quota)); } else if (strcasecmp(index, "PlacementRule") == 0) { diff --git a/src/test/rgw/test_rgw_lua.cc b/src/test/rgw/test_rgw_lua.cc index 7509b82d4f8..76de31cddef 100644 --- a/src/test/rgw/test_rgw_lua.cc +++ b/src/test/rgw/test_rgw_lua.cc @@ -7,6 +7,7 @@ #include "rgw_lua_data_filter.h" #include "rgw_sal_config.h" #include "rgw_perf_counters.h" +#include "rgw_tag.h" using namespace std; using namespace rgw; @@ -1723,4 +1724,55 @@ TEST(TestRGWLua, NotValidLua) const auto rc = lua::request::execute(nullptr, nullptr, &s, nullptr, script, return_code); ASSERT_EQ(rc, -1); EXPECT_NE(return_code, -EPERM); -} \ No newline at end of file +} + +TEST(TestRGWLua, BucketTags) +{ + const std::string script = R"( + assert(Request.Bucket.Tags["Project"] == "Ceph") + )"; + + DEFINE_REQ_STATE; + + RGWBucketInfo info; + info.bucket.tenant = "mytenant"; + info.bucket.name = "myname"; + + RGWObjTags tags; + tags.add_tag("Project", "Ceph"); + + bufferlist bl; + tags.encode(bl); + + s.bucket_attrs[RGW_ATTR_TAGS] = bl; + s.bucket.reset(new sal::RadosBucket(nullptr, info)); + + const auto rc = lua::request::execute(nullptr, nullptr, &s, nullptr, script); + ASSERT_EQ(rc, 0); +} + +TEST(TestRGWLua, BucketTagsCount) +{ + const std::string script = R"( + assert(#Request.Bucket.Tags == 3) + )"; + + DEFINE_REQ_STATE; + + RGWBucketInfo info; + info.bucket.name = "tag-test-bucket"; + + RGWObjTags tags; + tags.add_tag("Project", "Ceph"); + tags.add_tag("Owner", "Ceph Team"); + tags.add_tag("Status", "Testing"); + + bufferlist bl; + tags.encode(bl); + + s.bucket_attrs[RGW_ATTR_TAGS] = bl; + s.bucket.reset(new sal::RadosBucket(nullptr, info)); + + const auto rc = lua::request::execute(nullptr, nullptr, &s, nullptr, script); + ASSERT_EQ(rc, 0); +}