2 #include "services/svc_zone.h"
3 #include "services/svc_sys_obj.h"
4 #include "common/dout.h"
5 #include "rgw_lua_utils.h"
6 #include "rgw_sal_rados.h"
8 #ifdef WITH_RADOSGW_LUA_PACKAGES
9 #include <boost/process.hpp>
10 #include <boost/filesystem.hpp>
11 #include "rgw_lua_version.h"
14 #define dout_subsys ceph_subsys_rgw
18 context
to_context(const std::string
& s
)
20 if (strcasecmp(s
.c_str(), "prerequest") == 0) {
21 return context::preRequest
;
23 if (strcasecmp(s
.c_str(), "postrequest") == 0) {
24 return context::postRequest
;
29 std::string
to_string(context ctx
)
32 case context::preRequest
:
34 case context::postRequest
:
42 bool verify(const std::string
& script
, std::string
& err_msg
)
44 lua_State
*L
= luaL_newstate();
45 lua_state_guard
guard(L
);
46 open_standard_libs(L
);
48 if (luaL_loadstring(L
, script
.c_str()) != LUA_OK
) {
49 err_msg
.assign(lua_tostring(L
, -1));
52 } catch (const std::runtime_error
& e
) {
60 std::string
script_oid(context ctx
, const std::string
& tenant
) {
61 static const std::string
SCRIPT_OID_PREFIX("script.");
62 return SCRIPT_OID_PREFIX
+ to_string(ctx
) + "." + tenant
;
66 int read_script(rgw::sal::RGWRadosStore
* store
, const std::string
& tenant
, optional_yield y
, context ctx
, std::string
& script
)
68 RGWSysObjectCtx
obj_ctx(store
->svc()->sysobj
->init_obj_ctx());
69 RGWObjVersionTracker objv_tracker
;
71 rgw_raw_obj
obj(store
->svc()->zone
->get_zone_params().log_pool
, script_oid(ctx
, tenant
));
75 const auto rc
= rgw_get_system_obj(
90 auto iter
= bl
.cbegin();
92 ceph::decode(script
, iter
);
93 } catch (buffer::error
& err
) {
100 int write_script(const DoutPrefixProvider
*dpp
, rgw::sal::RGWRadosStore
* store
, const std::string
& tenant
, optional_yield y
, context ctx
, const std::string
& script
)
102 RGWSysObjectCtx
obj_ctx(store
->svc()->sysobj
->init_obj_ctx());
103 RGWObjVersionTracker objv_tracker
;
105 rgw_raw_obj
obj(store
->svc()->zone
->get_zone_params().log_pool
, script_oid(ctx
, tenant
));
108 ceph::encode(script
, bl
);
110 const auto rc
= rgw_put_system_obj(
128 int delete_script(const DoutPrefixProvider
*dpp
, rgw::sal::RGWRadosStore
* store
, const std::string
& tenant
, optional_yield y
, context ctx
)
130 RGWObjVersionTracker objv_tracker
;
132 rgw_raw_obj
obj(store
->svc()->zone
->get_zone_params().log_pool
, script_oid(ctx
, tenant
));
134 const auto rc
= rgw_delete_system_obj(
136 store
->svc()->sysobj
,
142 if (rc
< 0 && rc
!= -ENOENT
) {
149 #ifdef WITH_RADOSGW_LUA_PACKAGES
151 const std::string PACKAGE_LIST_OBJECT_NAME
= "lua_package_allowlist";
153 namespace bp
= boost::process
;
155 int add_package(const DoutPrefixProvider
*dpp
, rgw::sal::RGWRadosStore
* store
, optional_yield y
, const std::string
& package_name
, bool allow_compilation
) {
156 // verify that luarocks can load this oackage
157 const auto p
= bp::search_path("luarocks");
162 const auto cmd
= p
.string() + " search --porcelain" + (allow_compilation
? " " : " --binary ") + package_name
;
165 bp::std_err
> bp::null
,
169 bool package_found
= false;
170 while (c
.running() && std::getline(is
, line
) && !line
.empty()) {
171 package_found
= true;
174 auto ret
= c
.exit_code();
179 if (!package_found
) {
183 // add package to list
184 const bufferlist empty_bl
;
185 std::map
<std::string
, bufferlist
> new_package
{{package_name
, empty_bl
}};
186 librados::ObjectWriteOperation op
;
187 op
.omap_set(new_package
);
188 ret
= rgw_rados_operate(dpp
, *(store
->getRados()->get_lc_pool_ctx()),
189 PACKAGE_LIST_OBJECT_NAME
, &op
, y
);
197 int remove_package(const DoutPrefixProvider
*dpp
, rgw::sal::RGWRadosStore
* store
, optional_yield y
, const std::string
& package_name
) {
198 librados::ObjectWriteOperation op
;
199 op
.omap_rm_keys(std::set
<std::string
>({package_name
}));
200 const auto ret
= rgw_rados_operate(dpp
, *(store
->getRados()->get_lc_pool_ctx()),
201 PACKAGE_LIST_OBJECT_NAME
, &op
, y
);
210 int list_packages(const DoutPrefixProvider
*dpp
, rgw::sal::RGWRadosStore
* store
, optional_yield y
, packages_t
& packages
) {
211 constexpr auto max_chunk
= 1024U;
212 std::string start_after
;
216 librados::ObjectReadOperation op
;
217 packages_t packages_chunk
;
218 op
.omap_get_keys2(start_after
, max_chunk
, &packages_chunk
, &more
, &rval
);
219 const auto ret
= rgw_rados_operate(dpp
, *(store
->getRados()->get_lc_pool_ctx()),
220 PACKAGE_LIST_OBJECT_NAME
, &op
, nullptr, y
);
226 packages
.merge(packages_chunk
);
232 int install_packages(const DoutPrefixProvider
*dpp
, rgw::sal::RGWRadosStore
* store
, optional_yield y
, packages_t
& failed_packages
, std::string
& output
) {
233 // luarocks directory cleanup
234 boost::system::error_code ec
;
235 const auto& luarocks_path
= store
->get_luarocks_path();
236 boost::filesystem::remove_all(luarocks_path
, ec
);
237 if (ec
.value() != 0 && ec
.value() != ENOENT
) {
238 output
.append("failed to clear luarock directory: ");
239 output
.append(ec
.message());
245 auto ret
= list_packages(dpp
, store
, y
, packages
);
246 if (ret
== -ENOENT
) {
247 // allowlist is empty
253 // verify that luarocks exists
254 const auto p
= bp::search_path("luarocks");
259 // the lua rocks install dir will be created by luarocks the first time it is called
260 for (const auto& package
: packages
) {
262 bp::child
c(p
, "install", "--lua-version", CEPH_LUA_VERSION
, "--tree", luarocks_path
, "--deps-mode", "one", package
,
264 (bp::std_err
& bp::std_out
) > is
);
266 // once package reload is supported, code should yield when reading output
267 std::string line
= "CMD: luarocks install --lua-version " + std::string(CEPH_LUA_VERSION
) + std::string(" --tree ") +
268 luarocks_path
+ " --deps-mode one " + package
;
275 } while (c
.running() && std::getline(is
, line
));
279 failed_packages
.insert(package
);