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/");

Reply via email to