Added test case `MasterAPITest.CreateAndDetroyVolumes`. Review: https://reviews.apache.org/r/48938/
Project: http://git-wip-us.apache.org/repos/asf/mesos/repo Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/589d5b26 Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/589d5b26 Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/589d5b26 Branch: refs/heads/master Commit: 589d5b260a17969889430fc84728c2a4455be552 Parents: 1c7ff6e Author: Shuai Lin <linshuai2...@gmail.com> Authored: Wed Jun 22 14:18:12 2016 -0700 Committer: Vinod Kone <vinodk...@gmail.com> Committed: Wed Jun 22 14:18:12 2016 -0700 ---------------------------------------------------------------------- src/internal/evolve.cpp | 6 ++ src/internal/evolve.hpp | 1 + src/tests/api_tests.cpp | 150 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 157 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/mesos/blob/589d5b26/src/internal/evolve.cpp ---------------------------------------------------------------------- diff --git a/src/internal/evolve.cpp b/src/internal/evolve.cpp index 6b1cf3c..f63d606 100644 --- a/src/internal/evolve.cpp +++ b/src/internal/evolve.cpp @@ -162,6 +162,12 @@ v1::MasterInfo evolve(const MasterInfo& masterInfo) } +v1::Resource evolve(const Resource& resource) +{ + return evolve<v1::Resource>(resource); +} + + v1::agent::Response evolve(const mesos::agent::Response& response) { return evolve<v1::agent::Response>(response); http://git-wip-us.apache.org/repos/asf/mesos/blob/589d5b26/src/internal/evolve.hpp ---------------------------------------------------------------------- diff --git a/src/internal/evolve.hpp b/src/internal/evolve.hpp index 321e0cc..a8648f5 100644 --- a/src/internal/evolve.hpp +++ b/src/internal/evolve.hpp @@ -69,6 +69,7 @@ v1::TaskInfo evolve(const TaskInfo& taskInfo); v1::TaskStatus evolve(const TaskStatus& status); v1::Task evolve(const Task& task); v1::MasterInfo evolve(const MasterInfo& masterInfo); +v1::Resource evolve(const Resource& resource); v1::agent::Response evolve(const mesos::agent::Response& response); http://git-wip-us.apache.org/repos/asf/mesos/blob/589d5b26/src/tests/api_tests.cpp ---------------------------------------------------------------------- diff --git a/src/tests/api_tests.cpp b/src/tests/api_tests.cpp index bf1a294..7f16f43 100644 --- a/src/tests/api_tests.cpp +++ b/src/tests/api_tests.cpp @@ -63,6 +63,7 @@ using process::Failure; using process::Future; using process::Owned; +using process::http::Accepted; using process::http::OK; using process::http::Pipe; using process::http::Response; @@ -938,6 +939,155 @@ TEST_P(MasterAPITest, SetQuota) AWAIT_EXPECT_RESPONSE_STATUS_EQ(OK().status, response); } +// 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 +// is finished. +TEST_P(MasterAPITest, CreateAndDestroyVolumes) +{ + Try<Owned<cluster::Master>> master = StartMaster(); + ASSERT_SOME(master); + + // For capturing the SlaveID so we can use it in the create/destroy volumes + // API call. + Future<SlaveRegisteredMessage> slaveRegisteredMessage = + FUTURE_PROTOBUF(SlaveRegisteredMessage(), _, _); + + MockExecutor exec(DEFAULT_EXECUTOR_ID); + TestContainerizer containerizer(&exec); + + Owned<MasterDetector> detector = master.get()->createDetector(); + + slave::Flags slaveFlags = CreateSlaveFlags(); + // Do Static reservation so we can create persistent volumes from it. + slaveFlags.resources = "disk(role1):1024"; + + Try<Owned<cluster::Slave>> slave = StartSlave( + detector.get(), &containerizer, slaveFlags); + + ASSERT_SOME(slave); + + AWAIT_READY(slaveRegisteredMessage); + SlaveID slaveId = slaveRegisteredMessage.get().slave_id(); + + // Create the persistent volume. + v1::master::Call v1CreateVolumesCall; + v1CreateVolumesCall.set_type(v1::master::Call::CREATE_VOLUMES); + v1::master::Call_CreateVolumes* createVolumes = + v1CreateVolumesCall.mutable_create_volumes(); + + Resource volume = createPersistentVolume( + Megabytes(64), + "role1", + "id1", + "path1", + None(), + None(), + DEFAULT_CREDENTIAL.principal()); + + createVolumes->add_volumes()->CopyFrom(evolve<v1::Resource>(volume)); + createVolumes->mutable_agent_id()->CopyFrom(evolve<v1::AgentID>(slaveId)); + + ContentType contentType = GetParam(); + + process::http::Headers headers = createBasicAuthHeaders(DEFAULT_CREDENTIAL); + headers["Accept"] = stringify(contentType); + + Future<Nothing> v1CreateVolumesResponse = process::http::post( + master.get()->pid, + "api/v1", + headers, + serialize(contentType, v1CreateVolumesCall), + stringify(contentType)) + .then([contentType](const Response& response) -> Future<Nothing> { + if (response.status != Accepted().status) { + return Failure("Unexpected response status " + response.status); + } + return Nothing(); + }); + + AWAIT_READY(v1CreateVolumesResponse); + + FrameworkInfo frameworkInfo = DEFAULT_FRAMEWORK_INFO; + frameworkInfo.set_role("role1"); + + // Start a framework and launch a task on the persistent volume. + MockScheduler sched; + MesosSchedulerDriver driver( + &sched, frameworkInfo, master.get()->pid, DEFAULT_CREDENTIAL); + + EXPECT_CALL(sched, registered(&driver, _, _)) + .Times(1); + + 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()); + Offer offer = offers.get()[0]; + + EXPECT_TRUE(Resources(offer.resources()).contains(volume)); + + Resources taskResources = Resources::parse( + "disk:256", + frameworkInfo.role()).get(); + + TaskInfo taskInfo = createTask( + offer.slave_id(), + taskResources, + "sleep 1", + DEFAULT_EXECUTOR_ID); + + EXPECT_CALL(exec, registered(_, _, _, _)) + .Times(1); + + EXPECT_CALL(exec, launchTask(_, _)) + .WillOnce(SendStatusUpdateFromTask(TASK_FINISHED)); + + Future<TaskStatus> status; + EXPECT_CALL(sched, statusUpdate(&driver, _)) + .WillOnce(FutureArg<1>(&status)); + + driver.acceptOffers({offer.id()}, {LAUNCH({taskInfo})}); + + AWAIT_READY(status); + EXPECT_EQ(TASK_FINISHED, status.get().state()); + + // Destroy the persistent volume. + v1::master::Call v1DestroyVolumesCall; + v1DestroyVolumesCall.set_type(v1::master::Call::DESTROY_VOLUMES); + v1::master::Call_DestroyVolumes* destroyVolumes = + v1DestroyVolumesCall.mutable_destroy_volumes(); + + destroyVolumes->mutable_agent_id()->CopyFrom(evolve<v1::AgentID>(slaveId)); + destroyVolumes->add_volumes()->CopyFrom(evolve<v1::Resource>(volume)); + + Future<Nothing> v1DestroyVolumesResponse = process::http::post( + master.get()->pid, + "api/v1", + headers, + serialize(contentType, v1DestroyVolumesCall), + stringify(contentType)) + .then([contentType](const Response& response) -> Future<Nothing> { + if (response.status != Accepted().status) { + return Failure("Unexpected response status " + response.status); + } + return Nothing(); + }); + + AWAIT_READY(v1DestroyVolumesResponse); + + EXPECT_CALL(exec, shutdown(_)) + .Times(AtMost(1)); + + driver.stop(); + driver.join(); +} + TEST_P(MasterAPITest, GetWeights) {