You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by an...@apache.org on 2016/07/09 05:14:58 UTC

[6/8] mesos git commit: Implemented 'READ_FILE' for v1 Agent API.

Implemented 'READ_FILE' for v1 Agent API.

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


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

Branch: refs/heads/master
Commit: 4c6bf64edfecd90d909cd923a0898298c8e09813
Parents: 9130828
Author: zhou xing <xi...@cn.ibm.com>
Authored: Fri Jul 8 21:43:31 2016 -0700
Committer: Anand Mazumdar <an...@apache.org>
Committed: Fri Jul 8 22:03:04 2016 -0700

----------------------------------------------------------------------
 src/slave/http.cpp      |  52 ++++++++++++++++-
 src/slave/slave.hpp     |   5 ++
 src/tests/api_tests.cpp | 129 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 185 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/4c6bf64e/src/slave/http.cpp
----------------------------------------------------------------------
diff --git a/src/slave/http.cpp b/src/slave/http.cpp
index 362cf17..21c7ebf 100644
--- a/src/slave/http.cpp
+++ b/src/slave/http.cpp
@@ -382,7 +382,7 @@ Future<Response> Slave::Http::api(
       return listFiles(call, principal, acceptType);
 
     case agent::Call::READ_FILE:
-      return NotImplemented();
+      return readFile(call, principal, acceptType);
 
     case agent::Call::GET_STATE:
       return NotImplemented();
@@ -1387,6 +1387,56 @@ Try<string> Slave::Http::extractEndpoint(const process::http::URL& url) const
   return "/" + pathComponents[1];
 }
 
+
+Future<Response> Slave::Http::readFile(
+    const mesos::agent::Call& call,
+    const Option<string>& principal,
+    ContentType contentType) const
+{
+  CHECK_EQ(mesos::agent::Call::READ_FILE, call.type());
+
+  const size_t offset = call.read_file().offset();
+  const string& path = call.read_file().path();
+
+  Option<size_t> length;
+  if (call.read_file().has_length()) {
+    length = call.read_file().length();
+  }
+
+  return slave->files->read(offset, length, path, principal)
+    .then([contentType](const Try<tuple<size_t, string>, FilesError>& result)
+        -> Future<Response> {
+      if (result.isError()) {
+        const FilesError& error = result.error();
+
+        switch (error.type) {
+          case FilesError::Type::INVALID:
+            return BadRequest(error.message);
+
+          case FilesError::Type::UNAUTHORIZED:
+            return Forbidden(error.message);
+
+          case FilesError::Type::NOT_FOUND:
+            return NotFound(error.message);
+
+          case FilesError::Type::UNKNOWN:
+            return InternalServerError(error.message);
+        }
+
+        UNREACHABLE();
+      }
+
+      mesos::agent::Response response;
+      response.set_type(mesos::agent::Response::READ_FILE);
+
+      response.mutable_read_file()->set_size(std::get<0>(result.get()));
+      response.mutable_read_file()->set_data(std::get<1>(result.get()));
+
+      return OK(serialize(contentType, evolve(response)),
+                stringify(contentType));
+    });
+}
+
 } // namespace slave {
 } // namespace internal {
 } // namespace mesos {

http://git-wip-us.apache.org/repos/asf/mesos/blob/4c6bf64e/src/slave/slave.hpp
----------------------------------------------------------------------
diff --git a/src/slave/slave.hpp b/src/slave/slave.hpp
index a8952f0..42afa9e 100644
--- a/src/slave/slave.hpp
+++ b/src/slave/slave.hpp
@@ -544,6 +544,11 @@ private:
         const Option<std::string>& principal,
         ContentType contentType) const;
 
+    process::Future<process::http::Response> readFile(
+        const mesos::agent::Call& call,
+        const Option<std::string>& principal,
+        ContentType contentType) const;
+
     Slave* slave;
 
     // Used to rate limit the statistics endpoint.

http://git-wip-us.apache.org/repos/asf/mesos/blob/4c6bf64e/src/tests/api_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/api_tests.cpp b/src/tests/api_tests.cpp
index 239ab50..b9d4fe1 100644
--- a/src/tests/api_tests.cpp
+++ b/src/tests/api_tests.cpp
@@ -2512,6 +2512,135 @@ TEST_P(AgentAPITest, GetContainers)
   driver.join();
 }
 
