You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by vi...@apache.org on 2016/12/08 01:06:16 UTC
[1/9] mesos git commit: Ensured master always relinks during
scheduler re-registration.
Repository: mesos
Updated Branches:
refs/heads/master bc3b7ab3e -> 1350f946a
Ensured master always relinks during scheduler re-registration.
In the following scenario:
* Master sees a re-registration attempt from a PID-based scheduler,
* The scheduler was previously registered with the master,
* and the "force" flag is not set
The master neglected to re-link with the scheduler. For example, this
might happen if:
* The master sees an ExitedEvent for the framework and marks it
disconnected.
* The master sends a FrameworkErrorMessage to the framework but this
message is dropped, e.g., due to a transient network failure.
* The scheduler attempts to re-register with the master, e.g., because
it detects (spuriously) that the current leading master has changed.
This is problematic, because it might leave the master -> scheduler
connection using an ephemeral socket.
Review: https://reviews.apache.org/r/54495/
Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/fbcaed75
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/fbcaed75
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/fbcaed75
Branch: refs/heads/master
Commit: fbcaed756bfeba7cf978c2e914737a4b8cb5c304
Parents: bc3b7ab
Author: Neil Conway <ne...@gmail.com>
Authored: Wed Dec 7 17:03:58 2016 -0800
Committer: Vinod Kone <vi...@gmail.com>
Committed: Wed Dec 7 17:05:38 2016 -0800
----------------------------------------------------------------------
src/master/master.cpp | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mesos/blob/fbcaed75/src/master/master.cpp
----------------------------------------------------------------------
diff --git a/src/master/master.cpp b/src/master/master.cpp
index 67f3222..f2364e2 100644
--- a/src/master/master.cpp
+++ b/src/master/master.cpp
@@ -2838,7 +2838,9 @@ void Master::_subscribe(
removeInverseOffer(inverseOffer, true); // Rescind.
}
- // TODO(bmahler): Shouldn't this re-link with the scheduler?
+ // Relink to the framework and mark it connected. Relinking
+ // might be necessary if the framework link previously broke.
+ link(framework->pid.get());
framework->connected = true;
// Reactivate the framework.
[5/9] mesos git commit: Fixed incorrect warning messages.
Posted by vi...@apache.org.
Fixed incorrect warning messages.
These warning messages printed the old value of the `FrameworkInfo`
field, not the new (ignored) value.
Review: https://reviews.apache.org/r/54467/
Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/ca1e7249
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/ca1e7249
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/ca1e7249
Branch: refs/heads/master
Commit: ca1e72499ef877aa6a7942d231f9089fa98da457
Parents: 0dbceaf
Author: Neil Conway <ne...@gmail.com>
Authored: Wed Dec 7 17:04:35 2016 -0800
Committer: Vinod Kone <vi...@gmail.com>
Committed: Wed Dec 7 17:05:46 2016 -0800
----------------------------------------------------------------------
src/master/master.hpp | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mesos/blob/ca1e7249/src/master/master.hpp
----------------------------------------------------------------------
diff --git a/src/master/master.hpp b/src/master/master.hpp
index c0bdb80..d3c20d7 100644
--- a/src/master/master.hpp
+++ b/src/master/master.hpp
@@ -2434,7 +2434,7 @@ struct Framework
// MESOS-703.
if (source.user() != info.user()) {
- LOG(WARNING) << "Cannot update FrameworkInfo.user to '" << info.user()
+ LOG(WARNING) << "Cannot update FrameworkInfo.user to '" << source.user()
<< "' for framework " << id() << ". Check MESOS-703";
}
@@ -2448,12 +2448,12 @@ struct Framework
if (source.checkpoint() != info.checkpoint()) {
LOG(WARNING) << "Cannot update FrameworkInfo.checkpoint to '"
- << stringify(info.checkpoint()) << "' for framework " << id()
- << ". Check MESOS-703";
+ << stringify(source.checkpoint()) << "' for framework "
+ << id() << ". Check MESOS-703";
}
if (source.role() != info.role()) {
- LOG(WARNING) << "Cannot update FrameworkInfo.role to '" << info.role()
+ LOG(WARNING) << "Cannot update FrameworkInfo.role to '" << source.role()
<< "' for framework " << id() << ". Check MESOS-703";
}
@@ -2465,7 +2465,7 @@ struct Framework
if (source.principal() != info.principal()) {
LOG(WARNING) << "Cannot update FrameworkInfo.principal to '"
- << info.principal() << "' for framework " << id()
+ << source.principal() << "' for framework " << id()
<< ". Check MESOS-703";
}
[6/9] mesos git commit: Added some additional CHECKs to the master.
Posted by vi...@apache.org.
Added some additional CHECKs to the master.
Review: https://reviews.apache.org/r/54468/
Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/c0504ff2
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/c0504ff2
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/c0504ff2
Branch: refs/heads/master
Commit: c0504ff25516265c3767bef34be976a037681ed9
Parents: ca1e724
Author: Neil Conway <ne...@gmail.com>
Authored: Wed Dec 7 17:04:39 2016 -0800
Committer: Vinod Kone <vi...@gmail.com>
Committed: Wed Dec 7 17:05:47 2016 -0800
----------------------------------------------------------------------
src/master/master.cpp | 8 ++++++++
1 file changed, 8 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mesos/blob/c0504ff2/src/master/master.cpp
----------------------------------------------------------------------
diff --git a/src/master/master.cpp b/src/master/master.cpp
index 08a5733..b496783 100644
--- a/src/master/master.cpp
+++ b/src/master/master.cpp
@@ -2142,6 +2142,8 @@ void Master::drop(
const Offer::Operation& operation,
const string& message)
{
+ CHECK_NOTNULL(framework);
+
// TODO(jieyu): Increment a metric.
// NOTE: There is no direct feedback to the framework when an
@@ -3150,6 +3152,8 @@ Future<bool> Master::authorizeTask(
const TaskInfo& task,
Framework* framework)
{
+ CHECK_NOTNULL(framework);
+
if (authorizer.isNone()) {
return true; // Authorization is disabled.
}
@@ -7150,6 +7154,8 @@ void Master::activateRecoveredFramework(
void Master::failoverFramework(Framework* framework, const HttpConnection& http)
{
+ CHECK_NOTNULL(framework);
+
// Notify the old connected framework that it has failed over.
// This is safe to do even if it is a retry because the framework is expected
// to close the old connection (and hence not receive any more responses)
@@ -7194,6 +7200,8 @@ void Master::failoverFramework(Framework* framework, const HttpConnection& http)
// event of a scheduler failover.
void Master::failoverFramework(Framework* framework, const UPID& newPid)
{
+ CHECK_NOTNULL(framework);
+
const Option<UPID> oldPid = framework->pid;
// There are a few failover cases to consider:
[4/9] mesos git commit: Changed how master represents "recovered"
frameworks.
Posted by vi...@apache.org.
Changed how master represents "recovered" frameworks.
After master failover, the new master doesn't know which frameworks were
registered with the previous master (because this information is not
currently stored in the registry). In the period after the master fails
over but before the framework scheduler has re-registered, the master
learns about the frameworks in the cluster when agents re-register (an
agent reports the FrameworkInfo for all of the frameworks it is running
when it re-registers).
Such frameworks were previously represented separately from the normal
list of frameworks in the master: the master kept a collection of
`FrameworkInfo` for these "recovered" frameworks.
This commit removes this separate collection of "recovered" frameworks.
Instead, the master now treats recovered frameworks very similarly to
frameworks that are registered but currently disconnected. For example,
recovered frameworks will now have a `Framework` object which tracks the
tasks/executors running under that framework; recovered frameworks will
be reported via the normal "frameworks" key when querying HTTP
endpoints. Similarly, "teardown" operations on recovered frameworks will
now work correctly (MESOS-6419).
This means there is no longer a concept of "orphan tasks" [1]: if the
master knows about a task, the task will be running under a framework
(albeit the framework might be recovered or disconnected). A new
"recovered" key has been added to various HTTP endpoints/APIs to
determine if a framework hasn't yet re-registered after master failover.
Another behavioral change is that, previously, a framework
re-registering after master failover was allowed to make arbitrary
changes to its `FrameworkInfo`. The master now only applies updates to
FrameworkInfo fields that can be safely changed (as was already done
when a framework fails over to a master that hasn't failed over). The
previous behavior qualifies as a bug.
[1] The exception here is if the cluster contains Mesos agents older
than 1.0, because old Mesos agents don't report `FrameworkInfo`s when
they re-register.
Review: https://reviews.apache.org/r/53897/
Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/0dbceafa
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/0dbceafa
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/0dbceafa
Branch: refs/heads/master
Commit: 0dbceafa3b7caba9e541cd64bce3d5421e3b1262
Parents: b9b6e9f
Author: Neil Conway <ne...@gmail.com>
Authored: Wed Dec 7 17:04:22 2016 -0800
Committer: Vinod Kone <vi...@gmail.com>
Committed: Wed Dec 7 17:05:44 2016 -0800
----------------------------------------------------------------------
CHANGELOG | 7 +
include/mesos/master/master.proto | 28 +-
include/mesos/v1/master/master.proto | 28 +-
src/master/http.cpp | 130 +++-----
src/master/master.cpp | 423 +++++++++++++++-----------
src/master/master.hpp | 57 +++-
src/tests/api_tests.cpp | 1 +
src/tests/fault_tolerance_tests.cpp | 122 ++++++++
src/tests/master_allocator_tests.cpp | 15 +-
src/tests/master_authorization_tests.cpp | 32 +-
src/tests/master_tests.cpp | 392 ++++++++++++++++++------
src/tests/partition_tests.cpp | 52 ++--
src/tests/teardown_tests.cpp | 126 ++++++++
13 files changed, 1017 insertions(+), 396 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mesos/blob/0dbceafa/CHANGELOG
----------------------------------------------------------------------
diff --git a/CHANGELOG b/CHANGELOG
index 7847fe6..fac4daa 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -5,6 +5,13 @@ Additional API Changes:
* [MESOS-6675] - Changed the allocator API to support adding inactive
frameworks. Custom allocator implementations will need to be updated.
+ * [MESOS-6419] - When a framework re-registers after master failover,
+ it is only allowed to change certain fields in its FrameworkInfo.
+ For example, changing "failover_timeout" is allowed, but changing
+ "role" is not. In previous Mesos releases, the same restrictions on
+ changes to FrameworkInfo were only enforced after framework
+ failover, not master failover.
+
Release Notes - Mesos - Version 1.1.1 (WIP)
-------------------------------------------
http://git-wip-us.apache.org/repos/asf/mesos/blob/0dbceafa/include/mesos/master/master.proto
----------------------------------------------------------------------
diff --git a/include/mesos/master/master.proto b/include/mesos/master/master.proto
index 966105c..0d33251 100644
--- a/include/mesos/master/master.proto
+++ b/include/mesos/master/master.proto
@@ -320,6 +320,13 @@ message Response {
required bool active = 2;
required bool connected = 3;
+ // If true, this framework was previously subscribed but hasn't
+ // yet re-subscribed after a master failover. Recovered frameworks
+ // are only reported if one or more agents running a task or
+ // executor for the framework have re-registered after master
+ // failover.
+ required bool recovered = 11;
+
optional TimeInfo registered_time = 4;
optional TimeInfo reregistered_time = 5;
optional TimeInfo unregistered_time = 6;
@@ -338,8 +345,14 @@ message Response {
// Frameworks that have been teared down.
repeated Framework completed_frameworks = 2;
- // Frameworks that have previously subscribed but haven't yet subscribed
- // after a master failover.
+ // This field previously contained frameworks that previously
+ // subscribed but haven't yet re-subscribed after a master failover.
+ // As of Mesos 1.2, this field will always be empty; recovered
+ // frameworks are now reported in the `frameworks` list with the
+ // `recovered` field set to true.
+ //
+ // TODO(neilc): Remove this field after a deprecation cycle starting
+ // in Mesos 1.2.
repeated FrameworkInfo recovered_frameworks = 3;
}
@@ -353,6 +366,11 @@ message Response {
}
repeated Executor executors = 1;
+
+ // As of Mesos 1.2, this field will always be empty.
+ //
+ // TODO(neilc): Remove this field after a deprecation cycle starting
+ // in Mesos 1.2.
repeated Executor orphan_executors = 2;
}
@@ -372,8 +390,10 @@ message Response {
// acknowledged by the scheduler.
repeated Task completed_tasks = 3;
- // Tasks belonging to frameworks that have not yet re-subscribed with
- // master (e.g., immediately after master failover).
+ // As of Mesos 1.2, this field will always be empty.
+ //
+ // TODO(neilc): Remove this field after a deprecation cycle starting
+ // in Mesos 1.2.
repeated Task orphan_tasks = 4;
}
http://git-wip-us.apache.org/repos/asf/mesos/blob/0dbceafa/include/mesos/v1/master/master.proto
----------------------------------------------------------------------
diff --git a/include/mesos/v1/master/master.proto b/include/mesos/v1/master/master.proto
index 0e5a867..09a82af 100644
--- a/include/mesos/v1/master/master.proto
+++ b/include/mesos/v1/master/master.proto
@@ -321,6 +321,13 @@ message Response {
required bool active = 2;
required bool connected = 3;
+ // If true, this framework was previously subscribed but hasn't
+ // yet re-subscribed after a master failover. Recovered frameworks
+ // are only reported if one or more agents running a task or
+ // executor for the framework have re-registered after master
+ // failover.
+ required bool recovered = 11;
+
optional TimeInfo registered_time = 4;
optional TimeInfo reregistered_time = 5;
optional TimeInfo unregistered_time = 6;
@@ -339,8 +346,14 @@ message Response {
// Frameworks that have been teared down.
repeated Framework completed_frameworks = 2;
- // Frameworks that have previously subscribed but haven't yet subscribed
- // after a master failover.
+ // This field previously contained frameworks that previously
+ // subscribed but haven't yet re-subscribed after a master failover.
+ // As of Mesos 1.2, this field will always be empty; recovered
+ // frameworks are now reported in the `frameworks` list with the
+ // `recovered` field set to true.
+ //
+ // TODO(neilc): Remove this field after a deprecation cycle starting
+ // in Mesos 1.2.
repeated FrameworkInfo recovered_frameworks = 3;
}
@@ -354,6 +367,11 @@ message Response {
}
repeated Executor executors = 1;
+
+ // As of Mesos 1.2, this field will always be empty.
+ //
+ // TODO(neilc): Remove this field after a deprecation cycle starting
+ // in Mesos 1.2.
repeated Executor orphan_executors = 2;
}
@@ -373,8 +391,10 @@ message Response {
// acknowledged by the scheduler.
repeated Task completed_tasks = 3;
- // Tasks belonging to frameworks that have not yet re-subscribed with
- // master (e.g., immediately after master failover).
+ // As of Mesos 1.2, this field will always be empty.
+ //
+ // TODO(neilc): Remove this field after a deprecation cycle starting
+ // in Mesos 1.2.
repeated Task orphan_tasks = 4;
}
http://git-wip-us.apache.org/repos/asf/mesos/blob/0dbceafa/src/master/http.cpp
----------------------------------------------------------------------
diff --git a/src/master/http.cpp b/src/master/http.cpp
index e415124..d410c2f 100644
--- a/src/master/http.cpp
+++ b/src/master/http.cpp
@@ -380,6 +380,8 @@ static void json(JSON::ObjectWriter* writer, const Summary<Framework>& summary)
writer->field("hostname", framework.info.hostname());
writer->field("webui_url", framework.info.webui_url());
writer->field("active", framework.active);
+ writer->field("connected", framework.connected());
+ writer->field("recovered", framework.recovered());
}
@@ -1343,8 +1345,12 @@ Future<Response> Master::Http::frameworks(
}
});
- // Model all currently unregistered frameworks. This can happen
- // when a framework has yet to re-register after master failover.
+ // Model all unregistered frameworks. Such frameworks are only
+ // possible if the cluster contains pre-1.0 agents.
+ //
+ // TODO(neilc): Remove this once we break compatibility with
+ // pre-1.0 agents.
+ //
// TODO(vinod): Need to filter these frameworks based on authorization!
// See TODO in `state()` for further details.
writer->field("unregistered_frameworks", [this](
@@ -1377,6 +1383,7 @@ mesos::master::Response::GetFrameworks::Framework model(
_framework.set_active(framework.active);
_framework.set_connected(framework.connected());
+ _framework.set_recovered(framework.recovered());
int64_t time = framework.registeredTime.duration().ns();
if (time != 0) {
@@ -1475,33 +1482,6 @@ mesos::master::Response::GetFrameworks Master::Http::_getFrameworks(
getFrameworks.add_completed_frameworks()->CopyFrom(model(*framework));
}
- foreachvalue (const Slave* slave, master->slaves.registered) {
- foreachkey (const FrameworkID& frameworkId, slave->tasks) {
- if (!master->frameworks.registered.contains(frameworkId)) {
- // TODO(haosdent): This logic should be simplified after
- // a deprecation cycle starting with 1.0 as after that
- // we can rely on `master->frameworks.recovered` containing
- // all FrameworkInfos.
- // Until then there are 3 cases:
- // - No authorization enabled: show all orphaned frameworks.
- // - Authorization enabled, but no FrameworkInfo present:
- // do not show orphaned frameworks.
- // - Authorization enabled, FrameworkInfo present: filter
- // based on `approveViewFrameworkInfo`.
- if (master->authorizer.isSome() &&
- (!master->frameworks.recovered.contains(frameworkId) ||
- !approveViewFrameworkInfo(
- frameworksApprover,
- master->frameworks.recovered[frameworkId]))) {
- continue;
- }
-
- getFrameworks.add_recovered_frameworks()->CopyFrom(
- master->frameworks.recovered[frameworkId]);
- }
- }
- }
-
return getFrameworks;
}
@@ -1602,7 +1582,11 @@ mesos::master::Response::GetExecutors Master::Http::_getExecutors(
}
}
- // Orphan executors.
+ // Orphan executors. Such executors are only possible if the cluster
+ // contains pre-1.0 agents.
+ //
+ // TODO(neilc): Remove this once we break compatibility with pre-1.0
+ // agents.
foreachvalue (const Slave* slave, master->slaves.registered) {
typedef hashmap<ExecutorID, ExecutorInfo> ExecutorMap;
foreachpair (const FrameworkID& frameworkId,
@@ -1610,22 +1594,11 @@ mesos::master::Response::GetExecutors Master::Http::_getExecutors(
slave->executors) {
foreachvalue (const ExecutorInfo& executorInfo, executors) {
if (!master->frameworks.registered.contains(frameworkId)) {
- // TODO(haosdent): This logic should be simplified after
- // a deprecation cycle starting with 1.0 as after that
- // we can rely on `master->frameworks.recovered` containing
- // all FrameworkInfos.
- // Until then there are 3 cases:
- // - No authorization enabled: show all orphaned executors.
- // - Authorization enabled, but no FrameworkInfo present:
- // do not show orphaned executors.
- // - Authorization enabled, FrameworkInfo present: filter
- // based on `approveViewExecutorInfo`.
- if (master->authorizer.isSome() &&
- (!master->frameworks.recovered.contains(frameworkId) ||
- !approveViewExecutorInfo(
- executorsApprover,
- executorInfo,
- master->frameworks.recovered[frameworkId]))) {
+ // If authorization is enabled, do not show any orphaned
+ // executors. We need the executor's FrameworkInfo to
+ // authorize it, but if we had its FrameworkInfo, it would
+ // not be orphaned.
+ if (master->authorizer.isSome()) {
continue;
}
@@ -2706,33 +2679,24 @@ Future<Response> Master::Http::state(
}
});
- // Model all of the orphan tasks.
+ // Model all of the orphan tasks. Such tasks are only possible
+ // if the cluster contains pre-1.0 agents.
+ //
+ // TODO(neilc): Remove this once we break compatibility with
+ // pre-1.0 agents.
writer->field("orphan_tasks", [this, &tasksApprover](
JSON::ArrayWriter* writer) {
- // Find those orphan tasks.
foreachvalue (const Slave* slave, master->slaves.registered) {
typedef hashmap<TaskID, Task*> TaskMap;
foreachvalue (const TaskMap& tasks, slave->tasks) {
foreachvalue (const Task* task, tasks) {
- CHECK_NOTNULL(task);
const FrameworkID& frameworkId = task->framework_id();
if (!master->frameworks.registered.contains(frameworkId)) {
- // TODO(joerg84): This logic should be simplified after
- // a deprecation cycle starting with 1.0 as after that
- // we can rely on 'master->frameworks.recovered' containing
- // all FrameworkInfos.
- // Until then there are 3 cases:
- // - No authorization enabled: show all orphaned tasks.
- // - Authorization enabled, but no FrameworkInfo present:
- // do not show orphaned tasks.
- // - Authorization enabled, FrameworkInfo present: filter
- // based on 'approveViewTask'.
- if (master->authorizer.isSome() &&
- (!master->frameworks.recovered.contains(frameworkId) ||
- !approveViewTask(
- tasksApprover,
- *task,
- master->frameworks.recovered[frameworkId]))) {
+ // If authorization is enabled, do not show any
+ // orphan tasks. We need the task's FrameworkInfo to
+ // authorize it, but if we had its FrameworkInfo, it
+ // would not be an orphan.
+ if (master->authorizer.isSome()) {
continue;
}
@@ -2743,8 +2707,12 @@ Future<Response> Master::Http::state(
}
});
- // Model all currently unregistered frameworks. This can happen
- // when a framework has yet to re-register after master failover.
+ // Model all unregistered frameworks. Such frameworks are only
+ // possible if the cluster contains pre-1.0 agents.
+ //
+ // TODO(neilc): Remove this once we break compatibility with
+ // pre-1.0 agents.
+ //
// TODO(vinod): Need to filter these frameworks based on authorization!
// See the TODO above for "orphan_tasks" for further details.
writer->field("unregistered_frameworks", [this](
@@ -3830,30 +3798,22 @@ mesos::master::Response::GetTasks Master::Http::_getTasks(
}
}
- // Orphan tasks.
+ // Orphan tasks. Such tasks are only possible if the cluster
+ // contains pre-1.0 agents.
+ //
+ // TODO(neilc): Remove this once we break compatibility with pre-1.0
+ // agents.
foreachvalue (const Slave* slave, master->slaves.registered) {
typedef hashmap<TaskID, Task*> TaskMap;
foreachvalue (const TaskMap& tasks, slave->tasks) {
foreachvalue (const Task* task, tasks) {
- CHECK_NOTNULL(task);
const FrameworkID& frameworkId = task->framework_id();
if (!master->frameworks.registered.contains(frameworkId)) {
- // TODO(joerg84): This logic should be simplified after
- // a deprecation cycle starting with 1.0 as after that
- // we can rely on `master->frameworks.recovered` containing
- // all FrameworkInfos.
- // Until then there are 3 cases:
- // - No authorization enabled: show all orphaned tasks.
- // - Authorization enabled, but no FrameworkInfo present:
- // do not show orphaned tasks.
- // - Authorization enabled, FrameworkInfo present: filter
- // based on `approveViewTask`.
- if (master->authorizer.isSome() &&
- (!master->frameworks.recovered.contains(frameworkId) ||
- !approveViewTask(
- tasksApprover,
- *task,
- master->frameworks.recovered[frameworkId]))) {
+ // If authorization is enabled, do not show any orphan
+ // tasks. We need the task's FrameworkInfo to authorize it,
+ // but if we had its FrameworkInfo, it would not be an
+ // orphan.
+ if (master->authorizer.isSome()) {
continue;
}
http://git-wip-us.apache.org/repos/asf/mesos/blob/0dbceafa/src/master/master.cpp
----------------------------------------------------------------------
diff --git a/src/master/master.cpp b/src/master/master.cpp
index a3ad0b1..08a5733 100644
--- a/src/master/master.cpp
+++ b/src/master/master.cpp
@@ -1272,8 +1272,10 @@ void Master::exited(const UPID& pid)
// structs, its tasks transitioned to LOST and resources
// recovered.
//
- // NOTE: If the framework hasn't re-registered since the master
- // failed over, we assume the framework is checkpointing.
+ // NOTE: If the framework hasn't re-registered yet and no agents
+ // (>= Mesos 1.0) have re-registered that are running any of the
+ // framework's tasks, we can't determine if the framework has
+ // enabled checkpointing. In that case, we assume it has.
hashset<FrameworkID> frameworkIds =
slave->tasks.keys() | slave->executors.keys();
@@ -2477,16 +2479,26 @@ void Master::_subscribe(
return;
}
- // If we are here framework has already been assigned an id.
+ // If we are here the framework has already been assigned an id.
CHECK(!frameworkInfo.id().value().empty());
- if (frameworks.registered.contains(frameworkInfo.id())) {
- Framework* framework =
- CHECK_NOTNULL(frameworks.registered[frameworkInfo.id()]);
+ Framework* framework = getFramework(frameworkInfo.id());
- // It is now safe to update the framework fields since the request is now
- // guaranteed to be successful. We use the fields passed in during
- // subscription.
+ if (framework == nullptr) {
+ // The framework has not yet re-registered after master failover.
+ // Furthermore, no agents have re-registered running one of this
+ // framework's tasks. Reconstruct a `Framework` object from the
+ // supplied `FrameworkInfo`.
+ recoverFramework(frameworkInfo);
+
+ framework = getFramework(frameworkInfo.id());
+ }
+
+ CHECK_NOTNULL(framework);
+
+ if (!framework->recovered()) {
+ // The framework has previously been registered with this master;
+ // it may or may not currently be connected.
LOG(INFO) << "Updating info for framework " << framework->id();
framework->updateFrameworkInfo(frameworkInfo);
@@ -2497,46 +2509,10 @@ void Master::_subscribe(
// Always failover the old framework connection. See MESOS-4712 for details.
failoverFramework(framework, http);
} else {
- // We don't have a framework with this ID, so we must be a newly
- // elected Mesos master to which either an existing scheduler or a
- // failed-over one is connecting. Create a Framework object and add
- // any tasks it has that have been reported by reconnecting slaves.
- Framework* framework = new Framework(this, flags, frameworkInfo, http);
-
- // Add active tasks and executors to the framework.
- foreachvalue (Slave* slave, slaves.registered) {
- if (slave->tasks.contains(framework->id())) {
- foreachvalue (Task* task, slave->tasks.at(framework->id())) {
- framework->addTask(task);
- }
- }
-
- if (slave->executors.contains(framework->id())) {
- foreachvalue (const ExecutorInfo& executor,
- slave->executors.at(framework->id())) {
- framework->addExecutor(slave->id, executor);
- }
- }
- }
-
- // NOTE: Need to add the framework _after_ we add its tasks
- // (above) so that we can properly determine the resources it's
- // currently using!
- addFramework(framework);
-
- FrameworkReregisteredMessage message;
- message.mutable_framework_id()->MergeFrom(framework->id());
- message.mutable_master_info()->MergeFrom(info_);
- framework->send(message);
-
- // Start the heartbeat after sending SUBSCRIBED event.
- framework->heartbeat();
+ // The framework has not yet re-registered after master failover.
+ activateRecoveredFramework(framework, frameworkInfo, None(), http);
}
- CHECK(frameworks.registered.contains(frameworkInfo.id()))
- << "Unknown framework " << frameworkInfo.id()
- << " (" << frameworkInfo.name() << ")";
-
// Broadcast the new framework pid to all the slaves. We have to
// broadcast because an executor might be running on a slave but
// it currently isn't running any tasks.
@@ -2764,19 +2740,33 @@ void Master::_subscribe(
return;
}
- // If we are here framework has already been assigned an id.
+ // If we are here the framework has already been assigned an id.
CHECK(!frameworkInfo.id().value().empty());
- if (frameworks.registered.contains(frameworkInfo.id())) {
+ Framework* framework = getFramework(frameworkInfo.id());
+
+ if (framework == nullptr) {
+ // The framework has not yet re-registered after master failover.
+ // Furthermore, no agents have re-registered running one of this
+ // framework's tasks. Reconstruct a `Framework` object from the
+ // supplied `FrameworkInfo`.
+ recoverFramework(frameworkInfo);
+
+ framework = getFramework(frameworkInfo.id());
+ }
+
+ CHECK_NOTNULL(framework);
+
+ if (!framework->recovered()) {
+ // The framework has previously been registered with this master;
+ // it may or may not currently be connected.
+ //
// Using the "force" field of the scheduler allows us to keep a
// scheduler that got partitioned but didn't die (in ZooKeeper
// speak this means didn't lose their session) and then
// eventually tried to connect to this master even though
// another instance of their scheduler has reconnected.
- Framework* framework =
- CHECK_NOTNULL(frameworks.registered[frameworkInfo.id()]);
-
// Test for the error case first.
if ((framework->pid != from) && !force) {
LOG(ERROR) << "Disallowing subscription attempt of"
@@ -2858,47 +2848,10 @@ void Master::_subscribe(
return;
}
} else {
- // We don't have a framework with this ID, so we must be a newly
- // elected Mesos master to which either an existing scheduler or a
- // failed-over one is connecting. Create a Framework object and add
- // any tasks it has that have been reported by reconnecting slaves.
- Framework* framework = new Framework(this, flags, frameworkInfo, from);
-
- // Add active tasks and executors to the framework.
- foreachvalue (Slave* slave, slaves.registered) {
- if (slave->tasks.contains(framework->id())) {
- foreachvalue (Task* task, slave->tasks.at(framework->id())) {
- framework->addTask(task);
- }
- }
-
- if (slave->executors.contains(framework->id())) {
- foreachvalue (const ExecutorInfo& executor,
- slave->executors.at(framework->id())) {
- framework->addExecutor(slave->id, executor);
- }
- }
- }
-
- // N.B. Need to add the framework _after_ we add its tasks
- // (above) so that we can properly determine the resources it's
- // currently using!
- addFramework(framework);
-
- // TODO(bmahler): We have to send a registered message here for
- // the re-registering framework, per the API contract. Send
- // re-register here per MESOS-786; requires deprecation or it
- // will break frameworks.
- FrameworkRegisteredMessage message;
- message.mutable_framework_id()->MergeFrom(framework->id());
- message.mutable_master_info()->MergeFrom(info_);
- framework->send(message);
+ // The framework has not yet re-registered after master failover.
+ activateRecoveredFramework(framework, frameworkInfo, from, None());
}
- CHECK(frameworks.registered.contains(frameworkInfo.id()))
- << "Unknown framework " << frameworkInfo.id()
- << " (" << frameworkInfo.name() << ")";
-
// Broadcast the new framework pid to all the slaves. We have to
// broadcast because an executor might be running on a slave but
// it currently isn't running any tasks.
@@ -5561,33 +5514,25 @@ void Master::__reregisterSlave(
hashset<FrameworkID> ids;
// TODO(joerg84): Remove this after a deprecation cycle starting
- // with the 1.0 release. It is only required if an older
- // (pre 1.0 agent) reregisters with a newer master.
- // In that case the agent does not have the 'frameworks' message
- // set which is used below to retrieve the framework information.
+ // with the 1.0 release. It is only required if an older (pre 1.0)
+ // agent reregisters with a newer master. In that case the agent
+ // does not have the `frameworks` field set which is used below to
+ // retrieve the framework information.
foreach (const Task& task, tasks) {
- Framework* framework = getFramework(task.framework_id());
-
- if (framework != nullptr && !ids.contains(framework->id())) {
- UpdateFrameworkMessage message;
- message.mutable_framework_id()->MergeFrom(framework->id());
-
- // TODO(anand): We set 'pid' to UPID() for http frameworks
- // as 'pid' was made optional in 0.24.0. In 0.25.0, we
- // no longer have to set pid here for http frameworks.
- message.set_pid(framework->pid.getOrElse(UPID()));
-
- send(slave->pid, message);
-
- ids.insert(framework->id());
- }
+ ids.insert(task.framework_id());
}
foreach (const FrameworkInfo& frameworkInfo, frameworks) {
CHECK(frameworkInfo.has_id());
- Framework* framework = getFramework(frameworkInfo.id());
+ ids.insert(frameworkInfo.id());
+ }
- if (framework != nullptr && !ids.contains(framework->id())) {
+ foreach (const FrameworkID& frameworkId, ids) {
+ Framework* framework = getFramework(frameworkId);
+
+ // TODO(neilc): It doesn't seem useful to send the PIDs of
+ // frameworks that are not connected.
+ if (framework != nullptr) {
UpdateFrameworkMessage message;
message.mutable_framework_id()->MergeFrom(framework->id());
@@ -5597,15 +5542,25 @@ void Master::__reregisterSlave(
message.set_pid(framework->pid.getOrElse(UPID()));
send(slave->pid, message);
+ }
+ }
- ids.insert(framework->id());
- } else {
- // The framework hasn't yet reregistered with the master,
- // hence we store the 'FrameworkInfo' in the recovered list.
- // TODO(joerg84): Consider recovering this information from
- // registrar instead of from agents.
- this->frameworks.recovered[frameworkInfo.id()] = frameworkInfo;
+ // If the agent is running any frameworks the master doesn't know
+ // about, recover the framework using the `FrameworkInfo` supplied
+ // by the agent. We don't recover frameworks that have already
+ // completed at the master.
+ foreach (const FrameworkInfo& frameworkInfo, frameworks) {
+ if (getFramework(frameworkInfo.id()) != nullptr) {
+ continue;
}
+ if (isCompletedFramework(frameworkInfo.id())) {
+ continue;
+ }
+
+ LOG(INFO) << "Recovering framework " << frameworkInfo.id()
+ << " from re-registering agent " << *slave;
+
+ recoverFramework(frameworkInfo);
}
// NOTE: Here we always send the message. Slaves whose version are
@@ -5940,11 +5895,13 @@ void Master::exitedExecutor(
// TODO(vinod): Reliably forward this message to the scheduler.
Framework* framework = getFramework(frameworkId);
- if (framework == nullptr) {
+ if (framework == nullptr || !framework->connected()) {
+ string status = (framework == nullptr ? "unknown" : "disconnected");
+
LOG(WARNING)
<< "Not forwarding exited executor message for executor '" << executorId
<< "' of framework " << frameworkId << " on agent " << *slave
- << " because the framework is unknown";
+ << " because the framework is " << status;
return;
}
@@ -6088,24 +6045,13 @@ void Master::_markUnreachable(
foreachkey (const FrameworkID& frameworkId, utils::copy(slave->tasks)) {
Framework* framework = getFramework(frameworkId);
- // If the framework has not yet re-registered after master failover,
- // its FrameworkInfo will be in the `recovered` collection. Note that
- // if the master knows about a task, its FrameworkInfo must appear in
- // either the `registered` or `recovered` collections.
- //
- // NOTE: If the framework is only running tasks on pre-1.0 agents
- // and the framework hasn't yet re-registered, its FrameworkInfo
- // will not appear in `recovered`. We can't accurately determine
- // whether the framework is partition-aware; we assume it is NOT
- // partition-aware, since using TASK_LOST ensures compatibility
- // with the previous (and default) Mesos behavior.
- Option<FrameworkInfo> frameworkInfo;
-
- if (framework != nullptr) {
- frameworkInfo = framework->info;
- } else if (frameworks.recovered.contains(frameworkId)) {
- frameworkInfo = frameworks.recovered[frameworkId];
- } else {
+ if (framework == nullptr) {
+ // If the framework is only running tasks on pre-1.0 agents and
+ // the framework hasn't yet re-registered, the master doesn't
+ // have a FrameworkInfo for it, and hence we cannot accurately
+ // determine whether the framework is partition-aware. We assume
+ // it is NOT partition-aware, since using TASK_LOST ensures
+ // compatibility with the previous (and default) Mesos behavior.
LOG(WARNING) << "Unable to determine if framework " << frameworkId
<< " is partition-aware, because the cluster contains"
<< " agents running an old version of Mesos; upgrading"
@@ -6113,8 +6059,8 @@ void Master::_markUnreachable(
}
TaskState newTaskState = TASK_UNREACHABLE;
- if (frameworkInfo.isNone() || !protobuf::frameworkHasCapability(
- frameworkInfo.get(), FrameworkInfo::Capability::PARTITION_AWARE)) {
+ if (framework == nullptr || !protobuf::frameworkHasCapability(
+ framework->info, FrameworkInfo::Capability::PARTITION_AWARE)) {
newTaskState = TASK_LOST;
}
@@ -6138,9 +6084,12 @@ void Master::_markUnreachable(
updateTask(task, update);
removeTask(task);
- if (framework == nullptr) {
+ if (framework == nullptr || !framework->connected()) {
+ string status = (framework == nullptr ? "unknown" : "disconnected");
+
LOG(WARNING) << "Dropping update " << update
- << " for unknown framework " << frameworkId;
+ << " for " << status
+ << " framework " << frameworkId;
} else {
forward(update, UPID(), framework);
}
@@ -6917,8 +6866,8 @@ void Master::reconcileKnownSlave(
// master has a task that the agent doesn't know about, the
// framework must have reregistered with this master since the
// last master failover.
- Framework* framework = getFramework(frameworkId);
- CHECK_NOTNULL(framework);
+ Framework* framework = CHECK_NOTNULL(getFramework(frameworkId));
+ CHECK(!framework->recovered());
reconcile.mutable_framework_id()->CopyFrom(frameworkId);
reconcile.mutable_framework()->CopyFrom(framework->info);
@@ -6990,9 +6939,11 @@ void Master::reconcileKnownSlave(
// Send ShutdownFrameworkMessages for frameworks that are completed.
// This could happen if the message wasn't received by the slave
// (e.g., slave was down, partitioned).
+ //
// NOTE: This is a short-term hack because this information is lost
// when the master fails over. Also, we only store a limited number
// of completed frameworks.
+ //
// TODO(vinod): Revisit this when registrar is in place. It would
// likely involve storing this information in the registrar.
foreach (const shared_ptr<Framework>& framework, frameworks.completed) {
@@ -7018,18 +6969,17 @@ void Master::addFramework(Framework* framework)
frameworks.registered[framework->id()] = framework;
- // Remove from 'frameworks.recovered' if necessary.
- frameworks.recovered.erase(framework->id());
-
- if (framework->pid.isSome()) {
- link(framework->pid.get());
- } else {
- CHECK_SOME(framework->http);
+ if (framework->connected()) {
+ if (framework->pid.isSome()) {
+ link(framework->pid.get());
+ } else {
+ CHECK_SOME(framework->http);
- const HttpConnection& http = framework->http.get();
+ const HttpConnection& http = framework->http.get();
- http.closed()
- .onAny(defer(self(), &Self::exited, framework->id(), http));
+ http.closed()
+ .onAny(defer(self(), &Self::exited, framework->id(), http));
+ }
}
auto addFrameworkRole = [this](Framework* framework, const string& role) {
@@ -7086,6 +7036,118 @@ void Master::addFramework(Framework* framework)
}
+void Master::recoverFramework(const FrameworkInfo& info)
+{
+ CHECK(!frameworks.registered.contains(info.id()));
+
+ Framework* framework = new Framework(this, flags, info);
+
+ // Add active tasks and executors to the framework.
+ foreachvalue (Slave* slave, slaves.registered) {
+ if (slave->tasks.contains(framework->id())) {
+ foreachvalue (Task* task, slave->tasks.at(framework->id())) {
+ framework->addTask(task);
+ }
+ }
+
+ if (slave->executors.contains(framework->id())) {
+ foreachvalue (const ExecutorInfo& executor,
+ slave->executors.at(framework->id())) {
+ framework->addExecutor(slave->id, executor);
+ }
+ }
+ }
+
+ addFramework(framework);
+}
+
+
+void Master::activateRecoveredFramework(
+ Framework* framework,
+ const FrameworkInfo& frameworkInfo,
+ const Option<UPID>& pid,
+ const Option<HttpConnection>& http)
+{
+ // Exactly one of `pid` or `http` must be provided.
+ CHECK(pid.isSome() != http.isSome());
+
+ CHECK_NOTNULL(framework);
+ CHECK(framework->recovered());
+ CHECK(!framework->active);
+ CHECK(framework->offers.empty());
+ CHECK(framework->inverseOffers.empty());
+ CHECK(framework->pid.isNone());
+ CHECK(framework->http.isNone());
+
+ // The `FrameworkInfo` might have changed.
+ LOG(INFO) << "Updating info for framework " << framework->id();
+
+ framework->updateFrameworkInfo(frameworkInfo);
+ allocator->updateFramework(framework->id(), framework->info);
+
+ // Updating `registeredTime` here is debatable: ideally,
+ // `registeredTime` would be the time at which the framework first
+ // registered with the master. However, we cannot determine this
+ // because the time at which a framework first registered is not
+ // persisted across master failover.
+ framework->registeredTime = Clock::now();
+ framework->reregisteredTime = Clock::now();
+
+ // Update the framework's connection state.
+ framework->state = Framework::State::CONNECTED;
+
+ if (pid.isSome()) {
+ framework->updateConnection(pid.get());
+ link(pid.get());
+ } else {
+ framework->updateConnection(http.get());
+ http->closed()
+ .onAny(defer(self(), &Self::exited, framework->id(), http.get()));
+ }
+
+ // Activate the framework.
+ framework->active = true;
+ allocator->activateFramework(framework->id());
+
+ // Export framework metrics if a principal is specified in `FrameworkInfo`.
+ Option<string> principal = framework->info.has_principal()
+ ? Option<string>(framework->info.principal())
+ : None();
+
+ if (framework->pid.isSome()) {
+ CHECK(!frameworks.principals.contains(framework->pid.get()));
+ frameworks.principals.put(framework->pid.get(), principal);
+ }
+
+ // We expect the framework metrics for this principal to be created
+ // when the framework is recovered. This implies that the framework
+ // principal cannot change on re-registration, which is currently
+ // the case (MESOS-2842).
+ if (principal.isSome()) {
+ CHECK(metrics->frameworks.contains(principal.get()));
+ }
+
+ if (pid.isSome()) {
+ // TODO(bmahler): We have to send a registered message here for
+ // the re-registering framework, per the API contract. Send
+ // re-register here per MESOS-786; requires deprecation or it
+ // will break frameworks.
+ FrameworkRegisteredMessage message;
+ message.mutable_framework_id()->MergeFrom(framework->id());
+ message.mutable_master_info()->MergeFrom(info_);
+ framework->send(message);
+ } else {
+ FrameworkReregisteredMessage message;
+ message.mutable_framework_id()->MergeFrom(framework->id());
+ message.mutable_master_info()->MergeFrom(info_);
+ framework->send(message);
+
+ // Start the heartbeat after sending SUBSCRIBED event.
+ framework->heartbeat();
+ }
+}
+
+
void Master::failoverFramework(Framework* framework, const HttpConnection& http)
{
// Notify the old connected framework that it has failed over.
@@ -7380,9 +7442,6 @@ void Master::removeFramework(Framework* framework)
frameworks.registered.erase(framework->id());
allocator->removeFramework(framework->id());
- // Remove from 'frameworks.recovered' if necessary.
- frameworks.recovered.erase(framework->id());
-
// The completedFramework buffer now owns the framework pointer.
frameworks.completed.push_back(shared_ptr<Framework>(framework));
}
@@ -7419,7 +7478,10 @@ void Master::removeFramework(Slave* slave, Framework* framework)
updateTask(task, update);
removeTask(task);
- forward(update, UPID(), framework);
+
+ if (framework->connected()) {
+ forward(update, UPID(), framework);
+ }
}
}
@@ -7468,7 +7530,11 @@ void Master::addSlave(
foreachkey (const FrameworkID& frameworkId, slave->executors) {
Framework* framework = getFramework(frameworkId);
- // The framework might not be re-registered yet.
+ // If the framework has not re-registered yet and this is the
+ // first agent to re-register that is running the framework, we
+ // skip adding the framework's executors here. Instead, the
+ // framework will be recovered in `__reregisterSlave` and its
+ // executors will be added by `recoverFramework`.
if (framework == nullptr) {
continue;
}
@@ -7483,27 +7549,29 @@ void Master::addSlave(
foreachkey (const FrameworkID& frameworkId, slave->tasks) {
Framework* framework = getFramework(frameworkId);
+ // If the framework has not re-registered yet and this is the
+ // first agent to re-register that is running the framework, we
+ // skip adding the framework's tasks here. Instead, the framework
+ // will be recovered in `__reregisterSlave` and its tasks will be
+ // added by `recoverFramework`.
+ if (framework == nullptr) {
+ continue;
+ }
+
foreachvalue (Task* task, slave->tasks[frameworkId]) {
- // The framework might not be re-registered yet.
- if (framework != nullptr) {
- framework->addTask(task);
- } else {
- // TODO(benh): We should really put a timeout on how long we
- // keep tasks running on a slave that never have frameworks
- // reregister and claim them.
- LOG(WARNING) << "Possibly orphaned task " << task->task_id()
- << " of framework " << task->framework_id()
- << " running on agent " << *slave;
- }
+ framework->addTask(task);
}
}
// Re-add completed tasks reported by the slave.
+ //
// Note that a slave considers a framework completed when it has no
- // tasks/executors running for that framework. But a master considers a
- // framework completed when the framework is removed after a failover timeout.
- // TODO(vinod): Reconcile the notion of a completed framework across the
- // master and slave.
+ // tasks/executors running for that framework. But a master
+ // considers a framework completed when the framework is removed
+ // after a failover timeout.
+ //
+ // TODO(vinod): Reconcile the notion of a completed framework across
+ // the master and slave.
foreach (const Archive::Framework& completedFramework, completedFrameworks) {
Framework* framework = getFramework(
completedFramework.framework_info().id());
@@ -7515,7 +7583,8 @@ void Master::addSlave(
<< " that ran on agent " << *slave;
framework->addCompletedTask(task);
} else {
- // We could be here if the framework hasn't registered yet.
+ // The framework might not be re-registered yet.
+ //
// TODO(vinod): Revisit these semantics when we store frameworks'
// information in the registrar.
LOG(WARNING) << "Possibly orphaned completed task " << task.task_id()
@@ -7652,7 +7721,7 @@ void Master::_removeSlave(
updateTask(task, update);
removeTask(task);
- if (framework == nullptr) {
+ if (framework == nullptr || !framework->connected()) {
LOG(WARNING) << "Dropping update " << update
<< " for unknown framework " << frameworkId;
} else {
http://git-wip-us.apache.org/repos/asf/mesos/blob/0dbceafa/src/master/master.hpp
----------------------------------------------------------------------
diff --git a/src/master/master.hpp b/src/master/master.hpp
index 9f5929c..c0bdb80 100644
--- a/src/master/master.hpp
+++ b/src/master/master.hpp
@@ -643,9 +643,10 @@ protected:
Framework* framework,
const std::vector<TaskStatus>& statuses);
- // When a slave that is known to the master re-registers, we need to
- // reconcile the master's view of the slave's tasks and executors.
- // This function also sends the `ReregisterSlaveMessage`.
+ // When a slave that was previously registered with this master
+ // re-registers, we need to reconcile the master's view of the
+ // slave's tasks and executors. This function also sends the
+ // `ReregisterSlaveMessage`.
void reconcileKnownSlave(
Slave* slave,
const std::vector<ExecutorInfo>& executors,
@@ -654,6 +655,23 @@ protected:
// Add a framework.
void addFramework(Framework* framework);
+ // Recover a framework from its `FrameworkInfo`. This happens after
+ // master failover, when an agent running one of the framework's
+ // tasks re-registers or when the framework itself re-registers,
+ // whichever happens first. The result of this function is a
+ // registered, inactive framework with state `RECOVERED`.
+ void recoverFramework(const FrameworkInfo& info);
+
+ // Transition a framework from `RECOVERED` to `CONNECTED` state and
+ // activate it. This happens at most once after master failover, the
+ // first time that the framework re-registers with the new master.
+ // Exactly one of `newPid` or `http` must be provided.
+ void activateRecoveredFramework(
+ Framework* framework,
+ const FrameworkInfo& frameworkInfo,
+ const Option<process::UPID>& pid,
+ const Option<HttpConnection>& http);
+
// Replace the scheduler for a framework with a new process ID, in
// the event of a scheduler failover.
void failoverFramework(Framework* framework, const process::UPID& newPid);
@@ -1746,10 +1764,6 @@ private:
hashmap<FrameworkID, Framework*> registered;
- // `recovered` contains 'FrameworkInfo's for frameworks that have
- // not yet re-registered after master failover.
- hashmap<FrameworkID, FrameworkInfo> recovered;
-
boost::circular_buffer<std::shared_ptr<Framework>> completed;
// Principals of frameworks keyed by PID.
@@ -2190,7 +2204,13 @@ struct Framework
// Framework was previously connected to this master. A framework
// becomes disconnected when there is a socket error.
- DISCONNECTED
+ DISCONNECTED,
+
+ // Framework has never connected to this master. This implies the
+ // master failed over and the framework has not yet re-registered,
+ // but some framework state has been recovered from re-registering
+ // agents that are running tasks for the framework.
+ RECOVERED
};
Framework(Master* const _master,
@@ -2221,6 +2241,15 @@ struct Framework
reregisteredTime(time),
completedTasks(masterFlags.max_completed_tasks_per_framework) {}
+ Framework(Master* const _master,
+ const Flags& masterFlags,
+ const FrameworkInfo& _info)
+ : master(_master),
+ info(_info),
+ state(RECOVERED),
+ active(false),
+ completedTasks(masterFlags.max_completed_tasks_per_framework) {}
+
~Framework()
{
if (http.isSome()) {
@@ -2477,7 +2506,7 @@ struct Framework
// Wipe the PID if this is an upgrade from PID to HTTP.
// TODO(benh): unlink(oldPid);
pid = None();
- } else {
+ } else if (http.isSome()) {
// Cleanup the old HTTP connection.
// Note that master creates a new HTTP connection for every
// subscribe request, so 'newHttp' should always be different
@@ -2527,14 +2556,16 @@ struct Framework
bool connected() const { return state == CONNECTED; }
+ bool recovered() const { return state == RECOVERED; }
+
Master* const master;
FrameworkInfo info;
- // Frameworks can either be connected via HTTP or by message
- // passing (scheduler driver). Exactly one of 'http' and 'pid'
- // will be set according to the last connection made by the
- // framework.
+ // Frameworks can either be connected via HTTP or by message passing
+ // (scheduler driver). At most one of `http` and `pid` will be set
+ // according to the last connection made by the framework; neither
+ // field will be set if the framework is in state `RECOVERED`.
Option<HttpConnection> http;
Option<process::UPID> pid;
http://git-wip-us.apache.org/repos/asf/mesos/blob/0dbceafa/src/tests/api_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/api_tests.cpp b/src/tests/api_tests.cpp
index 21aefb2..4bc2c74 100644
--- a/src/tests/api_tests.cpp
+++ b/src/tests/api_tests.cpp
@@ -241,6 +241,7 @@ TEST_P(MasterAPITest, GetFrameworks)
ASSERT_FALSE(frameworks.frameworks(0).framework_info().checkpoint());
ASSERT_TRUE(frameworks.frameworks(0).active());
ASSERT_TRUE(frameworks.frameworks(0).connected());
+ ASSERT_FALSE(frameworks.frameworks(0).recovered());
driver.stop();
driver.join();
http://git-wip-us.apache.org/repos/asf/mesos/blob/0dbceafa/src/tests/fault_tolerance_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/fault_tolerance_tests.cpp b/src/tests/fault_tolerance_tests.cpp
index 59f68f6..277dcfa 100644
--- a/src/tests/fault_tolerance_tests.cpp
+++ b/src/tests/fault_tolerance_tests.cpp
@@ -873,6 +873,8 @@ TEST_F(FaultToleranceTest, FrameworkReregister)
JSON::Object framework = frameworks.values.front().as<JSON::Object>();
EXPECT_TRUE(framework.values["active"].as<JSON::Boolean>().value);
+ EXPECT_TRUE(framework.values["connected"].as<JSON::Boolean>().value);
+ EXPECT_FALSE(framework.values["recovered"].as<JSON::Boolean>().value);
EXPECT_EQ(
static_cast<int64_t>(registerTime.secs()),
@@ -2123,6 +2125,126 @@ TEST_F(FaultToleranceTest, UpdateFrameworkInfoOnSchedulerFailover)
EXPECT_EQ(DRIVER_STOPPED, driver1.join());
}
+
+// This test verifies that when a framework re-registers after master
+// failover with an updated FrameworkInfo, the updated FrameworkInfo
+// is reflected in the master.
+TEST_F(FaultToleranceTest, UpdateFrameworkInfoOnMasterFailover)
+{
+ Try<Owned<cluster::Master>> master = StartMaster();
+ ASSERT_SOME(master);
+
+ StandaloneMasterDetector detector(master.get()->pid);
+ Try<Owned<cluster::Slave>> slave = StartSlave(&detector);
+ ASSERT_SOME(slave);
+
+ FrameworkInfo frameworkInfo1 = DEFAULT_FRAMEWORK_INFO;
+ frameworkInfo1.set_name("Framework 1");
+ frameworkInfo1.set_failover_timeout(1000);
+ frameworkInfo1.set_checkpoint(true);
+
+ MockScheduler sched1;
+ MesosSchedulerDriver driver1(
+ &sched1, frameworkInfo1, master.get()->pid, DEFAULT_CREDENTIAL);
+
+ Future<FrameworkID> frameworkId;
+ EXPECT_CALL(sched1, registered(&driver1, _, _))
+ .WillOnce(FutureArg<1>(&frameworkId));
+
+ Future<vector<Offer>> offers;
+ EXPECT_CALL(sched1, resourceOffers(&driver1, _))
+ .WillOnce(FutureArg<1>(&offers));
+
+ driver1.start();
+
+ AWAIT_READY(frameworkId);
+
+ AWAIT_READY(offers);
+ ASSERT_FALSE(offers->empty());
+
+ Offer offer = offers.get()[0];
+
+ TaskInfo task = createTask(offer, "sleep 60");
+
+ Future<TaskStatus> runningStatus;
+ EXPECT_CALL(sched1, statusUpdate(&driver1, _))
+ .WillOnce(FutureArg<1>(&runningStatus));
+
+ Future<Nothing> statusUpdateAck = FUTURE_DISPATCH(
+ slave.get()->pid, &Slave::_statusUpdateAcknowledgement);
+
+ driver1.launchTasks(offer.id(), {task});
+
+ AWAIT_READY(runningStatus);
+ EXPECT_EQ(TASK_RUNNING, runningStatus->state());
+ EXPECT_EQ(task.task_id(), runningStatus->task_id());
+
+ AWAIT_READY(statusUpdateAck);
+
+ // Stop the master.
+ master->reset();
+
+ // While the master is down, shutdown the first framework.
+ driver1.stop();
+ driver1.join();
+
+ // Restart master; ensure the agent re-registers before the second
+ // scheduler connects. This ensures the first framework's
+ // FrameworkInfo is recovered from the re-registering agent.
+ Future<SlaveReregisteredMessage> slaveReregistered = FUTURE_PROTOBUF(
+ SlaveReregisteredMessage(), _, slave.get()->pid);
+
+ master = StartMaster();
+ ASSERT_SOME(master);
+
+ detector.appoint(master.get()->pid);
+
+ AWAIT_READY(slaveReregistered);
+
+ // Connect a new scheduler that uses the same framework ID but a
+ // different `FrameworkInfo`. Note that updating the `checkpoint`
+ // field is NOT supported, so we expect the master to ignore the
+ // updated version of this field.
+ FrameworkInfo frameworkInfo2 = DEFAULT_FRAMEWORK_INFO;
+ frameworkInfo2.mutable_id()->MergeFrom(frameworkId.get());
+ frameworkInfo2.set_name("Framework 2");
+ frameworkInfo2.set_failover_timeout(2000);
+ frameworkInfo2.set_checkpoint(false);
+
+ MockScheduler sched2;
+ MesosSchedulerDriver driver2(
+ &sched2, frameworkInfo2, master.get()->pid, DEFAULT_CREDENTIAL);
+
+ Future<Nothing> sched2Registered;
+ EXPECT_CALL(sched2, registered(&driver2, frameworkId.get(), _))
+ .WillOnce(FutureSatisfy(&sched2Registered));
+
+ driver2.start();
+
+ AWAIT_READY(sched2Registered);
+
+ Future<Response> response = process::http::get(
+ master.get()->pid,
+ "state",
+ None(),
+ createBasicAuthHeaders(DEFAULT_CREDENTIAL));
+
+ Try<JSON::Object> parse = JSON::parse<JSON::Object>(response->body);
+ ASSERT_SOME(parse);
+
+ JSON::Array frameworks = parse->values["frameworks"].as<JSON::Array>();
+ ASSERT_EQ(1u, frameworks.values.size());
+
+ JSON::Object framework = frameworks.values.front().as<JSON::Object>();
+ EXPECT_EQ(frameworkId.get(), framework.values["id"].as<JSON::String>().value);
+ EXPECT_EQ("Framework 2", framework.values["name"].as<JSON::String>().value);
+ EXPECT_EQ(2000, framework.values["failover_timeout"].as<JSON::Number>());
+ EXPECT_TRUE(framework.values["checkpoint"].as<JSON::Boolean>().value);
+
+ driver2.stop();
+ driver2.join();
+}
+
} // namespace tests {
} // namespace internal {
} // namespace mesos {
http://git-wip-us.apache.org/repos/asf/mesos/blob/0dbceafa/src/tests/master_allocator_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/master_allocator_tests.cpp b/src/tests/master_allocator_tests.cpp
index 266047b..34e2b49 100644
--- a/src/tests/master_allocator_tests.cpp
+++ b/src/tests/master_allocator_tests.cpp
@@ -1528,6 +1528,13 @@ TYPED_TEST(MasterAllocatorTest, SlaveReregistersFirst)
.WillOnce(DoAll(InvokeAddSlave(&allocator2),
FutureSatisfy(&addSlave)));
+ // Expect the framework to be added but to be inactive when the
+ // agent re-registers, until the framework re-registers below.
+ Future<Nothing> addFramework;
+ EXPECT_CALL(allocator2, addFramework(_, _, _, false))
+ .WillOnce(DoAll(InvokeAddFramework(&allocator2),
+ FutureSatisfy(&addFramework)));
+
Try<Owned<cluster::Master>> master2 = this->StartMaster(&allocator2);
ASSERT_SOME(master2);
@@ -1535,12 +1542,18 @@ TYPED_TEST(MasterAllocatorTest, SlaveReregistersFirst)
slaveDetector.appoint(master2.get()->pid);
AWAIT_READY(addSlave);
+ AWAIT_READY(addFramework);
EXPECT_CALL(sched, disconnected(_));
EXPECT_CALL(sched, registered(&driver, _, _));
- EXPECT_CALL(allocator2, addFramework(_, _, _, _));
+ // Because the framework was re-added above, we expect to only
+ // activate the framework when it re-registers.
+ EXPECT_CALL(allocator2, addFramework(_, _, _, _))
+ .Times(0);
+
+ EXPECT_CALL(allocator2, activateFramework(_));
Future<vector<Offer>> resourceOffers2;
EXPECT_CALL(sched, resourceOffers(&driver, _))
http://git-wip-us.apache.org/repos/asf/mesos/blob/0dbceafa/src/tests/master_authorization_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/master_authorization_tests.cpp b/src/tests/master_authorization_tests.cpp
index 06c6e47..f973cf4 100644
--- a/src/tests/master_authorization_tests.cpp
+++ b/src/tests/master_authorization_tests.cpp
@@ -2147,9 +2147,11 @@ TYPED_TEST(MasterAuthorizerTest, FilterRolesEndpoint)
// This test verifies that authorization based endpoint filtering
-// works correctly on the /state endpoint with orphaned tasks.
-// Both default users are allowed to to view high level frameworks, but only
-// one is allowed to view the tasks.
+// works correctly on the /state endpoint with orphaned tasks. Both
+// default users are allowed to to view high level frameworks, but
+// only one is allowed to view the tasks. Although the tasks are
+// "orphaned" (in the sense that their framework has not yet
+// re-registered), they are now reported under the "tasks" key.
TYPED_TEST(MasterAuthorizerTest, FilterOrphanedTasks)
{
ACLs acls;
@@ -2242,7 +2244,7 @@ TYPED_TEST(MasterAuthorizerTest, FilterOrphanedTasks)
EXPECT_CALL(exec, launchTask(_, _))
.WillOnce(SendStatusUpdateFromTask(TASK_RUNNING));
- // Wait until TASK_RUNNING of the task is received.
+ // Wait until TASK_RUNNING of the task is received.
AWAIT_READY(statusUpdate);
Future<SlaveReregisteredMessage> slaveReregisteredMessage =
@@ -2279,8 +2281,18 @@ TYPED_TEST(MasterAuthorizerTest, FilterOrphanedTasks)
ASSERT_SOME(parse);
JSON::Object tasks = parse.get();
+
+ // The "orphan_tasks" array should be empty, regardless of authorization.
ASSERT_TRUE(tasks.values["orphan_tasks"].is<JSON::Array>());
- EXPECT_EQ(1u, tasks.values["orphan_tasks"].as<JSON::Array>().values.size());
+ EXPECT_TRUE(tasks.values["orphan_tasks"].as<JSON::Array>().values.empty());
+
+ ASSERT_TRUE(tasks.values["frameworks"].is<JSON::Array>());
+
+ JSON::Array frameworks = tasks.values["frameworks"].as<JSON::Array>();
+ EXPECT_EQ(1u, frameworks.values.size());
+
+ JSON::Object framework = frameworks.values.front().as<JSON::Object>();
+ EXPECT_EQ(1u, framework.values["tasks"].as<JSON::Array>().values.size());
}
// Retrieve endpoint with the user allowed to view the framework,
@@ -2299,8 +2311,18 @@ TYPED_TEST(MasterAuthorizerTest, FilterOrphanedTasks)
ASSERT_SOME(parse);
JSON::Object tasks = parse.get();
+
+ // The "orphan_tasks" array should be empty, regardless of authorization.
ASSERT_TRUE(tasks.values["orphan_tasks"].is<JSON::Array>());
EXPECT_TRUE(tasks.values["orphan_tasks"].as<JSON::Array>().values.empty());
+
+ ASSERT_TRUE(tasks.values["frameworks"].is<JSON::Array>());
+
+ JSON::Array frameworks = tasks.values["frameworks"].as<JSON::Array>();
+ EXPECT_EQ(1u, frameworks.values.size());
+
+ JSON::Object framework = frameworks.values.front().as<JSON::Object>();
+ EXPECT_TRUE(framework.values["tasks"].as<JSON::Array>().values.empty());
}
EXPECT_CALL(exec, shutdown(_))
http://git-wip-us.apache.org/repos/asf/mesos/blob/0dbceafa/src/tests/master_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/master_tests.cpp b/src/tests/master_tests.cpp
index dfedbbd..5901614 100644
--- a/src/tests/master_tests.cpp
+++ b/src/tests/master_tests.cpp
@@ -2752,11 +2752,11 @@ TEST_F(MasterZooKeeperTest, MasterInfoAddress)
#endif // MESOS_HAS_JAVA
-// This test ensures that when a master fails over, those tasks that
-// belong to some currently unregistered frameworks will appear in the
-// "orphan_tasks" field in the state endpoint. And those unregistered
-// frameworks will appear in the "unregistered_frameworks" field.
-TEST_F(MasterTest, OrphanTasks)
+// This test ensures that when a master fails over, tasks that belong
+// to frameworks that have not re-registered will be reported in the
+// "/state" endpoint. The framework itself should have the "recovered"
+// field set to true.
+TEST_F(MasterTest, RecoveredFramework)
{
// Start a master.
Try<Owned<cluster::Master>> master = StartMaster();
@@ -2791,8 +2791,7 @@ TEST_F(MasterTest, OrphanTasks)
Future<TaskStatus> status;
EXPECT_CALL(sched, statusUpdate(&driver, _))
- .WillOnce(FutureArg<1>(&status))
- .WillRepeatedly(Return()); // Ignore subsequent updates.
+ .WillOnce(FutureArg<1>(&status));
driver.start();
@@ -2800,38 +2799,40 @@ TEST_F(MasterTest, OrphanTasks)
EXPECT_EQ(TASK_RUNNING, status.get().state());
// Get the master's state.
- Future<Response> response = process::http::get(
+ Future<Response> response1 = process::http::get(
master.get()->pid,
"state",
None(),
createBasicAuthHeaders(DEFAULT_CREDENTIAL));
- AWAIT_EXPECT_RESPONSE_STATUS_EQ(OK().status, response);
- AWAIT_EXPECT_RESPONSE_HEADER_EQ(APPLICATION_JSON, "Content-Type", response);
+ AWAIT_EXPECT_RESPONSE_STATUS_EQ(OK().status, response1);
+ AWAIT_EXPECT_RESPONSE_HEADER_EQ(APPLICATION_JSON, "Content-Type", response1);
- Try<JSON::Object> parse = JSON::parse<JSON::Object>(response.get().body);
- ASSERT_SOME(parse);
+ Try<JSON::Object> parse1 = JSON::parse<JSON::Object>(response1.get().body);
+ ASSERT_SOME(parse1);
- JSON::Object state = parse.get();
- // Record the original framework and task info.
- JSON::Array frameworks =
- state.values["frameworks"].as<JSON::Array>();
- JSON::Object activeFramework =
- frameworks.values.front().as<JSON::Object>();
- JSON::String activeFrameworkId =
- activeFramework.values["id"].as<JSON::String>();
- JSON::Array activeTasks =
- activeFramework.values["tasks"].as<JSON::Array>();
- JSON::Array orphanTasks =
- state.values["orphan_tasks"].as<JSON::Array>();
- JSON::Array unknownFrameworksArray =
- state.values["unregistered_frameworks"].as<JSON::Array>();
+ JSON::Array frameworks1 = parse1->values["frameworks"].as<JSON::Array>();
+ EXPECT_EQ(1u, frameworks1.values.size());
- EXPECT_EQ(1u, frameworks.values.size());
- EXPECT_EQ(1u, activeTasks.values.size());
- EXPECT_EQ(0u, orphanTasks.values.size());
- EXPECT_EQ(0u, unknownFrameworksArray.values.size());
- EXPECT_EQ(frameworkId.value(), activeFrameworkId.value);
+ JSON::Object activeFramework1 = frameworks1.values.front().as<JSON::Object>();
+
+ EXPECT_EQ(
+ frameworkId.value(),
+ activeFramework1.values["id"].as<JSON::String>().value);
+
+ EXPECT_TRUE(activeFramework1.values["active"].as<JSON::Boolean>().value);
+ EXPECT_TRUE(activeFramework1.values["connected"].as<JSON::Boolean>().value);
+ EXPECT_FALSE(activeFramework1.values["recovered"].as<JSON::Boolean>().value);
+
+ JSON::Array activeTasks1 = activeFramework1.values["tasks"].as<JSON::Array>();
+ EXPECT_EQ(1u, activeTasks1.values.size());
+
+ JSON::Array unregisteredFrameworks1 =
+ parse1->values["unregistered_frameworks"].as<JSON::Array>();
+
+ EXPECT_TRUE(unregisteredFrameworks1.values.empty());
+
+ EXPECT_TRUE(parse1->values["orphan_tasks"].as<JSON::Array>().values.empty());
EXPECT_CALL(sched, disconnected(&driver))
.Times(1);
@@ -2870,31 +2871,43 @@ TEST_F(MasterTest, OrphanTasks)
AWAIT_READY(subscribeCall);
// Get the master's state.
- response = process::http::get(
+ Future<Response> response2 = process::http::get(
master.get()->pid,
"state",
None(),
createBasicAuthHeaders(DEFAULT_CREDENTIAL));
- AWAIT_EXPECT_RESPONSE_STATUS_EQ(OK().status, response);
- AWAIT_EXPECT_RESPONSE_HEADER_EQ(APPLICATION_JSON, "Content-Type", response);
+ AWAIT_EXPECT_RESPONSE_STATUS_EQ(OK().status, response2);
+ AWAIT_EXPECT_RESPONSE_HEADER_EQ(APPLICATION_JSON, "Content-Type", response2);
- parse = JSON::parse<JSON::Object>(response.get().body);
- ASSERT_SOME(parse);
+ Try<JSON::Object> parse2 = JSON::parse<JSON::Object>(response2.get().body);
+ ASSERT_SOME(parse2);
- // Verify that we have some orphan tasks and unregistered
- // frameworks.
- state = parse.get();
- orphanTasks = state.values["orphan_tasks"].as<JSON::Array>();
- EXPECT_EQ(activeTasks, orphanTasks);
+ // Check that there is a single recovered framework, a single active
+ // task, and no orphan tasks.
- unknownFrameworksArray =
- state.values["unregistered_frameworks"].as<JSON::Array>();
- EXPECT_EQ(1u, unknownFrameworksArray.values.size());
+ JSON::Array frameworks2 = parse2->values["frameworks"].as<JSON::Array>();
+ EXPECT_EQ(1u, frameworks2.values.size());
+
+ JSON::Object activeFramework2 = frameworks2.values.front().as<JSON::Object>();
+
+ EXPECT_EQ(
+ frameworkId.value(),
+ activeFramework2.values["id"].as<JSON::String>().value);
+
+ EXPECT_FALSE(activeFramework2.values["active"].as<JSON::Boolean>().value);
+ EXPECT_FALSE(activeFramework2.values["connected"].as<JSON::Boolean>().value);
+ EXPECT_TRUE(activeFramework2.values["recovered"].as<JSON::Boolean>().value);
+
+ JSON::Array activeTasks2 = activeFramework2.values["tasks"].as<JSON::Array>();
+ EXPECT_EQ(activeTasks1, activeTasks2);
- JSON::String unknownFrameworkId =
- unknownFrameworksArray.values.front().as<JSON::String>();
- EXPECT_EQ(activeFrameworkId, unknownFrameworkId);
+ JSON::Array unregisteredFrameworks2 =
+ parse2->values["unregistered_frameworks"].as<JSON::Array>();
+
+ EXPECT_TRUE(unregisteredFrameworks2.values.empty());
+
+ EXPECT_TRUE(parse2->values["orphan_tasks"].as<JSON::Array>().values.empty());
Future<FrameworkRegisteredMessage> frameworkRegisteredMessage =
FUTURE_PROTOBUF(FrameworkRegisteredMessage(), _, _);
@@ -2907,40 +2920,55 @@ TEST_F(MasterTest, OrphanTasks)
AWAIT_READY(frameworkRegisteredMessage);
// Get the master's state.
- response = process::http::get(
+ Future<Response> response3 = process::http::get(
master.get()->pid,
"state",
None(),
createBasicAuthHeaders(DEFAULT_CREDENTIAL));
- AWAIT_EXPECT_RESPONSE_STATUS_EQ(OK().status, response);
- AWAIT_EXPECT_RESPONSE_HEADER_EQ(APPLICATION_JSON, "Content-Type", response);
+ AWAIT_EXPECT_RESPONSE_STATUS_EQ(OK().status, response3);
+ AWAIT_EXPECT_RESPONSE_HEADER_EQ(APPLICATION_JSON, "Content-Type", response3);
- parse = JSON::parse<JSON::Object>(response.get().body);
- ASSERT_SOME(parse);
+ Try<JSON::Object> parse3 = JSON::parse<JSON::Object>(response3.get().body);
+ ASSERT_SOME(parse3);
- // Verify the orphan tasks and unregistered frameworks are removed.
- state = parse.get();
- unknownFrameworksArray =
- state.values["unregistered_frameworks"].as<JSON::Array>();
- EXPECT_EQ(0u, unknownFrameworksArray.values.size());
+ // The framework should no longer be listed as recovered.
+
+ JSON::Array frameworks3 = parse3->values["frameworks"].as<JSON::Array>();
+ EXPECT_EQ(1u, frameworks3.values.size());
+
+ JSON::Object activeFramework3 = frameworks3.values.front().as<JSON::Object>();
+
+ EXPECT_EQ(
+ frameworkId.value(),
+ activeFramework3.values["id"].as<JSON::String>().value);
- orphanTasks = state.values["orphan_tasks"].as<JSON::Array>();
- EXPECT_EQ(0u, orphanTasks.values.size());
+ EXPECT_TRUE(activeFramework3.values["active"].as<JSON::Boolean>().value);
+ EXPECT_TRUE(activeFramework3.values["connected"].as<JSON::Boolean>().value);
+ EXPECT_FALSE(activeFramework3.values["recovered"].as<JSON::Boolean>().value);
+
+ JSON::Array activeTasks3 = activeFramework3.values["tasks"].as<JSON::Array>();
+ EXPECT_EQ(activeTasks1, activeTasks3);
+
+ JSON::Array unregisteredFrameworks3 =
+ parse3->values["unregistered_frameworks"].as<JSON::Array>();
+
+ EXPECT_TRUE(unregisteredFrameworks3.values.empty());
+
+ EXPECT_TRUE(parse3->values["orphan_tasks"].as<JSON::Array>().values.empty());
EXPECT_CALL(exec, shutdown(_))
.Times(AtMost(1));
- // Cleanup.
driver.stop();
driver.join();
}
-// This test verifies that a framework that has not yet re-registered after
-// a master failover doesn't show up multiple times in "unregistered_frameworks"
-// when quering "/state" or "/frameworks" endpoints. This is to catch
-// any regressions for MESOS-4973 and MESOS-6461.
+// This test verifies that a framework that has not yet re-registered
+// after a master failover doesn't show up multiple times in
+// "frameworks" when quering "/state" or "/frameworks" endpoints. This
+// is to catch any regressions for MESOS-4973 and MESOS-6461.
TEST_F(MasterTest, OrphanTasksMultipleAgents)
{
Try<Owned<cluster::Master>> master = StartMaster();
@@ -3047,8 +3075,8 @@ TEST_F(MasterTest, OrphanTasksMultipleAgents)
AWAIT_READY(slaveReregisteredMessage1);
AWAIT_READY(slaveReregisteredMessage2);
- // Ensure that there are 2 orphan tasks and 1 unregistered framework
- // in "/state" endpoint.
+ // Ensure that there are 2 tasks and 1 recovered framework in
+ // "/state" endpoint.
{
Future<Response> response = process::http::get(
master.get()->pid,
@@ -3059,24 +3087,26 @@ TEST_F(MasterTest, OrphanTasksMultipleAgents)
AWAIT_EXPECT_RESPONSE_STATUS_EQ(OK().status, response);
AWAIT_EXPECT_RESPONSE_HEADER_EQ(APPLICATION_JSON, "Content-Type", response);
- Try<JSON::Object> parse = JSON::parse<JSON::Object>(response.get().body);
+ Try<JSON::Object> parse = JSON::parse<JSON::Object>(response->body);
ASSERT_SOME(parse);
- JSON::Object state = parse.get();
-
JSON::Array frameworks =
- state.values["frameworks"].as<JSON::Array>();
+ parse->values["frameworks"].as<JSON::Array>();
JSON::Array orphanTasks =
- state.values["orphan_tasks"].as<JSON::Array>();
+ parse->values["orphan_tasks"].as<JSON::Array>();
JSON::Array unregisteredFrameworks =
- state.values["unregistered_frameworks"].as<JSON::Array>();
+ parse->values["unregistered_frameworks"].as<JSON::Array>();
+
+ ASSERT_EQ(1u, frameworks.values.size());
+ EXPECT_EQ(0u, orphanTasks.values.size());
+ EXPECT_EQ(0u, unregisteredFrameworks.values.size());
- EXPECT_EQ(0u, frameworks.values.size());
- EXPECT_EQ(2u, orphanTasks.values.size());
- EXPECT_EQ(1u, unregisteredFrameworks.values.size());
+ JSON::Object framework = frameworks.values.front().as<JSON::Object>();
+
+ EXPECT_TRUE(framework.values["recovered"].as<JSON::Boolean>().value);
}
- // Ensure that there is 1 unregistered framework in "/frameworks" endpoint.
+ // Ensure that there is 1 recovered framework in "/frameworks" endpoint.
{
Future<Response> response = process::http::get(
master.get()->pid,
@@ -3087,15 +3117,20 @@ TEST_F(MasterTest, OrphanTasksMultipleAgents)
AWAIT_EXPECT_RESPONSE_STATUS_EQ(OK().status, response);
AWAIT_EXPECT_RESPONSE_HEADER_EQ(APPLICATION_JSON, "Content-Type", response);
- Try<JSON::Object> parse = JSON::parse<JSON::Object>(response.get().body);
+ Try<JSON::Object> parse = JSON::parse<JSON::Object>(response->body);
ASSERT_SOME(parse);
- JSON::Object state = parse.get();
-
+ JSON::Array frameworks =
+ parse->values["frameworks"].as<JSON::Array>();
JSON::Array unregisteredFrameworks =
- state.values["unregistered_frameworks"].as<JSON::Array>();
+ parse->values["unregistered_frameworks"].as<JSON::Array>();
- EXPECT_EQ(1u, unregisteredFrameworks.values.size());
+ ASSERT_EQ(1u, frameworks.values.size());
+ EXPECT_EQ(0u, unregisteredFrameworks.values.size());
+
+ JSON::Object framework = frameworks.values.front().as<JSON::Object>();
+
+ EXPECT_TRUE(framework.values["recovered"].as<JSON::Boolean>().value);
}
EXPECT_CALL(exec1, shutdown(_))
@@ -5549,8 +5584,10 @@ TEST_F(MasterTest, DISABLED_RecoverResourcesOrphanedTask)
// Ensure that the resources are successfully recovered.
AWAIT_READY(recoverResources);
- // Ensure that the state of the task is updated to `TASK_FINISHED` on the
- // master.
+ // Ensure that the state of the task is updated to `TASK_FINISHED`
+ // on the master. We don't expect the task to be displayed as a
+ // "completed task", because the terminal status update has not yet
+ // been ack'ed by the scheduler.
{
v1::master::Call call;
call.set_type(v1::master::Call::GET_TASKS);
@@ -5571,8 +5608,10 @@ TEST_F(MasterTest, DISABLED_RecoverResourcesOrphanedTask)
contentType, response->body).get().get_tasks();
ASSERT_TRUE(tasks.IsInitialized());
- ASSERT_EQ(1, tasks.orphan_tasks().size());
- ASSERT_EQ(TASK_FINISHED, tasks.orphan_tasks(0).state());
+ ASSERT_EQ(1, tasks.tasks().size());
+ EXPECT_EQ(TASK_FINISHED, tasks.tasks(0).state());
+ EXPECT_TRUE(tasks.orphan_tasks().empty());
+ EXPECT_TRUE(tasks.completed_tasks().empty());
}
EXPECT_CALL(*executor, shutdown(_))
@@ -5582,6 +5621,189 @@ TEST_F(MasterTest, DISABLED_RecoverResourcesOrphanedTask)
.Times(AtMost(1));
}
+
+// This test checks that the "/state" endpoint displays the correct
+// information when the master fails over and an agent running one of
+// the framework's tasks re-registers before the framework does.
+TEST_F(MasterTest, FailoverAgentReregisterFirst)
+{
+ master::Flags masterFlags = CreateMasterFlags();
+ Try<Owned<cluster::Master>> master = StartMaster(masterFlags);
+ ASSERT_SOME(master);
+
+ StandaloneMasterDetector slaveDetector(master.get()->pid);
+ Try<Owned<cluster::Slave>> slave = StartSlave(&slaveDetector);
+ ASSERT_SOME(slave);
+
+ StandaloneMasterDetector schedDetector(master.get()->pid);
+ MockScheduler sched;
+ TestingMesosSchedulerDriver driver(
+ &sched, &schedDetector, DEFAULT_FRAMEWORK_INFO);
+
+ Future<FrameworkID> frameworkId;
+ EXPECT_CALL(sched, registered(&driver, _, _))
+ .WillOnce(FutureArg<1>(&frameworkId));
+
+ Future<vector<Offer>> offers;
+ EXPECT_CALL(sched, resourceOffers(&driver, _))
+ .WillOnce(FutureArg<1>(&offers))
+ .WillRepeatedly(Return()); // Ignore subsequent offers.
+
+ driver.start();
+
+ AWAIT_READY(frameworkId);
+
+ AWAIT_READY(offers);
+ EXPECT_FALSE(offers->empty());
+
+ TaskInfo task = createTask(offers.get()[0], "sleep 100");
+
+ Future<TaskStatus> runningStatus;
+ EXPECT_CALL(sched, statusUpdate(&driver, _))
+ .WillOnce(FutureArg<1>(&runningStatus));
+
+ Future<Nothing> statusUpdateAck = FUTURE_DISPATCH(
+ slave.get()->pid, &Slave::_statusUpdateAcknowledgement);
+
+ driver.launchTasks(offers.get()[0].id(), {task});
+
+ AWAIT_READY(runningStatus);
+ EXPECT_EQ(TASK_RUNNING, runningStatus.get().state());
+ EXPECT_EQ(task.task_id(), runningStatus.get().task_id());
+
+ AWAIT_READY(statusUpdateAck);
+
+ // Simulate master failover. We leave the scheduler without a master
+ // so it does not attempt to re-register yet.
+ EXPECT_CALL(sched, disconnected(&driver))
+ .Times(1);
+
+ schedDetector.appoint(None());
+ slaveDetector.appoint(None());
+
+ master->reset();
+ master = StartMaster(masterFlags);
+ ASSERT_SOME(master);
+
+ Future<SlaveReregisteredMessage> slaveReregisteredMessage =
+ FUTURE_PROTOBUF(SlaveReregisteredMessage(), _, _);
+
+ slaveDetector.appoint(master.get()->pid);
+
+ AWAIT_READY(slaveReregisteredMessage);
+
+ // Check the master's "/state" endpoint. Because the slave has
+ // re-registered, the master should know about the framework but
+ // view it as disconnected and inactive.
+ {
+ Future<Response> response = process::http::get(
+ master.get()->pid,
+ "state",
+ None(),
+ createBasicAuthHeaders(DEFAULT_CREDENTIAL));
+
+ AWAIT_EXPECT_RESPONSE_STATUS_EQ(OK().status, response);
+ AWAIT_EXPECT_RESPONSE_HEADER_EQ(APPLICATION_JSON, "Content-Type", response);
+
+ Try<JSON::Object> parse = JSON::parse<JSON::Object>(response.get().body);
+ ASSERT_SOME(parse);
+
+ JSON::Array frameworks = parse->values["frameworks"].as<JSON::Array>();
+
+ EXPECT_EQ(1u, frameworks.values.size());
+
+ JSON::Object framework = frameworks.values.front().as<JSON::Object>();
+
+ EXPECT_EQ(
+ frameworkId.get(),
+ framework.values["id"].as<JSON::String>().value);
+
+ EXPECT_FALSE(framework.values["active"].as<JSON::Boolean>().value);
+ EXPECT_FALSE(framework.values["connected"].as<JSON::Boolean>().value);
+ EXPECT_TRUE(framework.values["recovered"].as<JSON::Boolean>().value);
+ EXPECT_EQ(0u, framework.values["registered_time"].as<JSON::Number>());
+ EXPECT_EQ(0u, framework.values["unregistered_time"].as<JSON::Number>());
+ EXPECT_EQ(0u, framework.values.count("reregistered_time"));
+
+ JSON::Array unregisteredFrameworks =
+ parse->values["unregistered_frameworks"].as<JSON::Array>();
+
+ EXPECT_TRUE(unregisteredFrameworks.values.empty());
+
+ JSON::Array completedFrameworks =
+ parse->values["completed_frameworks"].as<JSON::Array>();
+
+ EXPECT_TRUE(completedFrameworks.values.empty());
+ }
+
+ // Cause the scheduler to re-register. We pause the clock to ensure
+ // the re-registration time is predictable. We get a "registered"
+ // callback in the scheduler driver because of MESOS-786.
+ Future<Nothing> registered;
+ EXPECT_CALL(sched, registered(&driver, _, _))
+ .WillOnce(FutureSatisfy(®istered));
+
+ Clock::pause();
+ process::Time reregisterTime = Clock::now();
+
+ schedDetector.appoint(master.get()->pid);
+ AWAIT_READY(registered);
+
+ Clock::resume();
+
+ // Check the master's "/state" endpoint. The framework should now be
+ // listed as connected and active.
+ {
+ Future<Response> response = process::http::get(
+ master.get()->pid,
+ "state",
+ None(),
+ createBasicAuthHeaders(DEFAULT_CREDENTIAL));
+
+ AWAIT_EXPECT_RESPONSE_STATUS_EQ(OK().status, response);
+ AWAIT_EXPECT_RESPONSE_HEADER_EQ(APPLICATION_JSON, "Content-Type", response);
+
+ Try<JSON::Object> parse = JSON::parse<JSON::Object>(response.get().body);
+ ASSERT_SOME(parse);
+
+ JSON::Array frameworks = parse->values["frameworks"].as<JSON::Array>();
+
+ EXPECT_EQ(1u, frameworks.values.size());
+
+ JSON::Object framework = frameworks.values.front().as<JSON::Object>();
+
+ EXPECT_EQ(
+ frameworkId.get(),
+ framework.values["id"].as<JSON::String>().value);
+
+ EXPECT_TRUE(framework.values["active"].as<JSON::Boolean>().value);
+ EXPECT_TRUE(framework.values["connected"].as<JSON::Boolean>().value);
+ EXPECT_FALSE(framework.values["recovered"].as<JSON::Boolean>().value);
+ EXPECT_EQ(0u, framework.values["unregistered_time"].as<JSON::Number>());
+
+ EXPECT_EQ(
+ static_cast<int64_t>(reregisterTime.secs()),
+ framework.values["registered_time"].as<JSON::Number>().as<int64_t>());
+
+ // The state endpoint does not return "reregistered_time" if it is
+ // the same as "registered_time".
+ EXPECT_EQ(0, framework.values.count("reregistered_time"));
+
+ JSON::Array unregisteredFrameworks =
+ parse->values["unregistered_frameworks"].as<JSON::Array>();
+
+ EXPECT_TRUE(unregisteredFrameworks.values.empty());
+
+ JSON::Array completedFrameworks =
+ parse->values["completed_frameworks"].as<JSON::Array>();
+
+ EXPECT_TRUE(completedFrameworks.values.empty());
+ }
+
+ driver.stop();
+ driver.join();
+}
+
} // namespace tests {
} // namespace internal {
} // namespace mesos {
http://git-wip-us.apache.org/repos/asf/mesos/blob/0dbceafa/src/tests/partition_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/partition_tests.cpp b/src/tests/partition_tests.cpp
index 5a0d4bd..e823672 100644
--- a/src/tests/partition_tests.cpp
+++ b/src/tests/partition_tests.cpp
@@ -718,9 +718,10 @@ TEST_F(PartitionTest, PartitionedSlaveReregistrationMasterFailover)
// This test causes a slave to be partitioned while it is running a
-// task for a PARTITION_AWARE scheduler. The scheduler disconnects
+// task for a PARTITION_AWARE framework. The scheduler is shutdown
// before the partition heals. Right now, the task is left running as
-// an orphan; once MESOS-4659 is fixed, the task should be shutdown.
+// an orphan; when MESOS-6602 is fixed, the task will be shutdown when
+// the agent re-registers.
TEST_F(PartitionTest, PartitionedSlaveOrphanedTask)
{
Clock::pause();
@@ -829,15 +830,11 @@ TEST_F(PartitionTest, PartitionedSlaveOrphanedTask)
AWAIT_READY(slaveLost);
// Disconnect the scheduler. The default `failover_timeout` is 0, so
- // the framework's tasks should be shutdown when the slave
- // reregisters, but this is currently not implemented (MESOS-4659).
+ // the framework's tasks should be shutdown when the slave reregisters.
driver.stop();
driver.join();
- // Simulate a master loss event at the slave and then cause the
- // slave to reregister with the master.
- detector.appoint(None());
-
+ // Cause the slave to re-register with the master.
Future<SlaveReregisteredMessage> slaveReregistered = FUTURE_PROTOBUF(
SlaveReregisteredMessage(), master.get()->pid, slave.get()->pid);
@@ -845,6 +842,8 @@ TEST_F(PartitionTest, PartitionedSlaveOrphanedTask)
AWAIT_READY(slaveReregistered);
+ Clock::resume();
+
// Check if `task` is still running by querying master's state endpoint.
Future<Response> response = process::http::get(
master.get()->pid,
@@ -855,33 +854,42 @@ TEST_F(PartitionTest, PartitionedSlaveOrphanedTask)
AWAIT_EXPECT_RESPONSE_STATUS_EQ(OK().status, response);
AWAIT_EXPECT_RESPONSE_HEADER_EQ(APPLICATION_JSON, "Content-Type", response);
- Try<JSON::Object> parse = JSON::parse<JSON::Object>(response.get().body);
+ Try<JSON::Object> parse = JSON::parse<JSON::Object>(response->body);
ASSERT_SOME(parse);
- JSON::Object state = parse.get();
+ JSON::Array unregisteredFrameworks =
+ parse->values["unregistered_frameworks"].as<JSON::Array>();
+
+ // TODO(neilc): When MESOS-6602 is fixed, this should be empty.
+ EXPECT_EQ(1u, unregisteredFrameworks.values.size());
+
+ EXPECT_TRUE(parse->values["frameworks"].as<JSON::Array>().values.empty());
+ EXPECT_TRUE(parse->values["orphan_tasks"].as<JSON::Array>().values.empty());
+
JSON::Array completedFrameworks =
- state.values["completed_frameworks"].as<JSON::Array>();
+ parse->values["completed_frameworks"].as<JSON::Array>();
- EXPECT_EQ(1u, completedFrameworks.values.size());
+ ASSERT_EQ(1u, completedFrameworks.values.size());
JSON::Object jsonFramework =
completedFrameworks.values.front().as<JSON::Object>();
- JSON::String jsonFrameworkId = jsonFramework.values["id"].as<JSON::String>();
-
- EXPECT_EQ(frameworkId.get(), jsonFrameworkId.value);
+ EXPECT_EQ(
+ frameworkId.get(),
+ jsonFramework.values["id"].as<JSON::String>().value);
- // TODO(neilc): Update this when MESOS-4659 is fixed.
- JSON::Array orphanTasks = state.values["orphan_tasks"].as<JSON::Array>();
+ EXPECT_TRUE(jsonFramework.values["tasks"].as<JSON::Array>().values.empty());
- EXPECT_EQ(1u, orphanTasks.values.size());
+ JSON::Array completedTasks =
+ jsonFramework.values["completed_tasks"].as<JSON::Array>();
- JSON::Object jsonTask = orphanTasks.values.front().as<JSON::Object>();
- JSON::String jsonTaskId = jsonTask.values["id"].as<JSON::String>();
+ ASSERT_EQ(1u, completedTasks.values.size());
- EXPECT_EQ(task.task_id(), jsonTaskId.value);
+ JSON::Object completedTask = completedTasks.values.front().as<JSON::Object>();
- Clock::resume();
+ EXPECT_EQ(
+ "TASK_UNREACHABLE",
+ completedTask.values["state"].as<JSON::String>().value);
}
http://git-wip-us.apache.org/repos/asf/mesos/blob/0dbceafa/src/tests/teardown_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/teardown_tests.cpp b/src/tests/teardown_tests.cpp
index 125e180..30c99f9 100644
--- a/src/tests/teardown_tests.cpp
+++ b/src/tests/teardown_tests.cpp
@@ -30,12 +30,17 @@
#include "master/flags.hpp"
#include "master/master.hpp"
+#include "master/detector/standalone.hpp"
+
#include "tests/mesos.hpp"
#include "tests/utils.hpp"
using mesos::internal::master::Master;
+
using mesos::internal::slave::Slave;
+using mesos::master::detector::StandaloneMasterDetector;
+
using process::Future;
using process::Owned;
using process::PID;
@@ -354,6 +359,127 @@ TEST_F(TeardownTest, NoHeader)
driver.join();
}
+
+TEST_F(TeardownTest, DisconnectedFrameworkAfterFailover)
+{
+ master::Flags masterFlags = CreateMasterFlags();
+ Try<Owned<cluster::Master>> master = StartMaster(masterFlags);
+ ASSERT_SOME(master);
+
+ StandaloneMasterDetector slaveDetector(master.get()->pid);
+ Try<Owned<cluster::Slave>> slave = StartSlave(&slaveDetector);
+ ASSERT_SOME(slave);
+
+ StandaloneMasterDetector schedDetector(master.get()->pid);
+ MockScheduler sched;
+ TestingMesosSchedulerDriver driver(&sched, &schedDetector);
+
+ Future<FrameworkID> frameworkId;
+ EXPECT_CALL(sched, registered(&driver, _, _))
+ .WillOnce(FutureArg<1>(&frameworkId));
+
+ Future<vector<Offer>> offers;
+ EXPECT_CALL(sched, resourceOffers(&driver, _))
+ .WillOnce(FutureArg<1>(&offers))
+ .WillRepeatedly(Return()); // Ignore subsequent offers.
+
+ ASSERT_EQ(DRIVER_RUNNING, driver.start());
+
+ AWAIT_READY(frameworkId);
+
+ AWAIT_READY(offers);
+ EXPECT_FALSE(offers->empty());
+
+ TaskInfo task = createTask(offers.get()[0], "sleep 100");
+
+ Future<TaskStatus> runningStatus;
+ EXPECT_CALL(sched, statusUpdate(&driver, _))
+ .WillOnce(FutureArg<1>(&runningStatus));
+
+ Future<Nothing> statusUpdateAck = FUTURE_DISPATCH(
+ slave.get()->pid, &Slave::_statusUpdateAcknowledgement);
+
+ driver.launchTasks(offers.get()[0].id(), {task});
+
+ AWAIT_READY(runningStatus);
+ EXPECT_EQ(TASK_RUNNING, runningStatus.get().state());
+ EXPECT_EQ(task.task_id(), runningStatus.get().task_id());
+
+ AWAIT_READY(statusUpdateAck);
+
+ // Simulate master failover. We leave the scheduler without a master
+ // so it does not attempt to re-register.
+ EXPECT_CALL(sched, disconnected(&driver));
+
+ schedDetector.appoint(None());
+ slaveDetector.appoint(None());
+
+ master->reset();
+ master = StartMaster(masterFlags);
+ ASSERT_SOME(master);
+
+ Future<SlaveReregisteredMessage> slaveReregisteredMessage =
+ FUTURE_PROTOBUF(SlaveReregisteredMessage(), _, _);
+
+ slaveDetector.appoint(master.get()->pid);
+
+ AWAIT_READY(slaveReregisteredMessage);
+
+ // Teardown the framework.
+ {
+ Future<Response> response = process::http::post(
+ master.get()->pid,
+ "teardown",
+ createBasicAuthHeaders(DEFAULT_CREDENTIAL),
+ "frameworkId=" + frameworkId.get().value());
+
+ AWAIT_READY(response);
+ AWAIT_EXPECT_RESPONSE_STATUS_EQ(OK().status, response);
+ }
+
+ // Check the master's "/state" endpoint to confirm that the
+ // "frameworks" and "unregistered_frameworks" keys are empty, and
+ // that the framework that was shutdown appears in the
+ // "completed_frameworks" key.
+ {
+ Future<Response> response = process::http::get(
+ master.get()->pid,
+ "state",
+ None(),
+ createBasicAuthHeaders(DEFAULT_CREDENTIAL));
+
+ AWAIT_EXPECT_RESPONSE_STATUS_EQ(OK().status, response);
+ AWAIT_EXPECT_RESPONSE_HEADER_EQ(APPLICATION_JSON, "Content-Type", response);
+
+ Try<JSON::Object> parse = JSON::parse<JSON::Object>(response.get().body);
+ ASSERT_SOME(parse);
+
+ JSON::Array frameworks = parse->values["frameworks"].as<JSON::Array>();
+
+ EXPECT_TRUE(frameworks.values.empty());
+
+ JSON::Array unregisteredFrameworks =
+ parse->values["unregistered_frameworks"].as<JSON::Array>();
+
+ EXPECT_TRUE(unregisteredFrameworks.values.empty());
+
+ JSON::Array completedFrameworks =
+ parse->values["completed_frameworks"].as<JSON::Array>();
+
+ ASSERT_EQ(1u, completedFrameworks.values.size());
+
+ JSON::Object firstCompletedFramework =
+ completedFrameworks.values.front().as<JSON::Object>();
+
+ EXPECT_EQ(
+ frameworkId.get(),
+ firstCompletedFramework.values["id"].as<JSON::String>().value);
+ }
+
+ driver.stop();
+ driver.join();
+}
+
} // namespace tests {
} // namespace internal {
} // namespace mesos {
[9/9] mesos git commit: Simplified some test code.
Posted by vi...@apache.org.
Simplified some test code.
Review: https://reviews.apache.org/r/54177/
Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/1350f946
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/1350f946
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/1350f946
Branch: refs/heads/master
Commit: 1350f946a3aa12e9b2b66720e81b5a4ba4c4d90d
Parents: 89c7228
Author: Neil Conway <ne...@gmail.com>
Authored: Wed Dec 7 17:05:01 2016 -0800
Committer: Vinod Kone <vi...@gmail.com>
Committed: Wed Dec 7 17:05:52 2016 -0800
----------------------------------------------------------------------
src/tests/fault_tolerance_tests.cpp | 9 ++--
src/tests/master_tests.cpp | 6 +--
src/tests/slave_tests.cpp | 77 +++++++++++---------------------
3 files changed, 31 insertions(+), 61 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mesos/blob/1350f946/src/tests/fault_tolerance_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/fault_tolerance_tests.cpp b/src/tests/fault_tolerance_tests.cpp
index 277dcfa..71fe0df 100644
--- a/src/tests/fault_tolerance_tests.cpp
+++ b/src/tests/fault_tolerance_tests.cpp
@@ -2030,8 +2030,6 @@ TEST_F(FaultToleranceTest, UpdateFrameworkInfoOnSchedulerFailover)
// updated FrameworkInfo and wait until it gets a registered
// callback.
- MockScheduler sched2;
-
FrameworkInfo finfo2 = DEFAULT_FRAMEWORK_INFO;
finfo2.mutable_id()->MergeFrom(frameworkId.get());
auto capabilityType = FrameworkInfo::Capability::REVOCABLE_RESOURCES;
@@ -2042,6 +2040,7 @@ TEST_F(FaultToleranceTest, UpdateFrameworkInfoOnSchedulerFailover)
finfo2.set_hostname("myHostname");
finfo2.mutable_labels()->add_labels()->CopyFrom(createLabel("baz", "qux"));
+ MockScheduler sched2;
MesosSchedulerDriver driver2(
&sched2, finfo2, master.get()->pid, DEFAULT_CREDENTIAL);
@@ -2075,14 +2074,12 @@ TEST_F(FaultToleranceTest, UpdateFrameworkInfoOnSchedulerFailover)
None(),
createBasicAuthHeaders(DEFAULT_CREDENTIAL));
- Try<JSON::Object> parse =
- JSON::parse<JSON::Object>(response.get().body);
+ Try<JSON::Object> parse = JSON::parse<JSON::Object>(response->body);
ASSERT_SOME(parse);
JSON::Object state = parse.get();
EXPECT_EQ(1u, state.values.count("frameworks"));
- JSON::Array frameworks =
- state.values["frameworks"].as<JSON::Array>();
+ JSON::Array frameworks = state.values["frameworks"].as<JSON::Array>();
EXPECT_EQ(1u, frameworks.values.size());
JSON::Object framework = frameworks.values.front().as<JSON::Object>();
http://git-wip-us.apache.org/repos/asf/mesos/blob/1350f946/src/tests/master_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/master_tests.cpp b/src/tests/master_tests.cpp
index 5901614..de48594 100644
--- a/src/tests/master_tests.cpp
+++ b/src/tests/master_tests.cpp
@@ -2194,11 +2194,9 @@ TEST_F(MasterTest, UnreachableTaskAfterFailover)
// Step 3: Start a scheduler.
StandaloneMasterDetector schedDetector(master.get()->pid);
MockScheduler sched;
- TestingMesosSchedulerDriver driver(
- &sched, &schedDetector, DEFAULT_FRAMEWORK_INFO);
+ TestingMesosSchedulerDriver driver(&sched, &schedDetector);
- EXPECT_CALL(sched, registered(&driver, _, _))
- .Times(1);
+ EXPECT_CALL(sched, registered(&driver, _, _));
Future<vector<Offer>> offers;
EXPECT_CALL(sched, resourceOffers(&driver, _))
http://git-wip-us.apache.org/repos/asf/mesos/blob/1350f946/src/tests/slave_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/slave_tests.cpp b/src/tests/slave_tests.cpp
index 3d06c3a..967c730 100644
--- a/src/tests/slave_tests.cpp
+++ b/src/tests/slave_tests.cpp
@@ -314,8 +314,7 @@ TEST_F(SlaveTest, ShutdownUnregisteredExecutor)
MesosSchedulerDriver driver(
&sched, DEFAULT_FRAMEWORK_INFO, master.get()->pid, DEFAULT_CREDENTIAL);
- EXPECT_CALL(sched, registered(&driver, _, _))
- .Times(1);
+ EXPECT_CALL(sched, registered(&driver, _, _));
Future<vector<Offer>> offers;
EXPECT_CALL(sched, resourceOffers(&driver, _))
@@ -430,8 +429,7 @@ TEST_F(SlaveTest, ExecutorTimeoutCausedBySlowFetch)
master.get()->pid,
DEFAULT_CREDENTIAL);
- EXPECT_CALL(sched, registered(&driver, _, _))
- .Times(1);
+ EXPECT_CALL(sched, registered(&driver, _, _));
Future<vector<Offer>> offers;
EXPECT_CALL(sched, resourceOffers(&driver, _))
@@ -529,8 +527,7 @@ TEST_F(SlaveTest, RemoveUnregisteredTerminatedExecutor)
MesosSchedulerDriver driver(
&sched, DEFAULT_FRAMEWORK_INFO, master.get()->pid, DEFAULT_CREDENTIAL);
- EXPECT_CALL(sched, registered(&driver, _, _))
- .Times(1);
+ EXPECT_CALL(sched, registered(&driver, _, _));
Future<vector<Offer>> offers;
EXPECT_CALL(sched, resourceOffers(&driver, _))
@@ -616,8 +613,7 @@ TEST_F(SlaveTest, CommandTaskWithArguments)
MesosSchedulerDriver driver(
&sched, DEFAULT_FRAMEWORK_INFO, master.get()->pid, DEFAULT_CREDENTIAL);
- EXPECT_CALL(sched, registered(&driver, _, _))
- .Times(1);
+ EXPECT_CALL(sched, registered(&driver, _, _));
Future<vector<Offer>> offers;
EXPECT_CALL(sched, resourceOffers(&driver, _))
@@ -976,8 +972,7 @@ TEST_F(SlaveTest, ROOT_RunTaskWithCommandInfoWithoutUser)
MesosSchedulerDriver driver(
&sched, DEFAULT_FRAMEWORK_INFO, master.get()->pid, DEFAULT_CREDENTIAL);
- EXPECT_CALL(sched, registered(&driver, _, _))
- .Times(1);
+ EXPECT_CALL(sched, registered(&driver, _, _));
Future<vector<Offer>> offers;
EXPECT_CALL(sched, resourceOffers(&driver, _))
@@ -1076,8 +1071,7 @@ TEST_F(SlaveTest, DISABLED_ROOT_RunTaskWithCommandInfoWithUser)
MesosSchedulerDriver driver(
&sched, DEFAULT_FRAMEWORK_INFO, master.get()->pid, DEFAULT_CREDENTIAL);
- EXPECT_CALL(sched, registered(&driver, _, _))
- .Times(1);
+ EXPECT_CALL(sched, registered(&driver, _, _));
Future<TaskStatus> statusRunning;
Future<TaskStatus> statusFinished;
@@ -1201,8 +1195,7 @@ TEST_F(SlaveTest, IgnoreNonLeaderStatusUpdateAcknowledgement)
MesosSchedulerDriver schedDriver(
&sched, DEFAULT_FRAMEWORK_INFO, master.get()->pid, DEFAULT_CREDENTIAL);
- EXPECT_CALL(sched, registered(&schedDriver, _, _))
- .Times(1);
+ EXPECT_CALL(sched, registered(&schedDriver, _, _));
Future<vector<Offer>> offers;
EXPECT_CALL(sched, resourceOffers(&schedDriver, _))
@@ -1223,9 +1216,7 @@ TEST_F(SlaveTest, IgnoreNonLeaderStatusUpdateAcknowledgement)
TaskInfo task = createTask(offers.get()[0], "", DEFAULT_EXECUTOR_ID);
- Future<ExecutorDriver*> execDriver;
- EXPECT_CALL(exec, registered(_, _, _, _))
- .WillOnce(FutureArg<0>(&execDriver));
+ EXPECT_CALL(exec, registered(_, _, _, _));
EXPECT_CALL(exec, launchTask(_, _))
.WillOnce(SendStatusUpdateFromTask(TASK_RUNNING));
@@ -1523,8 +1514,7 @@ TEST_F(SlaveTest, StateEndpoint)
MesosSchedulerDriver driver(
&sched, DEFAULT_FRAMEWORK_INFO, master.get()->pid, DEFAULT_CREDENTIAL);
- EXPECT_CALL(sched, registered(&driver, _, _))
- .Times(1);
+ EXPECT_CALL(sched, registered(&driver, _, _));
Future<vector<Offer>> offers;
EXPECT_CALL(sched, resourceOffers(&driver, _))
@@ -1546,8 +1536,7 @@ TEST_F(SlaveTest, StateEndpoint)
task.mutable_resources()->MergeFrom(offers.get()[0].resources());
task.mutable_executor()->MergeFrom(DEFAULT_EXECUTOR_INFO);
- EXPECT_CALL(exec, registered(_, _, _, _))
- .Times(1);
+ EXPECT_CALL(exec, registered(_, _, _, _));
EXPECT_CALL(exec, launchTask(_, _))
.WillOnce(SendStatusUpdateFromTask(TASK_RUNNING));
@@ -1643,8 +1632,7 @@ TEST_F(SlaveTest, StateEndpointUnavailableDuringRecovery)
MesosSchedulerDriver driver(
&sched, frameworkInfo, master.get()->pid, DEFAULT_CREDENTIAL);
- EXPECT_CALL(sched, registered(&driver, _, _))
- .Times(1);
+ EXPECT_CALL(sched, registered(&driver, _, _));
EXPECT_CALL(sched, resourceOffers(&driver, _))
.WillOnce(LaunchTasks(DEFAULT_EXECUTOR_INFO, 1, 1, 512, "*"))
@@ -2250,8 +2238,7 @@ TEST_F(SlaveTest, DISABLED_TerminatingSlaveDoesNotReregister)
MesosSchedulerDriver driver(
&sched, DEFAULT_FRAMEWORK_INFO, master.get()->pid, DEFAULT_CREDENTIAL);
- EXPECT_CALL(sched, registered(&driver, _, _))
- .Times(1);
+ EXPECT_CALL(sched, registered(&driver, _, _));
// Launch a task that uses less resource than the
// default(cpus:2, mem:1024).
@@ -2259,8 +2246,7 @@ TEST_F(SlaveTest, DISABLED_TerminatingSlaveDoesNotReregister)
.WillOnce(LaunchTasks(DEFAULT_EXECUTOR_INFO, 1, 1, 64, "*"))
.WillRepeatedly(Return()); // Ignore subsequent offers.
- EXPECT_CALL(exec, registered(_, _, _, _))
- .Times(1);
+ EXPECT_CALL(exec, registered(_, _, _, _));
EXPECT_CALL(exec, launchTask(_, _))
.WillOnce(SendStatusUpdateFromTask(TASK_RUNNING));
@@ -3274,8 +3260,7 @@ TEST_F(SlaveTest, KillTaskBetweenRunTaskParts)
MesosSchedulerDriver driver(
&sched, DEFAULT_FRAMEWORK_INFO, master.get()->pid, DEFAULT_CREDENTIAL);
- EXPECT_CALL(sched, registered(&driver, _, _))
- .Times(1);
+ EXPECT_CALL(sched, registered(&driver, _, _));
Future<vector<Offer>> offers;
EXPECT_CALL(sched, resourceOffers(&driver, _))
@@ -3912,8 +3897,7 @@ TEST_F(SlaveTest, ExecutorLabels)
MesosSchedulerDriver driver(
&sched, DEFAULT_FRAMEWORK_INFO, master.get()->pid, DEFAULT_CREDENTIAL);
- EXPECT_CALL(sched, registered(&driver, _, _))
- .Times(1);
+ EXPECT_CALL(sched, registered(&driver, _, _));
Future<vector<Offer>> offers;
EXPECT_CALL(sched, resourceOffers(&driver, _))
@@ -3939,8 +3923,7 @@ TEST_F(SlaveTest, ExecutorLabels)
labels->add_labels()->CopyFrom(createLabel("key2", "value2"));
labels->add_labels()->CopyFrom(createLabel("key1", "value3"));
- EXPECT_CALL(exec, registered(_, _, _, _))
- .Times(1);
+ EXPECT_CALL(exec, registered(_, _, _, _));
EXPECT_CALL(exec, launchTask(_, _))
.WillOnce(SendStatusUpdateFromTask(TASK_RUNNING));
@@ -4006,8 +3989,7 @@ TEST_F(SlaveTest, TaskLabels)
MesosSchedulerDriver driver(
&sched, DEFAULT_FRAMEWORK_INFO, master.get()->pid, DEFAULT_CREDENTIAL);
- EXPECT_CALL(sched, registered(&driver, _, _))
- .Times(1);
+ EXPECT_CALL(sched, registered(&driver, _, _));
Future<vector<Offer>> offers;
EXPECT_CALL(sched, resourceOffers(&driver, _))
@@ -4033,8 +4015,7 @@ TEST_F(SlaveTest, TaskLabels)
labels->add_labels()->CopyFrom(createLabel("bar", "baz"));
labels->add_labels()->CopyFrom(createLabel("bar", "qux"));
- EXPECT_CALL(exec, registered(_, _, _, _))
- .Times(1);
+ EXPECT_CALL(exec, registered(_, _, _, _));
EXPECT_CALL(exec, launchTask(_, _))
.WillOnce(SendStatusUpdateFromTask(TASK_RUNNING));
@@ -4112,8 +4093,7 @@ TEST_F(SlaveTest, TaskStatusLabels)
MesosSchedulerDriver driver(
&sched, DEFAULT_FRAMEWORK_INFO, master.get()->pid, DEFAULT_CREDENTIAL);
- EXPECT_CALL(sched, registered(&driver, _, _))
- .Times(1);
+ EXPECT_CALL(sched, registered(&driver, _, _));
Future<vector<Offer>> offers;
EXPECT_CALL(sched, resourceOffers(&driver, _))
@@ -4215,8 +4195,7 @@ TEST_F(SlaveTest, TaskStatusContainerStatus)
MesosSchedulerDriver driver(
&sched, DEFAULT_FRAMEWORK_INFO, master.get()->pid, DEFAULT_CREDENTIAL);
- EXPECT_CALL(sched, registered(&driver, _, _))
- .Times(1);
+ EXPECT_CALL(sched, registered(&driver, _, _));
Future<vector<Offer>> offers;
EXPECT_CALL(sched, resourceOffers(&driver, _))
@@ -4230,9 +4209,7 @@ TEST_F(SlaveTest, TaskStatusContainerStatus)
TaskInfo task = createTask(offers.get()[0], "sleep 100", DEFAULT_EXECUTOR_ID);
- ExecutorDriver* execDriver;
- EXPECT_CALL(exec, registered(_, _, _, _))
- .WillOnce(SaveArg<0>(&execDriver));
+ EXPECT_CALL(exec, registered(_, _, _, _));
EXPECT_CALL(exec, launchTask(_, _))
.WillOnce(SendStatusUpdateFromTask(TASK_RUNNING));
@@ -4313,8 +4290,7 @@ TEST_F(SlaveTest, ExecutorEnvironmentVariables)
MesosSchedulerDriver driver(
&sched, DEFAULT_FRAMEWORK_INFO, master.get()->pid, DEFAULT_CREDENTIAL);
- EXPECT_CALL(sched, registered(&driver, _, _))
- .Times(1);
+ EXPECT_CALL(sched, registered(&driver, _, _));
Future<vector<Offer>> offers;
EXPECT_CALL(sched, resourceOffers(&driver, _))
@@ -4824,8 +4800,7 @@ TEST_F(SlaveTest, ExecutorShutdownGracePeriod)
EXPECT_CALL(sched, statusUpdate(&driver, _))
.WillOnce(FutureArg<1>(&statusRunning));
- EXPECT_CALL(exec, registered(_, _, _, _))
- .Times(1);
+ EXPECT_CALL(exec, registered(_, _, _, _));
Future<TaskInfo> receivedTask;
EXPECT_CALL(exec, launchTask(_, _))
@@ -5591,8 +5566,7 @@ TEST_F(SlaveTest, MaxCompletedExecutorsPerFrameworkFlag)
task.mutable_resources()->MergeFrom(offer->resources());
task.mutable_executor()->MergeFrom(executorInfos[i]);
- EXPECT_CALL(*executors[i], registered(_, _, _, _))
- .Times(1);
+ EXPECT_CALL(*executors[i], registered(_, _, _, _));
// Make sure the task passes through its `TASK_FINISHED`
// state properly. We force this state change through
@@ -5610,7 +5584,8 @@ TEST_F(SlaveTest, MaxCompletedExecutorsPerFrameworkFlag)
AWAIT_READY(statusFinished);
EXPECT_EQ(TASK_FINISHED, statusFinished->state());
- EXPECT_CALL(*executors[i], shutdown(_)).Times(AtMost(1));
+ EXPECT_CALL(*executors[i], shutdown(_))
+ .Times(AtMost(1));
// Advance the clock to trigger a batch allocation.
Clock::advance(masterFlags.allocation_interval);
[2/9] mesos git commit: Changed the allocator API to allow adding
inactive frameworks.
Posted by vi...@apache.org.
Changed the allocator API to allow adding inactive frameworks.
Previously, a newly added framework was assumed to always be
active. Adding inactive frameworks will be used to support recovered
frameworks that haven't yet re-registered.
Review: https://reviews.apache.org/r/53895/
Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/51dfe768
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/51dfe768
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/51dfe768
Branch: refs/heads/master
Commit: 51dfe768741b5f9cff4895feff7a336d4a3039fd
Parents: fbcaed7
Author: Neil Conway <ne...@gmail.com>
Authored: Wed Dec 7 17:04:04 2016 -0800
Committer: Vinod Kone <vi...@gmail.com>
Committed: Wed Dec 7 17:05:40 2016 -0800
----------------------------------------------------------------------
CHANGELOG | 4 +
include/mesos/allocator/allocator.hpp | 5 +-
src/master/allocator/mesos/allocator.hpp | 12 +-
src/master/allocator/mesos/hierarchical.cpp | 9 +-
src/master/allocator/mesos/hierarchical.hpp | 3 +-
src/master/master.cpp | 3 +-
src/tests/allocator.hpp | 13 +-
src/tests/hierarchical_allocator_tests.cpp | 161 ++++++++++---------
src/tests/master_allocator_tests.cpp | 36 ++---
src/tests/persistent_volume_endpoints_tests.cpp | 4 +-
src/tests/reservation_tests.cpp | 6 +-
src/tests/resource_offers_tests.cpp | 2 +-
src/tests/slave_recovery_tests.cpp | 2 +-
13 files changed, 141 insertions(+), 119 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mesos/blob/51dfe768/CHANGELOG
----------------------------------------------------------------------
diff --git a/CHANGELOG b/CHANGELOG
index fe24e8e..7847fe6 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,6 +1,10 @@
Release Notes - Mesos - Version 1.2.0 (WIP)
-------------------------------------------
+Additional API Changes:
+ * [MESOS-6675] - Changed the allocator API to support adding inactive
+ frameworks. Custom allocator implementations will need to be updated.
+
Release Notes - Mesos - Version 1.1.1 (WIP)
-------------------------------------------
http://git-wip-us.apache.org/repos/asf/mesos/blob/51dfe768/include/mesos/allocator/allocator.hpp
----------------------------------------------------------------------
diff --git a/include/mesos/allocator/allocator.hpp b/include/mesos/allocator/allocator.hpp
index 3fe04f8..5585949 100644
--- a/include/mesos/allocator/allocator.hpp
+++ b/include/mesos/allocator/allocator.hpp
@@ -123,11 +123,14 @@ public:
* account for these resources when updating the allocation of this
* framework. The allocator should avoid double accounting when yet
* unknown agents are added later in `addSlave()`.
+ *
+ * @param active Whether the framework is initially activated.
*/
virtual void addFramework(
const FrameworkID& frameworkId,
const FrameworkInfo& frameworkInfo,
- const hashmap<SlaveID, Resources>& used) = 0;
+ const hashmap<SlaveID, Resources>& used,
+ bool active) = 0;
/**
* Removes a framework from the Mesos cluster. It is up to an allocator to
http://git-wip-us.apache.org/repos/asf/mesos/blob/51dfe768/src/master/allocator/mesos/allocator.hpp
----------------------------------------------------------------------
diff --git a/src/master/allocator/mesos/allocator.hpp b/src/master/allocator/mesos/allocator.hpp
index 61159a9..8e0f37a 100644
--- a/src/master/allocator/mesos/allocator.hpp
+++ b/src/master/allocator/mesos/allocator.hpp
@@ -66,7 +66,8 @@ public:
void addFramework(
const FrameworkID& frameworkId,
const FrameworkInfo& frameworkInfo,
- const hashmap<SlaveID, Resources>& used);
+ const hashmap<SlaveID, Resources>& used,
+ bool active);
void removeFramework(
const FrameworkID& frameworkId);
@@ -197,7 +198,8 @@ public:
virtual void addFramework(
const FrameworkID& frameworkId,
const FrameworkInfo& frameworkInfo,
- const hashmap<SlaveID, Resources>& used) = 0;
+ const hashmap<SlaveID, Resources>& used,
+ bool active) = 0;
virtual void removeFramework(
const FrameworkID& frameworkId) = 0;
@@ -356,14 +358,16 @@ template <typename AllocatorProcess>
inline void MesosAllocator<AllocatorProcess>::addFramework(
const FrameworkID& frameworkId,
const FrameworkInfo& frameworkInfo,
- const hashmap<SlaveID, Resources>& used)
+ const hashmap<SlaveID, Resources>& used,
+ bool active)
{
process::dispatch(
process,
&MesosAllocatorProcess::addFramework,
frameworkId,
frameworkInfo,
- used);
+ used,
+ active);
}
http://git-wip-us.apache.org/repos/asf/mesos/blob/51dfe768/src/master/allocator/mesos/hierarchical.cpp
----------------------------------------------------------------------
diff --git a/src/master/allocator/mesos/hierarchical.cpp b/src/master/allocator/mesos/hierarchical.cpp
index 3b75949..33db3b8 100644
--- a/src/master/allocator/mesos/hierarchical.cpp
+++ b/src/master/allocator/mesos/hierarchical.cpp
@@ -219,7 +219,8 @@ void HierarchicalAllocatorProcess::recover(
void HierarchicalAllocatorProcess::addFramework(
const FrameworkID& frameworkId,
const FrameworkInfo& frameworkInfo,
- const hashmap<SlaveID, Resources>& used)
+ const hashmap<SlaveID, Resources>& used,
+ bool active)
{
CHECK(initialized);
@@ -274,7 +275,11 @@ void HierarchicalAllocatorProcess::addFramework(
LOG(INFO) << "Added framework " << frameworkId;
- allocate();
+ if (active) {
+ allocate();
+ } else {
+ deactivateFramework(frameworkId);
+ }
}
http://git-wip-us.apache.org/repos/asf/mesos/blob/51dfe768/src/master/allocator/mesos/hierarchical.hpp
----------------------------------------------------------------------
diff --git a/src/master/allocator/mesos/hierarchical.hpp b/src/master/allocator/mesos/hierarchical.hpp
index 2c31471..a6424d6 100644
--- a/src/master/allocator/mesos/hierarchical.hpp
+++ b/src/master/allocator/mesos/hierarchical.hpp
@@ -109,7 +109,8 @@ public:
void addFramework(
const FrameworkID& frameworkId,
const FrameworkInfo& frameworkInfo,
- const hashmap<SlaveID, Resources>& used);
+ const hashmap<SlaveID, Resources>& used,
+ bool active);
void removeFramework(
const FrameworkID& frameworkId);
http://git-wip-us.apache.org/repos/asf/mesos/blob/51dfe768/src/master/master.cpp
----------------------------------------------------------------------
diff --git a/src/master/master.cpp b/src/master/master.cpp
index f2364e2..ef1aba5 100644
--- a/src/master/master.cpp
+++ b/src/master/master.cpp
@@ -7059,7 +7059,8 @@ void Master::addFramework(Framework* framework)
allocator->addFramework(
framework->id(),
framework->info,
- framework->usedResources);
+ framework->usedResources,
+ framework->active);
// Export framework metrics if a principal is specified in `FrameworkInfo`.
http://git-wip-us.apache.org/repos/asf/mesos/blob/51dfe768/src/tests/allocator.hpp
----------------------------------------------------------------------
diff --git a/src/tests/allocator.hpp b/src/tests/allocator.hpp
index bce1190..1f9261d 100644
--- a/src/tests/allocator.hpp
+++ b/src/tests/allocator.hpp
@@ -39,7 +39,7 @@ namespace tests {
// The following actions make up for the fact that DoDefault
// cannot be used inside a DoAll, for example:
-// EXPECT_CALL(allocator, addFramework(_, _, _))
+// EXPECT_CALL(allocator, addFramework(_, _, _, _))
// .WillOnce(DoAll(InvokeAddFramework(&allocator),
// FutureSatisfy(&addFramework)));
@@ -57,7 +57,7 @@ ACTION_P(InvokeRecover, allocator)
ACTION_P(InvokeAddFramework, allocator)
{
- allocator->real->addFramework(arg0, arg1, arg2);
+ allocator->real->addFramework(arg0, arg1, arg2, arg3);
}
@@ -239,9 +239,9 @@ public:
EXPECT_CALL(*this, recover(_, _))
.WillRepeatedly(DoDefault());
- ON_CALL(*this, addFramework(_, _, _))
+ ON_CALL(*this, addFramework(_, _, _, _))
.WillByDefault(InvokeAddFramework(this));
- EXPECT_CALL(*this, addFramework(_, _, _))
+ EXPECT_CALL(*this, addFramework(_, _, _, _))
.WillRepeatedly(DoDefault());
ON_CALL(*this, removeFramework(_))
@@ -372,10 +372,11 @@ public:
const int expectedAgentCount,
const hashmap<std::string, Quota>&));
- MOCK_METHOD3(addFramework, void(
+ MOCK_METHOD4(addFramework, void(
const FrameworkID&,
const FrameworkInfo&,
- const hashmap<SlaveID, Resources>&));
+ const hashmap<SlaveID, Resources>&,
+ bool active));
MOCK_METHOD1(removeFramework, void(
const FrameworkID&));
http://git-wip-us.apache.org/repos/asf/mesos/blob/51dfe768/src/tests/hierarchical_allocator_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/hierarchical_allocator_tests.cpp b/src/tests/hierarchical_allocator_tests.cpp
index f9dcdbf..cde32c9 100644
--- a/src/tests/hierarchical_allocator_tests.cpp
+++ b/src/tests/hierarchical_allocator_tests.cpp
@@ -259,7 +259,7 @@ TEST_F(HierarchicalAllocatorTest, UnreservedDRF)
// framework1 will be offered all of slave1's resources since it is
// the only framework running so far.
FrameworkInfo framework1 = createFrameworkInfo("role1");
- allocator->addFramework(framework1.id(), framework1, {});
+ allocator->addFramework(framework1.id(), framework1, {}, true);
Future<Allocation> allocation = allocations.get();
AWAIT_READY(allocation);
@@ -270,7 +270,7 @@ TEST_F(HierarchicalAllocatorTest, UnreservedDRF)
// framework1 share = 1
FrameworkInfo framework2 = createFrameworkInfo("role2");
- allocator->addFramework(framework2.id(), framework2, {});
+ allocator->addFramework(framework2.id(), framework2, {}, true);
// Total cluster resources will become cpus=3, mem=1536:
// role1 share = 0.66 (cpus=2, mem=1024)
@@ -313,7 +313,7 @@ TEST_F(HierarchicalAllocatorTest, UnreservedDRF)
// framework2 share = 1
FrameworkInfo framework3 = createFrameworkInfo("role1");
- allocator->addFramework(framework3.id(), framework3, {});
+ allocator->addFramework(framework3.id(), framework3, {}, true);
// Total cluster resources will become cpus=10, mem=7680:
// role1 share = 0.2 (cpus=2, mem=1024)
@@ -339,7 +339,7 @@ TEST_F(HierarchicalAllocatorTest, UnreservedDRF)
// framework2 share = 1
FrameworkInfo framework4 = createFrameworkInfo("role1");
- allocator->addFramework(framework4.id(), framework4, {});
+ allocator->addFramework(framework4.id(), framework4, {}, true);
// Total cluster resources will become cpus=11, mem=8192
// role1 share = 0.63 (cpus=6, mem=5120)
@@ -377,7 +377,7 @@ TEST_F(HierarchicalAllocatorTest, ReservedDRF)
// framework1 will be offered all of the resources.
FrameworkInfo framework1 = createFrameworkInfo("role1");
- allocator->addFramework(framework1.id(), framework1, {});
+ allocator->addFramework(framework1.id(), framework1, {}, true);
Future<Allocation> allocation = allocations.get();
AWAIT_READY(allocation);
@@ -385,7 +385,7 @@ TEST_F(HierarchicalAllocatorTest, ReservedDRF)
EXPECT_EQ(slave1.resources(), Resources::sum(allocation.get().resources));
FrameworkInfo framework2 = createFrameworkInfo("role2");
- allocator->addFramework(framework2.id(), framework2, {});
+ allocator->addFramework(framework2.id(), framework2, {}, true);
// framework2 will be allocated the new resources.
SlaveInfo slave2 = createSlaveInfo("cpus:2;mem:512;disk:0");
@@ -411,7 +411,7 @@ TEST_F(HierarchicalAllocatorTest, ReservedDRF)
// expect framework3 to receive the next allocation of role1
// resources.
FrameworkInfo framework3 = createFrameworkInfo("role1");
- allocator->addFramework(framework3.id(), framework3, {});
+ allocator->addFramework(framework3.id(), framework3, {}, true);
SlaveInfo slave4 = createSlaveInfo(
"cpus(role1):2;mem(role1):1024;disk(role1):0");
@@ -453,7 +453,7 @@ TEST_F(HierarchicalAllocatorTest, DRFWithFairnessExclusion)
FrameworkInfo framework1 = createFrameworkInfo(
"role1", {FrameworkInfo::Capability::GPU_RESOURCES});
- allocator->addFramework(framework1.id(), framework1, {});
+ allocator->addFramework(framework1.id(), framework1, {}, true);
Future<Allocation> allocation = allocations.get();
AWAIT_READY(allocation);
@@ -464,7 +464,7 @@ TEST_F(HierarchicalAllocatorTest, DRFWithFairnessExclusion)
// framework1 share = 1
FrameworkInfo framework2 = createFrameworkInfo("role2");
- allocator->addFramework(framework2.id(), framework2, {});
+ allocator->addFramework(framework2.id(), framework2, {}, true);
// Total cluster resources will become cpus=3, mem=1536, (ignored) gpus=1
// role1 share = 0.66 (cpus=2, mem=1024, (ignored) gpus=1)
@@ -507,7 +507,7 @@ TEST_F(HierarchicalAllocatorTest, DRFWithFairnessExclusion)
// framework2 share = 1
FrameworkInfo framework3 = createFrameworkInfo("role1");
- allocator->addFramework(framework3.id(), framework3, {});
+ allocator->addFramework(framework3.id(), framework3, {}, true);
// Total cluster resources will become cpus=10, mem=7680, (ignored) gpus=1
// role1 share = 0.2 (cpus=2, mem=1024, (ignored) gpus=1)
@@ -533,7 +533,7 @@ TEST_F(HierarchicalAllocatorTest, DRFWithFairnessExclusion)
// framework2 share = 1
FrameworkInfo framework4 = createFrameworkInfo("role1");
- allocator->addFramework(framework4.id(), framework4, {});
+ allocator->addFramework(framework4.id(), framework4, {}, true);
// Total cluster resources will become cpus=11, mem=8192, (ignored) gpus=1
// role1 share = 0.63 (cpus=6, mem=5120, (ignored) gpus=1)
@@ -570,7 +570,7 @@ TEST_F(HierarchicalAllocatorTest, OfferFilter)
initialize();
FrameworkInfo framework = createFrameworkInfo(ROLE);
- allocator->addFramework(framework.id(), framework, {});
+ allocator->addFramework(framework.id(), framework, {}, true);
SlaveInfo agent = createSlaveInfo("cpus:1;mem:512;disk:0");
allocator->addSlave(agent.id(), agent, None(), agent.resources(), {});
@@ -653,10 +653,10 @@ TEST_F(HierarchicalAllocatorTest, SmallOfferFilterTimeout)
initialize(flags_);
FrameworkInfo framework1 = createFrameworkInfo(ROLE);
- allocator->addFramework(framework1.id(), framework1, {});
+ allocator->addFramework(framework1.id(), framework1, {}, true);
FrameworkInfo framework2 = createFrameworkInfo(ROLE);
- allocator->addFramework(framework2.id(), framework2, {});
+ allocator->addFramework(framework2.id(), framework2, {}, true);
SlaveInfo agent1 = createSlaveInfo("cpus:1;mem:512;disk:0");
allocator->addSlave(
@@ -786,7 +786,7 @@ TEST_F(HierarchicalAllocatorTest, MaintenanceInverseOffers)
// This framework will be offered all of the resources.
FrameworkInfo framework = createFrameworkInfo("*");
- allocator->addFramework(framework.id(), framework, {});
+ allocator->addFramework(framework.id(), framework, {}, true);
// Check that the resources go to the framework.
Future<Allocation> allocation = allocations.get();
@@ -843,7 +843,7 @@ TEST_F(HierarchicalAllocatorTest, CoarseGrained)
// resources so that we can test what happens when there are 2
// frameworks and 2 slaves to consider during allocation.
FrameworkInfo framework1 = createFrameworkInfo("role1");
- allocator->addFramework(framework1.id(), framework1, {});
+ allocator->addFramework(framework1.id(), framework1, {}, true);
Future<Allocation> allocation = allocations.get();
AWAIT_READY(allocation);
@@ -865,7 +865,7 @@ TEST_F(HierarchicalAllocatorTest, CoarseGrained)
// Now add the second framework, we expect there to be 2 subsequent
// allocations, each framework being allocated a full slave.
FrameworkInfo framework2 = createFrameworkInfo("role2");
- allocator->addFramework(framework2.id(), framework2, {});
+ allocator->addFramework(framework2.id(), framework2, {}, true);
hashmap<FrameworkID, Allocation> frameworkAllocations;
@@ -902,10 +902,10 @@ TEST_F(HierarchicalAllocatorTest, SameShareFairness)
initialize();
FrameworkInfo framework1 = createFrameworkInfo("*");
- allocator->addFramework(framework1.id(), framework1, {});
+ allocator->addFramework(framework1.id(), framework1, {}, true);
FrameworkInfo framework2 = createFrameworkInfo("*");
- allocator->addFramework(framework2.id(), framework2, {});
+ allocator->addFramework(framework2.id(), framework2, {}, true);
SlaveInfo slave = createSlaveInfo("cpus:2;mem:1024;disk:0");
allocator->addSlave(slave.id(), slave, None(), slave.resources(), {});
@@ -961,7 +961,7 @@ TEST_F(HierarchicalAllocatorTest, Reservations)
// framework1 should get all the resources from slave1, and the
// unreserved resources from slave2.
FrameworkInfo framework1 = createFrameworkInfo("role1");
- allocator->addFramework(framework1.id(), framework1, {});
+ allocator->addFramework(framework1.id(), framework1, {}, true);
Future<Allocation> allocation = allocations.get();
AWAIT_READY(allocation);
@@ -974,7 +974,7 @@ TEST_F(HierarchicalAllocatorTest, Reservations)
// framework2 should get all of its reserved resources on slave2.
FrameworkInfo framework2 = createFrameworkInfo("role2");
- allocator->addFramework(framework2.id(), framework2, {});
+ allocator->addFramework(framework2.id(), framework2, {}, true);
allocation = allocations.get();
AWAIT_READY(allocation);
@@ -1000,7 +1000,7 @@ TEST_F(HierarchicalAllocatorTest, RecoverResources)
// Initially, all the resources are allocated.
FrameworkInfo framework = createFrameworkInfo("role1");
- allocator->addFramework(framework.id(), framework, {});
+ allocator->addFramework(framework.id(), framework, {}, true);
Future<Allocation> allocation = allocations.get();
AWAIT_READY(allocation);
@@ -1057,7 +1057,7 @@ TEST_F(HierarchicalAllocatorTest, Allocatable)
initialize();
FrameworkInfo framework = createFrameworkInfo("role1");
- allocator->addFramework(framework.id(), framework, {});
+ allocator->addFramework(framework.id(), framework, {}, true);
// Not enough memory or cpu to be considered allocatable.
SlaveInfo slave1 = createSlaveInfo(
@@ -1126,7 +1126,7 @@ TEST_F(HierarchicalAllocatorTest, UpdateAllocation)
// Initially, all the resources are allocated.
FrameworkInfo framework = createFrameworkInfo("role1");
- allocator->addFramework(framework.id(), framework, {});
+ allocator->addFramework(framework.id(), framework, {}, true);
Future<Allocation> allocation = allocations.get();
AWAIT_READY(allocation);
@@ -1201,7 +1201,7 @@ TEST_F(HierarchicalAllocatorTest, UpdateAllocationSharedPersistentVolume)
"role1",
{FrameworkInfo::Capability::SHARED_RESOURCES});
allocator->addFramework(
- framework.id(), framework, hashmap<SlaveID, Resources>());
+ framework.id(), framework, hashmap<SlaveID, Resources>(), true);
Future<Allocation> allocation = allocations.get();
AWAIT_READY(allocation);
@@ -1304,7 +1304,7 @@ TEST_F(HierarchicalAllocatorTest, SharedResourcesCapability)
// Create `framework1` without opting in for SHARED_RESOURCES.
FrameworkInfo framework1 = createFrameworkInfo("role1");
- allocator->addFramework(framework1.id(), framework1, {});
+ allocator->addFramework(framework1.id(), framework1, {}, true);
// Initially, all the resources are allocated to `framework1`.
Future<Allocation> allocation = allocations.get();
@@ -1363,7 +1363,7 @@ TEST_F(HierarchicalAllocatorTest, SharedResourcesCapability)
FrameworkInfo framework2 = createFrameworkInfo(
"role1",
{FrameworkInfo::Capability::SHARED_RESOURCES});
- allocator->addFramework(framework2.id(), framework2, {});
+ allocator->addFramework(framework2.id(), framework2, {}, true);
// The offer to 'framework2` should contain the shared volume since it
// has opted in for SHARED_RESOURCES.
@@ -1401,7 +1401,7 @@ TEST_F(HierarchicalAllocatorTest, UpdateAvailableSuccess)
// Expect to receive the updated available resources.
FrameworkInfo framework = createFrameworkInfo("role1");
- allocator->addFramework(framework.id(), framework, {});
+ allocator->addFramework(framework.id(), framework, {}, true);
Future<Allocation> allocation = allocations.get();
AWAIT_READY(allocation);
@@ -1432,7 +1432,7 @@ TEST_F(HierarchicalAllocatorTest, UpdateAvailableFail)
// Expect to receive the all of the available resources.
FrameworkInfo framework = createFrameworkInfo("role1");
- allocator->addFramework(framework.id(), framework, {});
+ allocator->addFramework(framework.id(), framework, {}, true);
Future<Allocation> allocation = allocations.get();
AWAIT_READY(allocation);
@@ -1470,7 +1470,7 @@ TEST_F(HierarchicalAllocatorTest, UpdateSlave)
FrameworkInfo framework = createFrameworkInfo(
"role1",
{FrameworkInfo::Capability::REVOCABLE_RESOURCES});
- allocator->addFramework(framework.id(), framework, {});
+ allocator->addFramework(framework.id(), framework, {}, true);
// Initially, all the resources are allocated.
Future<Allocation> allocation = allocations.get();
@@ -1522,7 +1522,7 @@ TEST_F(HierarchicalAllocatorTest, OversubscribedNotAllocated)
// Add a framework that does *not* accept revocable resources.
FrameworkInfo framework = createFrameworkInfo("role1");
- allocator->addFramework(framework.id(), framework, {});
+ allocator->addFramework(framework.id(), framework, {}, true);
// Initially, all the resources are allocated.
Future<Allocation> allocation = allocations.get();
@@ -1557,7 +1557,7 @@ TEST_F(HierarchicalAllocatorTest, RecoverOversubscribedResources)
FrameworkInfo framework = createFrameworkInfo(
"role1",
{FrameworkInfo::Capability::REVOCABLE_RESOURCES});
- allocator->addFramework(framework.id(), framework, {});
+ allocator->addFramework(framework.id(), framework, {}, true);
// Initially, all the resources are allocated.
Future<Allocation> allocation = allocations.get();
@@ -1607,7 +1607,7 @@ TEST_F(HierarchicalAllocatorTest, Whitelist)
allocator->addSlave(slave.id(), slave, None(), slave.resources(), {});
FrameworkInfo framework = createFrameworkInfo("*");
- allocator->addFramework(framework.id(), framework, {});
+ allocator->addFramework(framework.id(), framework, {}, true);
Future<Allocation> allocation = allocations.get();
@@ -1672,7 +1672,8 @@ TEST_F(HierarchicalAllocatorTest, NoDoubleAccounting)
// Call `addFramework()` and `addSlave()` in different order for
// `framework1` and `framework2`
- allocator->addFramework(framework1.id(), framework1, framework1Allocation);
+ allocator->addFramework(
+ framework1.id(), framework1, framework1Allocation, true);
allocator->addSlave(
agent1.id(), agent1, None(), agent1.resources(), agent1Allocation);
@@ -1680,7 +1681,8 @@ TEST_F(HierarchicalAllocatorTest, NoDoubleAccounting)
allocator->addSlave(
agent2.id(), agent2, None(), agent2.resources(), agent2Allocation);
- allocator->addFramework(framework2.id(), framework2, framework2Allocation);
+ allocator->addFramework(
+ framework2.id(), framework2, framework2Allocation, true);
// Process all triggered allocation events.
Clock::settle();
@@ -1740,14 +1742,14 @@ TEST_F(HierarchicalAllocatorTest, QuotaProvidesGuarantee)
// Create `framework1` and set quota for its role.
FrameworkInfo framework1 = createFrameworkInfo(QUOTA_ROLE);
- allocator->addFramework(framework1.id(), framework1, {});
+ allocator->addFramework(framework1.id(), framework1, {}, true);
const Quota quota = createQuota(QUOTA_ROLE, "cpus:2;mem:1024");
allocator->setQuota(QUOTA_ROLE, quota);
// Create `framework2` in a non-quota'ed role.
FrameworkInfo framework2 = createFrameworkInfo(NO_QUOTA_ROLE);
- allocator->addFramework(framework2.id(), framework2, {});
+ allocator->addFramework(framework2.id(), framework2, {}, true);
// Process all triggered allocation events.
//
@@ -1853,10 +1855,10 @@ TEST_F(HierarchicalAllocatorTest, RemoveQuota)
allocator->setQuota(QUOTA_ROLE, quota);
FrameworkInfo framework1 = createFrameworkInfo(QUOTA_ROLE);
- allocator->addFramework(framework1.id(), framework1, {});
+ allocator->addFramework(framework1.id(), framework1, {}, true);
FrameworkInfo framework2 = createFrameworkInfo(NO_QUOTA_ROLE);
- allocator->addFramework(framework2.id(), framework2, {});
+ allocator->addFramework(framework2.id(), framework2, {}, true);
SlaveInfo agent1 = createSlaveInfo("cpus:1;mem:512;disk:0");
allocator->addSlave(
@@ -1948,14 +1950,14 @@ TEST_F(HierarchicalAllocatorTest, MultipleFrameworksInRoleWithQuota)
// Create `framework1a` and set quota for its role.
FrameworkInfo framework1a = createFrameworkInfo(QUOTA_ROLE);
- allocator->addFramework(framework1a.id(), framework1a, {});
+ allocator->addFramework(framework1a.id(), framework1a, {}, true);
const Quota quota = createQuota(QUOTA_ROLE, "cpus:4;mem:2048");
allocator->setQuota(QUOTA_ROLE, quota);
// Create `framework2` in a non-quota'ed role.
FrameworkInfo framework2 = createFrameworkInfo(NO_QUOTA_ROLE);
- allocator->addFramework(framework2.id(), framework2, {});
+ allocator->addFramework(framework2.id(), framework2, {}, true);
// Process all triggered allocation events.
//
@@ -1980,7 +1982,7 @@ TEST_F(HierarchicalAllocatorTest, MultipleFrameworksInRoleWithQuota)
// Create `framework1b` in the quota'ed role.
FrameworkInfo framework1b = createFrameworkInfo(QUOTA_ROLE);
- allocator->addFramework(framework1b.id(), framework1b, {});
+ allocator->addFramework(framework1b.id(), framework1b, {}, true);
SlaveInfo agent2 = createSlaveInfo("cpus:2;mem:1024;disk:0");
allocator->addSlave(agent2.id(), agent2, None(), agent2.resources(), {});
@@ -2063,7 +2065,7 @@ TEST_F(HierarchicalAllocatorTest, QuotaAllocationGranularity)
// Create `framework1` and set quota for its role.
FrameworkInfo framework1 = createFrameworkInfo(QUOTA_ROLE);
- allocator->addFramework(framework1.id(), framework1, {});
+ allocator->addFramework(framework1.id(), framework1, {}, true);
// Set quota to be less than the agent resources.
const Quota quota = createQuota(QUOTA_ROLE, "cpus:0.5;mem:200");
@@ -2071,7 +2073,7 @@ TEST_F(HierarchicalAllocatorTest, QuotaAllocationGranularity)
// Create `framework2` in a non-quota'ed role.
FrameworkInfo framework2 = createFrameworkInfo(NO_QUOTA_ROLE);
- allocator->addFramework(framework2.id(), framework2, {});
+ allocator->addFramework(framework2.id(), framework2, {}, true);
// Process all triggered allocation events.
//
@@ -2117,10 +2119,10 @@ TEST_F(HierarchicalAllocatorTest, DRFWithQuota)
allocator->setQuota(QUOTA_ROLE, quota);
FrameworkInfo framework1 = createFrameworkInfo(QUOTA_ROLE);
- allocator->addFramework(framework1.id(), framework1, {});
+ allocator->addFramework(framework1.id(), framework1, {}, true);
FrameworkInfo framework2 = createFrameworkInfo(NO_QUOTA_ROLE);
- allocator->addFramework(framework2.id(), framework2, {});
+ allocator->addFramework(framework2.id(), framework2, {}, true);
// Process all triggered allocation events.
//
@@ -2235,10 +2237,10 @@ TEST_F(HierarchicalAllocatorTest, QuotaAgainstStarvation)
initialize();
FrameworkInfo framework1 = createFrameworkInfo(QUOTA_ROLE);
- allocator->addFramework(framework1.id(), framework1, {});
+ allocator->addFramework(framework1.id(), framework1, {}, true);
FrameworkInfo framework2 = createFrameworkInfo(NO_QUOTA_ROLE);
- allocator->addFramework(framework2.id(), framework2, {});
+ allocator->addFramework(framework2.id(), framework2, {}, true);
SlaveInfo agent1 = createSlaveInfo("cpus:1;mem:512;disk:0");
allocator->addSlave(
@@ -2351,7 +2353,7 @@ TEST_F(HierarchicalAllocatorTest, QuotaAbsentFramework)
// Add `framework` in the non-quota'ed role.
FrameworkInfo framework = createFrameworkInfo(NO_QUOTA_ROLE);
- allocator->addFramework(framework.id(), framework, {});
+ allocator->addFramework(framework.id(), framework, {}, true);
// Process all triggered allocation events.
//
@@ -2431,7 +2433,7 @@ TEST_F(HierarchicalAllocatorTest, MultiQuotaAbsentFrameworks)
// Add a framework in the `QUOTA_ROLE2` role.
FrameworkInfo framework = createFrameworkInfo(QUOTA_ROLE2);
- allocator->addFramework(framework.id(), framework, {});
+ allocator->addFramework(framework.id(), framework, {}, true);
// Due to the coarse-grained nature of the allocations, `framework` will
// get all `agent`'s resources.
@@ -2469,11 +2471,11 @@ TEST_F(HierarchicalAllocatorTest, MultiQuotaWithFrameworks)
// Add `framework1` in the `QUOTA_ROLE1` role.
FrameworkInfo framework1 = createFrameworkInfo(QUOTA_ROLE1);
- allocator->addFramework(framework1.id(), framework1, {});
+ allocator->addFramework(framework1.id(), framework1, {}, true);
// Add `framework2` in the `QUOTA_ROLE2` role.
FrameworkInfo framework2 = createFrameworkInfo(QUOTA_ROLE2);
- allocator->addFramework(framework2.id(), framework2, {});
+ allocator->addFramework(framework2.id(), framework2, {}, true);
// Process all triggered allocation events.
//
@@ -2541,10 +2543,10 @@ TEST_F(HierarchicalAllocatorTest, ReservationWithinQuota)
allocator->setQuota(QUOTA_ROLE, quota);
FrameworkInfo framework1 = createFrameworkInfo(QUOTA_ROLE);
- allocator->addFramework(framework1.id(), framework1, {});
+ allocator->addFramework(framework1.id(), framework1, {}, true);
FrameworkInfo framework2 = createFrameworkInfo(NON_QUOTA_ROLE);
- allocator->addFramework(framework2.id(), framework2, {});
+ allocator->addFramework(framework2.id(), framework2, {}, true);
// Process all triggered allocation events.
//
@@ -2627,7 +2629,7 @@ TEST_F(HierarchicalAllocatorTest, QuotaSetAsideReservedResources)
// Create `framework1` and set quota for its role.
FrameworkInfo framework1 = createFrameworkInfo(QUOTA_ROLE);
- allocator->addFramework(framework1.id(), framework1, {});
+ allocator->addFramework(framework1.id(), framework1, {}, true);
const Quota quota = createQuota(QUOTA_ROLE, "cpus:4");
allocator->setQuota(QUOTA_ROLE, quota);
@@ -2660,7 +2662,7 @@ TEST_F(HierarchicalAllocatorTest, QuotaSetAsideReservedResources)
// Create `framework2` in a non-quota'ed role.
FrameworkInfo framework2 = createFrameworkInfo(NO_QUOTA_ROLE);
- allocator->addFramework(framework2.id(), framework2, {});
+ allocator->addFramework(framework2.id(), framework2, {}, true);
// `framework2` will be offered the reserved resources at `agent2`
// because those resources are reserved for its role.
@@ -2710,7 +2712,7 @@ TEST_F(HierarchicalAllocatorTest, DeactivateAndReactivateFramework)
// Framework will be offered all of the agent's resources since it is
// the only framework running so far.
FrameworkInfo framework = createFrameworkInfo("role1");
- allocator->addFramework(framework.id(), framework, {});
+ allocator->addFramework(framework.id(), framework, {}, true);
Future<Allocation> allocation = allocations.get();
AWAIT_READY(allocation);
@@ -2765,7 +2767,7 @@ TEST_F(HierarchicalAllocatorTest, SuppressAndReviveOffers)
// Framework will be offered all of the agent's resources since it is
// the only framework running so far.
FrameworkInfo framework = createFrameworkInfo("role1");
- allocator->addFramework(framework.id(), framework, {});
+ allocator->addFramework(framework.id(), framework, {}, true);
Future<Allocation> allocation = allocations.get();
AWAIT_READY(allocation);
@@ -2838,7 +2840,7 @@ TEST_F(HierarchicalAllocatorTest, ResourceMetrics)
EXPECT_TRUE(metrics.contains(expected));
FrameworkInfo framework = createFrameworkInfo("role1");
- allocator->addFramework(framework.id(), framework, {});
+ allocator->addFramework(framework.id(), framework, {}, true);
Clock::settle();
// All of the resources should be offered.
@@ -2926,7 +2928,7 @@ TEST_F(HierarchicalAllocatorTest, AllocationRunsMetric)
++allocations; // Adding an agent triggers allocations.
FrameworkInfo framework = createFrameworkInfo("role");
- allocator->addFramework(framework.id(), framework, {});
+ allocator->addFramework(framework.id(), framework, {}, true);
++allocations; // Adding a framework triggers allocations.
Clock::settle();
@@ -2980,7 +2982,7 @@ TEST_F(HierarchicalAllocatorTest, AllocationRunTimerMetrics)
allocator->addSlave(agent.id(), agent, None(), agent.resources(), {});
FrameworkInfo framework = createFrameworkInfo("role1");
- allocator->addFramework(framework.id(), framework, {});
+ allocator->addFramework(framework.id(), framework, {}, true);
// Wait for the allocation to complete.
AWAIT_READY(allocations.get());
@@ -3034,7 +3036,7 @@ TEST_F(HierarchicalAllocatorTest, ActiveOfferFiltersMetrics)
offerFilter.set_refuse_seconds(filterTimeout.secs());
FrameworkInfo framework1 = createFrameworkInfo("roleA");
- allocator->addFramework(framework1.id(), framework1, {});
+ allocator->addFramework(framework1.id(), framework1, {}, true);
Future<Allocation> allocation = allocations.get();
@@ -3057,7 +3059,7 @@ TEST_F(HierarchicalAllocatorTest, ActiveOfferFiltersMetrics)
EXPECT_TRUE(metrics.contains(expected));
FrameworkInfo framework2 = createFrameworkInfo("roleB");
- allocator->addFramework(framework2.id(), framework2, {});
+ allocator->addFramework(framework2.id(), framework2, {}, true);
allocation = allocations.get();
@@ -3080,7 +3082,7 @@ TEST_F(HierarchicalAllocatorTest, ActiveOfferFiltersMetrics)
EXPECT_TRUE(metrics.contains(expected));
FrameworkInfo framework3 = createFrameworkInfo("roleA");
- allocator->addFramework(framework3.id(), framework3, {});
+ allocator->addFramework(framework3.id(), framework3, {}, true);
allocation = allocations.get();
@@ -3121,7 +3123,7 @@ TEST_F(HierarchicalAllocatorTest, DominantShareMetrics)
allocator->addSlave(agent1.id(), agent1, None(), agent1.resources(), {});
FrameworkInfo framework1 = createFrameworkInfo("roleA");
- allocator->addFramework(framework1.id(), framework1, {});
+ allocator->addFramework(framework1.id(), framework1, {}, true);
Clock::settle();
JSON::Object expected;
@@ -3155,7 +3157,7 @@ TEST_F(HierarchicalAllocatorTest, DominantShareMetrics)
// implicit filter has not yet timed out. The new framework
// will have the full share.
FrameworkInfo framework2 = createFrameworkInfo("roleB");
- allocator->addFramework(framework2.id(), framework2, {});
+ allocator->addFramework(framework2.id(), framework2, {}, true);
Clock::settle();
expected.values = {
@@ -3225,7 +3227,7 @@ TEST_F(HierarchicalAllocatorTest, DominantShareMetricsWithFairnessExclusion)
FrameworkInfo framework1 = createFrameworkInfo(
"roleA", {FrameworkInfo::Capability::GPU_RESOURCES});
- allocator->addFramework(framework1.id(), framework1, {});
+ allocator->addFramework(framework1.id(), framework1, {}, true);
Clock::settle();
JSON::Object expected;
@@ -3238,7 +3240,7 @@ TEST_F(HierarchicalAllocatorTest, DominantShareMetricsWithFairnessExclusion)
EXPECT_TRUE(metrics.contains(expected));
FrameworkInfo framework2 = createFrameworkInfo("roleB");
- allocator->addFramework(framework2.id(), framework2, {});
+ allocator->addFramework(framework2.id(), framework2, {}, true);
Clock::settle();
// Add a second, identical agent. Now `framework2` will
@@ -3319,13 +3321,13 @@ TEST_F(HierarchicalAllocatorTest, UpdateWeight)
// and all resources will be offered to this framework since it is the only
// framework running so far.
FrameworkInfo framework1 = createFrameworkInfo("role1");
- allocator->addFramework(framework1.id(), framework1, {});
+ allocator->addFramework(framework1.id(), framework1, {}, true);
// Framework2 registers with 'role2' which also uses the default weight.
// It will not get any offers due to all resources having outstanding offers
// to framework1 when it registered.
FrameworkInfo framework2 = createFrameworkInfo("role2");
- allocator->addFramework(framework2.id(), framework2, {});
+ allocator->addFramework(framework2.id(), framework2, {}, true);
Future<Allocation> allocation = allocations.get();
AWAIT_READY(allocation);
@@ -3436,7 +3438,7 @@ TEST_F(HierarchicalAllocatorTest, UpdateWeight)
// Framework3 registers with 'role3'.
FrameworkInfo framework3 = createFrameworkInfo("role3");
- allocator->addFramework(framework3.id(), framework3, {});
+ allocator->addFramework(framework3.id(), framework3, {}, true);
// 'addFramework' will trigger the allocation immediately, so it does not
// need to manually advance the clock here.
@@ -3497,7 +3499,7 @@ TEST_F(HierarchicalAllocatorTest, ReviveOffers)
// Framework will be offered all of agent's resources since it is
// the only framework running so far.
FrameworkInfo framework = createFrameworkInfo("role1");
- allocator->addFramework(framework.id(), framework, {});
+ allocator->addFramework(framework.id(), framework, {}, true);
Future<Allocation> allocation = allocations.get();
AWAIT_READY(allocation);
@@ -3556,12 +3558,13 @@ TEST_P(HierarchicalAllocatorTestWithParam, AllocateSharedResources)
FrameworkInfo framework1 = createFrameworkInfo(
"role1",
{FrameworkInfo::Capability::SHARED_RESOURCES});
- allocator->addFramework(framework1.id(), framework1, {});
FrameworkInfo framework2 = createFrameworkInfo(
"role1",
{FrameworkInfo::Capability::SHARED_RESOURCES});
- allocator->addFramework(framework2.id(), framework2, {});
+
+ allocator->addFramework(framework1.id(), framework1, {}, true);
+ allocator->addFramework(framework2.id(), framework2, {}, true);
if (GetParam()) {
// Assign a quota.
@@ -3690,7 +3693,7 @@ TEST_P(HierarchicalAllocator_BENCHMARK_Test, AddAndUpdateSlave)
watch.start();
foreach (const FrameworkInfo& framework, frameworks) {
- allocator->addFramework(framework.id(), framework, {});
+ allocator->addFramework(framework.id(), framework, {}, true);
}
// Wait for all the `addFramework` operations to be processed.
@@ -3800,7 +3803,7 @@ TEST_P(HierarchicalAllocator_BENCHMARK_Test, DeclineOffers)
for (size_t i = 0; i < frameworkCount; i++) {
frameworks.push_back(createFrameworkInfo("*"));
- allocator->addFramework(frameworks[i].id(), frameworks[i], {});
+ allocator->addFramework(frameworks[i].id(), frameworks[i], {}, true);
}
// Wait for all the `addFramework` operations to be processed.
@@ -3943,7 +3946,7 @@ TEST_P(HierarchicalAllocator_BENCHMARK_Test, ResourceLabels)
for (size_t i = 0; i < frameworkCount; i++) {
frameworks.push_back(createFrameworkInfo("role1"));
- allocator->addFramework(frameworks[i].id(), frameworks[i], {});
+ allocator->addFramework(frameworks[i].id(), frameworks[i], {}, true);
}
// Wait for all the `addFramework` operations to be processed.
@@ -4106,7 +4109,7 @@ TEST_P(HierarchicalAllocator_BENCHMARK_Test, SuppressOffers)
for (size_t i = 0; i < frameworkCount; i++) {
frameworks.push_back(createFrameworkInfo("*"));
- allocator->addFramework(frameworks[i].id(), frameworks[i], {});
+ allocator->addFramework(frameworks[i].id(), frameworks[i], {}, true);
}
// Wait for all the `addFramework` operations to be processed.
@@ -4243,7 +4246,7 @@ TEST_P(HierarchicalAllocator_BENCHMARK_Test, Metrics)
for (size_t i = 0; i < frameworkCount; i++) {
FrameworkInfo framework = createFrameworkInfo(stringify(i));
- allocator->addFramework(framework.id(), framework, {});
+ allocator->addFramework(framework.id(), framework, {}, true);
}
// Wait for all the `addFramework` operations to be processed.
http://git-wip-us.apache.org/repos/asf/mesos/blob/51dfe768/src/tests/master_allocator_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/master_allocator_tests.cpp b/src/tests/master_allocator_tests.cpp
index bb94e38..266047b 100644
--- a/src/tests/master_allocator_tests.cpp
+++ b/src/tests/master_allocator_tests.cpp
@@ -178,7 +178,7 @@ TYPED_TEST(MasterAllocatorTest, SingleFramework)
MesosSchedulerDriver driver(
&sched, DEFAULT_FRAMEWORK_INFO, master.get()->pid, DEFAULT_CREDENTIAL);
- EXPECT_CALL(allocator, addFramework(_, _, _));
+ EXPECT_CALL(allocator, addFramework(_, _, _, _));
EXPECT_CALL(sched, registered(_, _, _));
@@ -228,7 +228,7 @@ TYPED_TEST(MasterAllocatorTest, ResourcesUnused)
MesosSchedulerDriver driver1(
&sched1, DEFAULT_FRAMEWORK_INFO, master.get()->pid, DEFAULT_CREDENTIAL);
- EXPECT_CALL(allocator, addFramework(_, _, _));
+ EXPECT_CALL(allocator, addFramework(_, _, _, _));
EXPECT_CALL(sched1, registered(_, _, _));
@@ -273,7 +273,7 @@ TYPED_TEST(MasterAllocatorTest, ResourcesUnused)
MesosSchedulerDriver driver2(
&sched2, frameworkInfo2, master.get()->pid, DEFAULT_CREDENTIAL);
- EXPECT_CALL(allocator, addFramework(_, _, _));
+ EXPECT_CALL(allocator, addFramework(_, _, _, _));
EXPECT_CALL(sched2, registered(_, _, _));
@@ -335,7 +335,7 @@ TYPED_TEST(MasterAllocatorTest, OutOfOrderDispatch)
MesosSchedulerDriver driver1(
&sched1, frameworkInfo1, master.get()->pid, DEFAULT_CREDENTIAL);
- EXPECT_CALL(allocator, addFramework(_, Eq(frameworkInfo1), _))
+ EXPECT_CALL(allocator, addFramework(_, Eq(frameworkInfo1), _, _))
.WillOnce(InvokeAddFramework(&allocator));
Future<FrameworkID> frameworkId1;
@@ -403,7 +403,7 @@ TYPED_TEST(MasterAllocatorTest, OutOfOrderDispatch)
MesosSchedulerDriver driver2(
&sched2, frameworkInfo2, master.get()->pid, DEFAULT_CREDENTIAL);
- EXPECT_CALL(allocator, addFramework(_, Eq(frameworkInfo2), _))
+ EXPECT_CALL(allocator, addFramework(_, Eq(frameworkInfo2), _, _))
.WillOnce(InvokeAddFramework(&allocator));
FrameworkID frameworkId2;
@@ -469,7 +469,7 @@ TYPED_TEST(MasterAllocatorTest, SchedulerFailover)
MesosSchedulerDriver driver1(
&sched1, frameworkInfo1, master.get()->pid, DEFAULT_CREDENTIAL);
- EXPECT_CALL(allocator, addFramework(_, _, _));
+ EXPECT_CALL(allocator, addFramework(_, _, _, _));
FrameworkID frameworkId;
EXPECT_CALL(sched1, registered(&driver1, _, _))
@@ -599,7 +599,7 @@ TYPED_TEST(MasterAllocatorTest, FrameworkExited)
MesosSchedulerDriver driver1(
&sched1, DEFAULT_FRAMEWORK_INFO, master.get()->pid, DEFAULT_CREDENTIAL);
- EXPECT_CALL(allocator, addFramework(_, _, _));
+ EXPECT_CALL(allocator, addFramework(_, _, _, _));
EXPECT_CALL(sched1, registered(_, _, _));
@@ -643,7 +643,7 @@ TYPED_TEST(MasterAllocatorTest, FrameworkExited)
MesosSchedulerDriver driver2(
&sched2, DEFAULT_FRAMEWORK_INFO, master.get()->pid, DEFAULT_CREDENTIAL);
- EXPECT_CALL(allocator, addFramework(_, _, _));
+ EXPECT_CALL(allocator, addFramework(_, _, _, _));
EXPECT_CALL(sched2, registered(_, _, _));
@@ -739,7 +739,7 @@ TYPED_TEST(MasterAllocatorTest, SlaveLost)
MesosSchedulerDriver driver(
&sched, DEFAULT_FRAMEWORK_INFO, master.get()->pid, DEFAULT_CREDENTIAL);
- EXPECT_CALL(allocator, addFramework(_, _, _));
+ EXPECT_CALL(allocator, addFramework(_, _, _, _));
EXPECT_CALL(sched, registered(_, _, _));
@@ -859,7 +859,7 @@ TYPED_TEST(MasterAllocatorTest, SlaveAdded)
MesosSchedulerDriver driver(
&sched, DEFAULT_FRAMEWORK_INFO, master.get()->pid, DEFAULT_CREDENTIAL);
- EXPECT_CALL(allocator, addFramework(_, _, _));
+ EXPECT_CALL(allocator, addFramework(_, _, _, _));
EXPECT_CALL(sched, registered(_, _, _));
@@ -956,7 +956,7 @@ TYPED_TEST(MasterAllocatorTest, TaskFinished)
MesosSchedulerDriver driver(
&sched, DEFAULT_FRAMEWORK_INFO, master.get()->pid, DEFAULT_CREDENTIAL);
- EXPECT_CALL(allocator, addFramework(_, _, _));
+ EXPECT_CALL(allocator, addFramework(_, _, _, _));
EXPECT_CALL(sched, registered(_, _, _));
@@ -1061,7 +1061,7 @@ TYPED_TEST(MasterAllocatorTest, CpusOnlyOfferedAndTaskLaunched)
MesosSchedulerDriver driver(
&sched, DEFAULT_FRAMEWORK_INFO, master.get()->pid, DEFAULT_CREDENTIAL);
- EXPECT_CALL(allocator, addFramework(_, _, _));
+ EXPECT_CALL(allocator, addFramework(_, _, _, _));
EXPECT_CALL(sched, registered(_, _, _));
@@ -1142,7 +1142,7 @@ TYPED_TEST(MasterAllocatorTest, MemoryOnlyOfferedAndTaskLaunched)
MesosSchedulerDriver driver(
&sched, DEFAULT_FRAMEWORK_INFO, master.get()->pid, DEFAULT_CREDENTIAL);
- EXPECT_CALL(allocator, addFramework(_, _, _));
+ EXPECT_CALL(allocator, addFramework(_, _, _, _));
EXPECT_CALL(sched, registered(_, _, _));
@@ -1291,7 +1291,7 @@ TYPED_TEST(MasterAllocatorTest, RoleTest)
.WillOnce(FutureSatisfy(®istered2));
Future<Nothing> addFramework;
- EXPECT_CALL(allocator, addFramework(_, _, _))
+ EXPECT_CALL(allocator, addFramework(_, _, _, _))
.WillOnce(FutureSatisfy(&addFramework));
driver2.start();
@@ -1357,7 +1357,7 @@ TYPED_TEST(MasterAllocatorTest, FrameworkReregistersFirst)
slave = this->StartSlave(&slaveDetector, &containerizer, flags);
ASSERT_SOME(slave);
- EXPECT_CALL(allocator, addFramework(_, _, _));
+ EXPECT_CALL(allocator, addFramework(_, _, _, _));
EXPECT_CALL(sched, registered(&driver, _, _));
@@ -1401,7 +1401,7 @@ TYPED_TEST(MasterAllocatorTest, FrameworkReregistersFirst)
EXPECT_CALL(allocator2, initialize(_, _, _, _, _));
Future<Nothing> addFramework;
- EXPECT_CALL(allocator2, addFramework(_, _, _))
+ EXPECT_CALL(allocator2, addFramework(_, _, _, _))
.WillOnce(DoAll(InvokeAddFramework(&allocator2),
FutureSatisfy(&addFramework)));
@@ -1481,7 +1481,7 @@ TYPED_TEST(MasterAllocatorTest, SlaveReregistersFirst)
slave = this->StartSlave(&slaveDetector, &containerizer, flags);
ASSERT_SOME(slave);
- EXPECT_CALL(allocator, addFramework(_, _, _));
+ EXPECT_CALL(allocator, addFramework(_, _, _, _));
EXPECT_CALL(allocator, recoverResources(_, _, _, _));
EXPECT_CALL(sched, registered(&driver, _, _));
@@ -1540,7 +1540,7 @@ TYPED_TEST(MasterAllocatorTest, SlaveReregistersFirst)
EXPECT_CALL(sched, registered(&driver, _, _));
- EXPECT_CALL(allocator2, addFramework(_, _, _));
+ EXPECT_CALL(allocator2, addFramework(_, _, _, _));
Future<vector<Offer>> resourceOffers2;
EXPECT_CALL(sched, resourceOffers(&driver, _))
http://git-wip-us.apache.org/repos/asf/mesos/blob/51dfe768/src/tests/persistent_volume_endpoints_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/persistent_volume_endpoints_tests.cpp b/src/tests/persistent_volume_endpoints_tests.cpp
index f35592a..241970f 100644
--- a/src/tests/persistent_volume_endpoints_tests.cpp
+++ b/src/tests/persistent_volume_endpoints_tests.cpp
@@ -1559,7 +1559,7 @@ TEST_F(PersistentVolumeEndpointsTest, OfferCreateThenEndpointRemove)
frameworkInfo.role(),
createReservationInfo(DEFAULT_CREDENTIAL.principal())).get();
- EXPECT_CALL(allocator, addFramework(_, _, _));
+ EXPECT_CALL(allocator, addFramework(_, _, _, _));
EXPECT_CALL(sched, registered(_, _, _));
@@ -1857,7 +1857,7 @@ TEST_F(PersistentVolumeEndpointsTest, ReserveAndSlaveRemoval)
MesosSchedulerDriver driver(
&sched, frameworkInfo, master.get()->pid, DEFAULT_CREDENTIAL);
- EXPECT_CALL(allocator, addFramework(_, _, _));
+ EXPECT_CALL(allocator, addFramework(_, _, _, _));
EXPECT_CALL(sched, registered(_, _, _));
http://git-wip-us.apache.org/repos/asf/mesos/blob/51dfe768/src/tests/reservation_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/reservation_tests.cpp b/src/tests/reservation_tests.cpp
index dddfbbe..ffbb50b 100644
--- a/src/tests/reservation_tests.cpp
+++ b/src/tests/reservation_tests.cpp
@@ -553,7 +553,7 @@ TEST_F(ReservationTest, DropReserveTooLarge)
EXPECT_CALL(sched, resourceOffers(&driver, _))
.WillOnce(FutureArg<1>(&offers));
- EXPECT_CALL(allocator, addFramework(_, _, _));
+ EXPECT_CALL(allocator, addFramework(_, _, _, _));
driver.start();
@@ -644,7 +644,7 @@ TEST_F(ReservationTest, DropReserveStaticReservation)
EXPECT_CALL(sched, resourceOffers(&driver, _))
.WillOnce(FutureArg<1>(&offers));
- EXPECT_CALL(allocator, addFramework(_, _, _));
+ EXPECT_CALL(allocator, addFramework(_, _, _, _));
driver.start();
@@ -2129,7 +2129,7 @@ TEST_F(ReservationTest, DropReserveWithInvalidRole)
EXPECT_CALL(sched, resourceOffers(&driver, _))
.WillOnce(FutureArg<1>(&offers));
- EXPECT_CALL(allocator, addFramework(_, _, _));
+ EXPECT_CALL(allocator, addFramework(_, _, _, _));
driver.start();
http://git-wip-us.apache.org/repos/asf/mesos/blob/51dfe768/src/tests/resource_offers_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/resource_offers_tests.cpp b/src/tests/resource_offers_tests.cpp
index 3dde7bf..b6c15cb 100644
--- a/src/tests/resource_offers_tests.cpp
+++ b/src/tests/resource_offers_tests.cpp
@@ -299,7 +299,7 @@ TEST_F(ResourceOffersTest, Request)
MesosSchedulerDriver driver(
&sched, DEFAULT_FRAMEWORK_INFO, master.get()->pid, DEFAULT_CREDENTIAL);
- EXPECT_CALL(allocator, addFramework(_, _, _))
+ EXPECT_CALL(allocator, addFramework(_, _, _, _))
.Times(1);
Future<Nothing> registered;
http://git-wip-us.apache.org/repos/asf/mesos/blob/51dfe768/src/tests/slave_recovery_tests.cpp
----------------------------------------------------------------------
diff --git a/src/tests/slave_recovery_tests.cpp b/src/tests/slave_recovery_tests.cpp
index 324cf59..5b86c06 100644
--- a/src/tests/slave_recovery_tests.cpp
+++ b/src/tests/slave_recovery_tests.cpp
@@ -3148,7 +3148,7 @@ TYPED_TEST(SlaveRecoveryTest, ReconcileTasksMissingFromSlave)
MesosSchedulerDriver driver(
&sched, frameworkInfo, master.get()->pid, DEFAULT_CREDENTIAL);
- EXPECT_CALL(allocator, addFramework(_, _, _));
+ EXPECT_CALL(allocator, addFramework(_, _, _, _));
Future<FrameworkID> frameworkId;
EXPECT_CALL(sched, registered(_, _, _))
[3/9] mesos git commit: Refactored representation of framework
connectedness.
Posted by vi...@apache.org.
Refactored representation of framework connectedness.
Previously, the master used a bool to track whether a given framework is
connected. This commit adjusts the master to use an enum instead. The
enum currently only has two values, CONNECTED and DISCONNECTED, but an
additional value (RECOVERED) will be introduced shortly.
Review: https://reviews.apache.org/r/53896/
Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/b9b6e9fc
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/b9b6e9fc
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/b9b6e9fc
Branch: refs/heads/master
Commit: b9b6e9fca687c5cba7dc795435b9987ef3d816bc
Parents: 51dfe76
Author: Neil Conway <ne...@gmail.com>
Authored: Wed Dec 7 17:04:14 2016 -0800
Committer: Vinod Kone <vi...@gmail.com>
Committed: Wed Dec 7 17:05:42 2016 -0800
----------------------------------------------------------------------
src/master/http.cpp | 4 ++--
src/master/master.cpp | 22 +++++++++++-----------
src/master/master.hpp | 30 ++++++++++++++++++++++--------
src/master/quota_handler.cpp | 2 +-
4 files changed, 36 insertions(+), 22 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mesos/blob/b9b6e9fc/src/master/http.cpp
----------------------------------------------------------------------
diff --git a/src/master/http.cpp b/src/master/http.cpp
index ac560d1..e415124 100644
--- a/src/master/http.cpp
+++ b/src/master/http.cpp
@@ -837,7 +837,7 @@ Future<Response> Master::Http::scheduler(
"`FrameworkInfo`");
}
- if (!framework->connected) {
+ if (!framework->connected()) {
return Forbidden("Framework is not subscribed");
}
@@ -1376,7 +1376,7 @@ mesos::master::Response::GetFrameworks::Framework model(
_framework.mutable_framework_info()->CopyFrom(framework.info);
_framework.set_active(framework.active);
- _framework.set_connected(framework.connected);
+ _framework.set_connected(framework.connected());
int64_t time = framework.registeredTime.duration().ns();
if (time != 0) {
http://git-wip-us.apache.org/repos/asf/mesos/blob/b9b6e9fc/src/master/master.cpp
----------------------------------------------------------------------
diff --git a/src/master/master.cpp b/src/master/master.cpp
index ef1aba5..a3ad0b1 100644
--- a/src/master/master.cpp
+++ b/src/master/master.cpp
@@ -1953,7 +1953,7 @@ void Master::_markUnreachableAfterFailover(
void Master::sendSlaveLost(const SlaveInfo& slaveInfo)
{
foreachvalue (Framework* framework, frameworks.registered) {
- if (!framework->connected) {
+ if (!framework->connected()) {
continue;
}
@@ -2189,7 +2189,7 @@ void Master::receive(
// is no way for driver based frameworks to detect this in the absence
// of periodic heartbeat events. We send an error message to the framework
// causing the scheduler driver to abort when this happens.
- if (!framework->connected) {
+ if (!framework->connected()) {
const string error = "Framework disconnected";
LOG(INFO) << "Refusing " << call.type() << " call from framework "
@@ -2841,7 +2841,7 @@ void Master::_subscribe(
// Relink to the framework and mark it connected. Relinking
// might be necessary if the framework link previously broke.
link(framework->pid.get());
- framework->connected = true;
+ framework->state = Framework::State::CONNECTED;
// Reactivate the framework.
// NOTE: We do this after recovering resources (above) so that
@@ -2962,7 +2962,7 @@ void Master::disconnect(Framework* framework)
LOG(INFO) << "Disconnecting framework " << *framework;
- framework->connected = false;
+ framework->state = Framework::State::DISCONNECTED;
if (framework->pid.isSome()) {
// Remove the framework from authenticated. This is safe because
@@ -5824,7 +5824,7 @@ void Master::statusUpdate(StatusUpdate update, const UPID& pid)
// A framework might not have re-registered upon a master failover or
// got disconnected.
- if (framework != nullptr && framework->connected) {
+ if (framework != nullptr && framework->connected()) {
forward(update, pid, framework);
} else {
validStatusUpdate = false;
@@ -6469,7 +6469,7 @@ void Master::frameworkFailoverTimeout(const FrameworkID& frameworkId,
{
Framework* framework = getFramework(frameworkId);
- if (framework != nullptr && !framework->connected) {
+ if (framework != nullptr && !framework->connected()) {
// If the re-registration time has not changed, then the framework
// has not re-registered within the failover timeout.
if (framework->reregisteredTime == reregisteredTime) {
@@ -7092,7 +7092,7 @@ void Master::failoverFramework(Framework* framework, const HttpConnection& http)
// This is safe to do even if it is a retry because the framework is expected
// to close the old connection (and hence not receive any more responses)
// before sending subscription request on a new connection.
- if (framework->connected) {
+ if (framework->connected()) {
FrameworkErrorMessage message;
message.set_message("Framework failed over");
framework->send(message);
@@ -7144,7 +7144,7 @@ void Master::failoverFramework(Framework* framework, const UPID& newPid)
// scheduler as it is necessarily dead.
// 2.2 This is a duplicate message. In this case, the scheduler
// has not failed over, so we do not want to shut it down.
- if (oldPid != newPid && framework->connected) {
+ if (oldPid != newPid && framework->connected()) {
FrameworkErrorMessage message;
message.set_message("Framework failed over");
framework->send(message);
@@ -7194,7 +7194,7 @@ void Master::_failoverFramework(Framework* framework)
}
// Reconnect and reactivate the framework.
- framework->connected = true;
+ framework->state = Framework::State::CONNECTED;
// Reactivate the framework.
// NOTE: We do this after recovering resources (above) so that
@@ -8183,7 +8183,7 @@ double Master::_frameworks_connected()
{
double count = 0.0;
foreachvalue (Framework* framework, frameworks.registered) {
- if (framework->connected) {
+ if (framework->connected()) {
count++;
}
}
@@ -8195,7 +8195,7 @@ double Master::_frameworks_disconnected()
{
double count = 0.0;
foreachvalue (Framework* framework, frameworks.registered) {
- if (!framework->connected) {
+ if (!framework->connected()) {
count++;
}
}
http://git-wip-us.apache.org/repos/asf/mesos/blob/b9b6e9fc/src/master/master.hpp
----------------------------------------------------------------------
diff --git a/src/master/master.hpp b/src/master/master.hpp
index b444b23..9f5929c 100644
--- a/src/master/master.hpp
+++ b/src/master/master.hpp
@@ -2178,11 +2178,21 @@ private:
};
-// Information about a connected or completed framework.
// TODO(bmahler): Keeping the task and executor information in sync
// across the Slave and Framework structs is error prone!
struct Framework
{
+ enum State
+ {
+ // Framework is currently connected. Note that frameworks must
+ // also be `active` to be eligible to receive offers.
+ CONNECTED,
+
+ // Framework was previously connected to this master. A framework
+ // becomes disconnected when there is a socket error.
+ DISCONNECTED
+ };
+
Framework(Master* const _master,
const Flags& masterFlags,
const FrameworkInfo& _info,
@@ -2191,7 +2201,7 @@ struct Framework
: master(_master),
info(_info),
pid(_pid),
- connected(true),
+ state(CONNECTED),
active(true),
registeredTime(time),
reregisteredTime(time),
@@ -2205,7 +2215,7 @@ struct Framework
: master(_master),
info(_info),
http(_http),
- connected(true),
+ state(CONNECTED),
active(true),
registeredTime(time),
reregisteredTime(time),
@@ -2263,7 +2273,7 @@ struct Framework
template <typename Message>
void send(const Message& message)
{
- if (!connected) {
+ if (!connected()) {
LOG(WARNING) << "Master attempted to send message to disconnected"
<< " framework " << *this;
}
@@ -2482,13 +2492,13 @@ struct Framework
// Closes the HTTP connection and stops the heartbeat.
//
- // TODO(vinod): Currently 'connected' variable is set separately
+ // TODO(vinod): Currently `state` variable is set separately
// from this method. We need to make sure these are in sync.
void closeHttpConnection()
{
CHECK_SOME(http);
- if (connected && !http.get().close()) {
+ if (connected() && !http.get().close()) {
LOG(WARNING) << "Failed to close HTTP pipe for " << *this;
}
@@ -2515,6 +2525,8 @@ struct Framework
process::spawn(heartbeater.get().get());
}
+ bool connected() const { return state == CONNECTED; }
+
Master* const master;
FrameworkInfo info;
@@ -2526,12 +2538,14 @@ struct Framework
Option<HttpConnection> http;
Option<process::UPID> pid;
- // Framework becomes disconnected when the socket closes.
- bool connected;
+ State state;
// Framework becomes deactivated when it is disconnected or
// the master receives a DeactivateFrameworkMessage.
// No offers will be made to a deactivated framework.
+ //
+ // TODO(neilc): Consider replacing this with an additional
+ // `state` enumeration value (MESOS-6719).
bool active;
process::Time registeredTime;
http://git-wip-us.apache.org/repos/asf/mesos/blob/b9b6e9fc/src/master/quota_handler.cpp
----------------------------------------------------------------------
diff --git a/src/master/quota_handler.cpp b/src/master/quota_handler.cpp
index 5578663..6e6e737 100644
--- a/src/master/quota_handler.cpp
+++ b/src/master/quota_handler.cpp
@@ -134,7 +134,7 @@ void Master::QuotaHandler::rescindOffers(const QuotaInfo& request) const
if (master->activeRoles.contains(role)) {
Role* roleState = master->activeRoles[role];
foreachvalue (const Framework* framework, roleState->frameworks) {
- if (framework->connected && framework->active) {
+ if (framework->connected() && framework->active) {
++frameworksInRole;
}
}
[7/9] mesos git commit: Don't send PIDs of disconnected frameworks to
re-registering agents.
Posted by vi...@apache.org.
Don't send PIDs of disconnected frameworks to re-registering agents.
Review: https://reviews.apache.org/r/54380/
Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/310864a4
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/310864a4
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/310864a4
Branch: refs/heads/master
Commit: 310864a45932b40e9c682f0ef2ce5dac70f5ef42
Parents: c0504ff
Author: Neil Conway <ne...@gmail.com>
Authored: Wed Dec 7 17:04:46 2016 -0800
Committer: Vinod Kone <vi...@gmail.com>
Committed: Wed Dec 7 17:05:49 2016 -0800
----------------------------------------------------------------------
src/master/master.cpp | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mesos/blob/310864a4/src/master/master.cpp
----------------------------------------------------------------------
diff --git a/src/master/master.cpp b/src/master/master.cpp
index b496783..588b8cc 100644
--- a/src/master/master.cpp
+++ b/src/master/master.cpp
@@ -5534,9 +5534,9 @@ void Master::__reregisterSlave(
foreach (const FrameworkID& frameworkId, ids) {
Framework* framework = getFramework(frameworkId);
- // TODO(neilc): It doesn't seem useful to send the PIDs of
- // frameworks that are not connected.
- if (framework != nullptr) {
+ // We don't need to send the PIDs of disconnected frameworks to
+ // re-registering slaves.
+ if (framework != nullptr && framework->connected()) {
UpdateFrameworkMessage message;
message.mutable_framework_id()->MergeFrom(framework->id());
[8/9] mesos git commit: Removed an inaccurate comment.
Posted by vi...@apache.org.
Removed an inaccurate comment.
Review: https://reviews.apache.org/r/54387/
Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/89c72283
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/89c72283
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/89c72283
Branch: refs/heads/master
Commit: 89c722839b14098c6c9f6563123b408b70140266
Parents: 310864a
Author: Neil Conway <ne...@gmail.com>
Authored: Wed Dec 7 17:04:53 2016 -0800
Committer: Vinod Kone <vi...@gmail.com>
Committed: Wed Dec 7 17:05:51 2016 -0800
----------------------------------------------------------------------
src/master/master.cpp | 3 ---
1 file changed, 3 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mesos/blob/89c72283/src/master/master.cpp
----------------------------------------------------------------------
diff --git a/src/master/master.cpp b/src/master/master.cpp
index 588b8cc..353e6ea 100644
--- a/src/master/master.cpp
+++ b/src/master/master.cpp
@@ -7240,9 +7240,6 @@ void Master::failoverFramework(Framework* framework, const UPID& newPid)
void Master::_failoverFramework(Framework* framework)
{
// Remove the framework's offers (if they weren't removed before).
- // We do this after we have updated the pid and sent the framework
- // registered message so that the allocator can immediately re-offer
- // these resources to this framework if it wants.
foreach (Offer* offer, utils::copy(framework->offers)) {
allocator->recoverResources(
offer->framework_id(), offer->slave_id(), offer->resources(), None());