This is an automated email from the ASF dual-hosted git repository.

asekretenko pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mesos.git


The following commit(s) were added to refs/heads/master by this push:
     new 7aee5a8  Added an endpoint for debugging offer constraints.
7aee5a8 is described below

commit 7aee5a87d117601b0f551a68dac4ea25903e5f81
Author: Andrei Sekretenko <asekrete...@apache.org>
AuthorDate: Wed Sep 9 14:48:00 2020 +0200

    Added an endpoint for debugging offer constraints.
    
    Review: https://reviews.apache.org/r/72851
---
 include/mesos/allocator/allocator.hpp       |   9 +-
 src/master/allocator/mesos/hierarchical.cpp | 125 ++++++++++++++++++++++++++++
 src/master/allocator/mesos/hierarchical.hpp |   9 ++
 src/master/master.cpp                       |   2 +
 4 files changed, 143 insertions(+), 2 deletions(-)

diff --git a/include/mesos/allocator/allocator.hpp 
b/include/mesos/allocator/allocator.hpp
index c6fca65..6d67d5d 100644
--- a/include/mesos/allocator/allocator.hpp
+++ b/include/mesos/allocator/allocator.hpp
@@ -24,10 +24,9 @@
 #include <mesos/allocator/allocator.pb.h>
 #include <mesos/scheduler/scheduler.pb.h>
 
+#include <mesos/authorizer/authorizer.hpp>
 #include <mesos/maintenance/maintenance.hpp>
-
 #include <mesos/quota/quota.hpp>
-
 #include <mesos/resource_quantities.hpp>
 #include <mesos/resources.hpp>
 
@@ -66,6 +65,12 @@ struct Options
   size_t maxCompletedFrameworks = 0;
 
   bool publishPerFrameworkMetrics = true;
+
+  // Authentication realm for HTTP debug endpoints exposed by the allocator.
+  Option<std::string> readonlyHttpAuthenticationRealm;
+
+  // Mesos master's authorizer.
+  Option<::mesos::Authorizer*> authorizer;
 };
 
 
diff --git a/src/master/allocator/mesos/hierarchical.cpp 
b/src/master/allocator/mesos/hierarchical.cpp
index 0b9588d..d4374c3 100644
--- a/src/master/allocator/mesos/hierarchical.cpp
+++ b/src/master/allocator/mesos/hierarchical.cpp
@@ -32,6 +32,7 @@
 #include <process/delay.hpp>
 #include <process/dispatch.hpp>
 #include <process/event.hpp>
+#include <process/help.hpp>
 #include <process/id.hpp>
 #include <process/loop.hpp>
 #include <process/timeout.hpp>
@@ -42,6 +43,7 @@
 #include <stout/stopwatch.hpp>
 #include <stout/stringify.hpp>
 
+#include "common/authorization.hpp"
 #include "common/http.hpp"
 #include "common/protobuf_utils.hpp"
 #include "common/resources_utils.hpp"
@@ -58,6 +60,7 @@ using mesos::allocator::InverseOfferStatus;
 using mesos::allocator::Options;
 
 using process::after;
+using process::http::authentication::Principal;
 using process::Continue;
 using process::ControlFlow;
 using process::Failure;