+
+// This test verifies if we can retrieve file data in the agent.
+TEST_P(AgentAPITest, ReadFile)
+{
+  Files files;
+
+  // Now write a file.
+  ASSERT_SOME(os::write("file", "body"));
+  AWAIT_EXPECT_READY(files.attach("file", "myname"));
+
+  Future<Nothing> __recover = FUTURE_DISPATCH(_, &Slave::__recover);
+
+  StandaloneMasterDetector detector;
+  Try<Owned<cluster::Slave>> slave = StartSlave(&detector);
+  ASSERT_SOME(slave);
+
+  AWAIT_READY(__recover);
+
+  // Wait until the agent has finished recovery.
+  Clock::pause();
+  Clock::settle();
+
+  ContentType contentType = GetParam();
+
+  {
+    v1::agent::Call v1Call;
+    v1Call.set_type(v1::agent::Call::READ_FILE);
+
+    v1::agent::Call::ReadFile* readFile = v1Call.mutable_read_file();
+    readFile->set_offset(1);
+    readFile->set_length(2);
+    readFile->set_path("myname");
+
+    Future<v1::agent::Response> v1Response =
+        post(slave.get()->pid, v1Call, contentType);
+
+    AWAIT_READY(v1Response);
+
+    ASSERT_TRUE(v1Response.get().IsInitialized());
+    ASSERT_EQ(v1::agent::Response::READ_FILE, v1Response.get().type());
+
+    ASSERT_EQ("od", v1Response.get().read_file().data());
+    ASSERT_EQ(4, v1Response.get().read_file().size());
+  }
+
+  // Read the file with `offset >= size`. This should return the size of file
+  // and empty data.
+  {
+    v1::agent::Call v1Call;
+    v1Call.set_type(v1::agent::Call::READ_FILE);
+
+    v1::agent::Call::ReadFile* readFile = v1Call.mutable_read_file();
+    readFile->set_offset(5);
+    readFile->set_length(2);
+    readFile->set_path("myname");
+
+    Future<v1::agent::Response> v1Response =
+        post(slave.get()->pid, v1Call, contentType);
+
+    AWAIT_READY(v1Response);
+
+    ASSERT_TRUE(v1Response.get().IsInitialized());
+    ASSERT_EQ(v1::agent::Response::READ_FILE, v1Response.get().type());
+
+    ASSERT_EQ("", v1Response.get().read_file().data());
+    ASSERT_EQ(4, v1Response.get().read_file().size());
+  }
+
+  // Read the file without length being set and `offset=0`. This should read
+  // the entire file.
+  {
+    v1::agent::Call v1Call;
+    v1Call.set_type(v1::agent::Call::READ_FILE);
+
+    v1::agent::Call::ReadFile* readFile = v1Call.mutable_read_file();
+    readFile->set_offset(0);
+    readFile->set_path("myname");
+
+    Future<v1::agent::Response> v1Response =
+        post(slave.get()->pid, v1Call, contentType);
+
+    AWAIT_READY(v1Response);
+
+    ASSERT_TRUE(v1Response.get().IsInitialized());
+    ASSERT_EQ(v1::agent::Response::READ_FILE, v1Response.get().type());
+
+    ASSERT_EQ("body", v1Response.get().read_file().data());
+    ASSERT_EQ(4, v1Response.get().read_file().size());
+  }
+}
+
+
+// This test verifies that the client will receive a `NotFound` response when
+// it tries to make a `READ_FILE` call with an invalid path.
+TEST_P(AgentAPITest, ReadFileInvalidPath)
+{
+  Future<Nothing> __recover = FUTURE_DISPATCH(_, &Slave::__recover);
+
+  StandaloneMasterDetector detector;
+  Try<Owned<cluster::Slave>> slave = StartSlave(&detector);
+  ASSERT_SOME(slave);
+
+  AWAIT_READY(__recover);
+
+  // Wait until the agent has finished recovery.
+  Clock::pause();
+  Clock::settle();
+
+  // Read an invalid file.
+  v1::agent::Call v1Call;
+  v1Call.set_type(v1::agent::Call::READ_FILE);
+
+  v1::agent::Call::ReadFile* readFile = v1Call.mutable_read_file();
+  readFile->set_offset(1);
+  readFile->set_length(2);
+  readFile->set_path("invalid_file");
+
+  ContentType contentType = GetParam();
+
+  Future<Response> response = process::http::post(
+    slave.get()->pid,
+    "api/v1",
+    createBasicAuthHeaders(DEFAULT_CREDENTIAL),
+    serialize(contentType, v1Call),
+    stringify(contentType));
+
+  AWAIT_EXPECT_RESPONSE_STATUS_EQ(NotFound().status, response);
+}
+
 } // namespace tests {
 } // namespace internal {
 } // namespace mesos {