You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by ji...@apache.org on 2017/11/30 00:04:19 UTC

[08/13] mesos git commit: Added filesystem layout for CSI plugins.

Added filesystem layout for CSI plugins.

A CSI plugin can now store the following persistent CSI
data in `<work_dir>/csi/<type>/<name>/`:

1. Mount points of CSI volumes: `volumes/<volume_id>`
2. States of CSI volumes: `states/<volume_id>/state`
3. Directory to place CSI endpoints: `/tmp/mesos-csi-XXXXXX`, which
   would be symlinked by `containers/<container_id>/endpoint`.

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


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

Branch: refs/heads/master
Commit: bec1cfd2186c7a17b6e7bd9235ffe1389f72afa8
Parents: 236fa59
Author: Chun-Hung Hsiao <ch...@mesosphere.io>
Authored: Wed Nov 29 15:31:02 2017 -0800
Committer: Jie Yu <yu...@gmail.com>
Committed: Wed Nov 29 15:31:02 2017 -0800

----------------------------------------------------------------------
 src/Makefile.am     |   4 +-
 src/csi/paths.cpp   | 255 +++++++++++++++++++++++++++++++++++++++++++++++
 src/csi/paths.hpp   | 134 +++++++++++++++++++++++++
 src/slave/paths.cpp |   7 ++
 src/slave/paths.hpp |   6 ++
 5 files changed, 405 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/bec1cfd2/src/Makefile.am
----------------------------------------------------------------------
diff --git a/src/Makefile.am b/src/Makefile.am
index 1148453..a82ec7f 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1492,9 +1492,11 @@ if ENABLE_GRPC
 # Convenience library for build the CSI client.
 noinst_LTLIBRARIES += libcsi.la
 libcsi_la_SOURCES =							\
-  csi/client.cpp
+  csi/client.cpp							\
+  csi/paths.cpp
 libcsi_la_SOURCES +=							\
   csi/client.hpp							\
+  csi/paths.hpp								\
   csi/spec.hpp
 nodist_libcsi_la_SOURCES = $(CXX_CSI_PROTOS)
 libcsi_la_CPPFLAGS = $(MESOS_CPPFLAGS)

