Support BE plugin framework, include: * update Plugin Manager, support Plugin find method * support Builtin-Plugin register method * plugin install/uninstall process * PluginLoader: * dynamic install and check Plugin .so file * dynamic uninstall and check Plugin status * PluginZip: * support plugin remote/local .zip file download and extract TODO: * We should support a PluginContext to transmit necessary system variable when the plugin's init/close method invoke * Add the entry which is BE dynamic Plugin install/uninstall process, include: * The FE send install/uninstall Plugin statement (RPC way) * The FE meta update request with Plugin list information * The FE operation request(update/query) with Plugin (maybe don't need) * Add the plugin status upload way * Load already install Plugin when BE start
This commit is contained in:
131
be/src/plugin/plugin_zip.cpp
Normal file
131
be/src/plugin/plugin_zip.cpp
Normal file
@ -0,0 +1,131 @@
|
||||
// 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 <boost/algorithm/string/predicate.hpp>
|
||||
#include <string.h>
|
||||
|
||||
#include "plugin/plugin_zip.h"
|
||||
|
||||
#include "http/http_client.h"
|
||||
#include "gutil/strings/util.h"
|
||||
#include "gutil/strings/substitute.h"
|
||||
#include "util/file_utils.h"
|
||||
#include "util/md5.h"
|
||||
#include "util/time.h"
|
||||
#include "util/zip_util.h"
|
||||
#include "util/slice.h"
|
||||
#include "env/env.h"
|
||||
|
||||
namespace doris {
|
||||
|
||||
using namespace strings;
|
||||
|
||||
bool is_local_source(const std::string& source) {
|
||||
if (HasPrefixString(source, "http") || HasPrefixString(source, "https")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
PluginZip::~PluginZip() {
|
||||
for (auto& p : _clean_paths) {
|
||||
WARN_IF_ERROR(FileUtils::remove_all(p), "clean plugin_zip temp path failed: " + p);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Status PluginZip::extract(const std::string& target_dir, const std::string& plugin_name) {
|
||||
// check plugin install path
|
||||
std::string plugin_install_path = Substitute("$0/$1", target_dir, plugin_name);
|
||||
|
||||
if (FileUtils::check_exist(plugin_install_path)) {
|
||||
return Status::AlreadyExist(Substitute("plugin $0 already install!", plugin_name));
|
||||
}
|
||||
|
||||
if (!FileUtils::check_exist(target_dir)) {
|
||||
RETURN_IF_ERROR(FileUtils::create_dir(target_dir));
|
||||
}
|
||||
|
||||
std::string zip_path = _source;
|
||||
if (!is_local_source(_source)) {
|
||||
zip_path = Substitute("$0/.temp_$1_$2.zip", target_dir, GetCurrentTimeMicros(), plugin_name);
|
||||
_clean_paths.push_back(zip_path);
|
||||
|
||||
RETURN_IF_ERROR(download(zip_path));
|
||||
}
|
||||
|
||||
// zip extract
|
||||
ZipFile zip_file(zip_path);
|
||||
RETURN_IF_ERROR(zip_file.extract(target_dir, plugin_name));
|
||||
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
Status PluginZip::download(const std::string& zip_path) {
|
||||
// download .zip
|
||||
Status status;
|
||||
HttpClient client;
|
||||
Md5Digest digest;
|
||||
|
||||
std::unique_ptr<WritableFile> file;
|
||||
|
||||
RETURN_IF_ERROR(Env::Default()->new_writable_file(zip_path, &file));
|
||||
RETURN_IF_ERROR(client.init(_source));
|
||||
|
||||
auto download_cb = [&status, &digest, &file](const void* data, size_t length) {
|
||||
digest.update(data, length);
|
||||
|
||||
Slice slice((const char *)data, length);
|
||||
status = file->append(slice);
|
||||
if (!status.ok()) {
|
||||
LOG(WARNING) << "fail to download data, file: " << file->filename()
|
||||
<< ", error: " << status.to_string();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
RETURN_IF_ERROR(client.execute(download_cb));
|
||||
RETURN_IF_ERROR(status);
|
||||
RETURN_IF_ERROR(file->flush(WritableFile::FLUSH_ASYNC));
|
||||
RETURN_IF_ERROR(file->sync());
|
||||
RETURN_IF_ERROR(file->close());
|
||||
|
||||
// md5 check
|
||||
HttpClient md5_client;
|
||||
RETURN_IF_ERROR(md5_client.init(_source + ".md5"));
|
||||
|
||||
std::string expect;
|
||||
auto download_md5_cb = [&status, &expect](const void* data, size_t length) {
|
||||
expect = std::string((const char*) data, length);
|
||||
return true;
|
||||
};
|
||||
|
||||
RETURN_IF_ERROR(md5_client.execute(download_md5_cb));
|
||||
|
||||
digest.digest();
|
||||
if (0 != strncmp(digest.hex().c_str(), expect.c_str(), 32)) {
|
||||
return Status::InternalError(
|
||||
Substitute("plugin install checksum failed. expect: $0, actual:$1", expect, digest.hex()));
|
||||
}
|
||||
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user