Added helpers for supporting resource provider selectors.

This patches validates that a profile's manifest must have a selector
and adds a helper function for selecting resource providers.

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


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

Branch: refs/heads/1.5.x
Commit: be736e50b5c04cf3d9956a3ac16eddd39dd29d56
Parents: 913a704
Author: Chun-Hung Hsiao <chhs...@mesosphere.io>
Authored: Thu Feb 8 14:41:25 2018 -0800
Committer: Jie Yu <yujie....@gmail.com>
Committed: Thu Feb 8 17:36:05 2018 -0800

----------------------------------------------------------------------
 .../storage/disk_profile_utils.cpp              | 124 ++++++++++++++++---
 .../storage/disk_profile_utils.hpp              |   8 ++
 2 files changed, 118 insertions(+), 14 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/be736e50/src/resource_provider/storage/disk_profile_utils.cpp
----------------------------------------------------------------------
diff --git a/src/resource_provider/storage/disk_profile_utils.cpp 
b/src/resource_provider/storage/disk_profile_utils.cpp
index c84b6e1..cc1c629 100644
--- a/src/resource_provider/storage/disk_profile_utils.cpp
+++ b/src/resource_provider/storage/disk_profile_utils.cpp
@@ -19,7 +19,9 @@
 #include <google/protobuf/util/json_util.h>
 
 #include <stout/bytes.hpp>
+#include <stout/check.hpp>
 #include <stout/foreach.hpp>
+#include <stout/unreachable.hpp>
 
 using std::string;
 
@@ -42,43 +44,137 @@ Try<DiskProfileMapping> parseDiskProfileMapping(
 
   if (!status.ok()) {
     return Error(
-        "Failed to parse DiskProfileMapping message: "
-        + status.ToString());
+        "Failed to parse DiskProfileMapping message: " +
+        status.ToString());
   }
 
   Option<Error> validation = validate(output);
   if (validation.isSome()) {
     return Error(
-      "Fetched profile mapping failed validation with: " + 
validation->message);
+        "Fetched profile mapping failed validation with: " +
+        validation->message);
   }
 
   return output;
 }
 
 
