| 10368 | |
| 10369 | |
| 10370 | void Master::removeFramework(Framework* framework) |
| 10371 | { |
| 10372 | CHECK_NOTNULL(framework); |
| 10373 | |
| 10374 | LOG(INFO) << "Removing framework " << *framework; |
| 10375 | |
| 10376 | if (framework->active()) { |
| 10377 | // Deactivate framework, but don't bother rescinding offers |
| 10378 | // because the framework is being removed. |
| 10379 | deactivate(framework, false); |
| 10380 | } |
| 10381 | |
| 10382 | // The framework's offers should have been removed when the |
| 10383 | // framework was deactivated. |
| 10384 | CHECK(framework->offers.empty()); |
| 10385 | CHECK(framework->inverseOffers.empty()); |
| 10386 | |
| 10387 | foreachvalue (Slave* slave, slaves.registered) { |
| 10388 | // Tell slaves to shutdown the framework. |
| 10389 | ShutdownFrameworkMessage message; |
| 10390 | message.mutable_framework_id()->MergeFrom(framework->id()); |
| 10391 | send(slave->pid, message); |
| 10392 | } |
| 10393 | |
| 10394 | // Remove pointers to the framework's tasks in slaves and mark those |
| 10395 | // tasks as completed. |
| 10396 | foreachvalue (Task* task, utils::copy(framework->tasks)) { |
| 10397 | Slave* slave = slaves.registered.get(task->slave_id()); |
| 10398 | |
| 10399 | // Since we only find out about tasks when the slave reregisters, |
| 10400 | // it must be the case that the slave exists! |
| 10401 | CHECK(slave != nullptr) |
| 10402 | << "Unknown agent " << task->slave_id() |
| 10403 | << " for task " << task->task_id(); |
| 10404 | |
| 10405 | // The task is implicitly killed, and TASK_KILLED is the closest |
| 10406 | // state we have by now. We mark the task and remove it, without |
| 10407 | // sending the update. However, a task may finish during the |
| 10408 | // executor graceful shutdown period. By marking such task as |
| 10409 | // killed and moving it to completed, we lose the opportunity to |
| 10410 | // collect the possible finished status. We tolerate this, |
| 10411 | // because we expect that if the framework has been asked to shut |
| 10412 | // down, its user is not interested in results anymore. |
| 10413 | // |
| 10414 | // TODO(alex): Consider a more descriptive state, e.g. TASK_ABANDONED. |
| 10415 | // |
| 10416 | // TODO(neilc): Marking the task KILLED before it has actually |
| 10417 | // terminated is misleading. Instead, we should consider leaving |
| 10418 | // the task in its current state at the master; if/when the agent |
| 10419 | // shuts down the framework, we should arrange for a terminal |
| 10420 | // status update to be delivered to the master and update the |
| 10421 | // state of the task at that time (MESOS-6608). |
| 10422 | const StatusUpdate& update = protobuf::createStatusUpdate( |
| 10423 | task->framework_id(), |
| 10424 | task->slave_id(), |
| 10425 | task->task_id(), |
| 10426 | TASK_KILLED, |
| 10427 | TaskStatus::SOURCE_MASTER, |
no test coverage detected