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