Skip to content

Commit

Permalink
[License Manager Adaption] Integrate license manager connector into M…
Browse files Browse the repository at this point in the history
…eta service (vesoft-inc#2568)
  • Loading branch information
Aiee authored Apr 10, 2023
1 parent 3a9df7c commit 93987e5
Show file tree
Hide file tree
Showing 33 changed files with 1,449 additions and 280 deletions.
4 changes: 4 additions & 0 deletions conf/nebula-metad.conf.default
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
--pid_file=pids/nebula-metad.pid
--license_path=share/resources/nebula.license

########## enterprise license ##########
# The address of license manager in format of ip:port
--license_manager_url=license.vesoft-inc.com:9119

########## logging ##########
# The directory to host logging files
--log_dir=logs
Expand Down
6 changes: 6 additions & 0 deletions conf/nebula-metad.conf.production
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,14 @@
--daemonize=true
# The file to host the process id
--pid_file=pids/nebula-metad.pid

# TODO(Aiee): remove this option
--license_path=share/resources/nebula.license

########## enterprise license ##########
# The address of license manager in format of ip:port
--license_manager_url=license.vesoft-inc.com:9119

########## logging ##########
# The directory to host logging files
--log_dir=logs
Expand Down
98 changes: 19 additions & 79 deletions src/clients/meta/MetaClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
#include "common/base/Base.h"
#include "common/base/MurmurHash2.h"
#include "common/conf/Configuration.h"
#include "common/encryption/License.h"
#include "common/http/HttpClient.h"
#include "common/meta/NebulaSchemaProvider.h"
#include "common/network/NetworkUtils.h"
Expand Down Expand Up @@ -64,10 +63,6 @@ DEFINE_validator(failed_login_attempts, &ValidateFailedLoginAttempts);
namespace nebula {
namespace meta {

// The period used to request enterprise license from the meta service in seconds.
// 28800 secs is 8 hours.
const uint32 kLicenseCheckPeriodInSecs = 28800;

// Update the hardware information every hour.
const uint32 kHwUploadPeriodInSecs = 3600;

Expand Down Expand Up @@ -143,10 +138,7 @@ bool MetaClient::waitForMetadReady(int count, int retryIntervalSecs) {
if (!waitForMetadReadyMock(count, retryIntervalSecs)) {
return false;
}
// Repeatedly request and check license from meta
size_t delayMS = FLAGS_heartbeat_interval_secs * 1000 + folly::Random::rand32(900);
bgThread_->addDelayTask(delayMS, &MetaClient::licenseCheckThreadFunc, this);
bgThread_->addDelayTask(delayMS, &MetaClient::updateHwThreadFunc, this);
bgThread_->addDelayTask(1 * 1000, &MetaClient::updateHwThreadFunc, this);

return ready_;
}
Expand Down Expand Up @@ -1333,8 +1325,24 @@ Status MetaClient::handleResponse(const RESP& resp) {
return Status::Error("Invalid variable!");
case nebula::cpp2::ErrorCode::E_VARIABLE_TYPE_VALUE_MISMATCH:
return Status::Error("Variable type and value mismatch!");
case nebula::cpp2::ErrorCode::E_NODE_NUMBER_EXCEED_LIMIT:
return Status::Error("[License] Nodes number exceeds the limit!");
case nebula::cpp2::ErrorCode::E_NODE_NUMBER_EXCEED_LIMIT: {
LOG(ERROR) << "[License Manager] The number of nodes exceeds the limit, shutting down the "
"current node!";
std::raise(SIGTERM);
return Status::Error(" Nodes number exceeds the limit!");
}
case nebula::cpp2::ErrorCode::E_TOTAL_CPU_CORE_EXCEED_LIMIT: {
LOG(ERROR) << "[License Manager] The number of CPU cores exceeds the limit, shutting down "
"the current node!";
std::raise(SIGTERM);
return Status::Error(" Cpu cores exceeds the limit!");
}
case nebula::cpp2::ErrorCode::E_INVALID_LICENSE_MANAGER_STATUS: {
LOG(ERROR)
<< "[License Manager] Invalid license manager status, shutting down the current node!";
std::raise(SIGTERM);
return Status::Error(" Invalid license manager status!");
}
case nebula::cpp2::ErrorCode::E_SCHEMA_NAME_EXISTS:
return Status::Error("Schema with same name exists");
case nebula::cpp2::ErrorCode::E_RELATED_INDEX_EXISTS:
Expand Down Expand Up @@ -4829,74 +4837,6 @@ bool MetaClient::currentSpaceReadOnly(GraphSpaceID spaceId) {
}
}

StatusOr<cpp2::GetLicenseResp> MetaClient::getLicenseFromMeta() {
memory::MemoryCheckOffGuard g;
cpp2::GetLicenseReq req;
folly::Promise<StatusOr<cpp2::GetLicenseResp>> promise;
auto future = promise.getFuture();
getResponse(
std::move(req),
[](auto client, auto request) { return client->future_getLicense(request); },
[](cpp2::GetLicenseResp&& resp) -> decltype(auto) { return std::move(resp); },
std::move(promise));

auto respStatus = std::move(future).get();
if (!respStatus.ok()) {
return respStatus.status();
}
auto resp = std::move(respStatus).value();
if (resp.get_code() != nebula::cpp2::ErrorCode::SUCCEEDED) {
return Status::Error("Failed to get enterprise license from Meta service: %s",
resp.get_error_msg()->c_str());
}

return resp;
}

void MetaClient::licenseCheckThreadFunc() {
SCOPE_EXIT {
bgThread_->addDelayTask(
kLicenseCheckPeriodInSecs * 1000, &MetaClient::licenseCheckThreadFunc, this);
};

LOG(INFO) << "[License] Scheduled license checking started";
// Get the license content in string
auto ret = getLicenseFromMeta();
if (!ret.ok()) {
LOG(ERROR) << "[License] Failed to retrieve license from meta server, status:" << ret.status();
return;
}

// Validate license
// Get the license content and key from the response
auto licenseContent = ret.value().get_licenseContent();
auto licenseKey = ret.value().get_licenseKey();

// If the content or key is empty, it means the meta service could not read the license properly
if (licenseContent.empty() || licenseKey.empty()) {
LOG(ERROR) << "[License] Failed to get license, please check the license file is set in the "
"meta service correctly";
std::raise(SIGTERM);
return;
}

auto checkRes = encryption::License::checkContent(licenseContent, licenseKey);
if (!checkRes.ok()) {
LOG(ERROR) << "[License] Failed to validate license, status: " << checkRes;
std::raise(SIGTERM);
return;
}

// Check expiration
checkRes = encryption::License::checkExpiration(folly::parseJson(licenseContent));
if (!checkRes.ok()) {
LOG(ERROR) << "[License] License expiration check failed, status: " << checkRes;
std::raise(SIGTERM);
return;
}
LOG(INFO) << "[License] Scheduled license checking passed";
}

void MetaClient::updateHwThreadFunc() {
SCOPE_EXIT {
bgThread_->addDelayTask(kHwUploadPeriodInSecs * 1000, &MetaClient::updateHwThreadFunc, this);
Expand Down
7 changes: 0 additions & 7 deletions src/clients/meta/MetaClient.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
#include "common/base/Base.h"
#include "common/base/ObjectPool.h"
#include "common/base/StatusOr.h"
#include "common/encryption/License.h"
#include "common/meta/Common.h"
#include "common/meta/GflagsManager.h"
#include "common/meta/NebulaSchemaProvider.h"
Expand Down Expand Up @@ -866,12 +865,6 @@ class MetaClient : public BaseMetaClient {
return options_.localHost_.toString();
}

// TODO(Aiee) Deprecated when license manager is implemented
// Requests license content
StatusOr<cpp2::GetLicenseResp> getLicenseFromMeta();

// Repeatedly request and validate the license
void licenseCheckThreadFunc();
// Repeatedly update hardware information and store it in the cache
void updateHwThreadFunc();

Expand Down
9 changes: 4 additions & 5 deletions src/common/encryption/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,9 @@ nebula_add_library(
EncryptionUtils.cpp
)

# TODO(Aiee) add in next PR
# nebula_add_library(
# license_manager_obj OBJECT
# LicenseManagerConnector.cpp
# )
nebula_add_library(
license_manager_connector_obj OBJECT
LicenseManagerConnector.cpp
)

nebula_add_subdirectory(test)
41 changes: 18 additions & 23 deletions src/common/encryption/EncryptionUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,12 +80,12 @@ int EncryptionUtils::aes256GCMEncryptImpl(unsigned char* plaintext,
return ciphertext_len;
}

int EncryptionUtils::aes256GCMEncrypt(const std::string& plaintext,
const std::string& aad,
const std::string& key,
const std::string& iv,
std::string& ciphertext,
std::string& tag) {
Status EncryptionUtils::aes256GCMEncrypt(const std::string& plaintext,
const std::string& aad,
const std::string& key,
const std::string& iv,
std::string& ciphertext,
std::string& tag) {
auto len =
aes256GCMEncryptImpl(reinterpret_cast<unsigned char*>(const_cast<char*>(plaintext.c_str())),
plaintext.size(),
Expand All @@ -97,10 +97,10 @@ int EncryptionUtils::aes256GCMEncrypt(const std::string& plaintext,
reinterpret_cast<unsigned char*>(const_cast<char*>(ciphertext.c_str())),
reinterpret_cast<unsigned char*>(const_cast<char*>(tag.c_str())));
if (len < 1) {
return len;
return Status::Error("AES encryption failed");
}
ciphertext.resize(len);
return len;
return Status::OK();
}

// static
Expand Down Expand Up @@ -171,12 +171,12 @@ int EncryptionUtils::aes256GCMDecryptImpl(unsigned char* ciphertext,
return plaintext_len;
}

int EncryptionUtils::aes256GCMDecrypt(const std::string& ciphertext,
const std::string& aad,
const std::string& tag,
const std::string& key,
const std::string& iv,
std::string& plaintext) {
Status EncryptionUtils::aes256GCMDecrypt(const std::string& ciphertext,
const std::string& aad,
const std::string& tag,
const std::string& key,
const std::string& iv,
std::string& plaintext) {
auto len =
aes256GCMDecryptImpl(reinterpret_cast<unsigned char*>(const_cast<char*>(ciphertext.c_str())),
ciphertext.size(),
Expand All @@ -188,10 +188,11 @@ int EncryptionUtils::aes256GCMDecrypt(const std::string& ciphertext,
iv.size(),
reinterpret_cast<unsigned char*>(const_cast<char*>(plaintext.c_str())));
if (len < 1) {
return len;
return Status::Error("Aes decryption failed");
}
plaintext.resize(len);
return len;
// plaintext = plaintext.data();
return Status::OK();
}

std::string EncryptionUtils::base64Encode(std::string& input) {
Expand Down Expand Up @@ -244,13 +245,7 @@ StatusOr<std::string> EncryptionUtils::sha256Digest(const std::string& message)
// Clean up the digest context
EVP_MD_CTX_free(mdctx);

// Convert the digest value to a string
std::stringstream oss;
oss << std::hex << std::setfill('0');
for (unsigned int i = 0; i < digestLen; ++i) {
oss << std::setw(2) << static_cast<unsigned int>(digest[i]);
}
std::string digestStr = oss.str();
std::string digestStr(reinterpret_cast<char*>(digest), digestLen);

return digestStr;
}
Expand Down
26 changes: 14 additions & 12 deletions src/common/encryption/EncryptionUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,12 @@ class EncryptionUtils final {
// tag: the generated authentication tag (output parameter)
//
// Returns the length of the ciphertext or an error code.
static int aes256GCMEncrypt(const std::string& plaintext,
const std::string& aad,
const std::string& key,
const std::string& iv,
std::string& ciphertext,
std::string& tag);
static Status aes256GCMEncrypt(const std::string& plaintext,
const std::string& aad,
const std::string& key,
const std::string& iv,
std::string& ciphertext,
std::string& tag);

// Decrypts the input ciphertext message using AES256-GCM
// decryption. The method allows an additional data parameter that
Expand All @@ -70,17 +70,19 @@ class EncryptionUtils final {
//
// Returns the length of the plaintext or an error code.

static int aes256GCMDecrypt(const std::string& ciphertext,
const std::string& aad,
const std::string& tag,
const std::string& key,
const std::string& iv,
std::string& plaintext);
static Status aes256GCMDecrypt(const std::string& ciphertext,
const std::string& aad,
const std::string& tag,
const std::string& key,
const std::string& iv,
std::string& plaintext);

static std::string base64Encode(std::string& input);

static std::string base64Decode(const std::string& input);

static std::string shaDigestToStr(const std::string& input);

// Calculates the SHA256 digest of a message
static StatusOr<std::string> sha256Digest(const std::string& message);

Expand Down
Loading

0 comments on commit 93987e5

Please sign in to comment.