Implemented REMOVE_QUOTA Call in v1 master API. Review: https://reviews.apache.org/r/49247/
Project: http://git-wip-us.apache.org/repos/asf/mesos/repo Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/aaecd723 Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/aaecd723 Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/aaecd723 Branch: refs/heads/master Commit: aaecd723048ad96e0df736271d3ae9df6f7bd815 Parents: 14b8c3a Author: Abhishek Dasgupta <a10gu...@linux.vnet.ibm.com> Authored: Tue Jun 28 11:01:15 2016 -0700 Committer: Anand Mazumdar <an...@apache.org> Committed: Tue Jun 28 11:01:15 2016 -0700 ---------------------------------------------------------------------- src/master/http.cpp | 2 +- src/master/master.hpp | 8 ++++ src/master/quota_handler.cpp | 23 +++++++++- src/tests/api_tests.cpp | 91 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 121 insertions(+), 3 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/mesos/blob/aaecd723/src/master/http.cpp ---------------------------------------------------------------------- diff --git a/src/master/http.cpp b/src/master/http.cpp index 7d6db2d..e827e69 100644 --- a/src/master/http.cpp +++ b/src/master/http.cpp @@ -595,7 +595,7 @@ Future<Response> Master::Http::api( return quotaHandler.set(call, principal); case mesos::master::Call::REMOVE_QUOTA: - return NotImplemented(); + return quotaHandler.remove(call, principal); case mesos::master::Call::SUBSCRIBE: { Pipe pipe; http://git-wip-us.apache.org/repos/asf/mesos/blob/aaecd723/src/master/master.hpp ---------------------------------------------------------------------- diff --git a/src/master/master.hpp b/src/master/master.hpp index daadebc..5c43f03 100644 --- a/src/master/master.hpp +++ b/src/master/master.hpp @@ -1000,6 +1000,10 @@ private: const Option<std::string>& principal) const; process::Future<process::http::Response> remove( + const mesos::master::Call& call, + const Option<std::string>& principal) const; + + process::Future<process::http::Response> remove( const process::http::Request& request, const Option<std::string>& principal) const; @@ -1076,6 +1080,10 @@ private: bool forced) const; process::Future<process::http::Response> _remove( + const std::string& role, + const Option<std::string>& principal) const; + + process::Future<process::http::Response> __remove( const std::string& role) const; // To perform actions related to quota management, we require access to the http://git-wip-us.apache.org/repos/asf/mesos/blob/aaecd723/src/master/quota_handler.cpp ---------------------------------------------------------------------- diff --git a/src/master/quota_handler.cpp b/src/master/quota_handler.cpp index 0ad7bc9..bf6a613 100644 --- a/src/master/quota_handler.cpp +++ b/src/master/quota_handler.cpp @@ -432,6 +432,17 @@ Future<http::Response> Master::QuotaHandler::__set( Future<http::Response> Master::QuotaHandler::remove( + const mesos::master::Call& call, + const Option<string>& principal) const +{ + CHECK_EQ(mesos::master::Call::REMOVE_QUOTA, call.type()); + CHECK(call.has_remove_quota()); + + return _remove(call.remove_quota().role(), principal); +} + + +Future<http::Response> Master::QuotaHandler::remove( const http::Request& request, const Option<string>& principal) const { @@ -474,14 +485,22 @@ Future<http::Response> Master::QuotaHandler::remove( "': Role '" + role + "' has no quota set"); } + return _remove(role, principal); +} + + +Future<http::Response> Master::QuotaHandler::_remove( + const string& role, + const Option<string>& principal) const +{ return authorizeRemoveQuota(principal, master->quotas[role].info) .then(defer(master->self(), [=](bool authorized) -> Future<http::Response> { - return !authorized ? Forbidden() : _remove(role); + return !authorized ? Forbidden() : __remove(role); })); } -Future<http::Response> Master::QuotaHandler::_remove(const string& role) const +Future<http::Response> Master::QuotaHandler::__remove(const string& role) const { // 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 http://git-wip-us.apache.org/repos/asf/mesos/blob/aaecd723/src/tests/api_tests.cpp ---------------------------------------------------------------------- diff --git a/src/tests/api_tests.cpp b/src/tests/api_tests.cpp index 32a0649..fd51fe9 100644 --- a/src/tests/api_tests.cpp +++ b/src/tests/api_tests.cpp @@ -1257,6 +1257,97 @@ TEST_P(MasterAPITest, SetQuota) } +// This test verifies if we can remove a quota through `REMOVE_QUOTA` call, +// after we set quota resources through `SET_QUOTA` call. +TEST_P(MasterAPITest, RemoveQuota) +{ + Try<Owned<cluster::Master>> master = StartMaster(); + ASSERT_SOME(master); + + v1::Resources quotaResources = + v1::Resources::parse("cpus:1;mem:512").get(); + + { + v1::master::Call v1Call; + v1Call.set_type(v1::master::Call::SET_QUOTA); + + v1::quota::QuotaRequest* quotaRequest = + v1Call.mutable_set_quota()->mutable_quota_request(); + + // Use the force flag for setting quota that cannot be satisfied in + // this empty cluster without any agents. + quotaRequest->set_force(true); + quotaRequest->set_role("role1"); + quotaRequest->mutable_guarantee()->CopyFrom(quotaResources); + + ContentType contentType = GetParam(); + + // Send a quota request for the specified role. + Future<Response> response = process::http::post( + master.get()->pid, + "api/v1", + createBasicAuthHeaders(DEFAULT_CREDENTIAL), + serialize(contentType, v1Call), + stringify(contentType)); + + AWAIT_EXPECT_RESPONSE_STATUS_EQ(OK().status, response); + } + + // Verify if the quota is set using `GET_QUOTA` call. + { + v1::master::Call v1Call; + v1Call.set_type(v1::master::Call::GET_QUOTA); + + ContentType contentType = GetParam(); + + Future<v1::master::Response> v1Response = + post(master.get()->pid, v1Call, contentType); + + AWAIT_READY(v1Response); + ASSERT_TRUE(v1Response->IsInitialized()); + ASSERT_EQ(v1::master::Response::GET_QUOTA, v1Response->type()); + ASSERT_EQ(1, v1Response->get_quota().status().infos().size()); + EXPECT_EQ(quotaResources, + v1Response->get_quota().status().infos(0).guarantee()); + } + + // Remove the quota using `REMOVE_QUOTA` call. + { + v1::master::Call v1Call; + v1Call.set_type(v1::master::Call::REMOVE_QUOTA); + v1Call.mutable_remove_quota()->set_role("role1"); + + ContentType contentType = GetParam(); + + // Send a quota request for the specified role. + Future<Response> response = process::http::post( + master.get()->pid, + "api/v1", + createBasicAuthHeaders(DEFAULT_CREDENTIAL), + serialize(contentType, v1Call), + stringify(contentType)); + + AWAIT_EXPECT_RESPONSE_STATUS_EQ(OK().status, response); + } + + // Verify if the quota is removed using `GET_QUOTA` call. + { + v1::master::Call v1Call; + v1Call.set_type(v1::master::Call::GET_QUOTA); + + ContentType contentType = GetParam(); + + Future<v1::master::Response> v1Response = + post(master.get()->pid, v1Call, contentType); + + AWAIT_READY(v1Response); + ASSERT_TRUE(v1Response->IsInitialized()); + ASSERT_EQ(v1::master::Response::GET_QUOTA, v1Response->type()); + ASSERT_EQ(0, v1Response->get_quota().status().infos().size()); + } +} + + // Test create and destroy persistent volumes through the master operator API. // In this test case, we create a persistent volume with the API, then launch a // task using the volume. Then we destroy the volume with the API after the task