Added the v1 API 'GET_OPERATIONS' call for master and agent.

The 'GET_OPERATIONS' call lists all operations known to master or agent.

Review: https://reviews.apache.org/r/65044/


Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/c6de89e1
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/c6de89e1
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/c6de89e1

Branch: refs/heads/master
Commit: c6de89e148bec735bb6fb975a1d6b17e3f6192c9
Parents: 2aed1d6
Author: Jan Schlicht <j...@mesosphere.io>
Authored: Mon Feb 19 15:15:45 2018 +0100
Committer: Benjamin Bannier <bbann...@apache.org>
Committed: Mon Feb 19 15:15:45 2018 +0100

----------------------------------------------------------------------
 include/mesos/agent/agent.proto      |  11 ++
 include/mesos/master/master.proto    |   9 +
 include/mesos/v1/agent/agent.proto   |  11 ++
 include/mesos/v1/master/master.proto |   9 +
 src/master/http.cpp                  |  28 +++
 src/master/master.hpp                |   5 +
 src/master/validation.cpp            |   3 +
 src/slave/http.cpp                   |  28 +++
 src/slave/http.hpp                   |   5 +
 src/slave/validation.cpp             |   3 +
 src/tests/api_tests.cpp              | 289 ++++++++++++++++++++++++++++++
 11 files changed, 401 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/c6de89e1/include/mesos/agent/agent.proto
