From: Yuval Lifshitz Date: Wed, 5 Jul 2023 18:33:55 +0000 (+0000) Subject: rgw/lua/doc: support reloading lua packages on all RGWs X-Git-Tag: v19.0.0~315^2 X-Git-Url: http://git.apps.os.sepia.ceph.com/?a=commitdiff_plain;h=7a11f1d574266d66239c7ea6b49130606ed810a0;p=ceph-ci.git rgw/lua/doc: support reloading lua packages on all RGWs without requiring a restart of the RGWs test instructions: https://gist.github.com/yuvalif/95b8ed9ea73ab4591c59644a050e01e2 also use capitalized "Lua" in logs/doc Signed-off-by: Yuval Lifshitz --- diff --git a/doc/radosgw/lua-scripting.rst b/doc/radosgw/lua-scripting.rst index 9f32dac1a49..29cba258efe 100644 --- a/doc/radosgw/lua-scripting.rst +++ b/doc/radosgw/lua-scripting.rst @@ -23,7 +23,8 @@ To change this default value, use the ``rgw_lua_max_memory_per_state`` configura By default, all Lua standard libraries are available in the script, however, in order to allow for other Lua modules to be used in the script, we support adding packages to an allowlist: - - All packages in the allowlist are being re-installed using the luarocks package manager on radosgw restart. Therefore a restart is needed for adding or removing of packages to take effect + - Adding a Lua package to the allowlist, or removing a packge from it does not install or remove it. For the changes to take affect a "reload" command should be called. + - In addition all packages in the allowlist are being re-installed using the luarocks package manager on radosgw restart. - To add a package that contains C source code that needs to be compiled, use the ``--allow-compilation`` flag. In this case a C compiler needs to be available on the host - Lua packages are installed in, and used from, a directory local to the radosgw. Meaning that Lua packages in the allowlist are separated from any Lua packages available on the host. By default, this directory would be ``/tmp/luarocks/``. Its prefix part (``/tmp/luarocks/``) could be set to a different location via the ``rgw_luarocks_location`` configuration parameter. @@ -116,6 +117,13 @@ To print the list of packages in the allowlist: # radosgw-admin script-package list +To apply changes from the allowlist to all RGWs: + +:: + + # radosgw-admin script-package reload + + Context Free Functions ---------------------- Debug Log diff --git a/src/rgw/driver/daos/rgw_sal_daos.cc b/src/rgw/driver/daos/rgw_sal_daos.cc index ebd6957d884..46db3dd654c 100644 --- a/src/rgw/driver/daos/rgw_sal_daos.cc +++ b/src/rgw/driver/daos/rgw_sal_daos.cc @@ -880,8 +880,8 @@ const std::string& DaosZone::get_current_period_id() { return current_period->get_id(); } -std::unique_ptr DaosStore::get_lua_manager() { - return std::make_unique(this); +std::unique_ptr DaosStore::get_lua_manager(const DoutPrefixProvider *dpp, const std::string& luarocks_path) { + return std::make_unique(this, dpp, luarocks_path); } int DaosObject::get_obj_state(const DoutPrefixProvider* dpp, diff --git a/src/rgw/driver/daos/rgw_sal_daos.h b/src/rgw/driver/daos/rgw_sal_daos.h index d8f1d276da2..0eaf495d2e2 100644 --- a/src/rgw/driver/daos/rgw_sal_daos.h +++ b/src/rgw/driver/daos/rgw_sal_daos.h @@ -997,7 +997,7 @@ class DaosStore : public StoreDriver { } virtual std::string get_host_id() { return ""; } - virtual std::unique_ptr get_lua_manager() override; + std::unique_ptr get_lua_manager(const DoutPrefixProvider *dpp = nullptr, const std::string& luarocks_path = "") override; virtual std::unique_ptr get_role( std::string name, std::string tenant, std::string path = "", std::string trust_policy = "", std::string max_session_duration_str = "", diff --git a/src/rgw/driver/motr/rgw_sal_motr.cc b/src/rgw/driver/motr/rgw_sal_motr.cc index c0dff1c1f9f..06df127594e 100644 --- a/src/rgw/driver/motr/rgw_sal_motr.cc +++ b/src/rgw/driver/motr/rgw_sal_motr.cc @@ -1151,9 +1151,9 @@ const std::string& MotrZone::get_current_period_id() return current_period->get_id(); } -std::unique_ptr MotrStore::get_lua_manager() +std::unique_ptr MotrStore::get_lua_manager(const DoutPrefixProvider *dpp, const std::string& luarocks_path) { - return std::make_unique(this); + return std::make_unique(this, dpp, luarocks_path); } int MotrObject::get_obj_state(const DoutPrefixProvider* dpp, RGWObjState **_state, optional_yield y, bool follow_olh) @@ -3901,6 +3901,11 @@ int MotrStore::init_metadata_cache(const DoutPrefixProvider *dpp, { return -ENOENT; } + + int MotrLuaManager::reload_packages(const DoutPrefixProvider* dpp, optional_yield y) + { + return -ENOENT; + } } // namespace rgw::sal extern "C" { diff --git a/src/rgw/driver/motr/rgw_sal_motr.h b/src/rgw/driver/motr/rgw_sal_motr.h index c9e6fab6a0f..eee843d7eff 100644 --- a/src/rgw/driver/motr/rgw_sal_motr.h +++ b/src/rgw/driver/motr/rgw_sal_motr.h @@ -559,6 +559,8 @@ class MotrLuaManager : public StoreLuaManager { virtual int remove_package(const DoutPrefixProvider* dpp, optional_yield y, const std::string& package_name) override; /** List lua packages */ virtual int list_packages(const DoutPrefixProvider* dpp, optional_yield y, rgw::lua::packages_t& packages) override; + /** Reload lua packages */ + virtual int reload_packages(const DoutPrefixProvider* dpp, optional_yield y) override; }; class MotrOIDCProvider : public RGWOIDCProvider { @@ -1047,7 +1049,7 @@ class MotrStore : public StoreDriver { virtual const RGWSyncModuleInstanceRef& get_sync_module() { return sync_module; } virtual std::string get_host_id() { return ""; } - virtual std::unique_ptr get_lua_manager() override; + std::unique_ptr get_lua_manager(const DoutPrefixProvider *dpp = nullptr, const std::string& luarocks_path = "") override; virtual std::unique_ptr get_role(std::string name, std::string tenant, std::string path="", diff --git a/src/rgw/driver/rados/rgw_sal_rados.cc b/src/rgw/driver/rados/rgw_sal_rados.cc index ffbfb65dacd..0c24a36a0a5 100644 --- a/src/rgw/driver/rados/rgw_sal_rados.cc +++ b/src/rgw/driver/rados/rgw_sal_rados.cc @@ -853,7 +853,7 @@ int RadosBucket::set_acl(const DoutPrefixProvider* dpp, RGWAccessControlPolicy & cerr << "ERROR: failed to set bucket owner: " << cpp_strerror(-r) << std::endl; return r; } - + return 0; } @@ -1003,8 +1003,8 @@ std::string RadosBucket::topics_oid() const { return pubsub_oid_prefix + get_tenant() + ".bucket." + get_name() + "/" + get_marker(); } -int RadosBucket::read_topics(rgw_pubsub_bucket_topics& notifications, - RGWObjVersionTracker* objv_tracker, optional_yield y, const DoutPrefixProvider *dpp) +int RadosBucket::read_topics(rgw_pubsub_bucket_topics& notifications, + RGWObjVersionTracker* objv_tracker, optional_yield y, const DoutPrefixProvider *dpp) { // read from cache auto cache = store->getRados()->get_topic_cache(); @@ -1030,7 +1030,7 @@ int RadosBucket::read_topics(rgw_pubsub_bucket_topics& notifications, try { decode(notifications, iter); } catch (buffer::error& err) { - ldpp_dout(dpp, 20) << " failed to decode bucket notifications from oid: " << topics_oid() << ". for bucket: " + ldpp_dout(dpp, 20) << " failed to decode bucket notifications from oid: " << topics_oid() << ". for bucket: " << get_name() << ". error: " << err.what() << dendl; return -EIO; } @@ -1049,14 +1049,14 @@ int RadosBucket::write_topics(const rgw_pubsub_bucket_topics& notifications, encode(notifications, bl); return rgw_put_system_obj(dpp, store->svc()->sysobj, - store->svc()->zone->get_zone_params().log_pool, + store->svc()->zone->get_zone_params().log_pool, topics_oid(), bl, false, objv_tracker, real_time(), y); } -int RadosBucket::remove_topics(RGWObjVersionTracker* objv_tracker, +int RadosBucket::remove_topics(RGWObjVersionTracker* objv_tracker, optional_yield y, const DoutPrefixProvider *dpp) { - return rgw_delete_system_obj(dpp, store->svc()->sysobj, + return rgw_delete_system_obj(dpp, store->svc()->sysobj, store->svc()->zone->get_zone_params().log_pool, topics_oid(), objv_tracker, y); @@ -1337,7 +1337,7 @@ int RadosStore::read_topics(const std::string& tenant, rgw_pubsub_topics& topics try { decode(topics, iter); } catch (buffer::error& err) { - ldpp_dout(dpp, 20) << " failed to decode topics from oid: " << topics_oid(tenant) << + ldpp_dout(dpp, 20) << " failed to decode topics from oid: " << topics_oid(tenant) << ". error: " << err.what() << dendl; return -EIO; } @@ -1351,14 +1351,14 @@ int RadosStore::write_topics(const std::string& tenant, const rgw_pubsub_topics& encode(topics, bl); return rgw_put_system_obj(dpp, svc()->sysobj, - svc()->zone->get_zone_params().log_pool, + svc()->zone->get_zone_params().log_pool, topics_oid(tenant), bl, false, objv_tracker, real_time(), y); } int RadosStore::remove_topics(const std::string& tenant, RGWObjVersionTracker* objv_tracker, optional_yield y, const DoutPrefixProvider *dpp) { - return rgw_delete_system_obj(dpp, svc()->sysobj, + return rgw_delete_system_obj(dpp, svc()->sysobj, svc()->zone->get_zone_params().log_pool, topics_oid(tenant), objv_tracker, y); @@ -1515,9 +1515,9 @@ void RadosStore::register_admin_apis(RGWRESTMgr* mgr) mgr->register_resource("ratelimit", new RGWRESTMgr_Ratelimit); } -std::unique_ptr RadosStore::get_lua_manager() +std::unique_ptr RadosStore::get_lua_manager(const std::string& luarocks_path) { - return std::make_unique(this); + return std::make_unique(this, luarocks_path); } std::unique_ptr RadosStore::get_role(std::string name, @@ -2479,7 +2479,7 @@ int RadosMultipartUpload::abort(const DoutPrefixProvider *dpp, CephContext *cct, if (!remove_objs.empty()) { del_op->params.remove_objs = &remove_objs; } - + del_op->params.abortmp = true; del_op->params.parts_accounted_size = parts_accounted_size; @@ -2748,9 +2748,9 @@ int RadosMultipartUpload::complete(const DoutPrefixProvider *dpp, ldpp_dout(dpp, 0) << "ERROR: compression type was changed during multipart upload (" << cs_info.compression_type << ">>" << obj_part.cs_info.compression_type << ")" << dendl; ret = -ERR_INVALID_PART; - return ret; + return ret; } - + if (part_compressed) { int64_t new_ofs; // offset in compression data for new part if (cs_info.blocks.size() > 0) @@ -2764,7 +2764,7 @@ int RadosMultipartUpload::complete(const DoutPrefixProvider *dpp, cb.len = block.len; cs_info.blocks.push_back(cb); new_ofs = cb.new_ofs + cb.len; - } + } if (!compressed) cs_info.compression_type = obj_part.cs_info.compression_type; cs_info.orig_size += obj_part.cs_info.orig_size; @@ -3318,15 +3318,18 @@ RGWBucketSyncPolicyHandlerRef RadosZone::get_sync_policy_handler() return store->svc()->zone->get_sync_policy_handler(get_id()); } -RadosLuaManager::RadosLuaManager(RadosStore* _s) : +RadosLuaManager::RadosLuaManager(RadosStore* _s, const std::string& _luarocks_path) : + StoreLuaManager(_luarocks_path), store(_s), - pool((store->svc() && store->svc()->zone) ? store->svc()->zone->get_zone_params().log_pool : rgw_pool()) + pool((store->svc() && store->svc()->zone) ? store->svc()->zone->get_zone_params().log_pool : rgw_pool()), + ioctx(*store->getRados()->get_lc_pool_ctx()), + packages_watcher(this) { } int RadosLuaManager::get_script(const DoutPrefixProvider* dpp, optional_yield y, const std::string& key, std::string& script) { if (pool.empty()) { - ldpp_dout(dpp, 10) << "WARNING: missing pool when reading lua script " << dendl; + ldpp_dout(dpp, 10) << "WARNING: missing pool when reading Lua script " << dendl; return 0; } bufferlist bl; @@ -3349,7 +3352,7 @@ int RadosLuaManager::get_script(const DoutPrefixProvider* dpp, optional_yield y, int RadosLuaManager::put_script(const DoutPrefixProvider* dpp, optional_yield y, const std::string& key, const std::string& script) { if (pool.empty()) { - ldpp_dout(dpp, 10) << "WARNING: missing pool when writing lua script " << dendl; + ldpp_dout(dpp, 10) << "WARNING: missing pool when writing Lua script " << dendl; return 0; } bufferlist bl; @@ -3366,7 +3369,7 @@ int RadosLuaManager::put_script(const DoutPrefixProvider* dpp, optional_yield y, int RadosLuaManager::del_script(const DoutPrefixProvider* dpp, optional_yield y, const std::string& key) { if (pool.empty()) { - ldpp_dout(dpp, 10) << "WARNING: missing pool when deleting lua script " << dendl; + ldpp_dout(dpp, 10) << "WARNING: missing pool when deleting Lua script " << dendl; return 0; } int r = rgw_delete_system_obj(dpp, store->svc()->sysobj, pool, key, nullptr, y); @@ -3381,28 +3384,31 @@ const std::string PACKAGE_LIST_OBJECT_NAME = "lua_package_allowlist"; int RadosLuaManager::add_package(const DoutPrefixProvider *dpp, optional_yield y, const std::string& package_name) { + if (!ioctx.is_valid()) { + ldpp_dout(dpp, 10) << "WARNING: missing pool when adding Lua package" << dendl; + return 0; + } // add package to list const bufferlist empty_bl; std::map new_package{{package_name, empty_bl}}; librados::ObjectWriteOperation op; op.omap_set(new_package); - auto ret = rgw_rados_operate(dpp, *(store->getRados()->get_lc_pool_ctx()), + return rgw_rados_operate(dpp, ioctx, PACKAGE_LIST_OBJECT_NAME, &op, y); - - if (ret < 0) { - return ret; - } - return 0; } int RadosLuaManager::remove_package(const DoutPrefixProvider *dpp, optional_yield y, const std::string& package_name) { + if (!ioctx.is_valid()) { + ldpp_dout(dpp, 10) << "WARNING: missing pool when removing Lua package" << dendl; + return -ENOENT; + } librados::ObjectWriteOperation op; size_t pos = package_name.find(" "); if (pos != package_name.npos) { // remove specfic version of the the package op.omap_rm_keys(std::set({package_name})); - auto ret = rgw_rados_operate(dpp, *(store->getRados()->get_lc_pool_ctx()), + auto ret = rgw_rados_operate(dpp, ioctx, PACKAGE_LIST_OBJECT_NAME, &op, y); if (ret < 0) { return ret; @@ -3419,7 +3425,7 @@ int RadosLuaManager::remove_package(const DoutPrefixProvider *dpp, optional_yiel const std::string package_no_version = package.substr(0, package.find(" ")); if (package_no_version.compare(package_name) == 0) { op.omap_rm_keys(std::set({package})); - ret = rgw_rados_operate(dpp, *(store->getRados()->get_lc_pool_ctx()), + ret = rgw_rados_operate(dpp, ioctx, PACKAGE_LIST_OBJECT_NAME, &op, y); if (ret < 0) { return ret; @@ -3431,6 +3437,10 @@ int RadosLuaManager::remove_package(const DoutPrefixProvider *dpp, optional_yiel int RadosLuaManager::list_packages(const DoutPrefixProvider *dpp, optional_yield y, rgw::lua::packages_t& packages) { + if (!ioctx.is_valid()) { + ldpp_dout(dpp, 10) << "WARNING: missing pool when listing Lua packages" << dendl; + return -ENOENT; + } constexpr auto max_chunk = 1024U; std::string start_after; bool more = true; @@ -3439,7 +3449,7 @@ int RadosLuaManager::list_packages(const DoutPrefixProvider *dpp, optional_yield librados::ObjectReadOperation op; rgw::lua::packages_t packages_chunk; op.omap_get_keys2(start_after, max_chunk, &packages_chunk, &more, &rval); - const auto ret = rgw_rados_operate(dpp, *(store->getRados()->get_lc_pool_ctx()), + const auto ret = rgw_rados_operate(dpp, ioctx, PACKAGE_LIST_OBJECT_NAME, &op, nullptr, y); if (ret < 0) { @@ -3452,6 +3462,162 @@ int RadosLuaManager::list_packages(const DoutPrefixProvider *dpp, optional_yield return 0; } +int RadosLuaManager::watch_reload(const DoutPrefixProvider* dpp) +{ + if (!ioctx.is_valid()) { + ldpp_dout(dpp, 10) << "WARNING: missing pool when watching reloads of Lua packages" << dendl; + return -ENOENT; + } + // create the object to watch (object may already exist) + librados::ObjectWriteOperation op; + op.create(false); + auto r = rgw_rados_operate(dpp, ioctx, + PACKAGE_LIST_OBJECT_NAME, &op, null_yield); + if (r < 0) { + ldpp_dout(dpp, 1) << "ERROR: failed to watch " << PACKAGE_LIST_OBJECT_NAME + << ". cannot create object. error: " << cpp_strerror(r) << dendl; + return r; + } + r = ioctx.watch2(PACKAGE_LIST_OBJECT_NAME, &watch_handle, &packages_watcher); + if (r < 0) { + ldpp_dout(dpp, 1) << "ERROR: failed to watch " << PACKAGE_LIST_OBJECT_NAME + << ". error: " << cpp_strerror(r) << dendl; + return r; + } + ldpp_dout(dpp, 20) << "Started watching for reloads of " << PACKAGE_LIST_OBJECT_NAME + << " with handle: " << watch_handle << dendl; + + return 0; +} + +int RadosLuaManager::unwatch_reload(const DoutPrefixProvider* dpp) +{ + if (watch_handle == 0) { + // nothing to unwatch + return 0; + } + + if (!ioctx.is_valid()) { + ldpp_dout(dpp, 10) << "WARNING: missing pool when unwatching reloads of Lua packages" << dendl; + return -ENOENT; + } + const auto r = ioctx.unwatch2(watch_handle); + if (r < 0) { + ldpp_dout(dpp, 1) << "ERROR: failed to unwatch " << PACKAGE_LIST_OBJECT_NAME + << ". error: " << cpp_strerror(r) << dendl; + return r; + } + ldpp_dout(dpp, 20) << "Stopped watching for reloads of " << PACKAGE_LIST_OBJECT_NAME + << " with handle: " << watch_handle << dendl; + + return 0; +} + +void RadosLuaManager::ack_reload(const DoutPrefixProvider* dpp, uint64_t notify_id, uint64_t cookie, int reload_status) { + if (!ioctx.is_valid()) { + ldpp_dout(dpp, 10) << "WARNING: missing pool when acking reload of Lua packages" << dendl; + return; + } + bufferlist reply; + ceph::encode(reload_status, reply); + ioctx.notify_ack(PACKAGE_LIST_OBJECT_NAME, notify_id, cookie, reply); +} + +void RadosLuaManager::handle_reload_notify(const DoutPrefixProvider* dpp, optional_yield y, uint64_t notify_id, uint64_t cookie) { + if (cookie != watch_handle) { + return; + } + + rgw::lua::packages_t failed_packages; + std::string install_dir; + auto r = rgw::lua::install_packages(dpp, store, + y, store->ctx()->_conf.get_val("rgw_luarocks_location"), + failed_packages, install_dir); + if (r < 0) { + ldpp_dout(dpp, 1) << "WARNING: failed to install Lua packages from allowlist. error code: " << r + << dendl; + } + set_luarocks_path(install_dir); + for (const auto &p : failed_packages) { + ldpp_dout(dpp, 5) << "WARNING: failed to install Lua package: " << p + << " from allowlist" << dendl; + } + + ack_reload(dpp, notify_id, cookie, r); +} + +int RadosLuaManager::reload_packages(const DoutPrefixProvider *dpp, optional_yield y) +{ + if (!ioctx.is_valid()) { + ldpp_dout(dpp, 10) << "WARNING: missing pool trying to notify reload of Lua packages" << dendl; + return -ENOENT; + } + bufferlist empty_bl; + bufferlist reply_bl; + const uint64_t timeout_ms = 0; + auto r = rgw_rados_notify(dpp, + ioctx, + PACKAGE_LIST_OBJECT_NAME, + empty_bl, timeout_ms, &reply_bl, y); + if (r < 0) { + ldpp_dout(dpp, 1) << "ERROR: failed to notify reload on " << PACKAGE_LIST_OBJECT_NAME + << ". error: " << cpp_strerror(r) << dendl; + return r; + } + + std::vector acks; + std::vector timeouts; + ioctx.decode_notify_response(reply_bl, &acks, &timeouts); + if (timeouts.size() > 0) { + ldpp_dout(dpp, 1) << "ERROR: failed to notify reload on " << PACKAGE_LIST_OBJECT_NAME + << ". error: timeout" << dendl; + return -EAGAIN; + } + for (auto& ack : acks) { + try { + auto iter = ack.payload_bl.cbegin(); + ceph::decode(r, iter); + } catch (buffer::error& err) { + ldpp_dout(dpp, 1) << "ERROR: couldn't decode Lua packages reload status. error: " << + err.what() << dendl; + return -EINVAL; + } + if (r < 0) { + return r; + } + } + + return 0; +} + +void RadosLuaManager::PackagesWatcher::handle_notify(uint64_t notify_id, uint64_t cookie, uint64_t notifier_id, bufferlist &bl) +{ + parent->handle_reload_notify(this, null_yield, notify_id, cookie); +} + +void RadosLuaManager::PackagesWatcher::handle_error(uint64_t cookie, int err) +{ + if (parent->watch_handle != cookie) { + return; + } + ldpp_dout(this, 5) << "WARNING: restarting reload watch handler. error: " << err << dendl; + + parent->unwatch_reload(this); + parent->watch_reload(this); +} + +CephContext* RadosLuaManager::PackagesWatcher::get_cct() const { + return parent->store->ctx(); +} + +unsigned RadosLuaManager::PackagesWatcher::get_subsys() const { + return dout_subsys; +} + +std::ostream& RadosLuaManager::PackagesWatcher::gen_prefix(std::ostream& out) const { + return out << "rgw lua package reloader: "; +} + int RadosOIDCProvider::store_url(const DoutPrefixProvider *dpp, const std::string& url, bool exclusive, optional_yield y) { auto sysobj = store->svc()->sysobj; diff --git a/src/rgw/driver/rados/rgw_sal_rados.h b/src/rgw/driver/rados/rgw_sal_rados.h index 75d4be843de..228ba532869 100644 --- a/src/rgw/driver/rados/rgw_sal_rados.h +++ b/src/rgw/driver/rados/rgw_sal_rados.h @@ -198,7 +198,7 @@ class RadosStore : public StoreDriver { virtual int meta_remove(const DoutPrefixProvider* dpp, std::string& metadata_key, optional_yield y) override; virtual const RGWSyncModuleInstanceRef& get_sync_module() { return rados->get_sync_module(); } virtual std::string get_host_id() { return rados->host_id; } - virtual std::unique_ptr get_lua_manager() override; + std::unique_ptr get_lua_manager(const std::string& luarocks_path) override; virtual std::unique_ptr get_role(std::string name, std::string tenant, std::string path="", @@ -889,19 +889,43 @@ public: }; class RadosLuaManager : public StoreLuaManager { + class PackagesWatcher : public librados::WatchCtx2, public DoutPrefixProvider { + RadosLuaManager* const parent; + public: + PackagesWatcher(RadosLuaManager* _parent) : + parent(_parent) {} + ~PackagesWatcher() override = default; + void handle_notify(uint64_t notify_id, uint64_t cookie, + uint64_t notifier_id, bufferlist& bl) override; + void handle_error(uint64_t cookie, int err) override; + + // DoutPrefixProvider iterface + CephContext* get_cct() const override; + unsigned get_subsys() const override; + std::ostream& gen_prefix(std::ostream& out) const override; + }; + RadosStore* const store; rgw_pool pool; + librados::IoCtx& ioctx; + PackagesWatcher packages_watcher; + void ack_reload(const DoutPrefixProvider* dpp, uint64_t notify_id, uint64_t cookie, int reload_status); + void handle_reload_notify(const DoutPrefixProvider* dpp, optional_yield y, uint64_t notify_id, uint64_t cookie); + uint64_t watch_handle = 0; public: - RadosLuaManager(RadosStore* _s); - virtual ~RadosLuaManager() = default; - - virtual int get_script(const DoutPrefixProvider* dpp, optional_yield y, const std::string& key, std::string& script); - virtual int put_script(const DoutPrefixProvider* dpp, optional_yield y, const std::string& key, const std::string& script); - virtual int del_script(const DoutPrefixProvider* dpp, optional_yield y, const std::string& key); - virtual int add_package(const DoutPrefixProvider* dpp, optional_yield y, const std::string& package_name); - virtual int remove_package(const DoutPrefixProvider* dpp, optional_yield y, const std::string& package_name); - virtual int list_packages(const DoutPrefixProvider* dpp, optional_yield y, rgw::lua::packages_t& packages); + RadosLuaManager(RadosStore* _s, const std::string& _luarocks_path); + ~RadosLuaManager() override = default; + + int get_script(const DoutPrefixProvider* dpp, optional_yield y, const std::string& key, std::string& script) override; + int put_script(const DoutPrefixProvider* dpp, optional_yield y, const std::string& key, const std::string& script) override; + int del_script(const DoutPrefixProvider* dpp, optional_yield y, const std::string& key) override; + int add_package(const DoutPrefixProvider* dpp, optional_yield y, const std::string& package_name) override; + int remove_package(const DoutPrefixProvider* dpp, optional_yield y, const std::string& package_name) override; + int list_packages(const DoutPrefixProvider* dpp, optional_yield y, rgw::lua::packages_t& packages) override; + int reload_packages(const DoutPrefixProvider* dpp, optional_yield y) override; + int watch_reload(const DoutPrefixProvider* dpp); + int unwatch_reload(const DoutPrefixProvider* dpp); }; class RadosOIDCProvider : public RGWOIDCProvider { diff --git a/src/rgw/rgw_admin.cc b/src/rgw/rgw_admin.cc index 0b82da7774f..a4e17b8895a 100644 --- a/src/rgw/rgw_admin.cc +++ b/src/rgw/rgw_admin.cc @@ -316,12 +316,13 @@ void usage() cout << " topic get get a bucket notifications topic\n"; cout << " topic rm remove a bucket notifications topic\n"; cout << " topic stats get a bucket notifications persistent topic stats (i.e. reservations, entries & size)\n"; - cout << " script put upload a lua script to a context\n"; - cout << " script get get the lua script of a context\n"; - cout << " script rm remove the lua scripts of a context\n"; - cout << " script-package add add a lua package to the scripts allowlist\n"; - cout << " script-package rm remove a lua package from the scripts allowlist\n"; - cout << " script-package list get the lua packages allowlist\n"; + cout << " script put upload a Lua script to a context\n"; + cout << " script get get the Lua script of a context\n"; + cout << " script rm remove the Lua scripts of a context\n"; + cout << " script-package add add a Lua package to the scripts allowlist\n"; + cout << " script-package rm remove a Lua package from the scripts allowlist\n"; + cout << " script-package list get the Lua packages allowlist\n"; + cout << " script-package reload install/remove Lua packages according to allowlist\n"; cout << " notification list list bucket notifications configuration\n"; cout << " notification get get a bucket notifications configuration\n"; cout << " notification rm remove a bucket notifications configuration\n"; @@ -493,7 +494,7 @@ void usage() cout << " --notification-id bucket notifications id\n"; cout << "\nScript options:\n"; cout << " --context context in which the script runs. one of: "+LUA_CONTEXT_LIST+"\n"; - cout << " --package name of the lua package that should be added/removed to/from the allowlist\n"; + cout << " --package name of the Lua package that should be added/removed to/from the allowlist\n"; cout << " --allow-compilation package is allowed to compile C code as part of its installation\n"; cout << "\nBucket check olh/unlinked options:\n"; cout << " --min-age-hours minimum age of unlinked objects to consider for bucket check unlinked (default: 1)\n"; @@ -857,7 +858,8 @@ enum class OPT { SCRIPT_RM, SCRIPT_PACKAGE_ADD, SCRIPT_PACKAGE_RM, - SCRIPT_PACKAGE_LIST + SCRIPT_PACKAGE_LIST, + SCRIPT_PACKAGE_RELOAD }; } @@ -1096,6 +1098,7 @@ static SimpleCmd::Commands all_cmds = { { "script-package add", OPT::SCRIPT_PACKAGE_ADD }, { "script-package rm", OPT::SCRIPT_PACKAGE_RM }, { "script-package list", OPT::SCRIPT_PACKAGE_LIST }, + { "script-package reload", OPT::SCRIPT_PACKAGE_RELOAD }, }; static SimpleCmd::Aliases cmd_aliases = { @@ -10732,7 +10735,7 @@ next: cerr << "ERROR: cannot specify tenant in background context" << std::endl; return EINVAL; } - auto lua_manager = driver->get_lua_manager(); + auto lua_manager = driver->get_lua_manager(""); rc = rgw::lua::write_script(dpp(), lua_manager.get(), tenant, null_yield, script_ctx, script); if (rc < 0) { cerr << "ERROR: failed to put script. error: " << rc << std::endl; @@ -10750,7 +10753,7 @@ next: cerr << "ERROR: invalid script context: " << *str_script_ctx << ". must be one of: " << LUA_CONTEXT_LIST << std::endl; return EINVAL; } - auto lua_manager = driver->get_lua_manager(); + auto lua_manager = driver->get_lua_manager(""); std::string script; const auto rc = rgw::lua::read_script(dpp(), lua_manager.get(), tenant, null_yield, script_ctx, script); if (rc == -ENOENT) { @@ -10774,7 +10777,7 @@ next: cerr << "ERROR: invalid script context: " << *str_script_ctx << ". must be one of: " << LUA_CONTEXT_LIST << std::endl; return EINVAL; } - auto lua_manager = driver->get_lua_manager(); + auto lua_manager = driver->get_lua_manager(""); const auto rc = rgw::lua::delete_script(dpp(), lua_manager.get(), tenant, null_yield, script_ctx); if (rc < 0) { cerr << "ERROR: failed to remove script. error: " << rc << std::endl; @@ -10785,16 +10788,16 @@ next: if (opt_cmd == OPT::SCRIPT_PACKAGE_ADD) { #ifdef WITH_RADOSGW_LUA_PACKAGES if (!script_package) { - cerr << "ERROR: lua package name was not provided (via --package)" << std::endl; + cerr << "ERROR: Lua package name was not provided (via --package)" << std::endl; return EINVAL; } const auto rc = rgw::lua::add_package(dpp(), driver, null_yield, *script_package, bool(allow_compilation)); if (rc < 0) { - cerr << "ERROR: failed to add lua package: " << script_package << " .error: " << rc << std::endl; + cerr << "ERROR: failed to add Lua package: " << script_package << " .error: " << rc << std::endl; return -rc; } #else - cerr << "ERROR: adding lua packages is not permitted" << std::endl; + cerr << "ERROR: adding Lua packages is not permitted" << std::endl; return EPERM; #endif } @@ -10802,7 +10805,7 @@ next: if (opt_cmd == OPT::SCRIPT_PACKAGE_RM) { #ifdef WITH_RADOSGW_LUA_PACKAGES if (!script_package) { - cerr << "ERROR: lua package name was not provided (via --package)" << std::endl; + cerr << "ERROR: Lua package name was not provided (via --package)" << std::endl; return EINVAL; } const auto rc = rgw::lua::remove_package(dpp(), driver, null_yield, *script_package); @@ -10811,11 +10814,11 @@ next: return 0; } if (rc < 0) { - cerr << "ERROR: failed to remove lua package: " << script_package << " .error: " << rc << std::endl; + cerr << "ERROR: failed to remove Lua package: " << script_package << " .error: " << rc << std::endl; return -rc; } #else - cerr << "ERROR: removing lua packages in not permitted" << std::endl; + cerr << "ERROR: removing Lua packages in not permitted" << std::endl; return EPERM; #endif } @@ -10825,9 +10828,9 @@ next: rgw::lua::packages_t packages; const auto rc = rgw::lua::list_packages(dpp(), driver, null_yield, packages); if (rc == -ENOENT) { - std::cout << "no lua packages in allowlist" << std::endl; + std::cout << "no Lua packages in allowlist" << std::endl; } else if (rc < 0) { - cerr << "ERROR: failed to read lua packages allowlist. error: " << rc << std::endl; + cerr << "ERROR: failed to read Lua packages allowlist. error: " << rc << std::endl; return rc; } else { for (const auto& package : packages) { @@ -10835,11 +10838,23 @@ next: } } #else - cerr << "ERROR: listing lua packages in not permitted" << std::endl; + cerr << "ERROR: listing Lua packages in not permitted" << std::endl; return EPERM; #endif } + if (opt_cmd == OPT::SCRIPT_PACKAGE_RELOAD) { +#ifdef WITH_RADOSGW_LUA_PACKAGES + const auto rc = rgw::lua::reload_packages(dpp(), driver, null_yield); + if (rc < 0) { + cerr << "ERROR: failed to reload Lua packages. error: " << rc << std::endl; + return rc; + } +#else + cerr << "ERROR: reloading Lua packages in not permitted" << std::endl; + return EPERM; +#endif + } return 0; } diff --git a/src/rgw/rgw_appmain.cc b/src/rgw/rgw_appmain.cc index 5eaf03e5793..57a1a16783a 100644 --- a/src/rgw/rgw_appmain.cc +++ b/src/rgw/rgw_appmain.cc @@ -550,29 +550,29 @@ void rgw::AppMain::init_lua() { rgw::sal::Driver* driver = env.driver; int r{0}; - std::string path = g_conf().get_val("rgw_luarocks_location"); + std::string install_dir; #ifdef WITH_RADOSGW_LUA_PACKAGES rgw::lua::packages_t failed_packages; - r = rgw::lua::install_packages(dpp, driver, null_yield, path, - failed_packages, env.lua.luarocks_path); + r = rgw::lua::install_packages(dpp, driver, null_yield, g_conf().get_val("rgw_luarocks_location"), + failed_packages, install_dir); if (r < 0) { - dout(1) << "WARNING: failed to install lua packages from allowlist. error: " << r + ldpp_dout(dpp, 5) << "WARNING: failed to install Lua packages from allowlist. error: " << r << dendl; } for (const auto &p : failed_packages) { - dout(5) << "WARNING: failed to install lua package: " << p + ldpp_dout(dpp, 5) << "WARNING: failed to install Lua package: " << p << " from allowlist" << dendl; } #endif - env.lua.manager = env.driver->get_lua_manager(); - + env.lua.manager = env.driver->get_lua_manager(install_dir); if (driver->get_name() == "rados") { /* Supported for only RadosStore */ lua_background = std::make_unique< - rgw::lua::Background>(driver, dpp->get_cct(), path); + rgw::lua::Background>(driver, dpp->get_cct(), env.lua.manager.get()); lua_background->start(); env.lua.background = lua_background.get(); + static_cast(env.lua.manager.get())->watch_reload(dpp); } } /* init_lua */ @@ -580,6 +580,7 @@ void rgw::AppMain::shutdown(std::function finalize_async_signals) { if (env.driver->get_name() == "rados") { reloader.reset(); // stop the realm reloader + static_cast(env.lua.manager.get())->unwatch_reload(dpp); } for (auto& fe : fes) { diff --git a/src/rgw/rgw_lua.cc b/src/rgw/rgw_lua.cc index 505c5fc25cd..6a5780a3eb1 100644 --- a/src/rgw/rgw_lua.cc +++ b/src/rgw/rgw_lua.cc @@ -97,7 +97,7 @@ int delete_script(const DoutPrefixProvider *dpp, sal::LuaManager* manager, const namespace bp = boost::process; -int add_package(const DoutPrefixProvider *dpp, rgw::sal::Driver* driver, optional_yield y, const std::string& package_name, bool allow_compilation) +int add_package(const DoutPrefixProvider* dpp, rgw::sal::Driver* driver, optional_yield y, const std::string& package_name, bool allow_compilation) { // verify that luarocks can load this package const auto p = bp::search_path("luarocks"); @@ -133,25 +133,19 @@ int add_package(const DoutPrefixProvider *dpp, rgw::sal::Driver* driver, optiona return ret; } - auto lua_mgr = driver->get_lua_manager(); - - return lua_mgr->add_package(dpp, y, package_name); + return driver->get_lua_manager("")->add_package(dpp, y, package_name); } int remove_package(const DoutPrefixProvider *dpp, rgw::sal::Driver* driver, optional_yield y, const std::string& package_name) { - auto lua_mgr = driver->get_lua_manager(); - - return lua_mgr->remove_package(dpp, y, package_name); + return driver->get_lua_manager("")->remove_package(dpp, y, package_name); } namespace bp = boost::process; int list_packages(const DoutPrefixProvider *dpp, rgw::sal::Driver* driver, optional_yield y, packages_t& packages) { - auto lua_mgr = driver->get_lua_manager(); - - return lua_mgr->list_packages(dpp, y, packages); + return driver->get_lua_manager("")->list_packages(dpp, y, packages); } namespace fs = std::filesystem; @@ -244,34 +238,14 @@ int install_packages(const DoutPrefixProvider *dpp, rgw::sal::Driver* driver, ldpp_dout(dpp, 20) << lines << dendl; } - // luarocks directory cleanup - /*std::error_code ec; - if (fs::remove_all(luarocks_path, ec) - == static_cast(-1) && - ec != std::errc::no_such_file_or_directory) { - ldpp_dout(dpp, 1) << "Lua ERROR: failed to clear luarocks directory: " << - luarocks_path << ". error: " << ec.message() << dendl; - return -ec.value(); - }*/ - /*auto rc = create_directory_p(dpp, luarocks_path); - if (rc < 0) { - ldpp_dout(dpp, 1) << "Lua ERROR: failed to recreate luarocks directory: " << - luarocks_path << ". error: " << rc << dendl; - return rc; - }*/ - - // switch temporary install directory to luarocks one - /*fs::rename(tmp_luarocks_path, luarocks_path, ec); - if (ec) { - ldpp_dout(dpp, 1) << "Lua ERROR: failed to switch between temp directory: " << - tmp_luarocks_path << " and luarocks directory: " << luarocks_path << - " . error: " << ec.message() << dendl; - return -ec.value(); - }*/ - return 0; } +int reload_packages(const DoutPrefixProvider *dpp, rgw::sal::Driver* driver, optional_yield y) +{ + return driver->get_lua_manager("")->reload_packages(dpp, y); +} + #endif // WITH_RADOSGW_LUA_PACKAGES } diff --git a/src/rgw/rgw_lua.h b/src/rgw/rgw_lua.h index e8962aba6c4..30b3272c4e4 100644 --- a/src/rgw/rgw_lua.h +++ b/src/rgw/rgw_lua.h @@ -57,6 +57,9 @@ int remove_package(const DoutPrefixProvider *dpp, rgw::sal::Driver* driver, opti // list lua packages in the allowlist int list_packages(const DoutPrefixProvider *dpp, rgw::sal::Driver* driver, optional_yield y, packages_t& packages); +// reload lua packages +int reload_packages(const DoutPrefixProvider *dpp, rgw::sal::Driver* driver, optional_yield y); + // install all packages from the allowlist // return (by reference) the list of packages that failed to install // and return (by reference) the temporary director in which the packages were installed @@ -64,6 +67,7 @@ int install_packages(const DoutPrefixProvider *dpp, rgw::sal::Driver* driver, optional_yield y, const std::string& luarocks_path, packages_t& failed_packages, std::string& install_dir); + #endif } diff --git a/src/rgw/rgw_lua_background.cc b/src/rgw/rgw_lua_background.cc index 16a6ca5b4d8..93c509a78cc 100644 --- a/src/rgw/rgw_lua_background.cc +++ b/src/rgw/rgw_lua_background.cc @@ -56,15 +56,15 @@ int RGWTable::increment_by(lua_State* L) { return 0; } -Background::Background(rgw::sal::Driver* driver, - CephContext* cct, - const std::string& luarocks_path, - int execute_interval) : - execute_interval(execute_interval), - dp(cct, dout_subsys, "lua background: "), - lua_manager(driver->get_lua_manager()), - cct(cct), - luarocks_path(luarocks_path) {} +Background::Background(rgw::sal::Driver* _driver, + CephContext* _cct, + rgw::sal::LuaManager* _lua_manager, + int _execute_interval) : + execute_interval(_execute_interval) + , dp(_cct, dout_subsys, "lua background: ") + , lua_manager(_lua_manager) + , cct(_cct) +{} void Background::shutdown(){ stopped = true; @@ -97,7 +97,6 @@ void Background::pause() { } void Background::resume(rgw::sal::Driver* driver) { - lua_manager = driver->get_lua_manager(); paused = false; cond.notify_all(); } @@ -108,7 +107,7 @@ int Background::read_script() { return -EAGAIN; } std::string tenant; - return rgw::lua::read_script(&dp, lua_manager.get(), tenant, null_yield, rgw::lua::context::background, rgw_script); + return rgw::lua::read_script(&dp, lua_manager, tenant, null_yield, rgw::lua::context::background, rgw_script); } const BackgroundMapValue Background::empty_table_value; @@ -135,7 +134,7 @@ void Background::run() { } try { open_standard_libs(L); - set_package_path(L, luarocks_path); + set_package_path(L, lua_manager->luarocks_path()); create_debug_action(L, cct); create_background_metatable(L); } catch (const std::runtime_error& e) { @@ -155,6 +154,7 @@ void Background::run() { } ldpp_dout(dpp, 10) << "Lua background thread resumed" << dendl; } + const auto rc = read_script(); if (rc == -ENOENT || rc == -EAGAIN) { // either no script or paused, nothing to do @@ -190,5 +190,9 @@ void Background::create_background_metatable(lua_State* L) { ceph_assert(lua_istable(L, -1)); } +void Background::set_manager(rgw::sal::LuaManager* _lua_manager) { + lua_manager = _lua_manager; +} + } //namespace rgw::lua diff --git a/src/rgw/rgw_lua_background.h b/src/rgw/rgw_lua_background.h index dbca399a695..e2f290213b5 100644 --- a/src/rgw/rgw_lua_background.h +++ b/src/rgw/rgw_lua_background.h @@ -135,6 +135,7 @@ struct RGWTable : EmptyMetaTable { class Background : public RGWRealmReloader::Pauser { public: static const BackgroundMapValue empty_table_value; + private: BackgroundMap rgw_map; bool stopped = false; @@ -142,9 +143,8 @@ private: bool paused = false; int execute_interval; const DoutPrefix dp; - std::unique_ptr lua_manager; + rgw::sal::LuaManager* lua_manager; CephContext* const cct; - const std::string luarocks_path; std::thread runner; mutable std::mutex table_mutex; std::mutex cond_mutex; @@ -158,24 +158,26 @@ protected: virtual int read_script(); public: - Background(rgw::sal::Driver* driver, - CephContext* cct, - const std::string& luarocks_path, - int execute_interval = INIT_EXECUTE_INTERVAL); - - virtual ~Background() = default; - void start(); - void shutdown(); - void create_background_metatable(lua_State* L); - const BackgroundMapValue& get_table_value(const std::string& key) const; - template - void put_table_value(const std::string& key, T value) { - std::unique_lock cond_lock(table_mutex); - rgw_map[key] = value; - } - - void pause() override; - void resume(rgw::sal::Driver* _driver) override; + Background(rgw::sal::Driver* _driver, + CephContext* _cct, + rgw::sal::LuaManager* _lua_manager, + int _execute_interval = INIT_EXECUTE_INTERVAL); + + ~Background() override = default; + void start(); + void shutdown(); + void create_background_metatable(lua_State* L); + const BackgroundMapValue& get_table_value(const std::string& key) const; + template + void put_table_value(const std::string& key, T value) { + std::unique_lock cond_lock(table_mutex); + rgw_map[key] = value; + } + + // update the manager after + void set_manager(rgw::sal::LuaManager* _lua_manager); + void pause() override; + void resume(rgw::sal::Driver* _driver) override; }; } //namepsace rgw::lua diff --git a/src/rgw/rgw_lua_request.cc b/src/rgw/rgw_lua_request.cc index cfbf511aac2..058384929b3 100644 --- a/src/rgw/rgw_lua_request.cc +++ b/src/rgw/rgw_lua_request.cc @@ -784,7 +784,7 @@ int execute( int rc = 0; try { open_standard_libs(L); - set_package_path(L, s->penv.lua.luarocks_path); + set_package_path(L, s->penv.lua.manager->luarocks_path()); create_debug_action(L, s->cct); diff --git a/src/rgw/rgw_perf_counters.cc b/src/rgw/rgw_perf_counters.cc index fd058ab00a9..6757dd8913c 100644 --- a/src/rgw/rgw_perf_counters.cc +++ b/src/rgw/rgw_perf_counters.cc @@ -60,8 +60,8 @@ int rgw_perf_start(CephContext *cct) plb.add_u64(l_rgw_pubsub_push_pending, "pubsub_push_pending", "Pubsub events pending reply from endpoint"); plb.add_u64_counter(l_rgw_pubsub_missing_conf, "pubsub_missing_conf", "Pubsub events could not be handled because of missing configuration"); - plb.add_u64_counter(l_rgw_lua_script_ok, "lua_script_ok", "Successfull executions of lua scripts"); - plb.add_u64_counter(l_rgw_lua_script_fail, "lua_script_fail", "Failed executions of lua scripts"); + plb.add_u64_counter(l_rgw_lua_script_ok, "lua_script_ok", "Successfull executions of Lua scripts"); + plb.add_u64_counter(l_rgw_lua_script_fail, "lua_script_fail", "Failed executions of Lua scripts"); plb.add_u64(l_rgw_lua_current_vms, "lua_current_vms", "Number of Lua VMs currently being executed"); perfcounter = plb.create_perf_counters(); diff --git a/src/rgw/rgw_process_env.h b/src/rgw/rgw_process_env.h index 905c0a5411c..710340f0a25 100644 --- a/src/rgw/rgw_process_env.h +++ b/src/rgw/rgw_process_env.h @@ -32,7 +32,6 @@ namespace rgw::flight { #endif struct RGWLuaProcessEnv { - std::string luarocks_path; rgw::lua::Background* background = nullptr; std::unique_ptr manager; }; diff --git a/src/rgw/rgw_realm_reloader.cc b/src/rgw/rgw_realm_reloader.cc index 4973ec14080..745dac7fefe 100644 --- a/src/rgw/rgw_realm_reloader.cc +++ b/src/rgw/rgw_realm_reloader.cc @@ -183,7 +183,10 @@ void RGWRealmReloader::reload() * the dynamic reconfiguration. */ env.auth_registry = rgw::auth::StrategyRegistry::create( cct, implicit_tenants, env.driver); - env.lua.manager = env.driver->get_lua_manager(); + env.lua.manager = env.driver->get_lua_manager(env.lua.manager->luarocks_path()); + if (env.lua.background) { + env.lua.background->set_manager(env.lua.manager.get()); + } ldpp_dout(&dp, 1) << "Resuming frontends with new realm configuration." << dendl; diff --git a/src/rgw/rgw_sal.h b/src/rgw/rgw_sal.h index 6b54067fb4c..84731f333d7 100644 --- a/src/rgw/rgw_sal.h +++ b/src/rgw/rgw_sal.h @@ -396,8 +396,8 @@ class Driver { virtual const RGWSyncModuleInstanceRef& get_sync_module() = 0; /** Get the ID of the current host */ virtual std::string get_host_id() = 0; - /** Get a Lua script manager for running lua scripts */ - virtual std::unique_ptr get_lua_manager() = 0; + /** Get a Lua script manager for running lua scripts and reloading packages */ + virtual std::unique_ptr get_lua_manager(const std::string& luarocks_path) = 0; /** Get an IAM Role by name etc. */ virtual std::unique_ptr get_role(std::string name, std::string tenant, @@ -1514,6 +1514,12 @@ public: virtual int remove_package(const DoutPrefixProvider* dpp, optional_yield y, const std::string& package_name) = 0; /** List lua packages */ virtual int list_packages(const DoutPrefixProvider* dpp, optional_yield y, rgw::lua::packages_t& packages) = 0; + /** Reload lua packages */ + virtual int reload_packages(const DoutPrefixProvider* dpp, optional_yield y) = 0; + /** Get the path to the loarocks install location **/ + virtual const std::string& luarocks_path() const = 0; + /** Set the path to the loarocks install location **/ + virtual void set_luarocks_path(const std::string& path) = 0; }; /** @} namespace rgw::sal in group RGWSAL */ diff --git a/src/rgw/rgw_sal_dbstore.cc b/src/rgw/rgw_sal_dbstore.cc index c640c5bfe8c..aa1243fe598 100644 --- a/src/rgw/rgw_sal_dbstore.cc +++ b/src/rgw/rgw_sal_dbstore.cc @@ -596,7 +596,7 @@ namespace rgw::sal { return nullptr; } - std::unique_ptr DBStore::get_lua_manager() + std::unique_ptr DBStore::get_lua_manager(const std::string& luarocks_path) { return std::make_unique(this); } @@ -1986,6 +1986,12 @@ namespace rgw::sal { { return -ENOENT; } + + int DBLuaManager::reload_packages(const DoutPrefixProvider* dpp, optional_yield y) + { + return -ENOENT; + } + } // namespace rgw::sal extern "C" { diff --git a/src/rgw/rgw_sal_dbstore.h b/src/rgw/rgw_sal_dbstore.h index ed56e8c1149..65ffd909109 100644 --- a/src/rgw/rgw_sal_dbstore.h +++ b/src/rgw/rgw_sal_dbstore.h @@ -368,6 +368,8 @@ protected: virtual int remove_package(const DoutPrefixProvider* dpp, optional_yield y, const std::string& package_name) override; /** List lua packages */ virtual int list_packages(const DoutPrefixProvider* dpp, optional_yield y, rgw::lua::packages_t& packages) override; + /** Reload lua packages */ + virtual int reload_packages(const DoutPrefixProvider* dpp, optional_yield y) override; }; class DBOIDCProvider : public RGWOIDCProvider { @@ -843,7 +845,7 @@ public: virtual const RGWSyncModuleInstanceRef& get_sync_module() { return sync_module; } virtual std::string get_host_id() { return ""; } - virtual std::unique_ptr get_lua_manager() override; + std::unique_ptr get_lua_manager(const std::string& luarocks_path) override; virtual std::unique_ptr get_role(std::string name, std::string tenant, std::string path="", diff --git a/src/rgw/rgw_sal_filter.cc b/src/rgw/rgw_sal_filter.cc index 6980cd01cd1..13e9155c524 100644 --- a/src/rgw/rgw_sal_filter.cc +++ b/src/rgw/rgw_sal_filter.cc @@ -432,9 +432,9 @@ const RGWSyncModuleInstanceRef& FilterDriver::get_sync_module() return next->get_sync_module(); } -std::unique_ptr FilterDriver::get_lua_manager() +std::unique_ptr FilterDriver::get_lua_manager(const std::string& luarocks_path) { - std::unique_ptr nm = next->get_lua_manager(); + std::unique_ptr nm = next->get_lua_manager(luarocks_path); return std::make_unique(std::move(nm)); } @@ -1319,6 +1319,19 @@ int FilterLuaManager::list_packages(const DoutPrefixProvider* dpp, optional_yiel return next->list_packages(dpp, y, packages); } +int FilterLuaManager::reload_packages(const DoutPrefixProvider* dpp, optional_yield y) +{ + return next->reload_packages(dpp, y); +} + +const std::string& FilterLuaManager::luarocks_path() const { + return next->luarocks_path(); +} + +void FilterLuaManager::set_luarocks_path(const std::string& path) { + next->set_luarocks_path(path); +} + } } // namespace rgw::sal extern "C" { diff --git a/src/rgw/rgw_sal_filter.h b/src/rgw/rgw_sal_filter.h index 5011b89df61..6db44a19100 100644 --- a/src/rgw/rgw_sal_filter.h +++ b/src/rgw/rgw_sal_filter.h @@ -264,7 +264,7 @@ public: std::string& metadata_key, optional_yield y) override; virtual const RGWSyncModuleInstanceRef& get_sync_module() override; virtual std::string get_host_id() override { return next->get_host_id(); } - virtual std::unique_ptr get_lua_manager() override; + virtual std::unique_ptr get_lua_manager(const std::string& luarocks_path) override; virtual std::unique_ptr get_role(std::string name, std::string tenant, std::string path="", @@ -896,6 +896,10 @@ public: virtual int add_package(const DoutPrefixProvider* dpp, optional_yield y, const std::string& package_name) override; virtual int remove_package(const DoutPrefixProvider* dpp, optional_yield y, const std::string& package_name) override; virtual int list_packages(const DoutPrefixProvider* dpp, optional_yield y, rgw::lua::packages_t& packages) override; + virtual int reload_packages(const DoutPrefixProvider* dpp, optional_yield y) override; + const std::string& luarocks_path() const override; + void set_luarocks_path(const std::string& path) override; + }; } } // namespace rgw::sal diff --git a/src/rgw/rgw_sal_store.h b/src/rgw/rgw_sal_store.h index 124debdb7b4..f5efdc3494f 100644 --- a/src/rgw/rgw_sal_store.h +++ b/src/rgw/rgw_sal_store.h @@ -410,7 +410,18 @@ class StoreZone : public Zone { }; class StoreLuaManager : public LuaManager { +protected: + std::string _luarocks_path; public: + const std::string& luarocks_path() const override { + return _luarocks_path; + } + void set_luarocks_path(const std::string& path) override { + _luarocks_path = path; + } + StoreLuaManager() = default; + StoreLuaManager(const std::string& __luarocks_path) : + _luarocks_path(__luarocks_path) {} virtual ~StoreLuaManager() = default; }; diff --git a/src/test/cli/radosgw-admin/help.t b/src/test/cli/radosgw-admin/help.t index 8762c43c5c9..179094dc4b5 100644 --- a/src/test/cli/radosgw-admin/help.t +++ b/src/test/cli/radosgw-admin/help.t @@ -185,12 +185,13 @@ topic get get a bucket notifications topic topic rm remove a bucket notifications topic topic stats get a bucket notifications persistent topic stats (i.e. reservations, entries & size) - script put upload a lua script to a context - script get get the lua script of a context - script rm remove the lua scripts of a context - script-package add add a lua package to the scripts allowlist - script-package rm remove a lua package from the scripts allowlist - script-package list get the lua packages allowlist + script put upload a Lua script to a context + script get get the Lua script of a context + script rm remove the Lua scripts of a context + script-package add add a Lua package to the scripts allowlist + script-package rm remove a Lua package from the scripts allowlist + script-package list get the Lua packages allowlist + script-package reload install/remove Lua packages according to allowlist notification list list bucket notifications configuration notification get get a bucket notifications configuration notification rm remove a bucket notifications configuration @@ -370,7 +371,7 @@ Script options: --context context in which the script runs. one of: prerequest, postrequest, background, getdata, putdata - --package name of the lua package that should be added/removed to/from the allowlist + --package name of the Lua package that should be added/removed to/from the allowlist --allow-compilation package is allowed to compile C code as part of its installation Bucket check olh/unlinked options: diff --git a/src/test/rgw/test_rgw_lua.cc b/src/test/rgw/test_rgw_lua.cc index 9eca926e30f..e8656ac8e39 100644 --- a/src/test/rgw/test_rgw_lua.cc +++ b/src/test/rgw/test_rgw_lua.cc @@ -163,7 +163,15 @@ CctCleaner cleaner(g_cct); tracing::Tracer tracer; -#define DEFINE_REQ_STATE RGWProcessEnv pe; RGWEnv e; req_state s(g_cct, pe, &e, 0); +#define MAKE_STORE auto store = std::unique_ptr(new sal::RadosStore); \ + store->setRados(new RGWRados); + +#define DEFINE_REQ_STATE RGWProcessEnv pe; \ + MAKE_STORE; \ + pe.lua.manager = store->get_lua_manager(""); \ + RGWEnv e; \ + req_state s(g_cct, pe, &e, 0); + #define INIT_TRACE tracer.init(g_cct, "test"); \ s.trace = tracer.start_trace("test", true); @@ -775,9 +783,6 @@ TEST(TestRGWLua, NotAllowedInLib) ASSERT_NE(rc, 0); } -#define MAKE_STORE auto store = std::unique_ptr(new sal::RadosStore); \ - store->setRados(new RGWRados); - TEST(TestRGWLua, OpsLog) { const std::string script = R"( @@ -789,8 +794,6 @@ TEST(TestRGWLua, OpsLog) end )"; - MAKE_STORE; - struct MockOpsLogSink : OpsLogSink { bool logged = false; int log(req_state*, rgw_log_entry&) override { logged = true; return 0; } @@ -840,8 +843,11 @@ protected: } public: - TestBackground(sal::RadosStore* store, const std::string& script, unsigned read_time = 0) : - rgw::lua::Background(store, g_cct, "", /* luarocks path */ 1 /* run every second */), + TestBackground(sal::RadosStore* store, const std::string& script, rgw::sal::LuaManager* manager, unsigned read_time = 0) : + rgw::lua::Background(store, + g_cct, + manager, + 1 /* run every second */), read_time(read_time) { // the script is passed in the constructor rgw_script = script; @@ -855,13 +861,14 @@ public: TEST(TestRGWLuaBackground, Start) { MAKE_STORE; + auto manager = store->get_lua_manager(""); { // ctr and dtor without running - TestBackground lua_background(store.get(), ""); + TestBackground lua_background(store.get(), "", manager.get()); } { // ctr and dtor with running - TestBackground lua_background(store.get(), ""); + TestBackground lua_background(store.get(), "", manager.get()); lua_background.start(); } } @@ -888,7 +895,8 @@ TEST(TestRGWLuaBackground, Script) )"; MAKE_STORE; - TestBackground lua_background(store.get(), script); + auto manager = store->get_lua_manager(""); + TestBackground lua_background(store.get(), script, manager.get()); lua_background.start(); std::this_thread::sleep_for(wait_time); EXPECT_EQ(get_table_value(lua_background, "hello"), "world"); @@ -902,8 +910,8 @@ TEST(TestRGWLuaBackground, RequestScript) RGW[key] = value )"; - MAKE_STORE; - TestBackground lua_background(store.get(), background_script); + DEFINE_REQ_STATE; + TestBackground lua_background(store.get(), background_script, pe.lua.manager.get()); lua_background.start(); std::this_thread::sleep_for(wait_time); @@ -914,7 +922,6 @@ TEST(TestRGWLuaBackground, RequestScript) RGW[key] = value )"; - DEFINE_REQ_STATE; pe.lua.background = &lua_background; // to make sure test is consistent we have to puase the background @@ -941,7 +948,8 @@ TEST(TestRGWLuaBackground, Pause) )"; MAKE_STORE; - TestBackground lua_background(store.get(), script); + auto manager = store->get_lua_manager(""); + TestBackground lua_background(store.get(), script, manager.get()); lua_background.start(); std::this_thread::sleep_for(wait_time); const auto value_len = get_table_value(lua_background, "hello").size(); @@ -966,9 +974,10 @@ TEST(TestRGWLuaBackground, PauseWhileReading) )"; MAKE_STORE; - constexpr auto long_wait_time = std::chrono::seconds(6); - TestBackground lua_background(store.get(), script, 2); + auto manager = store->get_lua_manager(""); + TestBackground lua_background(store.get(), script, manager.get(), 2); lua_background.start(); + constexpr auto long_wait_time = std::chrono::seconds(6); std::this_thread::sleep_for(long_wait_time); const auto value_len = get_table_value(lua_background, "hello").size(); EXPECT_GT(value_len, 0); @@ -987,7 +996,8 @@ TEST(TestRGWLuaBackground, ReadWhilePaused) )"; MAKE_STORE; - TestBackground lua_background(store.get(), script); + auto manager = store->get_lua_manager(""); + TestBackground lua_background(store.get(), script, manager.get()); lua_background.pause(); lua_background.start(); std::this_thread::sleep_for(wait_time); @@ -1010,7 +1020,8 @@ TEST(TestRGWLuaBackground, PauseResume) )"; MAKE_STORE; - TestBackground lua_background(store.get(), script); + auto manager = store->get_lua_manager(""); + TestBackground lua_background(store.get(), script, manager.get()); lua_background.start(); std::this_thread::sleep_for(wait_time); const auto value_len = get_table_value(lua_background, "hello").size(); @@ -1038,7 +1049,8 @@ TEST(TestRGWLuaBackground, MultipleStarts) )"; MAKE_STORE; - TestBackground lua_background(store.get(), script); + auto manager = store->get_lua_manager(""); + TestBackground lua_background(store.get(), script, manager.get()); lua_background.start(); std::this_thread::sleep_for(wait_time); const auto value_len = get_table_value(lua_background, "hello").size(); @@ -1055,8 +1067,8 @@ TEST(TestRGWLuaBackground, MultipleStarts) TEST(TestRGWLuaBackground, TableValues) { - MAKE_STORE; - TestBackground lua_background(store.get(), ""); + DEFINE_REQ_STATE; + TestBackground lua_background(store.get(), "", pe.lua.manager.get()); const std::string request_script = R"( RGW["key1"] = "string value" @@ -1065,7 +1077,6 @@ TEST(TestRGWLuaBackground, TableValues) RGW["key4"] = true )"; - DEFINE_REQ_STATE; pe.lua.background = &lua_background; const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, nullptr, request_script); @@ -1078,15 +1089,14 @@ TEST(TestRGWLuaBackground, TableValues) TEST(TestRGWLuaBackground, TablePersist) { - MAKE_STORE; - TestBackground lua_background(store.get(), ""); + DEFINE_REQ_STATE; + TestBackground lua_background(store.get(), "", pe.lua.manager.get()); std::string request_script = R"( RGW["key1"] = "string value" RGW["key2"] = 42 )"; - DEFINE_REQ_STATE; pe.lua.background = &lua_background; auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, nullptr, request_script); @@ -1109,8 +1119,8 @@ TEST(TestRGWLuaBackground, TablePersist) TEST(TestRGWLuaBackground, TableValuesFromRequest) { - MAKE_STORE; - TestBackground lua_background(store.get(), ""); + DEFINE_REQ_STATE; + TestBackground lua_background(store.get(), "", pe.lua.manager.get()); lua_background.start(); const std::string request_script = R"( @@ -1120,7 +1130,6 @@ TEST(TestRGWLuaBackground, TableValuesFromRequest) RGW["key4"] = Request.Tags["key1"] == Request.Tags["key2"] )"; - DEFINE_REQ_STATE; pe.lua.background = &lua_background; s.tagset.add_tag("key1", "val1"); @@ -1138,8 +1147,8 @@ TEST(TestRGWLuaBackground, TableValuesFromRequest) TEST(TestRGWLuaBackground, TableInvalidValue) { - MAKE_STORE; - TestBackground lua_background(store.get(), ""); + DEFINE_REQ_STATE; + TestBackground lua_background(store.get(), "", pe.lua.manager.get()); lua_background.start(); const std::string request_script = R"( @@ -1150,7 +1159,6 @@ TEST(TestRGWLuaBackground, TableInvalidValue) RGW["key5"] = Request.Tags )"; - DEFINE_REQ_STATE; pe.lua.background = &lua_background; s.tagset.add_tag("key1", "val1"); s.tagset.add_tag("key2", "val2"); @@ -1165,8 +1173,8 @@ TEST(TestRGWLuaBackground, TableInvalidValue) TEST(TestRGWLuaBackground, TableErase) { - MAKE_STORE; - TestBackground lua_background(store.get(), ""); + DEFINE_REQ_STATE; + TestBackground lua_background(store.get(), "", pe.lua.manager.get()); std::string request_script = R"( RGW["size"] = 0 @@ -1176,7 +1184,6 @@ TEST(TestRGWLuaBackground, TableErase) RGW["size"] = #RGW )"; - DEFINE_REQ_STATE; pe.lua.background = &lua_background; auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, nullptr, request_script); @@ -1204,8 +1211,8 @@ TEST(TestRGWLuaBackground, TableErase) TEST(TestRGWLuaBackground, TableIterate) { - MAKE_STORE; - TestBackground lua_background(store.get(), ""); + DEFINE_REQ_STATE; + TestBackground lua_background(store.get(), "", pe.lua.manager.get()); const std::string request_script = R"( RGW["key1"] = "string value" @@ -1218,7 +1225,6 @@ TEST(TestRGWLuaBackground, TableIterate) end )"; - DEFINE_REQ_STATE; pe.lua.background = &lua_background; const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, nullptr, request_script); @@ -1232,8 +1238,8 @@ TEST(TestRGWLuaBackground, TableIterate) TEST(TestRGWLuaBackground, TableIterateWrite) { - MAKE_STORE; - TestBackground lua_background(store.get(), ""); + DEFINE_REQ_STATE; + TestBackground lua_background(store.get(), "", pe.lua.manager.get()); const std::string request_script = R"( RGW["a"] = 1 @@ -1253,7 +1259,6 @@ TEST(TestRGWLuaBackground, TableIterateWrite) assert(counter == 4) )"; - DEFINE_REQ_STATE; pe.lua.background = &lua_background; const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, nullptr, request_script); @@ -1263,8 +1268,8 @@ TEST(TestRGWLuaBackground, TableIterateWrite) TEST(TestRGWLuaBackground, TableIncrement) { - MAKE_STORE; - TestBackground lua_background(store.get(), ""); + DEFINE_REQ_STATE; + TestBackground lua_background(store.get(), "", pe.lua.manager.get()); const std::string request_script = R"( RGW["key1"] = 42 @@ -1275,7 +1280,6 @@ TEST(TestRGWLuaBackground, TableIncrement) assert(RGW["key2"] == 43.2) )"; - DEFINE_REQ_STATE; pe.lua.background = &lua_background; const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, nullptr, request_script); @@ -1284,8 +1288,8 @@ TEST(TestRGWLuaBackground, TableIncrement) TEST(TestRGWLuaBackground, TableIncrementBy) { - MAKE_STORE; - TestBackground lua_background(store.get(), ""); + DEFINE_REQ_STATE; + TestBackground lua_background(store.get(), "", pe.lua.manager.get()); const std::string request_script = R"( RGW["key1"] = 42 @@ -1298,7 +1302,6 @@ TEST(TestRGWLuaBackground, TableIncrementBy) assert(RGW["key1"] == 52.2) )"; - DEFINE_REQ_STATE; pe.lua.background = &lua_background; const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, nullptr, request_script); @@ -1307,8 +1310,8 @@ TEST(TestRGWLuaBackground, TableIncrementBy) TEST(TestRGWLuaBackground, TableDecrement) { - MAKE_STORE; - TestBackground lua_background(store.get(), ""); + DEFINE_REQ_STATE; + TestBackground lua_background(store.get(), "", pe.lua.manager.get()); const std::string request_script = R"( RGW["key1"] = 42 @@ -1319,7 +1322,6 @@ TEST(TestRGWLuaBackground, TableDecrement) assert(RGW["key2"] == 41.2) )"; - DEFINE_REQ_STATE; pe.lua.background = &lua_background; const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, nullptr, request_script); @@ -1328,8 +1330,8 @@ TEST(TestRGWLuaBackground, TableDecrement) TEST(TestRGWLuaBackground, TableDecrementBy) { - MAKE_STORE; - TestBackground lua_background(store.get(), ""); + DEFINE_REQ_STATE; + TestBackground lua_background(store.get(), "", pe.lua.manager.get()); const std::string request_script = R"( RGW["key1"] = 42 @@ -1342,7 +1344,6 @@ TEST(TestRGWLuaBackground, TableDecrementBy) assert(RGW["key1"] == 31.2) )"; - DEFINE_REQ_STATE; pe.lua.background = &lua_background; const auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, nullptr, request_script); @@ -1351,8 +1352,8 @@ TEST(TestRGWLuaBackground, TableDecrementBy) TEST(TestRGWLuaBackground, TableIncrementValueError) { - MAKE_STORE; - TestBackground lua_background(store.get(), ""); + DEFINE_REQ_STATE; + TestBackground lua_background(store.get(), "", pe.lua.manager.get()); std::string request_script = R"( -- cannot increment string values @@ -1360,7 +1361,6 @@ TEST(TestRGWLuaBackground, TableIncrementValueError) RGW.increment("key1") )"; - DEFINE_REQ_STATE; pe.lua.background = &lua_background; auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, nullptr, request_script); @@ -1387,8 +1387,8 @@ TEST(TestRGWLuaBackground, TableIncrementValueError) TEST(TestRGWLuaBackground, TableIncrementError) { - MAKE_STORE; - TestBackground lua_background(store.get(), ""); + DEFINE_REQ_STATE; + TestBackground lua_background(store.get(), "", pe.lua.manager.get()); std::string request_script = R"( -- missing argument @@ -1396,7 +1396,6 @@ TEST(TestRGWLuaBackground, TableIncrementError) RGW.increment() )"; - DEFINE_REQ_STATE; pe.lua.background = &lua_background; auto rc = lua::request::execute(nullptr, nullptr, nullptr, &s, nullptr, request_script); @@ -1477,9 +1476,8 @@ TEST(TestRGWLua, Data) assert(Offset == 12345678) )"; - MAKE_STORE; - TestBackground lua_background(store.get(), ""); DEFINE_REQ_STATE; + TestBackground lua_background(store.get(), "", pe.lua.manager.get()); s.host_id = "foo"; pe.lua.background = &lua_background; lua::RGWObjFilter filter(&s, script);