Apache Mesos
manager.hpp
Go to the documentation of this file.
1 // Licensed to the Apache Software Foundation (ASF) under one
2 // or more contributor license agreements. See the NOTICE file
3 // distributed with this work for additional information
4 // regarding copyright ownership. The ASF licenses this file
5 // to you under the Apache License, Version 2.0 (the
6 // "License"); you may not use this file except in compliance
7 // with the License. You may obtain a copy of the License at
8 //
9 // http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 
17 #ifndef __MODULE_MANAGER_HPP__
18 #define __MODULE_MANAGER_HPP__
19 
20 #include <list>
21 #include <mutex>
22 #include <string>
23 #include <vector>
24 
25 #include <glog/logging.h>
26 
27 #include <mesos/mesos.hpp>
28 #include <mesos/module.hpp>
29 
30 #include <mesos/module/module.hpp>
31 
32 #include <process/owned.hpp>
33 
34 #include <stout/check.hpp>
35 #include <stout/dynamiclibrary.hpp>
36 #include <stout/hashmap.hpp>
37 #include <stout/nothing.hpp>
38 #include <stout/synchronized.hpp>
39 #include <stout/try.hpp>
40 
41 #include "messages/messages.hpp"
42 
43 namespace mesos {
44 namespace modules {
45 
46 // Mesos module loading.
47 //
48 // Phases:
49 
50 // 1. Load dynamic libraries that contain modules from the Modules
51 // instance which may have come from a commandline flag.
52 // 2. Verify versions and compatibilities.
53 // a) Library compatibility. (Module API version check)
54 // b) Module compatibility. (Module Kind version check)
55 // 3. Instantiate singleton per module. (happens in the library)
56 // 4. Bind reference to use case. (happens in Mesos)
57 
58 
60 {
61 public:
62  // Loads dynamic libraries, and verifies the compatibility of the
63  // modules in them.
64  //
65  // NOTE: If loading fails at a particular library we don't unload
66  // all of the already loaded libraries.
67  static Try<Nothing> load(const Modules& modules)
68  {
69  return loadManifest(modules);
70  }
71 
72  // NOTE: If loading fails at a particular library we don't unload
73  // all of the already loaded libraries.
74  static Try<Nothing> load(const std::string& modulesDir);
75 
76  // create() should be called only after load().
77  template <typename T>
78  static Try<T*> create(
79  const std::string& moduleName,
80  const Option<Parameters>& params = None())
81  {
82  synchronized (mutex) {
83  if (!moduleBases.contains(moduleName)) {
84  return Error(
85  "Module '" + moduleName + "' unknown");
86  }
87 
88  Module<T>* module = (Module<T>*) moduleBases[moduleName];
89  if (module->create == nullptr) {
90  return Error(
91  "Error creating module instance for '" + moduleName + "': "
92  "create() method not found");
93  }
94 
95  std::string expectedKind = kind<T>();
96  if (expectedKind != module->kind) {
97  return Error(
98  "Error creating module instance for '" + moduleName + "': "
99  "module is of kind '" + module->kind + "', but the requested "
100  "kind is '" + expectedKind + "'");
101  }
102 
103  T* instance =
104  module->create(
105  params.isSome() ? params.get() : moduleParameters[moduleName]);
106  if (instance == nullptr) {
107  return Error("Error creating Module instance for '" + moduleName + "'");
108  }
109  return instance;
110  }
111  }
112 
113  template <typename T>
114  static bool contains(const std::string& moduleName)
115  {
116  synchronized (mutex) {
117  return (moduleBases.contains(moduleName) &&
118  moduleBases[moduleName]->kind == stringify(kind<T>()));
119  }
120  }
121 
122  // Returns all module names that have been loaded that implement the
123  // specified interface 'T'. For example:
124  //
125  // std::vector<std::string> modules = ModuleManager::find<Hook>();
126  //
127  // Will return all of the module names for modules that implement
128  // the `Hook` interface.
129  template <typename T>
130  static std::vector<std::string> find()
131  {
132  std::vector<std::string> names;
133 
134  synchronized (mutex) {
135  foreachpair (const std::string& name, ModuleBase* base, moduleBases) {
136  if (base->kind == stringify(kind<T>())) {
137  names.push_back(name);
138  }
139  }
140  }
141 
142  return names;
143  }
144 
145  // Exposed just for testing so that we can unload a given
146  // module and remove it from the list of `ModuleBase`.
147  static Try<Nothing> unload(const std::string& moduleName);
148 
149 private:
150  static void initialize();
151 
152  static Try<Nothing> loadManifest(const Modules& modules);
153 
154  static Try<Nothing> verifyModule(
155  const std::string& moduleName,
156  const ModuleBase* moduleBase);
157 
158  // Allow multiple calls to `load()` by verifying that the modules with same
159  // name are indeed identical. Thus, multiple loadings of a module manifest
160  // are harmless.
161  static Try<Nothing> verifyIdenticalModule(
162  const std::string& libraryName,
163  const Modules::Library::Module& module,
164  const ModuleBase* base);
165 
166  static std::mutex mutex;
167 
168  static hashmap<std::string, std::string> kindToVersion;
169 
170  // Mapping from module name to the actual `ModuleBase`. If two
171  // modules from different libraries have the same name then the last
172  // one specified in the protobuf `Modules` will be picked.
173  static hashmap<std::string, ModuleBase*> moduleBases;
174 
175  // Module-specific command-line parameters.
176  static hashmap<std::string, Parameters> moduleParameters;
177 
178  // A list of dynamic libraries to keep the object from getting
179  // destructed.
180  // NOTE: We do leak loaded dynamic libraries. This is to allow
181  // modules to make use of e.g., libprocess which otherwise could
182  // lead to situations where libprocess (which we depend on ourself)
183  // is unloaded before the destructor of below `static` is called.
184  // Unloading the dynamic library could then lead to the linker
185  // attempting to unload the libprocess loaded from the module which
186  // is not there anymore.
187  static hashmap<std::string, DynamicLibrary*> dynamicLibraries;
188 
189  // Module to library name mapping.
190  static hashmap<std::string, std::string> moduleLibraries;
191 };
192 
193 } // namespace modules {
194 } // namespace mesos {
195 
196 #endif // __MODULE_MANAGER_HPP__
Definition: errorbase.hpp:36
Definition: option.hpp:28
static bool contains(const std::string &moduleName)
Definition: manager.hpp:114
Definition: check.hpp:33
static Try< T * > create(const std::string &moduleName, const Option< Parameters > &params=None())
Definition: manager.hpp:78
Definition: module.hpp:56
event_base * base
Definition: manager.hpp:59
static Try< Nothing > load(const Modules &modules)
Definition: manager.hpp:67
static Try< Nothing > unload(const std::string &moduleName)
const char * kind
Definition: module.hpp:78
Definition: spec.hpp:30
#define foreachpair(KEY, VALUE, ELEMS)
Definition: foreach.hpp:51
Definition: none.hpp:27
std::string stringify(int flags)
static std::vector< std::string > find()
Definition: manager.hpp:130
constexpr const char * name
Definition: shell.hpp:43
Definition: module.hpp:97