http://git-wip-us.apache.org/repos/asf/mesos/blob/bec1cfd2/src/csi/paths.cpp
----------------------------------------------------------------------
diff --git a/src/csi/paths.cpp b/src/csi/paths.cpp
new file mode 100644
index 0000000..6caefc5
--- /dev/null
+++ b/src/csi/paths.cpp
@@ -0,0 +1,255 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "csi/paths.hpp"
+
+#include <mesos/type_utils.hpp>
+
+#include <process/address.hpp>
+#include <process/http.hpp>
+
+#include <stout/check.hpp>
+#include <stout/fs.hpp>
+#include <stout/os.hpp>
+#include <stout/path.hpp>
+#include <stout/stringify.hpp>
+#include <stout/strings.hpp>
+
+namespace http = process::http;
+namespace unix = process::network::unix;
+
+using std::list;
+using std::string;
+using std::vector;
+
+namespace mesos {
+namespace csi {
+namespace paths {
+
+// File names.
+const char CONTAINER_INFO_FILE[] = "container.info";
+const char ENDPOINT_SOCKET_FILE[] = "endpoint.sock";
+const char VOLUME_STATE_FILE[] = "volume.state";
+
+
+const char CONTAINERS_DIR[] = "containers";
+const char VOLUMES_DIR[] = "volumes";
+const char MOUNTS_DIR[] = "mounts";
+
+
+const char ENDPOINT_DIR_SYMLINK[] = "endpoint";
+const char ENDPOINT_DIR[] = "mesos-csi-XXXXXX";
+
+
+Try<list<string>> getContainerPaths(
+    const string& rootDir,
+    const string& type,
+    const string& name)
+{
+  return fs::list(path::join(rootDir, type, name, CONTAINERS_DIR, "*"));
+}
+
+
+string getContainerPath(
+    const string& rootDir,
+    const string& type,
+    const string& name,
+    const ContainerID& containerId)
+{
+  return path::join(
+      rootDir,
+      type,
+      name,
+      CONTAINERS_DIR,
+      stringify(containerId));
+}
+
+
+string getContainerInfoPath(
+    const string& rootDir,
+    const string& type,
+    const string& name,
+    const ContainerID& containerId)
+{
+  return path::join(
+      getContainerPath(rootDir, type, name, containerId),
+      CONTAINER_INFO_FILE);
+}
+
+
+string getEndpointDirSymlinkPath(
+    const string& rootDir,
+    const string& type,
+    const string& name,
+    const ContainerID& containerId)
+{
+  return path::join(
+      getContainerPath(rootDir, type, name, containerId),
+      ENDPOINT_DIR_SYMLINK);
+}
+
+
+Try<string> getEndpointSocketPath(
+    const string& rootDir,
+    const string& type,
+    const string& name,
+    const ContainerID& containerId)
+{
+  const string symlinkPath =
+    getEndpointDirSymlinkPath(rootDir, type, name, containerId);
+
+  Try<Nothing> mkdir = os::mkdir(Path(symlinkPath).dirname());
+  if(mkdir.isError()) {
+    return Error(
+        "Failed to create directory '" + Path(symlinkPath).dirname()  + "': " +
+        mkdir.error());
+  }
+
+  Result<string> endpointDir = os::realpath(symlinkPath);
+  if (endpointDir.isSome()) {
+    return path::join(endpointDir.get(), ENDPOINT_SOCKET_FILE);
+  }
+
+  if (os::exists(symlinkPath)) {
+    Try<Nothing> rm = os::rm(symlinkPath);
+    if (rm.isError()) {
+      return Error(
+          "Failed to remove endpoint symlink '" + symlinkPath + "': " +
+          rm.error());
+    }
+  }
+
+  Try<string> mkdtemp = os::mkdtemp(path::join(os::temp(), ENDPOINT_DIR));
+  if (mkdtemp.isError()) {
+    return Error(
+        "Failed to create endpoint directory in '" + os::temp() + "': " +
+        mkdtemp.error());
+  }
+
+  Try<Nothing> symlink = fs::symlink(mkdtemp.get(), symlinkPath);
+  if (symlink.isError()) {
+    return Error(
+        "Failed to symlink directory '" + mkdtemp.get() + "' to '" +
+        symlinkPath + "': " + symlink.error());
+  }
+
+  const string socketPath = path::join(mkdtemp.get(), ENDPOINT_SOCKET_FILE);
+
+  // Check if the socket path is too long.
+  Try<unix::Address> address = unix::Address::create(socketPath);
+  if (address.isError()) {
+    return Error(
+        "Failed to create address from '" + socketPath + "': " +
+        address.error());
+  }
+
+  return socketPath;
+}
+
+
+Try<list<string>> getVolumePaths(
+    const string& rootDir,
+    const string& type,
+    const string& name)
+{
+  return fs::list(path::join(rootDir, type, name, VOLUMES_DIR, "*"));
+}
+
+
+string getVolumePath(
+    const string& rootDir,
+    const string& type,
+    const string& name,
+    const string& volumeId)
+{
+  // Volume ID is percent-encoded to avoid invalid characters in the path.
+  return path::join(rootDir, type, name, VOLUMES_DIR, http::encode(volumeId));
+}
+
+
+Try<VolumePath> parseVolumePath(const string& rootDir, const string& dir)
+{
+  // TODO(chhsiao): Consider using `<regex>`, which requires GCC 4.9+.
+
+  // Make sure there's a separator at the end of the `rootdir` so that
+  // we don't accidentally slice off part of a directory.
+  const string prefix = path::join(rootDir, "");
+
+  if (!strings::startsWith(dir, prefix)) {
+    return Error(
+        "Directory '" + dir + "' does not fall under the root directory '" +
+        rootDir + "'");
+  }
+
+  vector<string> tokens = strings::tokenize(
+      dir.substr(prefix.size()),
+      stringify(os::PATH_SEPARATOR));
+
+  // A complete volume path consists of 4 tokens:
+  //   <type>/<name>/volumes/<volume_id>
+  if (tokens.size() != 4 || tokens[2] != VOLUMES_DIR) {
+    return Error(
+        "Path '" + path::join(tokens) + "' does not match the structure of a "
+        "volume path");
+  }
+
+  // Volume ID is percent-encoded to avoid invalid characters in the path.
+  Try<string> volumeId = http::decode(tokens[3]);
+  if (volumeId.isError()) {
+    return Error(
+        "Could not decode volume ID from string '" + tokens[3] + "': " +
+        volumeId.error());
+  }
+
+  return VolumePath{tokens[0], tokens[1], volumeId.get()};
+}
+
+
+string getVolumeStatePath(
+    const string& rootDir,
+    const string& type,
+    const string& name,
+    const string& volumeId)
+{
+  return path::join(
+      getVolumePath(rootDir, type, name, volumeId),
+      VOLUME_STATE_FILE);
+}
+
+
+string getMountRootDir(
+    const string& rootDir,
+    const string& type,
+    const string& name)
+{
+  return path::join(rootDir, type, name, MOUNTS_DIR);
+}
+
+
+string getMountPath(
+    const string& rootDir,
+    const string& type,
+    const string& name,
+    const string& volumeId)
+{
+  return path::join(
+      getMountRootDir(rootDir, type, name),
+      http::encode(volumeId));
+}
+
+} // namespace paths {
+} // namespace csi {
+} // namespace mesos {

