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 {