Repository: mesos Updated Branches: refs/heads/master faae791ab -> 82c2a7866
Added a new callback enabling custom resource discovery logic. Review: https://reviews.apache.org/r/38279 Project: http://git-wip-us.apache.org/repos/asf/mesos/repo Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/82c2a786 Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/82c2a786 Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/82c2a786 Branch: refs/heads/master Commit: 82c2a78667bd4694b0de1be449cffd32ab0156b2 Parents: faae791 Author: Felix Abecassis <[email protected]> Authored: Fri Oct 9 16:45:36 2015 -0700 Committer: Niklas Q. Nielsen <[email protected]> Committed: Mon Oct 12 17:00:41 2015 -0700 ---------------------------------------------------------------------- include/mesos/hook.hpp | 10 +++++++ src/examples/test_hook_module.cpp | 22 +++++++++++++++ src/hook/manager.cpp | 27 ++++++++++++++++++ src/hook/manager.hpp | 3 ++ src/slave/slave.cpp | 9 +++++- src/tests/hook_tests.cpp | 50 ++++++++++++++++++++++++++++++++++ 6 files changed, 120 insertions(+), 1 deletion(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/mesos/blob/82c2a786/include/mesos/hook.hpp ---------------------------------------------------------------------- diff --git a/include/mesos/hook.hpp b/include/mesos/hook.hpp index 2fe060e..0c1042a 100644 --- a/include/mesos/hook.hpp +++ b/include/mesos/hook.hpp @@ -123,6 +123,16 @@ public: { return None(); } + + // This hook is called from within the slave when it initializes. A module + // implementing the hook creates and returns a Resources object with the new + // list of resources available on the slave before they are advertised to the + // master. These new resources overwrite the previous ones in SlaveInfo. + virtual Result<Resources> slaveResourcesDecorator( + const SlaveInfo& slaveInfo) + { + return None(); + } }; } // namespace mesos { http://git-wip-us.apache.org/repos/asf/mesos/blob/82c2a786/src/examples/test_hook_module.cpp ---------------------------------------------------------------------- diff --git a/src/examples/test_hook_module.cpp b/src/examples/test_hook_module.cpp index c09d7dd..cd7c184 100644 --- a/src/examples/test_hook_module.cpp +++ b/src/examples/test_hook_module.cpp @@ -265,6 +265,28 @@ public: return result; } + + + virtual Result<Resources> slaveResourcesDecorator( + const SlaveInfo& slaveInfo) + { + LOG(INFO) << "Executing 'slaveResourcesDecorator' hook"; + + Resources resources; + // Remove the existing "cpus" resource, it will be overwritten by the + // current hook. Keep other resources unchanged. + foreach (const Resource& resource, slaveInfo.resources()) { + if (resource.name() != "cpus") { + resources += resource; + } + } + + // Force the value of "cpus" to 4 and add a new custom resource named "foo" + // of type set. + resources += Resources::parse("cpus:4;foo:{bar,baz}").get(); + + return resources; + } }; http://git-wip-us.apache.org/repos/asf/mesos/blob/82c2a786/src/hook/manager.cpp ---------------------------------------------------------------------- diff --git a/src/hook/manager.cpp b/src/hook/manager.cpp index 52d53f0..108bd46 100644 --- a/src/hook/manager.cpp +++ b/src/hook/manager.cpp @@ -273,5 +273,32 @@ TaskStatus HookManager::slaveTaskStatusDecorator( } } +Resources HookManager::slaveResourcesDecorator( + const SlaveInfo& slaveInfo) +{ + // We need a mutable copy of the Resources object. Each hook will see the + // changes made by previous hooks, so the order of execution matters. The + // execution order is currently unspecified since availableHooks uses a + // hashmap. + SlaveInfo slaveInfo_ = slaveInfo; + + synchronized (mutex) { + foreachpair (const string& name, Hook* hook, availableHooks) { + const Result<Resources> result = + hook->slaveResourcesDecorator(slaveInfo_); + + // NOTE: Resources remain unchanged if the hook returns None(). + if (result.isSome()) { + slaveInfo_.mutable_resources()->CopyFrom(result.get()); + } else if (result.isError()) { + LOG(WARNING) << "Slave Resources decorator hook failed for " + << "module '" << name << "': " << result.error(); + } + } + + return slaveInfo_.resources(); + } +} + } // namespace internal { } // namespace mesos { http://git-wip-us.apache.org/repos/asf/mesos/blob/82c2a786/src/hook/manager.hpp ---------------------------------------------------------------------- diff --git a/src/hook/manager.hpp b/src/hook/manager.hpp index d35a762..3af1ff8 100644 --- a/src/hook/manager.hpp +++ b/src/hook/manager.hpp @@ -74,6 +74,9 @@ public: static TaskStatus slaveTaskStatusDecorator( const FrameworkID& frameworkId, TaskStatus status); + + static Resources slaveResourcesDecorator( + const SlaveInfo& slaveInfo); }; } // namespace internal { http://git-wip-us.apache.org/repos/asf/mesos/blob/82c2a786/src/slave/slave.cpp ---------------------------------------------------------------------- diff --git a/src/slave/slave.cpp b/src/slave/slave.cpp index d1c9977..01c5e42 100644 --- a/src/slave/slave.cpp +++ b/src/slave/slave.cpp @@ -351,7 +351,6 @@ void Slave::initialize() if (resources.isError()) { EXIT(1) << "Failed to determine slave resources: " << resources.error(); } - LOG(INFO) << "Slave resources: " << resources.get(); Attributes attributes; if (flags.attributes.isSome()) { @@ -382,7 +381,15 @@ void Slave::initialize() // Initialize slave info. info.set_hostname(hostname); info.set_port(self().address.port); + info.mutable_resources()->CopyFrom(resources.get()); + if (HookManager::hooksAvailable()) { + info.mutable_resources()->CopyFrom( + HookManager::slaveResourcesDecorator(info)); + } + + LOG(INFO) << "Slave resources: " << info.resources(); + info.mutable_attributes()->CopyFrom(attributes); // Checkpointing of slaves is always enabled. info.set_checkpoint(true); http://git-wip-us.apache.org/repos/asf/mesos/blob/82c2a786/src/tests/hook_tests.cpp ---------------------------------------------------------------------- diff --git a/src/tests/hook_tests.cpp b/src/tests/hook_tests.cpp index c9d35fb..b35ce72 100644 --- a/src/tests/hook_tests.cpp +++ b/src/tests/hook_tests.cpp @@ -707,6 +707,56 @@ TEST_F(HookTest, ROOT_DOCKER_VerifySlavePreLaunchDockerHook) Shutdown(); } +// Test that the changes made by the resources decorator hook are correctly +// propagated to the resource offer. +TEST_F(HookTest, VerifySlaveResourcesDecorator) +{ + Try<PID<Master>> master = StartMaster(CreateMasterFlags()); + ASSERT_SOME(master); + + MockExecutor exec(DEFAULT_EXECUTOR_ID); + + TestContainerizer containerizer(&exec); + + // Start a mock slave since we aren't testing the slave hooks yet. + Try<PID<Slave>> slave = StartSlave(&containerizer); + ASSERT_SOME(slave); + + MockScheduler sched; + MesosSchedulerDriver driver( + &sched, DEFAULT_FRAMEWORK_INFO, master.get(), DEFAULT_CREDENTIAL); + + EXPECT_CALL(sched, registered(&driver, _, _)); + + Future<vector<Offer>> offers; + EXPECT_CALL(sched, resourceOffers(&driver, _)) + .WillOnce(FutureArg<1>(&offers)) + .WillRepeatedly(Return()); // Ignore subsequent offers. + + driver.start(); + + AWAIT_READY(offers); + EXPECT_NE(0u, offers.get().size()); + + Resources resources = offers.get()[0].resources(); + + // The test hook sets "cpus" to 4. + EXPECT_EQ(4, resources.cpus().get()); + + // The test hook adds a resource named "foo" of type set with values "bar" + // and "baz". + EXPECT_EQ(Resources::parse("foo:{bar,baz}").get(), resources.get("foo")); + + // The test hook does not modify "mem", the default value must still be + // present. + EXPECT_SOME(resources.mem()); + + driver.stop(); + driver.join(); + + Shutdown(); +} + } // namespace tests { } // namespace internal { } // namespace mesos {