http://git-wip-us.apache.org/repos/asf/mesos/blob/bec1cfd2/src/csi/paths.hpp
----------------------------------------------------------------------
diff --git a/src/csi/paths.hpp b/src/csi/paths.hpp
new file mode 100644
index 0000000..37f65f8
--- /dev/null
+++ b/src/csi/paths.hpp
@@ -0,0 +1,134 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef __CSI_PATHS_HPP__
+#define __CSI_PATHS_HPP__
+
+#include <list>
+#include <string>
+
+#include <mesos/mesos.hpp>
+
+#include <stout/try.hpp>
+
+namespace mesos {
+namespace csi {
+namespace paths {
+
+// The file system layout is as follows:
+//
+//   root (<work_dir>/csi/)
+//   |-- <type>
+//       |-- <name>
+//           |-- containers
+//           |   |-- <container_id>
+//           |       |-- container.info
+//           |       |-- endpoint (symlink to /tmp/mesos-csi-XXXXXX)
+//           |           |-- endpoint.sock
+//           |-- volumes
+//           |   |-- <volume_id>
+//           |        |-- volume.state
+//           |-- mounts
+//               |-- <volume_id> (mount point)
+
+
+struct VolumePath
+{
+  std::string type;
+  std::string name;
+  std::string volumeId;
+};
+
+
+Try<std::list<std::string>> getContainerPaths(
+    const std::string& rootDir,
+    const std::string& type,
+    const std::string& name);
+
+
+std::string getContainerPath(
+    const std::string& rootDir,
+    const std::string& type,
+    const std::string& name,
+    const ContainerID& containerId);
+
+
+std::string getContainerInfoPath(
+    const std::string& rootDir,
+    const std::string& type,
+    const std::string& name,
+    const ContainerID& containerId);
+
+
+std::string getEndpointDirSymlinkPath(
+    const std::string& rootDir,
+    const std::string& type,
+    const std::string& name,
+    const ContainerID& containerId);
+
+
+// Returns the resolved path to the endpoint socket, even if the socket
+// file itself does not exist. Creates and symlinks the endpoint
+// directory if necessary.
+Try<std::string> getEndpointSocketPath(
+    const std::string& rootDir,
+    const std::string& type,
+    const std::string& name,
+    const ContainerID& containerId);
+
+
+Try<std::list<std::string>> getVolumePaths(
+    const std::string& rootDir,
+    const std::string& type,
+    const std::string& name);
+
+
+std::string getVolumePath(
+    const std::string& rootDir,
+    const std::string& type,
+    const std::string& name,
+    const std::string& volumeId);
+
+
+Try<VolumePath> parseVolumePath(
+    const std::string& rootDir,
+    const std::string& dir);
+
+
+std::string getVolumeStatePath(
+    const std::string& rootDir,
+    const std::string& type,
+    const std::string& name,
+    const std::string& volumeId);
+
+
+std::string getMountRootDir(
+    const std::string& rootDir,
+    const std::string& type,
+    const std::string& name);
+
+
+std::string getMountPath(
+    const std::string& rootDir,
+    const std::string& type,
+    const std::string& name,
+    const std::string& volumeId);
+
+} // namespace paths {
+} // namespace csi {
+} // namespace mesos {
+
+#endif // __CSI_PATHS_HPP__

http://git-wip-us.apache.org/repos/asf/mesos/blob/bec1cfd2/src/slave/paths.cpp
----------------------------------------------------------------------
diff --git a/src/slave/paths.cpp b/src/slave/paths.cpp
index f85e46c..fce18c5 100644
--- a/src/slave/paths.cpp
+++ b/src/slave/paths.cpp
@@ -68,6 +68,7 @@ const char RESOURCE_PROVIDER_STATE_FILE[] = "resource_provider.state";
 
 
 const char CONTAINERS_DIR[] = "containers";
+const char CSI_DIR[] = "csi";
 const char SLAVES_DIR[] = "slaves";
 const char FRAMEWORKS_DIR[] = "frameworks";
 const char EXECUTORS_DIR[] = "executors";
@@ -140,6 +141,12 @@ string getProvisionerDir(const string& rootDir)
 }
 
 
+string getCsiRootDir(const string& workDir)
+{
+  return path::join(workDir, CSI_DIR);
+}
+
+
 string getBootIdPath(const string& rootDir)
 {
   return path::join(rootDir, BOOT_ID_FILE);

http://git-wip-us.apache.org/repos/asf/mesos/blob/bec1cfd2/src/slave/paths.hpp
----------------------------------------------------------------------
diff --git a/src/slave/paths.hpp b/src/slave/paths.hpp
index 7944b7d..c73130fd 100644
--- a/src/slave/paths.hpp
+++ b/src/slave/paths.hpp
@@ -47,6 +47,8 @@ namespace paths {
 //
 //   (5) For provisioning root filesystems for containers.
 //
+//   (6) For CSI plugins to preserve data that persist across slaves.
+//
 // The file system layout is as follows:
 //
 //   root ('--work_dir' flag)
@@ -100,6 +102,7 @@ namespace paths {
 //   |       |-- <role>
 //   |           |-- <persistence_id> (persistent volume)
 //   |-- provisioner
+//   |-- csi
 
 
 struct ExecutorRunPath
@@ -138,6 +141,9 @@ std::string getSandboxRootDir(const std::string& rootDir);
 std::string getProvisionerDir(const std::string& rootDir);
 
 
+std::string getCsiRootDir(const std::string& workDir);
+
+
 std::string getLatestSlavePath(const std::string& rootDir);