@@ -612,6 +615,9 @@ Framework::Framework(
 {}
 
 
+static string OFFER_CONSTRAINTS_DEBUG_HELP();
+
+
 void HierarchicalAllocatorProcess::initialize(
     const Options& _options,
     const lambda::function<
@@ -633,6 +639,18 @@ void HierarchicalAllocatorProcess::initialize(
     BoundedHashMap<FrameworkID, process::Owned<FrameworkMetrics>>(
         options.maxCompletedFrameworks);
 
+  route("/offer_constraints_debug",
+        options.readonlyHttpAuthenticationRealm.getOrElse(""),
+        OFFER_CONSTRAINTS_DEBUG_HELP(),
+        [this](const process::http::Request& request,
+               const Option<Principal>& principal) {
+          logRequest(request);
+          return offerConstraintsDebug(request, principal)
+            .onReady([request](const process::http::Response& response) {
+              logResponse(request, response);
+            });
+        });
+
   roleSorter->initialize(options.fairnessExcludeResourceNames);
 
   VLOG(1) << "Initialized hierarchical allocator process";
@@ -3212,6 +3230,113 @@ void 
HierarchicalAllocatorProcess::untrackAllocatedResources(
 }
 
 
+static string OFFER_CONSTRAINTS_DEBUG_HELP()
+{
+  return process::HELP(
+    process::TLDR(
+        "Evaluates current framework offer constraints and returns results."),
+    process::DESCRIPTION(
+        "This endpoint evaluates for each role of each framework a list",
+        "of agents excluded from allocation by offer constraints.",
+        "",
+        "Example:",
+        "```",
+        "{\"frameworks\": {",
+        "   \"0f4c63a9-be1e-4a90-9e11-d7bf0aa6c8ad-0017\": {",
+        "     \"excluded_by_attribute_constraints\": {",
+        "       \"role1\": [",
+        "         \"0b1e7d60-dfbc-44c9-8222-48b57eca8637-S123\",",
+        "         \"654af69c-80f7-45ad-bcb3-c7c917f1811b-S045\"],",
+        "       \"role2\": [] }},",
+        "   \"b0377da6-090d-4338-9e2e-bf6cf0f309b7-0011\": {}",
+        "}}",
+        "```",
+        "In this example, two agents are excluded from allocation",
+        "to the first framework (-0017) under the role \"role1\", no agents",
+        "are excluded from allocation to this framework under \"role2\",",
+        "and the second framework (-0011) has no offer constraints set."
+        ),
+    process::AUTHENTICATION(true),
+    process::AUTHORIZATION(
+        "This endpoint skips frameworks for which the user is not authorized"
+        "to perform a VIEW_FRAMEWORK action."));
+}
+
+
+Future<process::http::Response>
+HierarchicalAllocatorProcess::offerConstraintsDebug(
+    const process::http::Request&,
+    const Option<process::http::authentication::Principal>& principal)
+{
+  if (options.authorizer.isNone()) {
+    return offerConstraintsDebug_(nullptr);
+  }
+
+  return (*options.authorizer)
+    ->getApprover(
+        authorization::createSubject(principal),
+        authorization::Action::VIEW_FRAMEWORK)
+    .then(defer(self(), &Self::offerConstraintsDebug_, lambda::_1));
+}
+
+
+process::http::Response HierarchicalAllocatorProcess::offerConstraintsDebug_(
+    shared_ptr<const ObjectApprover> frameworksApprover)
+{
+  vector<const Framework*> approvedFrameworks;
+  foreachvalue (const Framework& framework, frameworks) {
+    Try<bool> approved = frameworksApprover
+                           ? frameworksApprover->approved(framework.info)
+                           : true;
+
+    if (approved.isError()) {
+      LOG(WARNING) << "Error authorizing VIEW_FRAMEWORK for framework "
+                   << framework.info.id() << ": " << approved.error();
+
+      return process::http::InternalServerError(
+          "Failed to authorize VIEW_FRAMEWORK: " + approved.error());
+    }
+
+    if (*approved) {
+      approvedFrameworks.push_back(&framework);
+    }
+  }
+
+  auto writeFrameworks = [&](JSON::ObjectWriter* writer) {
+    for (const Framework* framework : approvedFrameworks) {
+      auto writeFramework = [&](JSON::ObjectWriter* writer) {
+        if (framework->offerConstraintsFilter.isNone()) {
+          // For an authorized frameworks without offer constraints,
+          // an empty object is written.
+          return;
+        }
+
+        writer->field(
+            "excluded_by_attribute_constraints",
+            [&](JSON::ObjectWriter* writer) {
+              for (const string& role : framework->roles) {
+                writer->field(role, [&](JSON::ArrayWriter* writer) {
+                  foreachvalue (const Slave& slave, slaves) {
+                    if (framework->offerConstraintsFilter->isAgentExcluded(
+                            role, slave.info)) {
+                      writer->element(stringify(slave.id));
+                    }
+                  }
+                });
+              }
+            });
+      };
+
+      writer->field(stringify(framework->info.id()), writeFramework);
+    }
+  };
+
+  return process::http::OK(jsonify([&](JSON::ObjectWriter* writer) {
+    writer->field("frameworks", writeFrameworks);
+  }));
+}
+
+
 } // namespace internal {
 } // namespace allocator {
 } // namespace master {
diff --git a/src/master/allocator/mesos/hierarchical.hpp 
b/src/master/allocator/mesos/hierarchical.hpp
index 225de16..63444de 100644
--- a/src/master/allocator/mesos/hierarchical.hpp
+++ b/src/master/allocator/mesos/hierarchical.hpp
@@ -21,10 +21,12 @@
 #include <set>
 #include <string>
 
+#include <mesos/authorizer/authorizer.hpp>
 #include <mesos/mesos.hpp>
 
 #include <process/future.hpp>
 #include <process/id.hpp>
+#include <process/http.hpp>
 #include <process/owned.hpp>
 
 #include <stout/boundedhashmap.hpp>
@@ -865,6 +867,13 @@ protected:
   const std::function<Sorter*()> frameworkSorterFactory;
 
 private:
+  process::Future<process::http::Response> offerConstraintsDebug(
+      const process::http::Request&,
+      const Option<process::http::authentication::Principal>& principal);
+
+  process::http::Response offerConstraintsDebug_(
+      std::shared_ptr<const ObjectApprover> frameworksApprover);
+
   bool isFrameworkTrackedUnderRole(
       const FrameworkID& frameworkId,
       const std::string& role) const;
diff --git a/src/master/master.cpp b/src/master/master.cpp
index 599d2c9..fefa72d 100644
--- a/src/master/master.cpp
+++ b/src/master/master.cpp
@@ -794,6 +794,8 @@ void Master::initialize()
   options.minAllocatableResources = minAllocatableResources;
   options.maxCompletedFrameworks = flags.max_completed_frameworks;
   options.publishPerFrameworkMetrics = flags.publish_per_framework_metrics;
+  options.readonlyHttpAuthenticationRealm = READONLY_HTTP_AUTHENTICATION_REALM;
+  options.authorizer = authorizer;
 
   // Initialize the allocator.
   allocator->initialize(

Reply via email to