blob: cab67a8b1ee7164bb3cb2a8b24e1a6e05b40fd19 [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.
*/
#ifndef __MODULE_MANAGER_HPP__
#define __MODULE_MANAGER_HPP__
#include <list>
#include <mutex>
#include <string>
#include <vector>
#include <glog/logging.h>
#include <mesos/mesos.hpp>
#include <mesos/module.hpp>
#include <mesos/module/module.hpp>
#include <process/owned.hpp>
#include <stout/check.hpp>
#include <stout/dynamiclibrary.hpp>
#include <stout/hashmap.hpp>
#include <stout/synchronized.hpp>
#include "messages/messages.hpp"
namespace mesos {
namespace modules {
// Mesos module loading.
//
// Phases:
// 1. Load dynamic libraries that contain modules from the Modules
// instance which may have come from a commandline flag.
// 2. Verify versions and compatibilities.
// a) Library compatibility. (Module API version check)
// b) Module compatibility. (Module Kind version check)
// 3. Instantiate singleton per module. (happens in the library)
// 4. Bind reference to use case. (happens in Mesos)
class ModuleManager
{
public:
// Loads dynamic libraries, and verifies the compatibility of the
// modules in them.
//
// NOTE: If loading fails at a particular library we don't unload
// all of the already loaded libraries.
static Try<Nothing> load(const Modules& modules);
// create() should be called only after load().
template <typename T>
static Try<T*> create(const std::string& moduleName)
{
synchronized (mutex) {
if (!moduleBases.contains(moduleName)) {
return Error(
"Module '" + moduleName + "' unknown");
}
Module<T>* module = (Module<T>*) moduleBases[moduleName];
if (module->create == NULL) {
return Error(
"Error creating module instance for '" + moduleName + "': "
"create() method not found");
}
std::string expectedKind = kind<T>();
if (expectedKind != module->kind) {
return Error(
"Error creating module instance for '" + moduleName + "': "
"module is of kind '" + module->kind + "', but the requested "
"kind is '" + expectedKind + "'");
}
T* instance = module->create(moduleParameters[moduleName]);
if (instance == NULL) {
return Error("Error creating Module instance for '" + moduleName + "'");
}
return instance;
}
}
template <typename T>
static bool contains(const std::string& moduleName)
{
synchronized (mutex) {
return (moduleBases.contains(moduleName) &&
moduleBases[moduleName]->kind == stringify(kind<T>()));
}
}
// Returns all module names that have been loaded that implement the
// specified interface 'T'. For example:
//
// std::vector<std::string> modules = ModuleManager::find<Hook>();
//
// Will return all of the module names for modules that implement
// the Isolator interface.
template <typename T>
static std::vector<std::string> find()
{
std::vector<std::string> names;
synchronized (mutex) {
foreachpair (const std::string& name, ModuleBase* base, moduleBases) {
if (base->kind == stringify(kind<T>())) {
names.push_back(name);
}
}
}
return names;
}
// Exposed just for testing so that we can unload a given
// module and remove it from the list of ModuleBases.
static Try<Nothing> unload(const std::string& moduleName);
private:
static void initialize();
static Try<Nothing> verifyModule(
const std::string& moduleName,
const ModuleBase* moduleBase);
static std::mutex mutex;
static hashmap<const std::string, std::string> kindToVersion;
// Mapping from "module name" to the actual ModuleBase. If two
// modules from different libraries have the same name then the last
// one specified in the protobuf Modules will be picked.
static hashmap<const std::string, ModuleBase*> moduleBases;
// Module-specific command-line parameters.
static hashmap<const std::string, Parameters> moduleParameters;
// A list of dynamic libraries to keep the object from getting
// destructed. Destroying the DynamicLibrary object could result in
// unloading the library from the process memory.
static hashmap<const std::string, process::Owned<DynamicLibrary>>
dynamicLibraries;
};
} // namespace modules {
} // namespace mesos {
#endif // __MODULE_MANAGER_HPP__