----------------------------------------------------------------------
diff --git a/include/mesos/agent/agent.proto b/include/mesos/agent/agent.proto
index 3158200..7d92cb8 100644
--- a/include/mesos/agent/agent.proto
+++ b/include/mesos/agent/agent.proto
@@ -60,6 +60,9 @@ message Call {
     // Retrieves the information about known executors.
     GET_EXECUTORS = 12;
 
+    // Retrieves the information about known operations.
+    GET_OPERATIONS = 31;
+
     // Retrieves the information about known tasks.
     GET_TASKS = 13;
 
@@ -413,6 +416,7 @@ message Response {
     GET_CONTAINERS = 9;
     GET_FRAMEWORKS = 10;           // See 'GetFrameworks' below.
     GET_EXECUTORS = 11;            // See 'GetExecutors' below.
+    GET_OPERATIONS = 17;           // See 'GetOperations' below.
     GET_TASKS = 12;                // See 'GetTasks' below.
     GET_AGENT = 14;                // See 'GetAgent' below.
     GET_RESOURCE_PROVIDERS = 16;   // See 'GetResourceProviders' below.
@@ -506,6 +510,12 @@ message Response {
     repeated Executor completed_executors = 2;
   }
 
+  // Lists information about all operations known to the agent at the
+  // current time.
+  message GetOperations {
+    repeated Operation operations = 1;
+  }
+
   // Lists information about all the tasks known to the agent at the current
   // time.
   message GetTasks {
@@ -599,6 +609,7 @@ message Response {
   optional GetContainers get_containers = 10;
   optional GetFrameworks get_frameworks = 11;
   optional GetExecutors get_executors = 12;
+  optional GetOperations get_operations = 18;
   optional GetTasks get_tasks = 13;
   optional GetAgent get_agent = 15;
   optional GetResourceProviders get_resource_providers = 17;

http://git-wip-us.apache.org/repos/asf/mesos/blob/c6de89e1/include/mesos/master/master.proto
----------------------------------------------------------------------
diff --git a/include/mesos/master/master.proto 
b/include/mesos/master/master.proto
index 3e34634..f40caa2 100644
--- a/include/mesos/master/master.proto
+++ b/include/mesos/master/master.proto
@@ -62,6 +62,7 @@ message Call {
     GET_AGENTS = 10;
     GET_FRAMEWORKS = 11;
     GET_EXECUTORS = 12;     // Retrieves the information about all executors.
+    GET_OPERATIONS = 33;    // Retrieves the information about known 
operations.
     GET_TASKS = 13;         // Retrieves the information about all known tasks.
     GET_ROLES = 14;         // Retrieves the information about roles.
 
@@ -260,6 +261,7 @@ message Response {
     GET_AGENTS = 9;
     GET_FRAMEWORKS = 10;
     GET_EXECUTORS = 11;            // See 'GetExecutors' below.
+    GET_OPERATIONS = 19;           // See 'GetOperations' below.
     GET_TASKS = 12;                // See 'GetTasks' below.
     GET_ROLES = 13;                // See 'GetRoles' below.
 
@@ -416,6 +418,12 @@ message Response {
     repeated Executor orphan_executors = 2 [deprecated=true];
   }
 
+  // Lists information about all operations known to the master at the
+  // current time.
+  message GetOperations {
+    repeated Operation operations = 1;
+  }
+
   // Lists information about all the tasks known to the master at the current
   // time. Note that there might be tasks unknown to the master running on
   // partitioned or unsubscribed agents.
@@ -498,6 +506,7 @@ message Response {
   optional GetAgents get_agents = 10;
   optional GetFrameworks get_frameworks = 11;
   optional GetExecutors get_executors = 12;
+  optional GetOperations get_operations = 20;
   optional GetTasks get_tasks = 13;
   optional GetRoles get_roles = 14;
   optional GetWeights get_weights = 15;

http://git-wip-us.apache.org/repos/asf/mesos/blob/c6de89e1/include/mesos/v1/agent/agent.proto
----------------------------------------------------------------------
diff --git a/include/mesos/v1/agent/agent.proto 
b/include/mesos/v1/agent/agent.proto
index 9e8b49d..59a9fd6 100644
--- a/include/mesos/v1/agent/agent.proto
+++ b/include/mesos/v1/agent/agent.proto
@@ -60,6 +60,9 @@ message Call {
     // Retrieves the information about known executors.
     GET_EXECUTORS = 12;
 
+    // Retrieves the information about known operations.
+    GET_OPERATIONS = 31;
+
     // Retrieves the information about known tasks.
     GET_TASKS = 13;
 
@@ -413,6 +416,7 @@ message Response {
     GET_CONTAINERS = 9;
     GET_FRAMEWORKS = 10;           // See 'GetFrameworks' below.
     GET_EXECUTORS = 11;            // See 'GetExecutors' below.
+    GET_OPERATIONS = 17;           // See 'GetOperations' below.
     GET_TASKS = 12;                // See 'GetTasks' below.
     GET_AGENT = 14;                // See 'GetAgent' below.
     GET_RESOURCE_PROVIDERS = 16;   // See 'GetResourceProviders' below.
@@ -506,6 +510,12 @@ message Response {
     repeated Executor completed_executors = 2;
   }
 
+  // Lists information about all operations known to the agent at the
+  // current time.
+  message GetOperations {
+    repeated Operation operations = 1;
+  }
+
   // Lists information about all the tasks known to the agent at the current
   // time.
   message GetTasks {
@@ -599,6 +609,7 @@ message Response {
   optional GetContainers get_containers = 10;
   optional GetFrameworks get_frameworks = 11;
   optional GetExecutors get_executors = 12;
+  optional GetOperations get_operations = 18;
   optional GetTasks get_tasks = 13;
   optional GetAgent get_agent = 15;
   optional GetResourceProviders get_resource_providers = 17;

http://git-wip-us.apache.org/repos/asf/mesos/blob/c6de89e1/include/mesos/v1/master/master.proto
----------------------------------------------------------------------
diff --git a/include/mesos/v1/master/master.proto 
b/include/mesos/v1/master/master.proto
index 6759c30..67c9560 100644
--- a/include/mesos/v1/master/master.proto
+++ b/include/mesos/v1/master/master.proto
@@ -60,6 +60,7 @@ message Call {
     GET_AGENTS = 10;
     GET_FRAMEWORKS = 11;
     GET_EXECUTORS = 12;     // Retrieves the information about all executors.
+    GET_OPERATIONS = 33;    // Retrieves the information about known 
operations.
     GET_TASKS = 13;         // Retrieves the information about all known tasks.
     GET_ROLES = 14;         // Retrieves the information about roles.
 
@@ -258,6 +259,7 @@ message Response {
     GET_AGENTS = 9;
     GET_FRAMEWORKS = 10;
     GET_EXECUTORS = 11;            // See 'GetExecutors' below.
+    GET_OPERATIONS = 19;           // See 'GetOperations' below.
     GET_TASKS = 12;                // See 'GetTasks' below.
     GET_ROLES = 13;                // See 'GetRoles' below.
 
@@ -413,6 +415,12 @@ message Response {
     repeated Executor orphan_executors = 2 [deprecated=true];
   }
 
+  // Lists information about all operations known to the master at the
+  // current time.
+  message GetOperations {
+    repeated Operation operations = 1;
+  }
+
   // Lists information about all the tasks known to the master at the current
   // time. Note that there might be tasks unknown to the master running on
   // partitioned or unsubscribed agents.
@@ -494,6 +502,7 @@ message Response {
   optional GetAgents get_agents = 10;
   optional GetFrameworks get_frameworks = 11;
   optional GetExecutors get_executors = 12;
+  optional GetOperations get_operations = 20;
   optional GetTasks get_tasks = 13;
   optional GetRoles get_roles = 14;
   optional GetWeights get_weights = 15;

http://git-wip-us.apache.org/repos/asf/mesos/blob/c6de89e1/src/master/http.cpp
----------------------------------------------------------------------
diff --git a/src/master/http.cpp b/src/master/http.cpp
index 46f2872..6f692e2 100644
--- a/src/master/http.cpp
+++ b/src/master/http.cpp
@@ -732,6 +732,9 @@ Future<Response> Master::Http::api(
     case mesos::master::Call::GET_EXECUTORS:
       return getExecutors(call, principal, acceptType);
 
+    case mesos::master::Call::GET_OPERATIONS:
+      return getOperations(call, principal, acceptType);
+
     case mesos::master::Call::GET_TASKS:
       return getTasks(call, principal, acceptType);
 
@@ -3887,6 +3890,31 @@ Future<Response> Master::Http::teardown(
 }
 
 
+Future<Response> Master::Http::getOperations(
+    const mesos::master::Call& call,
+    const Option<Principal>& principal,
+    ContentType contentType) const
+{
+  CHECK_EQ(mesos::master::Call::GET_OPERATIONS, call.type());
+
+  // TODO(nfnt): Authorize this call (MESOS-8473).
+
+  mesos::master::Response response;
+  response.set_type(mesos::master::Response::GET_OPERATIONS);
+
+  mesos::master::Response::GetOperations* operations =
+    response.mutable_get_operations();
+
+  foreachvalue (const Slave* slave, master->slaves.registered) {
+    foreachvalue (Operation* operation, slave->operations) {
+      operations->add_operations()->CopyFrom(*operation);
+    }
+  }
+
+  return OK(serialize(contentType, evolve(response)), stringify(contentType));
+}
+
+
 struct TaskComparator
 {
   static bool ascending(const Task* lhs, const Task* rhs)

http://git-wip-us.apache.org/repos/asf/mesos/blob/c6de89e1/src/master/master.hpp
----------------------------------------------------------------------
diff --git a/src/master/master.hpp b/src/master/master.hpp
index c4d3c80..92af852 100644
--- a/src/master/master.hpp
+++ b/src/master/master.hpp
@@ -1640,6 +1640,11 @@ private:
         const Option<process::http::authentication::Principal>& principal,
         ContentType contentType) const;
 
+    process::Future<process::http::Response> getOperations(
+        const mesos::master::Call& call,
+        const Option<process::http::authentication::Principal>& principal,
+        ContentType contentType) const;
+
     process::Future<process::http::Response> getTasks(
         const mesos::master::Call& call,
         const Option<process::http::authentication::Principal>& principal,

http://git-wip-us.apache.org/repos/asf/mesos/blob/c6de89e1/src/master/validation.cpp
----------------------------------------------------------------------
diff --git a/src/master/validation.cpp b/src/master/validation.cpp
index 42f767e..b15b75c 100644
--- a/src/master/validation.cpp
+++ b/src/master/validation.cpp
@@ -124,6 +124,9 @@ Option<Error> validate(
     case mesos::master::Call::GET_EXECUTORS:
       return None();
 
+    case mesos::master::Call::GET_OPERATIONS:
+      return None();
+
     case mesos::master::Call::GET_TASKS:
       return None();
 

http://git-wip-us.apache.org/repos/asf/mesos/blob/c6de89e1/src/slave/http.cpp
----------------------------------------------------------------------
diff --git a/src/slave/http.cpp b/src/slave/http.cpp
index 59eef7a..7d7fa2b 100644
--- a/src/slave/http.cpp
+++ b/src/slave/http.cpp
@@ -575,6 +575,9 @@ Future<Response> Http::_api(
     case mesos::agent::Call::GET_EXECUTORS:
       return getExecutors(call, mediaTypes.accept, principal);
 
+    case mesos::agent::Call::GET_OPERATIONS:
+      return getOperations(call, mediaTypes.accept, principal);
+
     case mesos::agent::Call::GET_TASKS:
       return getTasks(call, mediaTypes.accept, principal);
 
@@ -1672,6 +1675,31 @@ mesos::agent::Response::GetExecutors Http::_getExecutors(
 }
 
 
+Future<Response> Http::getOperations(
+    const mesos::agent::Call& call,
+    ContentType acceptType,
+    const Option<Principal>& principal) const
+{
+  CHECK_EQ(mesos::agent::Call::GET_OPERATIONS, call.type());
+
+  LOG(INFO) << "Processing GET_OPERATIONS call";
+
+  // TODO(nfnt): Authorize this call (MESOS-8473).
+
+  agent::Response response;
+  response.set_type(mesos::agent::Response::GET_OPERATIONS);
+
+  agent::Response::GetOperations* operations =
+    response.mutable_get_operations();
+
+  foreachvalue (Operation* operation, slave->operations) {
+    operations->add_operations()->CopyFrom(*operation);
+  }
+
+  return OK(serialize(acceptType, evolve(response)), stringify(acceptType));
+}
+
+
 Future<Response> Http::getTasks(
     const mesos::agent::Call& call,
     ContentType acceptType,

http://git-wip-us.apache.org/repos/asf/mesos/blob/c6de89e1/src/slave/http.hpp
----------------------------------------------------------------------
diff --git a/src/slave/http.hpp b/src/slave/http.hpp
index 1619bb7..c33adeb 100644
--- a/src/slave/http.hpp
+++ b/src/slave/http.hpp
@@ -188,6 +188,11 @@ private:
       const process::Owned<ObjectApprover>& frameworksApprover,
       const process::Owned<ObjectApprover>& executorsApprover) const;
 
+  process::Future<process::http::Response> getOperations(
+      const mesos::agent::Call& call,
+      ContentType acceptType,
+      const Option<process::http::authentication::Principal>& principal) const;
+
   process::Future<process::http::Response> getTasks(
       const mesos::agent::Call& call,
       ContentType acceptType,

http://git-wip-us.apache.org/repos/asf/mesos/blob/c6de89e1/src/slave/validation.cpp
----------------------------------------------------------------------
diff --git a/src/slave/validation.cpp b/src/slave/validation.cpp
index 0c2ccda..5d751d2 100644
--- a/src/slave/validation.cpp
+++ b/src/slave/validation.cpp
@@ -150,6 +150,9 @@ Option<Error> validate(
     case mesos::agent::Call::GET_EXECUTORS:
       return None();
 
+    case mesos::agent::Call::GET_OPERATIONS:
+      return None();
+
     case mesos::agent::Call::GET_TASKS:
       return None();
 

http://git-wip-us.apache.org/repos/asf/mesos/blob/c6de89e1/src/tests/api_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/api_tests.cpp b/src/tests/api_tests.cpp
index b042201..c6383c4 100644
--- a/src/tests/api_tests.cpp
+++ b/src/tests/api_tests.cpp
@@ -1004,6 +1004,151 @@ TEST_P(MasterAPITest, GetRoles)
 }
 
 
+TEST_P(MasterAPITest, GetOperations)
+{
+  Clock::pause();
+
+  master::Flags masterFlags = CreateMasterFlags();
+
+  Try<Owned<cluster::Master>> master = this->StartMaster(masterFlags);
+  ASSERT_SOME(master);
+
+  Owned<MasterDetector> detector = master.get()->createDetector();
+
+  // Start one agent.
+  Future<UpdateSlaveMessage> updateAgentMessage =
+    FUTURE_PROTOBUF(UpdateSlaveMessage(), _, _);
+
+  slave::Flags slaveFlags = CreateSlaveFlags();
+
+  // TODO(nfnt): Remove this once 'MockResourceProvider' supports
+  // authentication.
+  slaveFlags.authenticate_http_readwrite = false;
+
+  // Set the resource provider capability.
+  vector<SlaveInfo::Capability> capabilities = slave::AGENT_CAPABILITIES();
+  SlaveInfo::Capability capability;
+  capability.set_type(SlaveInfo::Capability::RESOURCE_PROVIDER);
+  capabilities.push_back(capability);
+
+  slaveFlags.agent_features = SlaveCapabilities();
+  slaveFlags.agent_features->mutable_capabilities()->CopyFrom(
+      {capabilities.begin(), capabilities.end()});
+
+  Try<Owned<cluster::Slave>> agent = StartSlave(detector.get(), slaveFlags);
+  ASSERT_SOME(agent);
+
+  Clock::advance(slaveFlags.registration_backoff_factor);
+  AWAIT_READY(updateAgentMessage);
+
+  mesos::v1::ResourceProviderInfo info;
+  info.set_type("org.apache.mesos.rp.test");
+  info.set_name("test");
+
+  v1::MockResourceProvider resourceProvider(
+      info,
+      v1::createDiskResource(
+          "200", "*", None(), None(), v1::createDiskSourceRaw()));
+
+  // Start and register resource provider.
+  Owned<EndpointDetector> endpointDetector(
+      resource_provider::createEndpointDetector(agent.get()->pid));
+
+  updateAgentMessage = FUTURE_PROTOBUF(UpdateSlaveMessage(), _, _);
+
+  const ContentType contentType = GetParam();
+
+  resourceProvider.start(endpointDetector, contentType, 
v1::DEFAULT_CREDENTIAL);
+
+  // Wait until the agent's resources have been updated to include the
+  // resource provider resources.
+  AWAIT_READY(updateAgentMessage);
+
+  v1::master::Call v1Call;
+  v1Call.set_type(v1::master::Call::GET_OPERATIONS);
+
+  Future<v1::master::Response> v1Response =
+    post(master.get()->pid, v1Call, contentType);
+
+  AWAIT_READY(v1Response);
+  ASSERT_TRUE(v1Response->IsInitialized());
+  ASSERT_EQ(v1::master::Response::GET_OPERATIONS, v1Response->type());
+  EXPECT_TRUE(v1Response->get_operations().operations().empty());
+
+  // Start a framework to operate on offers.
+  MockScheduler sched;
+  MesosSchedulerDriver driver(
+      &sched, DEFAULT_FRAMEWORK_INFO, master.get()->pid, DEFAULT_CREDENTIAL);
+
+  EXPECT_CALL(sched, registered(&driver, _, _));
+
+  Future<vector<Offer>> offers;
+  EXPECT_CALL(sched, resourceOffers(&driver, _))
+    .WillOnce(FutureArg<1>(&offers));
+
+  driver.start();
+
+  // We settle here to make sure that the framework has been authenticated
+  // before advancing the clock. Otherwise we would run into a authentication
+  // timeout due to the large allocation interval (1000s) of this fixture.
+  Clock::settle();
+
+  Clock::advance(masterFlags.allocation_interval);
+  Clock::settle();
+
+  AWAIT_READY(offers);
+  ASSERT_FALSE(offers->empty());
+  const Offer& offer = offers->front();
+
+  Option<Resource> rawDisk;
+
+  foreach (const Resource& resource, offer.resources()) {
+    if (resource.has_provider_id() &&
+        resource.has_disk() &&
+        resource.disk().has_source() &&
+        resource.disk().source().type() == Resource::DiskInfo::Source::RAW) {
+      rawDisk = resource;
+      break;
+    }
+  }
+
+  ASSERT_SOME(rawDisk);
+
+  // The operation is still pending when we receive this event.
+  Future<mesos::v1::resource_provider::Event::ApplyOperation> operation;
+  EXPECT_CALL(resourceProvider, applyOperation(_))
+    .WillOnce(FutureArg<0>(&operation));
+
+  // Start an operation.
+  driver.acceptOffers(
+      {offer.id()},
+      {CREATE_VOLUME(rawDisk.get(), Resource::DiskInfo::Source::MOUNT)});
+
+  AWAIT_READY(operation);
+
+  v1Response = post(master.get()->pid, v1Call, contentType);
+
+  AWAIT_READY(v1Response);
+  ASSERT_TRUE(v1Response->IsInitialized());
+  ASSERT_EQ(v1::master::Response::GET_OPERATIONS, v1Response->type());
+  EXPECT_EQ(1, v1Response->get_operations().operations_size());
+  EXPECT_EQ(
+      operation->framework_id(),
+      v1Response->get_operations().operations(0).framework_id());
+  EXPECT_EQ(
+      evolve(updateAgentMessage->slave_id()),
+      v1Response->get_operations().operations(0).agent_id());
+  EXPECT_EQ(
+      operation->info(), v1Response->get_operations().operations(0).info());
+  EXPECT_EQ(
+      operation->operation_uuid(),
+      v1Response->get_operations().operations(0).uuid());
+
+  driver.stop();
+  driver.join();
+}
+
+
 TEST_P(MasterAPITest, GetMaster)
 {
   master::Flags masterFlags = CreateMasterFlags();
@@ -6372,6 +6517,150 @@ TEST_P(AgentAPITest, GetResourceProviders)
 }
 
 
+TEST_P(AgentAPITest, GetOperations)
+{
+  Clock::pause();
+
+  master::Flags masterFlags = CreateMasterFlags();
+
+  Try<Owned<cluster::Master>> master = this->StartMaster(masterFlags);
+  ASSERT_SOME(master);
+
+  Owned<MasterDetector> detector = master.get()->createDetector();
+
+  Future<UpdateSlaveMessage> updateSlaveMessage =
+    FUTURE_PROTOBUF(UpdateSlaveMessage(), _, _);
+
+  slave::Flags slaveFlags = CreateSlaveFlags();
+
+  // TODO(nfnt): Remove this once 'MockResourceProvider' supports
+  // authentication.
+  slaveFlags.authenticate_http_readwrite = false;
+
+  // Set the resource provider capability.
+  vector<SlaveInfo::Capability> capabilities = slave::AGENT_CAPABILITIES();
+  SlaveInfo::Capability capability;
+  capability.set_type(SlaveInfo::Capability::RESOURCE_PROVIDER);
+  capabilities.push_back(capability);
+
+  slaveFlags.agent_features = SlaveCapabilities();
+  slaveFlags.agent_features->mutable_capabilities()->CopyFrom(
+      {capabilities.begin(), capabilities.end()});
+
+  Try<Owned<cluster::Slave>> agent = StartSlave(detector.get(), slaveFlags);
+  ASSERT_SOME(agent);
+
+  Clock::advance(slaveFlags.registration_backoff_factor);
+  AWAIT_READY(updateSlaveMessage);
+
+  mesos::v1::ResourceProviderInfo info;
+  info.set_type("org.apache.mesos.rp.test");
+  info.set_name("test");
+
+  v1::MockResourceProvider resourceProvider(
+      info,
+      v1::createDiskResource(
+          "200", "*", None(), None(), v1::createDiskSourceRaw()));
+
+  // Start and register a resource provider.
+  Owned<EndpointDetector> endpointDetector(
+      resource_provider::createEndpointDetector(agent.get()->pid));
+
+  updateSlaveMessage = FUTURE_PROTOBUF(UpdateSlaveMessage(), _, _);
+
+  const ContentType contentType = GetParam();
+
+  resourceProvider.start(endpointDetector, contentType, 
v1::DEFAULT_CREDENTIAL);
+
+  // Wait until the agent's resources have been updated to include the
+  // resource provider resources.
+  AWAIT_READY(updateSlaveMessage);
+
+  v1::agent::Call v1Call;
+  v1Call.set_type(v1::agent::Call::GET_OPERATIONS);
+
+  Future<v1::agent::Response> v1Response =
+    post(agent.get()->pid, v1Call, contentType);
+
+  AWAIT_READY(v1Response);
+  ASSERT_TRUE(v1Response->IsInitialized());
+  ASSERT_EQ(v1::agent::Response::GET_OPERATIONS, v1Response->type());
+  EXPECT_TRUE(v1Response->get_operations().operations().empty());
+
+  // Start a framework to operate on offers.
+  MockScheduler sched;
+  MesosSchedulerDriver driver(
+      &sched, DEFAULT_FRAMEWORK_INFO, master.get()->pid, DEFAULT_CREDENTIAL);
+
+  EXPECT_CALL(sched, registered(&driver, _, _));
+
+  Future<vector<Offer>> offers;
+  EXPECT_CALL(sched, resourceOffers(&driver, _))
+    .WillOnce(FutureArg<1>(&offers));
+
+  driver.start();
+
+  // We settle here to make sure that the framework has been authenticated
+  // before advancing the clock. Otherwise we would run into a authentication
+  // timeout due to the large allocation interval (1000s) of this fixture.
+  Clock::settle();
+
+  Clock::advance(masterFlags.allocation_interval);
+  Clock::settle();
+
+  AWAIT_READY(offers);
+  ASSERT_FALSE(offers->empty());
+  const Offer& offer = offers->front();
+
+  Option<Resource> rawDisk;
+
+  foreach (const Resource& resource, offer.resources()) {
+    if (resource.has_provider_id() &&
+        resource.has_disk() &&
+        resource.disk().has_source() &&
+        resource.disk().source().type() == Resource::DiskInfo::Source::RAW) {
+      rawDisk = resource;
+      break;
+    }
+  }
+
+  ASSERT_SOME(rawDisk);
+
+  // The operation is still pending when we receive this event.
+  Future<mesos::v1::resource_provider::Event::ApplyOperation> operation;
+  EXPECT_CALL(resourceProvider, applyOperation(_))
+    .WillOnce(FutureArg<0>(&operation));
+
+  // Start an operation.
+  driver.acceptOffers(
+      {offer.id()},
+      {CREATE_VOLUME(rawDisk.get(), Resource::DiskInfo::Source::MOUNT)});
+
+  AWAIT_READY(operation);
+
+  v1Response = post(agent.get()->pid, v1Call, contentType);
+
+  AWAIT_READY(v1Response);
+  ASSERT_TRUE(v1Response->IsInitialized());
+  ASSERT_EQ(v1::agent::Response::GET_OPERATIONS, v1Response->type());
+  EXPECT_EQ(1, v1Response->get_operations().operations_size());
+  EXPECT_EQ(
+      operation->framework_id(),
+      v1Response->get_operations().operations(0).framework_id());
+  EXPECT_EQ(
+      evolve(updateSlaveMessage->slave_id()),
+      v1Response->get_operations().operations(0).agent_id());
+  EXPECT_EQ(
+      operation->info(), v1Response->get_operations().operations(0).info());
+  EXPECT_EQ(
+      operation->operation_uuid(),
+      v1Response->get_operations().operations(0).uuid());
+
+  driver.stop();
+  driver.join();
+}
+
+
 class AgentAPIStreamingTest
   : public MesosTest,
     public WithParamInterface<ContentType> {};

Reply via email to