blob: 0b693d2564310d2a71f31e991672117d91983452 [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <mutex>
#include <string>
#include <vector>
#include <mesos/hook.hpp>
#include <mesos/module/hook.hpp>
#include <stout/check.hpp>
#include <stout/foreach.hpp>
#include <stout/nothing.hpp>
#include <stout/strings.hpp>
#include <stout/try.hpp>
#include "hook/manager.hpp"
#include "module/manager.hpp"
using std::string;
using std::vector;
using mesos::modules::ModuleManager;
namespace mesos {
namespace internal {
static std::mutex mutex;
static hashmap<string, Hook*> availableHooks;
Try<Nothing> HookManager::initialize(const string& hookList)
{
synchronized (mutex) {
const vector<string> hooks = strings::split(hookList, ",");
foreach (const string& hook, hooks) {
if (availableHooks.contains(hook)) {
return Error("Hook module '" + hook + "' already loaded");
}
if (!ModuleManager::contains<Hook>(hook)) {
return Error("No hook module named '" + hook + "' available");
}
// Let's create an instance of the hook module.
Try<Hook*> module = ModuleManager::create<Hook>(hook);
if (module.isError()) {
return Error(
"Failed to instantiate hook module '" + hook + "': " +
module.error());
}
// Add the hook module to the list of available hooks.
availableHooks[hook] = module.get();
}
}
return Nothing();
}
Try<Nothing> HookManager::unload(const std::string& hookName)
{
synchronized (mutex) {
if (!availableHooks.contains(hookName)) {
return Error(
"Error unloading hook module '" + hookName + "': module not loaded");
}
// Now remove the hook from the list of available hooks.
availableHooks.erase(hookName);
}
return Nothing();
}
bool HookManager::hooksAvailable()
{
synchronized (mutex) {
return !availableHooks.empty();
}
}
Labels HookManager::masterLaunchTaskLabelDecorator(
const TaskInfo& taskInfo,
const FrameworkInfo& frameworkInfo,
const SlaveInfo& slaveInfo)
{
synchronized (mutex) {
// We need a mutable copy of the task info and set the new
// labels after each hook invocation. Otherwise, the last hook
// will be the only effective hook setting the labels.
TaskInfo taskInfo_ = taskInfo;
foreachpair (const string& name, Hook* hook, availableHooks) {
const Result<Labels> result =
hook->masterLaunchTaskLabelDecorator(
taskInfo_,
frameworkInfo,
slaveInfo);
// NOTE: If the hook returns None(), the task labels won't be
// changed.
if (result.isSome()) {
taskInfo_.mutable_labels()->CopyFrom(result.get());
} else if (result.isError()) {
LOG(WARNING) << "Master label decorator hook failed for module '"
<< name << "': " << result.error();
}
}
return taskInfo_.labels();
}
}
Labels HookManager::slaveRunTaskLabelDecorator(
const TaskInfo& taskInfo,
const ExecutorInfo& executorInfo,
const FrameworkInfo& frameworkInfo,
const SlaveInfo& slaveInfo)
{
synchronized (mutex) {
TaskInfo taskInfo_ = taskInfo;
foreachpair (const string& name, Hook* hook, availableHooks) {
const Result<Labels> result = hook->slaveRunTaskLabelDecorator(
taskInfo_, executorInfo, frameworkInfo, slaveInfo);
// NOTE: If the hook returns None(), the task labels won't be
// changed.
if (result.isSome()) {
taskInfo_.mutable_labels()->CopyFrom(result.get());
} else if (result.isError()) {
LOG(WARNING) << "Slave label decorator hook failed for module '"
<< name << "': " << result.error();
}
}
return taskInfo_.labels();
}
}
Environment HookManager::slaveExecutorEnvironmentDecorator(
ExecutorInfo executorInfo)
{
synchronized (mutex) {
foreachpair (const string& name, Hook* hook, availableHooks) {
const Result<Environment> result =
hook->slaveExecutorEnvironmentDecorator(executorInfo);
// NOTE: If the hook returns None(), the environment won't be
// changed.
if (result.isSome()) {
executorInfo.mutable_command()->mutable_environment()->CopyFrom(
result.get());
} else if (result.isError()) {
LOG(WARNING) << "Slave environment decorator hook failed for module '"
<< name << "': " << result.error();
}
}
return executorInfo.command().environment();
}
}
void HookManager::slaveRemoveExecutorHook(
const FrameworkInfo& frameworkInfo,
const ExecutorInfo& executorInfo)
{
foreachpair (const string& name, Hook* hook, availableHooks) {
const Try<Nothing> result =
hook->slaveRemoveExecutorHook(frameworkInfo, executorInfo);
if (result.isError()) {
LOG(WARNING) << "Slave remove executor hook failed for module '"
<< name << "': " << result.error();
}
}
}
Labels HookManager::slaveTaskStatusLabelDecorator(
const FrameworkID& frameworkId,
TaskStatus status)
{
synchronized (mutex) {
foreachpair (const string& name, Hook* hook, availableHooks) {
const Result<Labels> result =
hook->slaveTaskStatusLabelDecorator(frameworkId, status);
// NOTE: Labels remain unchanged if the hook returns None().
if (result.isSome()) {
status.mutable_labels()->CopyFrom(result.get());
} else if (result.isError()) {
LOG(WARNING) << "Slave TaskStatus label decorator hook failed for "
<< "module '" << name << "': " << result.error();
}
}
return status.labels();
}
}
} // namespace internal {
} // namespace mesos {