You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by mz...@apache.org on 2019/05/16 15:41:47 UTC
[mesos] 01/02: Fix a bug where racing quota removal request could
crash the master.
This is an automated email from the ASF dual-hosted git repository.
mzhu pushed a commit to branch 1.8.x
in repository https://gitbox.apache.org/repos/asf/mesos.git
commit 91c4a8eb07fd646df479cc142190507aae0c1701
Author: Meng Zhu <mz...@mesosphere.io>
AuthorDate: Thu May 16 12:12:15 2019 +0200
Fix a bug where racing quota removal request could crash the master.
Also added a test.
Review: https://reviews.apache.org/r/70656
---
src/master/quota_handler.cpp | 7 +++++
src/tests/master_quota_tests.cpp | 60 ++++++++++++++++++++++++++++++++++++++++
2 files changed, 67 insertions(+)
diff --git a/src/master/quota_handler.cpp b/src/master/quota_handler.cpp
index 5d449e6..a18d8ba 100644
--- a/src/master/quota_handler.cpp
+++ b/src/master/quota_handler.cpp
@@ -735,6 +735,13 @@ Future<http::Response> Master::QuotaHandler::_remove(
Future<http::Response> Master::QuotaHandler::__remove(const string& role) const
{
+ // Double check if the quota still exists. It may have been removed
+ // by a previous removal already.
+ if (!master->quotas.contains(role)) {
+ return BadRequest(
+ "Failed to remove quota: Role '" + role + "' has no quota set");
+ }
+
// Remove quota from the quota-related local state. We do this before
// updating the registry in order to make sure that we are not already
// trying to remove quota for this role (since this is a multi-phase event).
diff --git a/src/tests/master_quota_tests.cpp b/src/tests/master_quota_tests.cpp
index 66641f2..146b977 100644
--- a/src/tests/master_quota_tests.cpp
+++ b/src/tests/master_quota_tests.cpp
@@ -65,6 +65,7 @@ using process::Clock;
using process::Future;
using process::Owned;
using process::PID;
+using process::Promise;
using process::http::BadRequest;
using process::http::Conflict;
@@ -508,6 +509,65 @@ TEST_F(MasterQuotaTest, RemoveSingleQuota)
}
+// This test ensures that master can handle two racing quota removal requests.
+// This is a regression test for MESOS-9786.
+TEST_F(MasterQuotaTest, RemoveQuotaRace)
+{
+ Clock::pause();
+
+ // Start master with a mock authorizer to block quota removal requests.
+ MockAuthorizer authorizer;
+
+ Try<Owned<cluster::Master>> master = StartMaster(&authorizer);
+ ASSERT_SOME(master);
+
+ // Use the force flag for setting quota that cannot be satisfied in
+ // this empty cluster without any agents.
+ const bool FORCE = true;
+
+ // Wrap the `http::requestDelete` into a lambda for readability of the test.
+ auto removeQuota = [&master](const string& path) {
+ return process::http::requestDelete(
+ master.get()->pid,
+ path,
+ createBasicAuthHeaders(DEFAULT_CREDENTIAL));
+ };
+
+ // Set quota for `ROLE1`.
+ {
+ Resources quotaResources = Resources::parse("cpus:1;mem:512").get();
+
+ Future<Response> response = process::http::post(
+ master.get()->pid,
+ "quota",
+ createBasicAuthHeaders(DEFAULT_CREDENTIAL),
+ createRequestBody(ROLE1, quotaResources, FORCE));
+
+ AWAIT_EXPECT_RESPONSE_STATUS_EQ(OK().status, response);
+ }
+
+ // Intercept both quota removal authorizations.
+ Future<Nothing> authorize1, authorize2;
+ Promise<bool> promise1, promise2;
+ EXPECT_CALL(authorizer, authorized(_))
+ .WillOnce(DoAll(FutureSatisfy(&authorize1), Return(promise1.future())))
+ .WillOnce(DoAll(FutureSatisfy(&authorize2), Return(promise2.future())));
+
+ Future<Response> response1 = removeQuota("quota/" + ROLE1);
+ AWAIT_READY(authorize1);
+
+ Future<Response> response2 = removeQuota("quota/" + ROLE1);
+ AWAIT_READY(authorize2);
+
+ // Authorize and process both requests. Only the first request will succeed.
+ promise1.set(true);
+ AWAIT_EXPECT_RESPONSE_STATUS_EQ(OK().status, response1);
+
+ promise2.set(true);
+ AWAIT_EXPECT_RESPONSE_STATUS_EQ(BadRequest().status, response2);
+}
+
+
// Tests whether we can retrieve the current quota status from
// /master/quota endpoint via a GET request against /quota.
TEST_F(MasterQuotaTest, Status)