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(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(
127 int delete_script(rgw::sal::RGWRadosStore
* store
, const std::string
& tenant
, optional_yield y
, context ctx
)
129 RGWObjVersionTracker objv_tracker
;
131 rgw_raw_obj
obj(store
->svc()->zone
->get_zone_params().log_pool
, script_oid(ctx
, tenant
));
133 const auto rc
= rgw_delete_system_obj(
134 store
->svc()->sysobj
,
140 if (rc
< 0 && rc
!= -ENOENT
) {
147 #ifdef WITH_RADOSGW_LUA_PACKAGES
149 const std::string PACKAGE_LIST_OBJECT_NAME
= "lua_package_allowlist";
151 namespace bp
= boost::process
;
153 int add_package(rgw::sal::RGWRadosStore
* store
, optional_yield y
, const std::string
& package_name
, bool allow_compilation
) {
154 // verify that luarocks can load this oackage
155 const auto p
= bp::search_path("luarocks");
160 const auto cmd
= p
.string() + " search --porcelain" + (allow_compilation
? " " : " --binary ") + package_name
;
163 bp::std_err
> bp::null
,
167 bool package_found
= false;
168 while (c
.running() && std::getline(is
, line
) && !line
.empty()) {
169 package_found
= true;
172 auto ret
= c
.exit_code();
177 if (!package_found
) {
181 // add package to list
182 const bufferlist empty_bl
;
183 std::map
<std::string
, bufferlist
> new_package
{{package_name
, empty_bl
}};
184 librados::ObjectWriteOperation op
;
185 op
.omap_set(new_package
);
186 ret
= rgw_rados_operate(*(store
->getRados()->get_lc_pool_ctx()),
187 PACKAGE_LIST_OBJECT_NAME
, &op
, y
);
195 int remove_package(rgw::sal::RGWRadosStore
* store
, optional_yield y
, const std::string
& package_name
) {
196 librados::ObjectWriteOperation op
;
197 op
.omap_rm_keys(std::set
<std::string
>({package_name
}));
198 const auto ret
= rgw_rados_operate(*(store
->getRados()->get_lc_pool_ctx()),
199 PACKAGE_LIST_OBJECT_NAME
, &op
, y
);
208 int list_packages(rgw::sal::RGWRadosStore
* store
, optional_yield y
, packages_t
& packages
) {
209 constexpr auto max_chunk
= 1024U;
210 std::string start_after
;
214 librados::ObjectReadOperation op
;
215 packages_t packages_chunk
;
216 op
.omap_get_keys2(start_after
, max_chunk
, &packages_chunk
, &more
, &rval
);
217 const auto ret
= rgw_rados_operate(*(store
->getRados()->get_lc_pool_ctx()),
218 PACKAGE_LIST_OBJECT_NAME
, &op
, nullptr, y
);
224 packages
.merge(packages_chunk
);
230 int install_packages(rgw::sal::RGWRadosStore
* store
, optional_yield y
, packages_t
& failed_packages
, std::string
& output
) {
231 // luarocks directory cleanup
232 boost::system::error_code ec
;
233 const auto& luarocks_path
= store
->get_luarocks_path();
234 boost::filesystem::remove_all(luarocks_path
, ec
);
235 if (ec
.value() != 0 && ec
.value() != ENOENT
) {
236 output
.append("failed to clear luarock directory: ");
237 output
.append(ec
.message());
243 auto ret
= list_packages(store
, y
, packages
);
244 if (ret
== -ENOENT
) {
245 // allowlist is empty
251 // verify that luarocks exists
252 const auto p
= bp::search_path("luarocks");
257 // the lua rocks install dir will be created by luarocks the first time it is called
258 for (const auto& package
: packages
) {
260 bp::child
c(p
, "install", "--lua-version", CEPH_LUA_VERSION
, "--tree", luarocks_path
, "--deps-mode", "one", package
,
262 (bp::std_err
& bp::std_out
) > is
);
264 // once package reload is supported, code should yield when reading output
265 std::string line
= "CMD: luarocks install --lua-version " + std::string(CEPH_LUA_VERSION
) + std::string(" --tree ") +
266 luarocks_path
+ " --deps-mode one " + package
;
273 } while (c
.running() && std::getline(is
, line
));
277 failed_packages
.insert(package
);