diff --git a/server/core/internal/service.hh b/server/core/internal/service.hh index 2de09cf5b..c32c29810 100644 --- a/server/core/internal/service.hh +++ b/server/core/internal/service.hh @@ -93,6 +93,11 @@ public: */ bool refresh_users(); + /** + * Unconditionally refreshes the users for all listeners of the service + */ + void load_users(); + /** * Dump service configuration into a file * @@ -131,6 +136,9 @@ private: // Update the local filter list on the current worker void update_local_filters(); + // Load the users + bool do_load_users(); + // Callback for updating the local filter list static void update_filters_cb(void* data) { diff --git a/server/core/resource.cc b/server/core/resource.cc index f79497e37..745001f80 100644 --- a/server/core/resource.cc +++ b/server/core/resource.cc @@ -683,6 +683,16 @@ HttpResponse cb_flush(const HttpRequest& request) return HttpResponse(code); } +HttpResponse cb_reload_users(const HttpRequest& request) +{ + Service* service = service_internal_find(request.uri_part(1).c_str()); + mxb_assert(service); + + service->load_users(); + + return HttpResponse(MHD_HTTP_NO_CONTENT); +} + HttpResponse cb_all_threads(const HttpRequest& request) { return HttpResponse(MHD_HTTP_OK, mxs_rworker_list_to_json(request.host())); @@ -1051,6 +1061,7 @@ public: /** For all module commands that modify state/data */ m_post.push_back(SResource(new Resource(cb_modulecmd, 4, "maxscale", "modules", ":module", "?"))); m_post.push_back(SResource(new Resource(cb_flush, 3, "maxscale", "logs", "flush"))); + m_post.push_back(SResource(new Resource(cb_reload_users, 3, "services", ":service", "reload"))); /** Update resources */ m_patch.push_back(SResource(new Resource(cb_alter_server, 2, "servers", ":server"))); diff --git a/server/core/service.cc b/server/core/service.cc index cc004b8d0..46f5757e2 100644 --- a/server/core/service.cc +++ b/server/core/service.cc @@ -1070,6 +1070,50 @@ void dListListeners(DCB* dcb) } } +bool Service::do_load_users() +{ + bool ret = true; + + for (const auto& listener : listener_find_by_service(this)) + { + switch (listener->load_users()) + { + case MXS_AUTH_LOADUSERS_FATAL: + MXS_ERROR("[%s] Fatal error when loading users for listener '%s', authentication will not work.", + name(), listener->name()); + ret = false; + break; + + case MXS_AUTH_LOADUSERS_ERROR: + MXS_WARNING("[%s] Failed to load users for listener '%s', authentication might not work.", + name(), listener->name()); + ret = false; + break; + + default: + break; + } + } + + return ret; +} + +void Service::load_users() +{ + if (capabilities & ACAP_TYPE_ASYNC) + { + mxs::RoutingWorker::execute_concurrently( + [this]() { + do_load_users(); + }); + } + else + { + std::lock_guard guard(lock); + do_load_users(); + } +} + bool Service::refresh_users() { mxs::WatchdogWorkaround workaround; @@ -1109,33 +1153,7 @@ bool Service::refresh_users() { m_rate_limits[self].last = now; m_rate_limits[self].warned = false; - - for (const auto& listener : listener_find_by_service(this)) - { - /** Load the authentication users before before starting the listener */ - - switch (listener->load_users()) - { - case MXS_AUTH_LOADUSERS_FATAL: - MXS_ERROR("[%s] Fatal error when loading users for listener '%s'," - " authentication will not work.", - name(), - listener->name()); - ret = false; - break; - - case MXS_AUTH_LOADUSERS_ERROR: - MXS_WARNING("[%s] Failed to load users for listener '%s', authentication" - " might not work.", - name(), - listener->name()); - ret = false; - break; - - default: - break; - } - } + ret = do_load_users(); } return ret; diff --git a/server/core/test/rest-api/test/service.js b/server/core/test/rest-api/test/service.js index 79616f2d3..7f908189a 100644 --- a/server/core/test/rest-api/test/service.js +++ b/server/core/test/rest-api/test/service.js @@ -168,5 +168,10 @@ describe("Service", function() { .should.be.fulfilled }); + it("reload users", function() { + return request.post(base_url + "/services/RW-Split-Router/reload") + .should.be.fulfilled + }); + after(stopMaxScale) });