Updated `FilesProcess` to support `LIST_FILES` Call in Operator API v1. Review: https://reviews.apache.org/r/49445/
Project: http://git-wip-us.apache.org/repos/asf/mesos/repo Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/7d124a4a Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/7d124a4a Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/7d124a4a Branch: refs/heads/master Commit: 7d124a4a840c157394a53b36f5a560ef7f21e8f0 Parents: 4d26ead Author: Abhishek Dasgupta <a10gu...@linux.vnet.ibm.com> Authored: Thu Jul 7 10:52:08 2016 -0700 Committer: Anand Mazumdar <an...@apache.org> Committed: Thu Jul 7 11:03:31 2016 -0700 ---------------------------------------------------------------------- src/files/files.cpp | 133 +++++++++++++++++++++++++++-------------- src/files/files.hpp | 21 +++---- src/tests/files_tests.cpp | 11 ++-- 3 files changed, 101 insertions(+), 64 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/mesos/blob/7d124a4a/src/files/files.cpp ---------------------------------------------------------------------- diff --git a/src/files/files.cpp b/src/files/files.cpp index 0368f67..44fe1ac 100644 --- a/src/files/files.cpp +++ b/src/files/files.cpp @@ -102,6 +102,10 @@ public: void detach(const string& name); + Future<Try<list<FileInfo>, FilesError>> browse( + const string& path, + const Option<string>& principal); + protected: virtual void initialize(); @@ -121,15 +125,11 @@ private: // Requests have the following parameters: // path: The directory to browse. Required. // The response will contain a list of JSON files and directories contained - // in the path (see files::jsonFileInfo for the format). - Future<Response> browse( + // in the path (see `FileInfo` model override for the format). + Future<Response> _browse( const Request& request, const Option<string>& principal); - Future<Response> _browse( - const string& path, - const Option<string>& jsonp); - // Reads data from a file at a given offset and for a given length. // See the jquery pailer for the expected behavior. Future<Response> read( @@ -195,7 +195,7 @@ void FilesProcess::initialize() route("/browse.json", authenticationRealm.get(), FilesProcess::BROWSE_HELP, - &FilesProcess::browse); + &FilesProcess::_browse); route("/read.json", authenticationRealm.get(), FilesProcess::READ_HELP, @@ -212,7 +212,7 @@ void FilesProcess::initialize() route("/browse", authenticationRealm.get(), FilesProcess::BROWSE_HELP, - &FilesProcess::browse); + &FilesProcess::_browse); route("/read", authenticationRealm.get(), FilesProcess::READ_HELP, @@ -230,7 +230,7 @@ void FilesProcess::initialize() // deprecation cycle on 0.26. route("/browse.json", FilesProcess::BROWSE_HELP, - lambda::bind(&FilesProcess::browse, this, lambda::_1, None())); + lambda::bind(&FilesProcess::_browse, this, lambda::_1, None())); route("/read.json", FilesProcess::READ_HELP, lambda::bind(&FilesProcess::read, this, lambda::_1, None())); @@ -243,7 +243,7 @@ void FilesProcess::initialize() route("/browse", FilesProcess::BROWSE_HELP, - lambda::bind(&FilesProcess::browse, this, lambda::_1, None())); + lambda::bind(&FilesProcess::_browse, this, lambda::_1, None())); route("/read", FilesProcess::READ_HELP, lambda::bind(&FilesProcess::read, this, lambda::_1, None())); @@ -349,7 +349,8 @@ Future<bool> FilesProcess::authorize( return true; } -Future<Response> FilesProcess::browse( + +Future<Response> FilesProcess::_browse( const Request& request, const Option<string>& principal) { @@ -362,54 +363,86 @@ Future<Response> FilesProcess::browse( string requestedPath = path.get(); Option<string> jsonp = request.url.query.get("jsonp"); - return authorize(requestedPath, principal) - .then(defer(self(), - [this, path, jsonp](bool authorized) -> Future<Response> { - if (authorized) { - return _browse(path.get(), jsonp); + return browse(requestedPath, principal) + .then([jsonp](const Try<list<FileInfo>, FilesError>& result) + -> Future<http::Response> { + if (result.isError()) { + const FilesError& error = result.error(); + + switch (error.type) { + case FilesError::Type::INVALID: + return BadRequest(error.message); + + case FilesError::Type::NOT_FOUND: + return NotFound(error.message); + + case FilesError::Type::UNAUTHORIZED: + return Forbidden(error.message); + + case FilesError::Type::UNKNOWN: + return InternalServerError(error.message); } - return Forbidden(); - })); + UNREACHABLE(); + } + + JSON::Array listing; + foreach (const FileInfo& fileInfo, result.get()) { + listing.values.push_back(model(fileInfo)); + } + + return OK(listing, jsonp); + }); } -Future<Response> FilesProcess::_browse( +Future<Try<list<FileInfo>, FilesError>> FilesProcess::browse( const string& path, - const Option<string>& jsonp) + const Option<string>& principal) { - Result<string> resolvedPath = resolve(path); + return authorize(path, principal) + .then(defer(self(), + [this, path](bool authorized) + -> Future<Try<list<FileInfo>, FilesError>> { + if (!authorized) { + return FilesError(FilesError::Type::UNAUTHORIZED); + } - if (resolvedPath.isError()) { - return InternalServerError(resolvedPath.error() + ".\n"); - } else if (resolvedPath.isNone()) { - return NotFound(); - } + Result<string> resolvedPath = resolve(path); - // The result will be a sorted (on path) array of files and dirs: - // [{"name": "README", "path": "dir/README" "dir":False, "size":42}, ...] - map<string, JSON::Object> files; - Try<list<string> > entries = os::ls(resolvedPath.get()); - if (entries.isSome()) { - foreach (const string& entry, entries.get()) { - struct stat s; - string fullPath = path::join(resolvedPath.get(), entry); - - if (stat(fullPath.c_str(), &s) < 0) { - PLOG(WARNING) << "Found " << fullPath << " in ls but stat failed"; - continue; + if (resolvedPath.isError()) { + return FilesError( + FilesError::Type::INVALID, + resolvedPath.error() + ".\n"); + } else if (resolvedPath.isNone()) { + return FilesError(FilesError::Type::NOT_FOUND); } - files[fullPath] = jsonFileInfo(path::join(path, entry), s); - } - } + // The result will be a sorted (on path) list of files and dirs. + map<string, FileInfo> files; + Try<list<string> > entries = os::ls(resolvedPath.get()); + if (entries.isSome()) { + foreach (const string& entry, entries.get()) { + struct stat s; + string fullPath = path::join(resolvedPath.get(), entry); + + if (stat(fullPath.c_str(), &s) < 0) { + PLOG(WARNING) << "Found " << fullPath << " in ls but stat failed"; + continue; + } - JSON::Array listing; - foreachvalue (const JSON::Object& file, files) { - listing.values.push_back(file); - } + files[fullPath] = + protobuf::createFileInfo(path::join(path, entry), s); + } + } + + list<FileInfo> listing; + foreachvalue (const FileInfo& fileInfo, files) { + listing.push_back(fileInfo); + } - return OK(listing, jsonp); + return listing; + })); } @@ -835,5 +868,13 @@ void Files::detach(const string& name) dispatch(process, &FilesProcess::detach, name); } + +Future<Try<list<FileInfo>, FilesError>> Files::browse( + const string& path, + const Option<string>& principal) +{ + return dispatch(process, &FilesProcess::browse, path, principal); +} + } // namespace internal { } // namespace mesos { http://git-wip-us.apache.org/repos/asf/mesos/blob/7d124a4a/src/files/files.hpp ---------------------------------------------------------------------- diff --git a/src/files/files.hpp b/src/files/files.hpp index 790a849..e28136a 100644 --- a/src/files/files.hpp +++ b/src/files/files.hpp @@ -17,16 +17,6 @@ #ifndef __FILES_HPP__ #define __FILES_HPP__ -#ifdef __WINDOWS__ -#include <stout/internal/windows/grp.hpp> -#include <stout/internal/windows/pwd.hpp> -#else -#include <grp.h> -#include <pwd.h> -#endif // __WINDOWS__ - -#include <sys/stat.h> - #include <string> #include <mesos/authorizer/authorizer.hpp> @@ -39,11 +29,9 @@ #include <stout/nothing.hpp> #include <stout/path.hpp> -#include <stout/os/permissions.hpp> +#include "common/protobuf_utils.hpp" -#ifdef __WINDOWS__ -#include <stout/windows.hpp> -#endif // __WINDOWS__ +#include "mesos/mesos.hpp" namespace mesos { namespace internal { @@ -101,6 +89,11 @@ public: // Removes the specified name. void detach(const std::string& name); + // Returns a file listing for a directory similar to `ls -l`. + process::Future<Try<std::list<FileInfo>, FilesError>> browse( + const std::string& path, + const Option<std::string>& principal); + private: FilesProcess* process; }; http://git-wip-us.apache.org/repos/asf/mesos/blob/7d124a4a/src/tests/files_tests.cpp ---------------------------------------------------------------------- diff --git a/src/tests/files_tests.cpp b/src/tests/files_tests.cpp index a30e452..78719da 100644 --- a/src/tests/files_tests.cpp +++ b/src/tests/files_tests.cpp @@ -33,6 +33,9 @@ #include <stout/tests/utils.hpp> +#include "common/http.hpp" +#include "common/protobuf_utils.hpp" + #include "files/files.hpp" #include "tests/mesos.hpp" @@ -331,13 +334,13 @@ TEST_F(FilesTest, BrowseTest) struct stat s; JSON::Array expected; ASSERT_EQ(0, stat("1/2", &s)); - expected.values.push_back(jsonFileInfo("one/2", s)); + expected.values.push_back(model(protobuf::createFileInfo("one/2", s))); ASSERT_EQ(0, stat("1/3", &s)); - expected.values.push_back(jsonFileInfo("one/3", s)); + expected.values.push_back(model(protobuf::createFileInfo("one/3", s))); ASSERT_EQ(0, stat("1/three", &s)); - expected.values.push_back(jsonFileInfo("one/three", s)); + expected.values.push_back(model(protobuf::createFileInfo("one/three", s))); ASSERT_EQ(0, stat("1/two", &s)); - expected.values.push_back(jsonFileInfo("one/two", s)); + expected.values.push_back(model(protobuf::createFileInfo("one/two", s))); Future<Response> response = process::http::get(upid, "browse", "path=one/");