blob: b0ce8882f50d2aebf9f26ce8863a3ca77bdc4c9a [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 "core/extension/ExtensionManager.h"
#include <algorithm>
#include "core/logging/LoggerConfiguration.h"
#include "core/extension/Extension.h"
#include "minifi-cpp/agent/agent_docs.h"
#include "utils/file/FilePattern.h"
#include "minifi-cpp/agent/agent_version.h"
#include "core/extension/Utils.h"
#include "properties/Configuration.h"
#include "utils/Locations.h"
namespace org::apache::nifi::minifi::core::extension {
ExtensionManager::ExtensionManager(const std::shared_ptr<Configure>& config): logger_(logging::LoggerFactory<ExtensionManager>::getLogger()) {
logger_->log_trace("Initializing extensions");
if (!config) {
logger_->log_error("Missing configuration");
return;
}
const std::string pattern = [&] {
/**
* Comma separated list of path patterns. Patterns prepended with "!" result in the exclusion
* of the extensions matching that pattern, unless some subsequent pattern re-enables it.
*/
if (const auto opt_pattern = config->get(minifi::Configuration::nifi_extension_path)) {
return *opt_pattern;
};
auto default_extension_path = utils::getDefaultExtensionsPattern();
logger_->log_warn("No extension path is provided in properties, using default: '{}'", default_extension_path);
return std::string(default_extension_path);
}();
auto candidates = utils::file::match(utils::file::FilePattern(pattern, [&] (std::string_view subpattern, std::string_view error_msg) {
logger_->log_error("Error in subpattern '{}': {}", subpattern, error_msg);
}));
for (const auto& candidate : candidates) {
auto library = internal::asDynamicLibrary(candidate);
if (!library) {
continue;
}
const auto library_type = library->verify(logger_);
if (library_type == internal::Invalid) {
logger_->log_warn("Skipping library '{}' at '{}': failed verification, different build?",
library->name, library->getFullPath());
continue;
}
logger_->log_trace("Verified library {} at {} as {} extension", library->name, library->getFullPath(), magic_enum::enum_name(library_type));
auto extension = std::make_unique<Extension>(library->name, library->getFullPath());
if (!extension->load()) {
// error already logged by method
continue;
}
// some shared libraries might need to be loaded into the global namespace exposing
// their definitions (e.g. python script extension)
if (extension->findSymbol("LOAD_MODULE_AS_GLOBAL")) {
// reload library as global
if (!extension->load(true)) {
continue;
}
}
if (!extension->initialize(config)) {
logger_->log_error("Failed to initialize extension '{}' at '{}'", library->name, library->getFullPath());
} else {
extensions_.push_back(std::move(extension));
}
}
}
} // namespace org::apache::nifi::minifi::core::extension