+bool isSelectedResourceProvider(
+    const DiskProfileMapping::CSIManifest& profileManifest,
+    const ResourceProviderInfo& resourceProviderInfo)
+{
+  switch (profileManifest.selector_case()) {
+    case DiskProfileMapping::CSIManifest::kResourceProviderSelector: {
+      CHECK(profileManifest.has_resource_provider_selector());
+
+      const auto& selector = profileManifest.resource_provider_selector();
+
+      foreach (const auto& resourceProvider, selector.resource_providers()) {
+        if (resourceProviderInfo.type() == resourceProvider.type() &&
+            resourceProviderInfo.name() == resourceProvider.name()) {
+          return true;
+        }
+      }
+
+      return false;
+    }
+    case DiskProfileMapping::CSIManifest::kCsiPluginTypeSelector: {
+      CHECK(profileManifest.has_csi_plugin_type_selector());
+
+      const auto& selector = profileManifest.csi_plugin_type_selector();
+
+      return resourceProviderInfo.has_storage() &&
+        resourceProviderInfo.storage().plugin().type() ==
+          selector.plugin_type();
+    }
+    case DiskProfileMapping::CSIManifest::SELECTOR_NOT_SET: {
+      UNREACHABLE();
+    }
+  }
+}
+
+
+static Option<Error> validateSelector(
+    const DiskProfileMapping::CSIManifest& profileManifest)
+{
+  switch (profileManifest.selector_case()) {
+    case DiskProfileMapping::CSIManifest::kResourceProviderSelector: {
+      if (!profileManifest.has_resource_provider_selector()) {
+        return Error("Expecting 'resource_provider_selector' to be present");
+      }
+
+      const auto& selector = profileManifest.resource_provider_selector();
+
+      if (selector.resource_providers_size() == 0) {
+        return Error(
+            "Expecting one or more 'resource_providers' for "
+            "ResourceProviderSelector");
+      }
+
+      foreach (const auto& resourceProvider, selector.resource_providers()) {
+        if (resourceProvider.type().empty()) {
+          return Error(
+              "'type' is a required field for ResourceProviderSelector");
+        }
+
+        if (resourceProvider.name().empty()) {
+          return Error(
+              "'name' is a required field for ResourceProviderSelector");
+        }
+      }
+
+      break;
+    }
+    case DiskProfileMapping::CSIManifest::kCsiPluginTypeSelector: {
+      if (!profileManifest.has_csi_plugin_type_selector()) {
+        return Error("Expecting 'csi_plugin_type_selector' to be present");
+      }
+
+      const auto& selector = profileManifest.csi_plugin_type_selector();
+
+      if (selector.plugin_type().empty()) {
+        return Error(
+            "'plugin_type' is a required field for CSIPluginTypeSelector");
+      }
+
+      break;
+    }
+    case DiskProfileMapping::CSIManifest::SELECTOR_NOT_SET: {
+      return Error("Expecting a selector to be present");
+    }
+  }
+
+  return None();
+}
+
+
 Option<Error> validate(const DiskProfileMapping& mapping)
 {
-  auto iterator = mapping.profile_matrix().begin();
-  while (iterator != mapping.profile_matrix().end()) {
-    if (!iterator->second.has_volume_capabilities()) {
+  foreach (const auto& entry, mapping.profile_matrix()) {
+    Option<Error> selector = validateSelector(entry.second);
+
+    if (selector.isSome()) {
       return Error(
-          "Profile '" + iterator->first + "' is missing the required field "
-          + "'volume_capabilities");
+          "Profile '" + entry.first + "' has no valid selector: " +
+          selector->message);
     }
 
-    Option<Error> capabilities =
-      validate(iterator->second.volume_capabilities());
+    if (!entry.second.has_volume_capabilities()) {
+      return Error(
+          "Profile '" + entry.first +
+          "' is missing the required field 'volume_capabilities'");
+    }
+
+    Option<Error> capabilities = validate(entry.second.volume_capabilities());
 
     if (capabilities.isSome()) {
       return Error(
-          "Profile '" + iterator->first + "' VolumeCapabilities are invalid: "
-          + capabilities->message);
+          "Profile '" + entry.first + "' has an invalid VolumeCapability: " +
+          capabilities->message);
     }
 
     // NOTE: The `create_parameters` field is optional and needs no further
     // validation after parsing.
-
-    iterator++;
   }
 
   return None();

http://git-wip-us.apache.org/repos/asf/mesos/blob/be736e50/src/resource_provider/storage/disk_profile_utils.hpp
----------------------------------------------------------------------
diff --git a/src/resource_provider/storage/disk_profile_utils.hpp 
b/src/resource_provider/storage/disk_profile_utils.hpp
index fa2c7ec..c267da2 100644
--- a/src/resource_provider/storage/disk_profile_utils.hpp
+++ b/src/resource_provider/storage/disk_profile_utils.hpp
@@ -17,6 +17,8 @@
 #ifndef __RESOURCE_PROVIDER_URI_DISK_PROFILE_UTILS_HPP__
 #define __RESOURCE_PROVIDER_URI_DISK_PROFILE_UTILS_HPP__
 
+#include <mesos/mesos.hpp>
+
 #include <stout/option.hpp>
 #include <stout/try.hpp>
 
@@ -32,6 +34,12 @@ Try<resource_provider::DiskProfileMapping> 
parseDiskProfileMapping(
     const std::string& data);
 
 
+// Helper for checking if a resource provider is selected for a profile.
+bool isSelectedResourceProvider(
+    const resource_provider::DiskProfileMapping::CSIManifest& profileManifest,
+    const ResourceProviderInfo& resourceProviderInfo);
+
+
 // Checks the fields inside a `DiskProfileMapping` according to the
 // comments above the protobuf.
 Option<Error> validate(const resource_provider::DiskProfileMapping& mapping);

Reply via email to