From de4fb6541f02676c04f3c1ad095b8747aeff5f0b Mon Sep 17 00:00:00 2001 From: Yichen Wang <18348405+Aiee@users.noreply.github.com> Date: Wed, 12 Apr 2023 12:23:38 +0800 Subject: [PATCH] Handle overflow error from license manager (#2590) * Handle overflow error in HB * Fix resource limit * Remove legacy license * Remove legacy license and fix hb logic * Modify log * Remove license from test cluster set up --------- Co-authored-by: Sophie <84560950+Sophie-Xie@users.noreply.github.com> --- .github/workflows/decrypt_secret.sh | 5 - .github/workflows/nightly.yml | 4 - .github/workflows/pull_request.yml | 4 - .github/workflows/rc.yml | 4 - .gitignore | 2 - conf/nebula-metad.conf.default | 1 - conf/nebula-metad.conf.production | 3 - conf/nebula-standalone.conf.default | 1 - conf/nebula-standalone.conf.production | 1 - src/clients/meta/MetaClient.cpp | 8 +- src/codec/test/CMakeLists.txt | 2 - src/common/base/test/CMakeLists.txt | 2 - src/common/datatypes/test/CMakeLists.txt | 2 - src/common/encryption/CMakeLists.txt | 5 - src/common/encryption/LMConnectorStatus.h | 6 + src/common/encryption/License.cpp | 1045 ----------------- src/common/encryption/License.h | 205 ---- .../encryption/LicenseManagerConnector.cpp | 111 +- .../encryption/LicenseManagerConnector.h | 25 +- src/common/encryption/test/CMakeLists.txt | 21 - .../test/LicenseManagerConnectorTest.cpp | 2 +- src/common/encryption/test/LicenseTest.cpp | 292 ----- src/common/expression/test/CMakeLists.txt | 1 - src/common/id/test/CMakeLists.txt | 4 - src/common/utils/test/CMakeLists.txt | 3 +- src/daemons/CMakeLists.txt | 1 - src/daemons/MetaDaemon.cpp | 6 +- src/daemons/StandAloneDaemon.cpp | 2 - src/drainer/test/CMakeLists.txt | 1 - src/graph/context/test/CMakeLists.txt | 2 - src/graph/executor/test/CMakeLists.txt | 1 - src/graph/optimizer/test/CMakeLists.txt | 1 - src/graph/planner/test/CMakeLists.txt | 1 - src/graph/service/GraphFlags.cpp | 3 - src/graph/service/GraphFlags.h | 2 - src/graph/util/test/CMakeLists.txt | 2 - src/graph/validator/test/CMakeLists.txt | 1 - src/graph/visitor/test/CMakeLists.txt | 1 - src/kvstore/cache/test/CMakeLists.txt | 1 - src/kvstore/listener/test/CMakeLists.txt | 1 - src/kvstore/raftex/test/CMakeLists.txt | 1 - src/kvstore/test/CMakeLists.txt | 1 - src/meta/CMakeLists.txt | 2 - src/meta/MetaServiceHandler.cpp | 7 - src/meta/MetaServiceHandler.h | 4 - .../processors/admin/GetLicenseProcessor.cpp | 47 - .../processors/admin/GetLicenseProcessor.h | 30 - src/meta/processors/admin/HBProcessor.cpp | 208 ++-- src/meta/processors/admin/HBProcessor.h | 12 +- src/mock/MockCluster.cpp | 1 - src/parser/test/CMakeLists.txt | 1 - src/storage/test/CMakeLists.txt | 1 - src/tools/CMakeLists.txt | 5 - .../cluster-code-generator/CMakeLists.txt | 30 - .../ClusterCodeGeneratorTool.cpp | 50 - .../machine-code-generator/CMakeLists.txt | 31 - .../machineCodeGeneratorTool.cpp | 25 - src/webservice/CMakeLists.txt | 1 - src/webservice/GetLicenseHandler.cpp | 72 -- src/webservice/GetLicenseHandler.h | 43 - src/webservice/WebService.cpp | 6 - src/webservice/test/CMakeLists.txt | 16 - src/webservice/test/LicenseHandlerTest.cpp | 77 -- tests/common/nebula_service.py | 9 - tests/secrets/nebula_test.license.gpg | Bin 958 -> 0 bytes 65 files changed, 167 insertions(+), 2298 deletions(-) delete mode 100644 .github/workflows/decrypt_secret.sh delete mode 100644 src/common/encryption/License.cpp delete mode 100644 src/common/encryption/License.h delete mode 100644 src/common/encryption/test/LicenseTest.cpp delete mode 100644 src/meta/processors/admin/GetLicenseProcessor.cpp delete mode 100644 src/meta/processors/admin/GetLicenseProcessor.h delete mode 100644 src/tools/cluster-code-generator/CMakeLists.txt delete mode 100644 src/tools/cluster-code-generator/ClusterCodeGeneratorTool.cpp delete mode 100644 src/tools/machine-code-generator/CMakeLists.txt delete mode 100644 src/tools/machine-code-generator/machineCodeGeneratorTool.cpp delete mode 100644 src/webservice/GetLicenseHandler.cpp delete mode 100644 src/webservice/GetLicenseHandler.h delete mode 100644 src/webservice/test/LicenseHandlerTest.cpp delete mode 100644 tests/secrets/nebula_test.license.gpg diff --git a/.github/workflows/decrypt_secret.sh b/.github/workflows/decrypt_secret.sh deleted file mode 100644 index e74991a4b8b..00000000000 --- a/.github/workflows/decrypt_secret.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh - -# Decrypt the file -gpg --quiet --batch --yes --decrypt --passphrase="$SECRET_PASSPHRASE" \ ---output ./tests/secrets/nebula.license ./tests/secrets/nebula_test.license.gpg diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index ee0a4fe7cdd..eb7c02724f8 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -248,10 +248,6 @@ jobs: run: | [ -d build/ ] && rm -rf build/* || mkdir -p build make init -C tests - - name: Decrypt License - run: sh ./.github/workflows/decrypt_secret.sh - env: - SECRET_PASSPHRASE: ${{ secrets.LICENSE_PASSWORD }} - name: CMake id: cmake run: | diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index 8ba0523e9b8..e65b1bf5cd1 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -98,10 +98,6 @@ jobs: run: | [ -d build/ ] && rm -rf build/* || mkdir -p build make init -C tests - - name: Decrypt License - run: sh ./.github/workflows/decrypt_secret.sh - env: - SECRET_PASSPHRASE: ${{ secrets.LICENSE_PASSWORD }} - name: CMake id: cmake run: | diff --git a/.github/workflows/rc.yml b/.github/workflows/rc.yml index b53c3ed845f..d06fd0227de 100644 --- a/.github/workflows/rc.yml +++ b/.github/workflows/rc.yml @@ -305,10 +305,6 @@ jobs: run: | [ -d build/ ] && rm -rf build/* || mkdir -p build make init -C tests - - name: Decrypt License - run: sh ./.github/workflows/decrypt_secret.sh - env: - SECRET_PASSPHRASE: ${{ secrets.LICENSE_PASSWORD }} - name: CMake id: cmake run: | diff --git a/.gitignore b/.gitignore index a6e743357fe..8890b286dbc 100644 --- a/.gitignore +++ b/.gitignore @@ -68,5 +68,3 @@ venv/ #ctags .tags /.vs -#license -tests/secrets/nebula.license diff --git a/conf/nebula-metad.conf.default b/conf/nebula-metad.conf.default index 397fb0e6c5d..0eccfb681dd 100644 --- a/conf/nebula-metad.conf.default +++ b/conf/nebula-metad.conf.default @@ -3,7 +3,6 @@ --daemonize=true # The file to host the process id --pid_file=pids/nebula-metad.pid ---license_path=share/resources/nebula.license ########## enterprise license ########## # The address of license manager in format of ip:port diff --git a/conf/nebula-metad.conf.production b/conf/nebula-metad.conf.production index 80a614510da..4c9fa86a7e3 100644 --- a/conf/nebula-metad.conf.production +++ b/conf/nebula-metad.conf.production @@ -4,9 +4,6 @@ # 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 diff --git a/conf/nebula-standalone.conf.default b/conf/nebula-standalone.conf.default index 53cdde9bc57..2e5a0b05056 100644 --- a/conf/nebula-standalone.conf.default +++ b/conf/nebula-standalone.conf.default @@ -3,7 +3,6 @@ --daemonize=true # The file to host the process id --pid_file=pids/nebula-standalone.pid ---license_path=share/resources/nebula.license # Whether to enable optimizer --enable_optimizer=true # The default charset when a space is created diff --git a/conf/nebula-standalone.conf.production b/conf/nebula-standalone.conf.production index 9234f653d9b..7ecb496a571 100644 --- a/conf/nebula-standalone.conf.production +++ b/conf/nebula-standalone.conf.production @@ -3,7 +3,6 @@ --daemonize=true # The file to host the process id --pid_file=pids/nebula-standalone.pid ---license_path=share/resources/nebula.license # Whether to enable optimizer --enable_optimizer=true # The default charset when a space is created diff --git a/src/clients/meta/MetaClient.cpp b/src/clients/meta/MetaClient.cpp index 83fc1733b1c..7576ca42055 100644 --- a/src/clients/meta/MetaClient.cpp +++ b/src/clients/meta/MetaClient.cpp @@ -1329,17 +1329,17 @@ Status MetaClient::handleResponse(const RESP& resp) { 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!"); + return Status::Error("The number of nodes 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!"); + return Status::Error("The number of 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!"; + LOG(ERROR) << "[License Manager] Invalid license manager status, shutting down the current " + "node, please check the license manager status!"; std::raise(SIGTERM); return Status::Error(" Invalid license manager status!"); } diff --git a/src/codec/test/CMakeLists.txt b/src/codec/test/CMakeLists.txt index e2eb97e5995..4076b00350f 100644 --- a/src/codec/test/CMakeLists.txt +++ b/src/codec/test/CMakeLists.txt @@ -15,8 +15,6 @@ set(expression_dep_libs $ $ $ - $ - $ $ $ $ diff --git a/src/common/base/test/CMakeLists.txt b/src/common/base/test/CMakeLists.txt index c13521f4587..cfd66911404 100644 --- a/src/common/base/test/CMakeLists.txt +++ b/src/common/base/test/CMakeLists.txt @@ -114,8 +114,6 @@ set(expression_dep_libs $ $ $ - $ - $ $ $ $ diff --git a/src/common/datatypes/test/CMakeLists.txt b/src/common/datatypes/test/CMakeLists.txt index 5d9b37d4bff..8a63f0784cd 100644 --- a/src/common/datatypes/test/CMakeLists.txt +++ b/src/common/datatypes/test/CMakeLists.txt @@ -42,8 +42,6 @@ set(expression_dep_libs $ $ $ - $ - $ $ $ $ diff --git a/src/common/encryption/CMakeLists.txt b/src/common/encryption/CMakeLists.txt index 223feccc798..d5c46d38521 100644 --- a/src/common/encryption/CMakeLists.txt +++ b/src/common/encryption/CMakeLists.txt @@ -2,11 +2,6 @@ # # This source code is licensed under Apache 2.0 License. -nebula_add_library( - encryption_obj OBJECT - License.cpp -) - nebula_add_library( encryption_utils_obj OBJECT EncryptionUtils.cpp diff --git a/src/common/encryption/LMConnectorStatus.h b/src/common/encryption/LMConnectorStatus.h index 7d915a5fd44..55a8ed94619 100644 --- a/src/common/encryption/LMConnectorStatus.h +++ b/src/common/encryption/LMConnectorStatus.h @@ -105,6 +105,12 @@ struct LMStatusHelper { return "Unknown"; } } + + // Overflow is considered normal, because it returns the maximum possible usage + static bool isStatusNormal(LMStatus status) { + return status == LMStatus::Ready || status == LMStatus::Expiring || + status == LMStatus::Expired || status == LMStatus::Overflow; + } }; } // namespace nebula diff --git a/src/common/encryption/License.cpp b/src/common/encryption/License.cpp deleted file mode 100644 index 5e58f6daa72..00000000000 --- a/src/common/encryption/License.cpp +++ /dev/null @@ -1,1045 +0,0 @@ -/* Copyright (c) 2021 vesoft inc. All rights reserved. - * - * This source code is licensed under Apache 2.0 License. - */ -#include "common/encryption/License.h" - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "common/base/StatusOr.h" -#include "common/fs/FileUtils.h" -#include "common/network/NetworkUtils.h" - -namespace nebula { -namespace encryption { - -// AES key/block size -const unsigned int kKeySize = 32; -const unsigned int kBlockSize = 16; -constexpr std::string_view kAesKeyBase64 = "241IYjd0+MKVhiXc0PWFetV7RhmsjTCJpZslOCPC5n8="; -constexpr std::string_view kAesIvBase64 = "rjJJOkaaueQmwFTVtzBAxw=="; - -// RSA public key -constexpr std::string_view kPubKeyBase64 = - "LS0tLS1CRUdJTiBSU0EgUFVCTElDIEtFWS0tLS0tCk1JSUJDZ0tDQVFFQTNGR0NvSW44VHZvYVNEYmx4RmJvL0l1VitxTF" - "l6U0IwU2QrdGkvYzJZWm9SWkJ3c0ZuTTkKNUhWYXN6UlJ5cmZw" - "ZlFTdFdMdThUcFlkc1l4ZkxUbmo1eWlYenlRMXluZzNnbytsZmozMXlidFNKVHNVU2pmRAo2RVNTRHlET3hvT0tRUlp1Wm" - "k5b0NCTDRCU2o3UXpGaFpoZ3pySHZLMXJCVXUzN0ovM0ZLVnp2" - "Tk8zSjFFbkI3CmlMODduRVJRdkRoUUxXVWQ0VDF4K3B6RXpPQkFvWnRMaE5GQTBjRjczdnZkWit1Y1UxZ3FCNU9RYitCR2" - "VQREcKUjQwL3VWWC9zdnZXempXRDBabVI4QkQ1SC9rb3hLUGth" - "Vm13c3ZOTCsrNk5qdENoUlV1NVBwVmFPclgwSUxMcgpKQzI5VzJuT0gvNWo3eVR4eUlsMU1uaWcyS3d6eUx0Ylh3SURBUU" - "FCCi0tLS0tRU5EIFJTQSBQVUJMSUMgS0VZLS0tLS0K"; - -// Length of base64 encoded -const size_t kSigSize = 344; - -// License headers/footers -const char kContentHeader[] = "----------License Content Start----------"; -const char kContentFooter[] = "----------License Content End----------"; -const char kKeyHeader[] = "----------License Key Start----------"; -const char kKeyFooter[] = "----------License Key End----------"; - -// Epoch secs -const std::time_t kSecsInDay = 86400; - -// Contact info -const char contactInfo[] = "Please contact Vesoft.Inc at inquiry@vesoft.com to renew the license."; - -// Inotify -const size_t EVENT_SIZE(sizeof(struct inotify_event)); -const size_t BUF_LEN(1024 * (EVENT_SIZE + 16)); - -License* License::getInstance() { - static License instance; - return &instance; -} - -Status License::validateLicense(const std::string& licensePath) { - LOG(INFO) << "[License] Validation started"; - - // Check existence of license file - if (!nebula::fs::FileUtils::exist(licensePath)) { - return Status::Error("Failed to find the license file: %s", licensePath.c_str()); - } - LOG(INFO) << "[License] File detected"; - VLOG(1) << "[License] File path: " << licensePath; - - // Parse license file to get license content - auto contentCheckStatus = parseLicenseContent(licensePath); - NG_RETURN_IF_ERROR(contentCheckStatus); - auto licenseContent = contentCheckStatus.value(); - - // Parse license file to get license key - auto parseLicenseKeyStatus = parseLicenseKey(licensePath); - NG_RETURN_IF_ERROR(parseLicenseKeyStatus); - auto licenseKey = parseLicenseKeyStatus.value(); - - // Validate the content - NG_RETURN_IF_ERROR(checkContent(licenseContent, licenseKey)); - - // Save the content to the instance - VLOG(1) << "[License] Loading license into program"; - rawContent_ = licenseContent; - key_ = licenseKey; - content_ = folly::parseJson(rawContent_); - licensePath_ = licensePath; - VLOG(1) << "[License] Loading finished"; - - // Check license fields - NG_RETURN_IF_ERROR(checkFields()); - - // Check expiration - NG_RETURN_IF_ERROR(checkExpiration(folly::parseJson(rawContent_))); - LOG(INFO) << "[License] Validation succeed"; - return Status::OK(); -} - -Status License::generateRsaSign(const std::string& digest, - const std::string& prikey, - std::string& outBuf) { - BIO* in = BIO_new_mem_buf(reinterpret_cast(prikey.c_str()), -1); - if (in == nullptr) { - return Status::Error("BIO_new_mem_buf failed"); - } - - RSA* rsa = PEM_read_bio_RSAPrivateKey(in, nullptr, nullptr, nullptr); - BIO_free(in); - if (rsa == nullptr) { - return Status::Error("PEM_read_bio_RSAPrivateKey failed"); - } - - unsigned int size = RSA_size(rsa); - std::vector sign; - sign.resize(size); - - int ret = RSA_sign(NID_sha256, - reinterpret_cast(digest.c_str()), - digest.length(), - reinterpret_cast(sign.data()), - &size, - rsa); - RSA_free(rsa); - if (ret != 1) { - return Status::Error("RSA_sign failed"); - } - outBuf = std::string(sign.begin(), sign.end()); - return Status::OK(); -} - -Status License::VerifyRsaSign(char* rsaSig, - uint32_t rsaSigLen, - const std::string& pubkey, - const std::string& digest) { - LOG(INFO) << "[License] Signature validation started"; - - BIO* in = BIO_new_mem_buf(reinterpret_cast(pubkey.c_str()), -1); - if (in == nullptr) { - return Status::Error("BIO_new_mem_buf failed"); - } - - // Load RSA public key - RSA* rsa = PEM_read_bio_RSAPublicKey(in, nullptr, nullptr, nullptr); - BIO_free(in); - if (rsa == nullptr) { - return Status::Error("Failed to load public key from the given string"); - } - - int ret = RSA_verify(NID_sha256, - reinterpret_cast(digest.c_str()), - digest.length(), - reinterpret_cast(rsaSig), - rsaSigLen, - rsa); - RSA_free(rsa); - if (ret != 1) { - logErrors(); - return Status::Error("Failed to verify the signature"); - } - - CRYPTO_cleanup_all_ex_data(); - LOG(INFO) << "[License] Signature validation succeed"; - return Status::OK(); -} - -Status License::computeSha256Digest(const std::string& message, std::string& outBuf) { - // Buffer to hold the calculated digest - unsigned char digest[EVP_MAX_MD_SIZE]; - unsigned int lengthOfDigest = 0; - int res = -1; - - // Compute message digest - EVP_MD_CTX* context = EVP_MD_CTX_new(); - - res = EVP_DigestInit_ex(context, EVP_sha256(), nullptr); - if (res != 1) { - logErrors(); - return Status::Error("EVP_DigestInit_ex failed"); - } - - res = EVP_DigestUpdate(context, message.c_str(), message.length()); - if (res != 1) { - logErrors(); - return Status::Error("EVP_DigestUpdate failed"); - } - - res = EVP_DigestFinal_ex(context, digest, &lengthOfDigest); - if (res != 1) { - logErrors(); - return Status::Error("EVP_DigestFinal_ex failed"); - } - - // Write result into buf - outBuf = std::string(digest, digest + lengthOfDigest); - EVP_MD_CTX_free(context); - return Status::OK(); -} - -Status License::aes256Encrypt(const unsigned char* key, - const unsigned char* iv, - const std::string& ptext, - std::string& ctext) { - EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new(); - int rc = EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), nullptr, key, iv); - if (rc != 1) return Status::Error("EVP_EncryptInit_ex failed"); - - // Recovered text expands upto kBlockSize - ctext.resize(ptext.size() + kBlockSize); - int out_len1 = static_cast(ctext.size()); - - rc = EVP_EncryptUpdate(ctx, - reinterpret_cast(&ctext[0]), - &out_len1, - reinterpret_cast(&ptext[0]), - static_cast(ptext.size())); - if (rc != 1) { - EVP_CIPHER_CTX_free(ctx); - return Status::Error("EVP_EncryptUpdate failed"); - } - - int out_len2 = static_cast(ctext.size()) - out_len1; - rc = EVP_EncryptFinal_ex(ctx, reinterpret_cast(&ctext[0]) + out_len1, &out_len2); - if (rc != 1) { - EVP_CIPHER_CTX_free(ctx); - return Status::Error("EVP_EncryptFinal_ex failed"); - } - - EVP_CIPHER_CTX_free(ctx); - // Set cipher text size now that we know it - ctext.resize(out_len1 + out_len2); - return Status::OK(); -} - -Status License::aes256Decrypt(const unsigned char* key, - const unsigned char* iv, - const std::string& ctext, - std::string& rtext) { - EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new(); - int rc = EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), nullptr, key, iv); - if (rc != 1) return Status::Error("EVP_DecryptInit_ex failed"); - - // Recovered text contracts upto kBlockSize - rtext.resize(ctext.size()); - int out_len1 = static_cast(rtext.size()); - - rc = EVP_DecryptUpdate(ctx, - reinterpret_cast(&rtext[0]), - &out_len1, - reinterpret_cast(&ctext[0]), - static_cast(ctext.size())); - if (rc != 1) return Status::Error("EVP_DecryptUpdate failed"); - - int out_len2 = static_cast(rtext.size()) - out_len1; - rc = EVP_DecryptFinal_ex(ctx, reinterpret_cast(&rtext[0]) + out_len1, &out_len2); - if (rc != 1) { - logErrors(); - EVP_CIPHER_CTX_free(ctx); - return Status::Error("EVP_DecryptFinal_ex failed"); - } - - EVP_CIPHER_CTX_free(ctx); - // Set recovered text size now that we know it - rtext.resize(out_len1 + out_len2); - return Status::OK(); -} - -Status License::checkContent(const std::string& licenseContent, const std::string& licenseKey) { - // Extract AES cipher from licenseKey - const size_t licenseKeySize = licenseKey.size(); - std::string aesCipherBase64 = licenseKey.substr(0, licenseKeySize - kSigSize); - auto aesCipherBase64paddingSz = - aesCipherBase64.size() - (aesCipherBase64.find_last_not_of('=') + 1); - auto aesCipherText = proxygen::Base64::decode(aesCipherBase64, aesCipherBase64paddingSz); - - // Extract RSA signature from licenseKey - std::string rsaSigBase64 = licenseKey.substr(licenseKeySize - kSigSize); - auto rsaSigBase64paddingSz = rsaSigBase64.size() - (rsaSigBase64.find_last_not_of('=') + 1); - auto rsaSig = proxygen::Base64::decode(rsaSigBase64, rsaSigBase64paddingSz); - - // Calculate message digest of AES256 encrypted license content - const std::string aesKey = getAesKey(); - const std::string aesIv = getAesIV(); - std::string encryptedBody = ""; - - NG_RETURN_IF_ERROR(aes256Encrypt(reinterpret_cast(aesKey.c_str()), - reinterpret_cast(aesIv.c_str()), - licenseContent, - encryptedBody)); - std::string digestBuf = ""; - NG_RETURN_IF_ERROR(computeSha256Digest(encryptedBody, digestBuf)); - - // Validate rsa signature - auto kPubKeyBase64paddingSz = kPubKeyBase64.size() - (kPubKeyBase64.find_last_not_of('=') + 1); - const std::string pubKey = - proxygen::Base64::decode(std::string(kPubKeyBase64), kPubKeyBase64paddingSz); - NG_RETURN_IF_ERROR(VerifyRsaSign(const_cast(rsaSig.c_str()), 256, pubKey, digestBuf)); - - // Decrypt license content - std::string rtext = ""; - NG_RETURN_IF_ERROR(aes256Decrypt(reinterpret_cast(aesKey.c_str()), - reinterpret_cast(aesIv.c_str()), - aesCipherText, - rtext)); - - auto contentJson = folly::parseJson(rtext); - VLOG(1) << "[License] content JSON: " << folly::toPrettyJson(contentJson); - - // Clean key string - OPENSSL_cleanse(reinterpret_cast(const_cast(aesKey.c_str())), kKeySize); - OPENSSL_cleanse(reinterpret_cast(const_cast(aesIv.c_str())), kBlockSize); - - return Status::OK(); -} - -Status License::checkExpiration(const folly::dynamic& content) { - // Get expiration date from content - auto expiration = content["expirationDate"].asString(); - // Get current time and covert to timestamp - auto currentTime = std::chrono::system_clock::now(); - std::time_t currentTimestamp = std::chrono::system_clock::to_time_t(currentTime); - // Convert expiration date to timestamp - auto getExpirationRes = getExpirationInLocalTZ(expiration); - NG_RETURN_IF_ERROR(getExpirationRes); - - auto localExpirationTimestamp = getExpirationRes.value(); - - std::time_t gracePeriod = 0; - std::time_t warningAhead = 0; - - // Determine if the license is a trial license, for trial license, no grace period is given - if (content["gracePeriod"].asInt() != 0) { - gracePeriod = content["gracePeriod"].asInt() * kSecsInDay; - warningAhead = 30 * kSecsInDay; - } else { // Trial license - gracePeriod = 0; - warningAhead = 7 * kSecsInDay; - } - VLOG(2) << "[License] gracePeriod: " << gracePeriod << " days"; - - // Give the user a grace period before disable the launch of meta service - // The length of the grace period is specified in the license - if (currentTimestamp > localExpirationTimestamp + gracePeriod) { - return Status::Error( - "[License] The license has expired on %s. %s", expiration.c_str(), contactInfo); - } else if (currentTimestamp > localExpirationTimestamp) { - LOG(WARNING) << folly::sformat( - "[License] The license has expired on {}. You can still use Nebula service for {} days. {}", - expiration.c_str(), - gracePeriod / kSecsInDay, - contactInfo); - - } else if (currentTimestamp > localExpirationTimestamp - warningAhead) { - // Warning about the expiration 30 days ahead - LOG(WARNING) << folly::sformat( - "[License] The license will be expired in {} days. The expiration date is {}. {}", - warningAhead / kSecsInDay, - expiration.c_str(), - contactInfo); - } - - VLOG(2) << "[License] Expiration check passed"; - return Status::OK(); -} - -StatusOr License::parseLicenseContent(const std::string& licensePath) { - nebula::fs::FileUtils::FileLineIterator iter(licensePath); - if (!iter.valid()) { - return Status::Error("Failed to parse license content, file path: %s, errno: %s", - licensePath.c_str(), - ::strerror(errno)); - } - - // Check license header - if (iter.entry() != kContentHeader) { - return Status::Error("Invalid license header"); - } - - std::string licenseContent = ""; - bool parsing = false; - // Parse license content - while (iter.valid()) { - if (iter.entry() == kContentHeader) { - parsing = true; - ++iter; - } - if (iter.entry() == kContentFooter) { - parsing = false; - } - if (parsing) { - licenseContent.append(iter.entry() + '\n'); - } - ++iter; - } - // TODO(Aiee) remove this part after integrating license generation/authentication in the server - // side. Delete newline literal at the end - licenseContent.erase(licenseContent.end() - 1, licenseContent.end()); - - VLOG(2) << "[License] Content parsing passed"; - return licenseContent; -} - -StatusOr License::parseLicenseKey(const std::string& licensePath) { - nebula::fs::FileUtils::FileLineIterator iter(licensePath); - if (!iter.valid()) { - return Status::Error("Failed to parse license key, file path: %s, errno: %s", - licensePath.c_str(), - ::strerror(errno)); - } - - std::string licenseKey = ""; - bool parsing = false; - // Parse license key - while (iter.valid()) { - if (iter.entry() == kKeyHeader) { - parsing = true; - ++iter; - } - if (iter.entry() == kKeyFooter) { - parsing = false; - } - if (parsing) { - licenseKey.append(iter.entry() + '\n'); - } - ++iter; - } - // TODO(Aiee) remove this part after integrating license generation/authentication in the server - // side. Delete newline literal at the end - licenseKey.erase(licenseKey.end() - 1, licenseKey.end()); - - VLOG(2) << "[License] Key check passed"; - return licenseKey; -} - -const folly::dynamic& License::getContent() const { - if (content_.empty()) { - LOG(ERROR) << "[License] data was not loaded"; - } - return content_; -} - -std::string License::getAesKey() { - auto kAesKeyBase64paddingSz = kAesKeyBase64.size() - (kAesKeyBase64.find_last_not_of('=') + 1); - std::string aesKey = proxygen::Base64::decode(std::string(kAesKeyBase64), kAesKeyBase64paddingSz); - - return aesKey; -} - -std::string License::getAesIV() { - auto kAesIvBase64paddingSz = kAesIvBase64.size() - (kAesIvBase64.find_last_not_of('=') + 1); - std::string aesIv = proxygen::Base64::decode(std::string(kAesIvBase64), kAesIvBase64paddingSz); - - return aesIv; -} - -void License::setContent(const folly::dynamic& content) { - content_ = content; -} - -const std::string& License::getRawContent() const { - if (rawContent_.empty()) { - LOG(ERROR) << "[License] data was not loaded"; - } - return rawContent_; -} - -const std::string& License::getkey() const { - if (key_.empty()) { - LOG(ERROR) << "[License] data was not loaded"; - } - return key_; -} - -const std::string& License::getLicensePath() const { - if (licensePath_.empty()) { - LOG(ERROR) << "[License] data was not loaded"; - } - return licensePath_; -} - -std::string License::getLicenseDirPath() const { - auto licensePath = getLicensePath(); - auto siz = licensePath.find_last_of('/'); - auto licenseDirPath = licensePath.substr(0, siz); - - return licenseDirPath; -} - -class License::BitVector { - private: - BitVector() = default; - ~BitVector() = default; - BitVector(const BitVector& bitVector); - const BitVector operator=(const BitVector& bitVector); - - public: - static void CreateFilter(const rocksdb::Slice* keys, int n, std::string* dst) { - auto bits_per_key = 10; - // Sanitize bits_per_key - if (bits_per_key < 1.0) { - bits_per_key = 1.0; - } else if (!(bits_per_key < 100.0)) { // including NaN - bits_per_key = 100.0; - } - - // Includes a nudge toward rounding up, to ensure on all platforms - // that doubles specified with three decimal digits after the decimal - // point are interpreted accurately. - auto millibits_per_key_ = static_cast(bits_per_key * 1000.0 + 0.500001); - - // For now configure Ribbon filter to match Bloom FP rate and save - // memory. (Ribbon bits per key will be ~30% less than Bloom bits per key - // for same FP rate.) - // desired_one_in_fp_rate_ = - // 1.0 / BloomMath::CacheLocalFpRate( - // bits_per_key, - // LegacyNoLocalityBloomImpl::ChooseNumProbes(millibits_per_key_), - // /*cache_line_bits*/ 512); - - // For better or worse, this is a rounding up of a nudged rounding up, - // e.g. 7.4999999999999 will round up to 8, but that provides more - // predictability against small arithmetic errors in floating point. - auto whole_bits_per_key_ = (millibits_per_key_ + 500) / 1000; - // Compute bloom filter size (in both bits and bytes) - uint32_t bits = static_cast(n * whole_bits_per_key_); - - // For small n, we can see a very high false positive rate. Fix it - // by enforcing a minimum bloom filter length. - if (bits < 64) bits = 64; - - uint32_t bytes = (bits + 7) / 8; - bits = bytes * 8; - - int num_probes = ChooseNumProbes(whole_bits_per_key_); - - const size_t init_size = dst->size(); - dst->resize(init_size + bytes, 0); - dst->push_back(static_cast(num_probes)); // Remember # of probes - char* array = &(*dst)[init_size]; - for (int i = 0; i < n; i++) { - AddHash(BloomHash(keys[i]), bits, num_probes, array); - } - } - - static bool KeyMayMatch(const rocksdb::Slice& key, const rocksdb::Slice& bloom_filter) { - const size_t len = bloom_filter.size(); - if (len < 2 || len > 0xffffffffU) { - return false; - } - - const char* array = bloom_filter.data(); - const uint32_t bits = static_cast(len - 1) * 8; - - // Use the encoded k so that we can read filters generated by - // bloom filters created using different parameters. - const int k = static_cast(array[len - 1]); - if (k > 30) { - // Reserved for potentially new encodings for short bloom filters. - // Consider it a match. - return true; - } - // NB: using stored k not num_probes for whole_bits_per_key_ - return HashMayMatch(BloomHash(key), bits, k, array); - } - - private: - static inline uint32_t DecodeFixed32(const char* ptr) { - // Load the raw bytes - uint32_t result; - memcpy(&result, ptr, sizeof(result)); // gcc optimizes this to a plain load - return result; - } - - static uint32_t Hash(const char* data, size_t n, uint32_t seed) { - // MurmurHash1 - fast but mediocre quality - // https://github.com/aappleby/smhasher/wiki/MurmurHash1 - // - const uint32_t m = 0xc6a4a793; - const uint32_t r = 24; - const char* limit = data + n; - uint32_t h = static_cast(seed ^ (n * m)); - - // Pick up four bytes at a time - while (data + 4 <= limit) { - uint32_t w = DecodeFixed32(data); - data += 4; - h += w; - h *= m; - h ^= (h >> 16); - } - - // Pick up remaining bytes - switch (limit - data) { - // Note: The original hash implementation used data[i] << shift, which - // promotes the char to int and then performs the shift. If the char is - // negative, the shift is undefined behavior in C++. The hash algorithm is - // part of the format definition, so we cannot change it; to obtain the same - // behavior in a legal way we just cast to uint32_t, which will do - // sign-extension. To guarantee compatibility with architectures where chars - // are unsigned we first cast the char to int8_t. - case 3: - h += static_cast(static_cast(data[2])) << 16; - [[fallthrough]]; - case 2: - h += static_cast(static_cast(data[1])) << 8; - [[fallthrough]]; - case 1: - h += static_cast(static_cast(data[0])); - h *= m; - h ^= (h >> r); - break; - } - return h; - } - - static inline uint32_t BloomHash(const rocksdb::Slice& key) { - return Hash(key.data(), key.size(), 0xbc9f1d34); - } - - // A legacy Bloom filter implementation with no locality of probes (slow). - // It uses double hashing to generate a sequence of hash values. - // Asymptotic analysis is in [Kirsch,Mitzenmacher 2006], but known to have - // subtle accuracy flaws for practical sizes [Dillinger,Manolios 2004]. - // - // DO NOT REUSE - // - - static inline int ChooseNumProbes(int bits_per_key) { - // We intentionally round down to reduce probing cost a little bit - int num_probes = static_cast(bits_per_key * 0.69); // 0.69 =~ ln(2) - if (num_probes < 1) num_probes = 1; - if (num_probes > 30) num_probes = 30; - return num_probes; - } - - static inline void AddHash(uint32_t h, uint32_t total_bits, int num_probes, char* data) { - const uint32_t delta = (h >> 17) | (h << 15); // Rotate right 17 bits - for (int i = 0; i < num_probes; i++) { - const uint32_t bitpos = h % total_bits; - data[bitpos / 8] |= (1 << (bitpos % 8)); - h += delta; - } - } - - static inline bool HashMayMatch(uint32_t h, - uint32_t total_bits, - int num_probes, - const char* data) { - const uint32_t delta = (h >> 17) | (h << 15); // Rotate right 17 bits - for (int i = 0; i < num_probes; i++) { - const uint32_t bitpos = h % total_bits; - if ((data[bitpos / 8] & (1 << (bitpos % 8))) == 0) { - return false; - } - h += delta; - } - return true; - } -}; - -std::string License::genBitVector(const std::vector& keyVec) { - std::string dst; - std::vector keys; - keys.reserve(keyVec.size()); - - // Load keys - LOG(INFO) << "Loading Machine codes......"; - for (const auto& key : keyVec) { - keys.emplace_back(key); - } - // Construct bloom filter - BitVector::CreateFilter(&keys[0], keys.size(), &dst); - return dst; -} - -bool License::lookupKey(const std::string& key, const std::string& bitVec) { - return BitVector::KeyMayMatch(key, bitVec); -} - -std::string License::genMachineCode() { - auto macAddrs = network::NetworkUtils::GetIPv4MacAddr(); - return genMachineCode(macAddrs); -} - -std::string License::genMachineCode(const std::string& macAddrs) { - if (macAddrs.empty()) { - DLOG(WARNING) << ("Failed to generate the Machine Code"); - return ""; - } - - // Encrypt machine code - std::string aes256MachineCode = ""; - const std::string aesKey = License::getAesKey(); - const std::string aesIv = License::getAesIV(); - License::aes256Encrypt(reinterpret_cast(aesKey.c_str()), - reinterpret_cast(aesIv.c_str()), - macAddrs, - aes256MachineCode); - // Encode with base64 - auto machineCode64 = proxygen::base64Encode(folly::StringPiece(aes256MachineCode)); - return machineCode64; -} - -std::vector License::decodeMachineCode(const std::string& machineCode) { - std::vector recoveredMachineCodes; - - // Decode with base64 - auto addingSz = machineCode.size() - (machineCode.find_last_not_of('=') + 1); - auto decodedMachineCode = proxygen::Base64::decode(machineCode, addingSz); - - // decrypt machine code - std::string aes256MachineCode = ""; - const std::string aesKey = License::getAesKey(); - const std::string aesIv = License::getAesIV(); - auto res = License::aes256Decrypt(reinterpret_cast(aesKey.c_str()), - reinterpret_cast(aesIv.c_str()), - decodedMachineCode, - aes256MachineCode); - - if (!res.ok()) { - LOG(ERROR) << "Failed to decrypt the machine code: " << machineCode; - return {}; - } - folly::split(",", aes256MachineCode, recoveredMachineCodes); - return recoveredMachineCodes; -} - -Status License::checkMachineCode(const std::string& machineCode, const std::string& clusterCode) { - // Decode clusterCode with base64 - auto addingSz = clusterCode.size() - (clusterCode.find_last_not_of('=') + 1); - auto plainClusterCode = proxygen::Base64::decode(clusterCode, addingSz); - - // Support old license format - // Check if the machine code can be found in the cluster code - if (lookupKey(machineCode, plainClusterCode)) { - return Status::OK(); - } - - // Add support for multiple mac addresses - // As long as one of the mac addresses can be found in the cluster code, it is valid - // Split the machine code into a vector of mac addresses and check each of them - auto macAddresses = decodeMachineCode(machineCode); - if (!macAddresses.empty()) { - // Iterate through the mac addresses and check the existence of each of them - for (auto& mac : macAddresses) { - if (lookupKey(mac, plainClusterCode)) { - return Status::OK(); - } - } - } - - return Status::Error( - "Failed to valid the hardware information, the current machine is not registered."); -} - -std::string License::genClusterCode(const std::vector& machineCodes) { - std::vector macAddrs; - std::vector invalidMachineCodes; - - // Iterate machine codes and decode the machine code to mac addresses - for (auto& machineCode : machineCodes) { - auto macAddresses = decodeMachineCode(machineCode); - if (!macAddresses.empty()) { - // Iterate through the mac addresses and check the existence of each of them - for (auto& mac : macAddresses) { - macAddrs.push_back(mac); - } - } else { - invalidMachineCodes.push_back(machineCode); - continue; - } - - // Add machine code to macAddrs. - // This is for backward compatibility(for version < v3.3). - macAddrs.push_back(machineCode); - } - - if (invalidMachineCodes.size() > 0) { - LOG(ERROR) << "Failed to generate the cluster code, invalid machine codes found: " - << folly::join(",", invalidMachineCodes); - return ""; - } - - auto bitVec = genBitVector(macAddrs); - if (bitVec.empty()) { - return ""; - } - auto clusterCode = proxygen::base64Encode(folly::StringPiece((bitVec))); - return clusterCode; -} - -Status License::checkHardware() { - // If the gracePeriod is 0, the license is a trial license, skip the hardware check. - if (content_["gracePeriod"].asInt() == 0) { - LOG(INFO) << "[License] GracePeriod is 0."; - return Status::OK(); - } - - // Check the machine code - auto curMachineCode = genMachineCode(); - auto clusterCode = content_["clusterCode"].asString(); - NG_RETURN_IF_ERROR(checkMachineCode(curMachineCode, clusterCode)); - - LOG(INFO) << "[License] Hardware checking passed, the current machine is registered."; - - return Status::OK(); -} - -Status License::checkFields() { - // Check the product type - auto productType = content_["product"].asString(); - if (productType != "nebula_graph") { - return Status::Error("The product type %s is incompatible with Nebula service.", - productType.c_str()); - } - - // Check license version - // If 'gracePeriod' cannot be found in the license content, the license is released - // prior to v3.1 - if (content_.find("gracePeriod") == content_.items().end()) { - return Status::Error( - "The attributes 'gracePeriod' is missing in the enterprise license, " - "license is not valid for the Nebula service running."); - } - - // If the 'gracePeriod' is not 0, there must be a 'clusterCode' filed - if (content_["gracePeriod"].asInt() != 0 && - content_.find("clusterCode") == content_.items().end()) { - return Status::Error( - "The attributes 'clusterCode' is missing in the enterprise license, " - "the license information is not complete."); - } - - return Status::OK(); -} - -StatusOr License::getExpirationInLocalTZ(const std::string& expiration) { - // Parse datetime string - std::tm t{}; - std::istringstream ss(expiration); - ss >> std::get_time(&t, "%Y-%m-%dT%H:%M:%S"); - if (ss.fail()) { - return Status::Error("failed to parse time string"); - } - - // Convert expiration datetime to timestamp - std::time_t UtcExpirationTimestamp = mktime(&t); - VLOG(1) << "[License] Expiration timestamp in UTC: " << UtcExpirationTimestamp; - - // Get the difference between current timezone and UTC - std::time_t t_epoch = 0; - auto tzDiffInSec = -1 * std::mktime(std::gmtime(&t_epoch)); - VLOG(1) << "[License] Timezone difference: " << tzDiffInSec << " seconds"; - - auto localExpirationTimestamp = UtcExpirationTimestamp + tzDiffInSec; - VLOG(1) << "[License] Expiration timestamp in local time zone: " << localExpirationTimestamp; - - return localExpirationTimestamp; -} - -LicenseMonitor* LicenseMonitor::getInstance() { - static LicenseMonitor instance; - return &instance; -} - -Status LicenseMonitor::init(License* licenseIns) { - licenseIns_ = licenseIns; - LOG(INFO) << "[License] Set up license monitor"; - - // Init inotify instance - inotifyFd_ = inotify_init(); - if (inotifyFd_ < 0) { - LOG(ERROR) << "inotify_init error, errno: " << errno << ", error: " << strerror(errno); - return Status::Error("Failed to initialize inotify instance, error: %s", strerror(errno)); - } - - // Add license directory into the watcher - auto licenseDirPath = licenseIns->getLicenseDirPath(); - - inotifyWd_ = inotify_add_watch(inotifyFd_, licenseDirPath.c_str(), IN_CLOSE_WRITE | IN_MOVED_TO); - if (inotifyWd_ < 0) { - LOG(ERROR) << "failed to add a watch to an initialized inotify instance, errno: " << errno - << ", error: " << strerror(errno); - return Status::Error("Failed to add a watch to an initialized inotify instance, error: %s", - strerror(errno)); - } - - // Init epoll instance - efd_ = epoll_create(sizeof(inotifyFd_)); - if (efd_ < 0) { - LOG(ERROR) << "[License Monitor] Could not initialized epoll file descriptor, errno: " << errno - << ", error: " << strerror(errno); - return Status::Error("Failed to initialize epoll file descriptor, error: %s", strerror(errno)); - } - - ev_.events = EPOLLIN; - ev_.data.fd = inotifyFd_; - cfg_ = epoll_ctl(efd_, EPOLL_CTL_ADD, inotifyFd_, &ev_); - if (cfg_ < 0) { - LOG(ERROR) << "[License Monitor] Could not add inotifyFd_ to the epoll interface, errno: " - << errno << ", error: " << strerror(errno); - return Status::Error("Failed to add inotifyFd_ to the epoll interface, error: %s", - strerror(errno)); - } - - // Create an eventfd for async notification - evfd_ = ::eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC); - if (evfd_ == -1) { - LOG(ERROR) << "Create eventfd failed: " << ::strerror(errno); - return Status::Error("Failed to create eventfd, error: %s", strerror(errno)); - } - - notify_event_.events = EPOLLIN; - notify_event_.data.fd = evfd_; - cfg_ = epoll_ctl(efd_, EPOLL_CTL_ADD, evfd_, ¬ify_event_); - if (cfg_ < 0) { - LOG(ERROR) << "[License Monitor] Could not add evfd_ to the epoll interface, errno: " << errno - << ", error: " << strerror(errno); - return Status::Error("Failed to add evfd_ to the epoll interface, error: %s", strerror(errno)); - } - - bgThread_ = std::thread(&LicenseMonitor::setLicenseMonitor, this); - LOG(INFO) << "[License Monitor] initialized successfully"; - - return Status::OK(); -} - -void LicenseMonitor::setLicenseMonitor() { - struct epoll_event events_arr[2 * sizeof(struct epoll_event)]; - - while (true) { - if (isShutdown.load(std::memory_order_acquire)) { - LOG(INFO) << "License monitor is shutting down"; - break; - } - - // block until there is an event on the file descriptor or timeout(300s) - ret_ = epoll_wait(efd_, events_arr, 10, 300000); - if (ret_ > 0) { - for (int i = 0; i < ret_; i++) { - if (events_arr[i].data.fd == inotifyFd_) { - // license file modified - DLOG(INFO) << "inotifyFd_ event"; - LOG(INFO) << "[License Monitor] The license file was modified, path: " - << licenseIns_->getLicensePath().c_str(); - handleInotifyEvent(); - } else if (events_arr[i].data.fd == evfd_) { - // shutdown() was called, break the loop - DLOG(INFO) << "evfd_ event captured"; - handleEpollEvent(); - LOG(INFO) << "[License Monitor] File monitor has been shut down"; - break; - } - } - } else if (ret_ < 0) { - LOG(ERROR) << "[License Monitor] Error in the polling"; - break; - } else { - DLOG(INFO) << "[License Monitor] No event captured, monitor timeout"; - continue; - } - } -} - -void LicenseMonitor::handleInotifyEvent() { - int inotifyLength, inotifyI = 0; - char inotifyBuffer[BUF_LEN]; - - inotifyLength = read(inotifyFd_, inotifyBuffer, BUF_LEN); - - if (inotifyLength < 0) { - LOG(ERROR) << "read error"; - return; - } - - VLOG(3) << "inotifyI: " << inotifyI << " inotifyLength: " << inotifyLength; - - while (inotifyI < inotifyLength) { - struct inotify_event* event = reinterpret_cast(&inotifyBuffer[inotifyI]); - VLOG(3) << "Event name: " << event->name; - - // Ignore other file changes - if (std::strcmp(event->name, "nebula.license") != 0) { - return; - } - - // Check event - if (event->len) { - if (event->mask & IN_CLOSE_WRITE || event->mask & IN_MOVED_TO) { - if (event->mask & IN_ISDIR) { - // Ignore directory change - } else { - LOG(INFO) << folly::sformat("[License Monitor] The license file {} was modified.", - event->name); - auto status = licenseIns_->validateLicense(licenseIns_->getLicensePath()); - if (!status.ok()) { - LOG(ERROR) << "[License Monitor] Failed to validate license: " << status; - } - } - } - } - inotifyI += EVENT_SIZE + event->len; - } -} - -void LicenseMonitor::handleEpollEvent() { - char buf[BUF_LEN]; - - // Consume the event - auto len = read(evfd_, buf, sizeof(buf)); - if (len == -1 && errno != EAGAIN) { - LOG(ERROR) << "read error"; - return; - } -} - -void LicenseMonitor::shutdown() { - LOG(INFO) << "[License Monitor] shutting down..."; - isShutdown.store(true, std::memory_order_release); - - // Notify the background thread to exit - DCHECK_NE(-1, evfd_); - DLOG(INFO) << "[License Monitor] writing to evfd_ ..."; - auto one = 1UL; - auto len = ::write(evfd_, &one, sizeof(one)); - DCHECK(len == sizeof(one)); - DLOG(INFO) << "[License Monitor] write to evfd_ done"; - - bgThread_.join(); - (void)inotify_rm_watch(inotifyFd_, inotifyWd_); - (void)close(inotifyFd_); - (void)close(efd_); - (void)close(evfd_); -} - -} // namespace encryption -} // namespace nebula diff --git a/src/common/encryption/License.h b/src/common/encryption/License.h deleted file mode 100644 index 4ec3e941029..00000000000 --- a/src/common/encryption/License.h +++ /dev/null @@ -1,205 +0,0 @@ -/* Copyright (c) 2021 vesoft inc. All rights reserved. - * - * This source code is licensed under Apache 2.0 License. - */ - -#pragma once - -#include -#include -#include -#include -#include -#include - -#include "common/base/Status.h" - -namespace nebula { -namespace encryption { - -class License final { - FRIEND_TEST(LicenseGeneratorTool, BloomFilterTest); - FRIEND_TEST(LicenseGeneratorTool, HardwareCheckTest); - FRIEND_TEST(LicenseGeneratorTool, CompatibilityTest); - FRIEND_TEST(LicenseGeneratorTool, MultiMacTest); - FRIEND_TEST(LicenseGeneratorTool, ExpirationCheckTest); - - private: - License() = default; - ~License() = default; - License(const License& license); - const License operator=(const License& license); - - public: - // Gets the singleton - static License* getInstance(); - - // Reads and validates License, save the parsed license content into content_ - // This method is called when the meta process starts - Status validateLicense(const std::string& licensePath); - - // Signs a RSA signature - static Status generateRsaSign(const std::string& digest, - const std::string& prikey, - std::string& outBuf); - - // Verifies RSA signature - static Status VerifyRsaSign(char* rsaSig, - uint32_t rsaSigLen, - const std::string& pubkey, - const std::string& digest); - - // Computes the message digest using sha256 - static Status computeSha256Digest(const std::string& message, std::string& outBuf); - - static Status aes256Encrypt(const unsigned char* key, - const unsigned char* iv, - const std::string& ptext, - std::string& ctext); - - static Status aes256Decrypt(const unsigned char* key, - const unsigned char* iv, - const std::string& ctext, - std::string& rtext); - - // Checks the expiration of the license - // For trial license, warn the user 7 days before the expiration and no grace period is given - // For official license, warn the user 30 days before the expiration and a grace period is given - static Status checkExpiration(const folly::dynamic& content); - - // Checks the expiration of the license - static Status checkContent(const std::string& licenseContent, const std::string& licenseKey); - - // Parses license file to get license body as a folly::dynamic object - static StatusOr parseLicenseContent(const std::string& licensePath); - - // Parses license file to get license key as a string - static StatusOr parseLicenseKey(const std::string& licensePath); - - static void logErrors() { - char errBuf[1024]; - ERR_error_string(ERR_get_error(), errBuf); - LOG(ERROR) << errBuf; - } - - // Get the default ase key - static std::string getAesKey(); - - // Get the default ase IV - static std::string getAesIV(); - - // Sets a dynamic object representing the license info - void setContent(const folly::dynamic& content); - - // Returns a dynamic object representing the license info - const folly::dynamic& getContent() const; - - // Returns a string representing the license content - const std::string& getRawContent() const; - - // Returns a string representing the license key - const std::string& getkey() const; - - // Returns a the license path - const std::string& getLicensePath() const; - - // Returns a the license dir path - std::string getLicenseDirPath() const; - - // **************** Hardware Registration **************** - // Generates a string as an unique id of the machine, return an empty string on failure. - static std::string genMachineCode(); - - // Generates a machine code from a encoded string of mac addresses "MAC1,MAC2,MAC3,MAC4" - // This method is mainly used for testing - static std::string genMachineCode(const std::string& macAddrs); - - // Recover the machine code to a vector of string - static std::vector decodeMachineCode(const std::string& machineCode); - - // Generates a string as an unique id of the CLUSTER, return an empty string on failure. - // The input is a vector of strings representing machine codes. - static std::string genClusterCode(const std::vector& machineCodes); - - // Validates the machine code of the current machine with license - static Status checkMachineCode(const std::string& machineCode, const std::string& clusterCode); - - // Checks if the machine is registered in the license or not. - // This check should only be executed once when the meta service launches. - Status checkHardware(); - - private: - // BitVector is a class that contains multiple deprecated interfaces from RocksDB 6.29.fb in - // filter_policy.cc. This is used to generate a bit vector for all machine code collected and - // lookup whether a machine code exists. - class BitVector; - - private: - // Generates a bit vector for all elements in the keyVec using a bloom filter. - static std::string genBitVector(const std::vector& keyVec); - - // Checks if the given key is in the bit vector. - // We can use this method to determine whether the machine is in the cluster. - static bool lookupKey(const std::string& key, const std::string& bitVec); - - // Checks the field of the license to determine if the license is valid or not. - // This check includes product type check and license version check. - Status checkFields(); - - // Parse the input string to a time object in the local time zone - static StatusOr getExpirationInLocalTZ(const std::string& expiration); - - private: - // Dynamic object representing the license info - folly::dynamic content_ = ""; - // String representing the license content - std::string rawContent_ = ""; - // String representing the license key - std::string key_ = ""; - // The license file path - std::string licensePath_ = ""; -}; - -class LicenseMonitor final { - private: - LicenseMonitor() = default; - ~LicenseMonitor() = default; - LicenseMonitor(const LicenseMonitor& licenseMonitor); - const LicenseMonitor operator=(const LicenseMonitor& licenseMonitor); - - public: - static LicenseMonitor* getInstance(); - - // Initializes the file descriptor for inotify and epoll - Status init(License* licenseIns); - - // Sets up license monitor using inotify - // This function will be called in metaDaemon with a function scheduler to execute repeatedly - void setLicenseMonitor(); - - // Shuts down the license monitor and release the file descriptors - void shutdown(); - - private: - // Handles the inotify event when the license file is modified - void handleInotifyEvent(); - - // Consume the eventfd when terminating the license monitor - void handleEpollEvent(); - - private: - std::atomic isShutdown{false}; - std::thread bgThread_; - License* licenseIns_ = nullptr; - int inotifyWd_ = -1; - int inotifyFd_ = -1; - int efd_ = -1; - int cfg_ = -1; - int ret_ = -1; - int evfd_ = -1; - epoll_event notify_event_; - epoll_event ev_; -}; - -} // namespace encryption -} // namespace nebula diff --git a/src/common/encryption/LicenseManagerConnector.cpp b/src/common/encryption/LicenseManagerConnector.cpp index dcd74d9f818..e914ee86adb 100644 --- a/src/common/encryption/LicenseManagerConnector.cpp +++ b/src/common/encryption/LicenseManagerConnector.cpp @@ -32,30 +32,29 @@ Status LicenseManagerConnector::init(std::string LmUrl, kvstore::KVStore* kvstor bgThread_ = std::make_unique(); productId_ = std::to_string(nebula::meta::ClusterIdMan::getClusterIdFromKV(kvstore, kClusterIdKey)); - DLOG(INFO) << "[License Manager] product id: " << productId_; - // get LMId + + // Get LMId auto res = getLMId(); if (!res.ok()) { - return Status::Error("Failed to get license manager ID, error: %s", - res.status().toString().c_str()); + return Status::Error("Failed to get license manager ID, error: %s", res.toString().c_str()); } - auto lmId = res.value(); - LMId_ = lmId; + // Start background thread auto ok = bgThread_->start("license_manager_connector"); if (!ok) { return Status::Error("Failed to start license manager connector thread"); } - // Delay 5 seconds to wait for heartbeat - bgThread_->addDelayTask(5 * 1000, &LicenseManagerConnector::threadFunc, this); + // Delay 1 seconds to wait for heartbeat + bgThread_->addDelayTask( + 1 * 1000 + folly::Random::rand32(900), &LicenseManagerConnector::threadFunc, this); - LOG(INFO) << "[License Manager] initialized successfully, LMId: " << lmId; + LOG(INFO) << "[License Manager] initialized successfully, LMId: " << LMId_; return Status::OK(); } -StatusOr LicenseManagerConnector::getLMId() { +Status LicenseManagerConnector::getLMId() { // send request auto httpClient = HttpClient::instance(); auto httpResp = httpClient.get(LMUrl_ + kGetLmIdApi); @@ -72,8 +71,8 @@ StatusOr LicenseManagerConnector::getLMId() { if (LMId.empty()) { return Status::Error("Failed to get license manager ID, the response is empty"); } - - return LMId; + LMId_ = LMId; + return Status::OK(); } LMStatus LicenseManagerConnector::validateLicense() { @@ -97,7 +96,6 @@ LMStatus LicenseManagerConnector::validateLicense() { return LMStatus::OtherError; } auto requestBody = request.value(); - DLOG(INFO) << "Request body in string: \n" << requestBody; DLOG(INFO) << "Request body pretty json: \n" << folly::toPrettyJson(request.value()); // Send request @@ -114,77 +112,71 @@ void LicenseManagerConnector::threadFunc() { CHECK_EQ(false, isMocking_) << "Should not call threadFunc when mocking"; DLOG(INFO) << "[License Manager] connector thread is running"; - unsigned int nextCheckPeriod = 60; - auto now = time::WallClock::fastNowInSec(); + unsigned int nextCheckPeriod = kDefaultCheckPeriodInSec + folly::Random::rand32(20 * 60); + if (isRetrying_) { LOG(WARNING) << "[License Manager] retrying to connect to license manager"; } + // validate license iff get LMId successfully auto rse = getLMId(); if (!rse.ok()) { - LOG(ERROR) << "[License Manager] failed to get license manager ID, error: " - << rse.status().toString(); - nextCheckPeriod = kRetryPeriodInSec + folly::Random::rand32(60 * 1000); - if (!isRetrying_) { - isRetrying_ = true; - retryStartTime_ = now; - } + LOG(ERROR) << "[License Manager] failed to get license manager ID, error: " << rse.toString(); + nextCheckPeriod = kRetryPeriodInSec + folly::Random::rand32(5 * 60); + setRetryFlag(); } else { - auto lmId = rse.value(); - LMId_ = lmId; - auto lmStatus = validateLicense(); switch (lmStatus) { case LMStatus::Ready: case LMStatus::Expiring: case LMStatus::Expired: { - lastVerifySuccess_ = true; - retryStartTime_ = -1; + // reset all flags dropAllHosts_ = false; + retryStartTime_ = INT64_MAX; isRetrying_ = false; - nextCheckPeriod = kDefaultCheckPeriodInSec + folly::Random::rand32(20 * 60 * 1000); + isOverLimit_ = false; + isLMNormal_ = true; LOG(INFO) << "[License Manager] validate license successfully"; break; + } + // TODO handle error + case LMStatus::Overflow: { + LOG(ERROR) << "[License Manager] cluster resource has exceeded the license limit"; + isOverLimit_ = true; + break; } case LMStatus::NotExist: case LMStatus::Invalid: case LMStatus::ExpiredAndTerminated: { dropAllHosts_ = true; + isLMNormal_ = false; [[fallthrough]]; } - case LMStatus::Overflow: // TODO handle error case LMStatus::Syncing: case LMStatus::ErrRequestExpired: case LMStatus::ErrInvalidCiphertext: case LMStatus::ErrParam: case LMStatus::ErrInternalServer: case LMStatus::OtherError: { - if (!lastVerifySuccess_) { + if (!isLMNormal_) { dropAllHosts_ = true; } - - if (!isRetrying_) { - isRetrying_ = true; - retryStartTime_ = now; - } - lastVerifySuccess_ = false; - nextCheckPeriod = kRetryPeriodInSec + folly::Random::rand32(5 * 60 * 1000); + setRetryFlag(); + nextCheckPeriod = kRetryPeriodInSec + folly::Random::rand32(5 * 60); } } } // Check retry timeout, if timeout, all hosts should be shut down - if (isRetrying_ && now - retryStartTime_ > kRetryTimeoutInSec) { - isRetrying_ = false; - retryStartTime_ = -1; + if (isRetryTimeout()) { dropAllHosts_ = true; LOG(ERROR) << "[License Manager] Failed to validate license with license manager, retry " "timeout, all hosts will be shut down"; } - // TODO(Aiee) for test only - nextCheckPeriod = 5; + // TODO(Aiee) for test only, should be removed before official v3.5 release + nextCheckPeriod = 10; bgThread_->addDelayTask(nextCheckPeriod * 1000, &LicenseManagerConnector::threadFunc, this); } @@ -204,7 +196,6 @@ StatusOr LicenseManagerConnector::buildValidateRequest(const std::s buildKeyRes.status().toString().c_str()); } auto key = buildKeyRes.value(); - DLOG(INFO) << "Aes key: " << key; auto ciphertext = buildCipherText(key, rawBody); if (!ciphertext.ok()) { @@ -284,7 +275,6 @@ StatusOr LicenseManagerConnector::buildCipherText(const std::string // Encrypt raw request const std::string& plaintext = rawRequest; - DLOG(INFO) << "plaintext: " << plaintext; std::string additional = ""; std::string ciphertext(128, '\0'); std::string decryptedtext(128, '\0'); @@ -312,8 +302,6 @@ StatusOr LicenseManagerConnector::encValidateBody(const std::string } // Append tag to ciphertext - DLOG(INFO) << "aes ciphertext size: " << ciphertext.size(); - ciphertext.append(tag); // Base64(random 3 byte + nonce + aes256(rawRequest)) auto message = fmt::format("{}{}{}", randBytes, iv, ciphertext); @@ -331,8 +319,6 @@ StatusOr LicenseManagerConnector::genAesEncKey(const std::string& l if (!digestRes.ok()) { return digestRes.status(); } - DLOG(INFO) << "encrypt key size: " << digestRes.value().size(); - DLOG(INFO) << "encrypt key: " << digestRes.value(); return std::move(digestRes.value()); } @@ -345,8 +331,6 @@ StatusOr LicenseManagerConnector::genAesDecKey(const std::string& l if (!digestRes.ok()) { return digestRes.status(); } - DLOG(INFO) << "decrypt key size: " << digestRes.value().size(); - DLOG(INFO) << "decrypt key: " << digestRes.value(); return std::move(digestRes.value()); } @@ -359,7 +343,6 @@ StatusOr LicenseManagerConnector::checkHttpResponse(const HttpRe // parse response folly::dynamic respJson; try { - DLOG(INFO) << "http response body: " << resp.body; respJson = folly::parseJson(resp.body); } catch (std::exception& e) { return Status::Error("Failed to parse response from license manager, error: %s", e.what()); @@ -464,7 +447,7 @@ LMStatus LicenseManagerConnector::checkRawResponse(const std::string& rawResp) { folly::dynamic rawInfo = folly::dynamic::object(); try { rawInfo = folly::parseJson(rawResp); - DLOG(INFO) << "rawInfo: " << rawInfo; + DLOG(INFO) << "Decrypted validate response: " << rawInfo; } catch (std::exception& e) { LOG(ERROR) << "[License Manager] Failed to parse response from license manager, error: " << e.what(); @@ -513,13 +496,13 @@ LMStatus LicenseManagerConnector::checkRawResponse(const std::string& rawResp) { LMStatus LicenseManagerConnector::handleErrMsg(const std::string& message) { if (message == "ErrInternalServer") { // messages from license manager - LOG(ERROR) << "Internal server error in license manager"; + LOG(ERROR) << "[License Manager] Internal server error in license manager"; return LMStatus::ErrInternalServer; } else if (message == "ErrInvalidCiphertext") { - LOG(ERROR) << "Invalid ciphertext in the license request"; + LOG(ERROR) << "[License Manager] Invalid ciphertext in the license request"; return LMStatus::ErrInvalidCiphertext; } else if (message == "ErrParam") { - LOG(ERROR) << "Invalid parameter in the license request"; + LOG(ERROR) << "[License Manager] Invalid parameter in the license request"; return LMStatus::ErrParam; } else if (message == "ErrRequestExpired") { return LMStatus::ErrRequestExpired; @@ -531,30 +514,32 @@ LMStatus LicenseManagerConnector::handleErrMsg(const std::string& message) { LMStatus LicenseManagerConnector::handleResponseStatus(const std::string& message, bool terminatedFlag) { if (message == "Ready") { // status from license manager - LOG(INFO) << "License is ready"; + LOG(INFO) << "[License Manager] License is ready"; return LMStatus::Ready; } else if (message == "Expiring") { - LOG(WARNING) << "License is expiring soon"; + LOG(WARNING) << "[License Manager] License is expiring soon"; return LMStatus::Expiring; } else if (message == "Expired" && terminatedFlag == true) { - LOG(ERROR) << "The license has expired, all graph and storage services are terminated, " + LOG(ERROR) << "[License Manager] The license has expired, all graph and storage services are " + "terminated, " "please contact your administrator to renew the license"; return LMStatus::ExpiredAndTerminated; } else if (message == "Expired" && terminatedFlag == false) { - LOG(ERROR) << "License has expired, all graph and storage services will be terminated soon, " + LOG(ERROR) << "[License Manager] License has expired, all graph and storage services will be " + "terminated soon, " "please contact your administrator to renew the license"; return LMStatus::Expired; } else if (message == "Overflow") { - LOG(WARNING) << "Resource usage has exceeded the license limit"; + LOG(WARNING) << "[License Manager] Resource usage has exceeded the license limit"; return LMStatus::Overflow; } else if (message == "NotExist") { - LOG(ERROR) << "License does not exist"; + LOG(ERROR) << "[License Manager] License does not exist"; return LMStatus::NotExist; } else if (message == "Invalid") { - LOG(ERROR) << "License is invalid"; + LOG(ERROR) << "[License Manager] License is invalid"; return LMStatus::Invalid; } else if (message == "Syncing") { - LOG(INFO) << "License manager is syncing"; + LOG(INFO) << "[License Manager] License manager is syncing"; return LMStatus::Syncing; } else { return LMStatus::OtherError; diff --git a/src/common/encryption/LicenseManagerConnector.h b/src/common/encryption/LicenseManagerConnector.h index c29d72a4714..af423962a34 100644 --- a/src/common/encryption/LicenseManagerConnector.h +++ b/src/common/encryption/LicenseManagerConnector.h @@ -20,6 +20,7 @@ static const int32_t kRetryPeriodInSec = 5 * 60; static const int32_t kRetryTimeoutInSec = 2 * 24 * 60 * 60; class LicenseManagerConnector final { + FRIEND_TEST(LicenseManagerConnectorTest, getLMIdTest); FRIEND_TEST(LicenseManagerConnectorTest, buildValidateBodyTest); FRIEND_TEST(LicenseManagerConnectorTest, handleValidateRespTest); @@ -53,7 +54,7 @@ class LicenseManagerConnector final { // lmid: "" // } // } - StatusOr getLMId(); + Status getLMId(); // Send request to license manager to verify license over http LMStatus validateLicense(); @@ -179,8 +180,16 @@ class LicenseManagerConnector final { // Handle the verify license response error message/status static LMStatus handleResponseStatus(const std::string& message, bool terminatedFlag = false); - static Status handleOverflow() { - return Status::OK(); + // Set retry flag and record the start time + void setRetryFlag() { + if (!isRetrying_) { + isRetrying_ = true; + retryStartTime_ = time::WallClock::fastNowInSec(); + } + } + + bool isRetryTimeout() { + return time::WallClock::fastNowInSec() - retryStartTime_ > kRetryTimeoutInSec; } private: @@ -190,16 +199,11 @@ class LicenseManagerConnector final { std::string LMUrl_ = ""; // The cluster id std::string productId_ = ""; - // Request period in secs (1 hour +- 10 mins) - // int32_t period_ = kDeCheckPeriodInSec; - // Retry timeout in secs (24 hours) - int64_t retryTimeout_ = kRetryTimeoutInSec; // Flag to indicate whether the license manager is retrying bool isRetrying_ = false; // Timestamp of the last failed verify license request - int64_t retryStartTime_ = 0; - // Flag to indicate whether the last verify license request is successful - bool lastVerifySuccess_ = false; + int64_t retryStartTime_ = INT64_MAX; + bool isLMNormal_ = false; std::unique_ptr bgThread_ = nullptr; kvstore::KVStore* kvstore_; @@ -225,6 +229,7 @@ class LicenseManagerConnector final { // If the LMC is not ready, all heartbeat will be rejected bool dropAllHosts_ = false; + bool isOverLimit_ = false; }; } // namespace nebula diff --git a/src/common/encryption/test/CMakeLists.txt b/src/common/encryption/test/CMakeLists.txt index 187fdaf00cf..540e39f1714 100644 --- a/src/common/encryption/test/CMakeLists.txt +++ b/src/common/encryption/test/CMakeLists.txt @@ -2,26 +2,6 @@ # # This source code is licensed under Apache 2.0 License. -nebula_add_test( - NAME - license_test - SOURCES - LicenseTest.cpp - OBJECTS - $ - $ - $ - $ - $ - # mac addr - $ - - LIBRARIES - gtest - ${THRIFT_LIBRARIES} - ${PROXYGEN_LIBRARIES} -) - nebula_add_test( NAME encryption_utils_test @@ -97,7 +77,6 @@ $ $ $ $ - $ $ $ $ diff --git a/src/common/encryption/test/LicenseManagerConnectorTest.cpp b/src/common/encryption/test/LicenseManagerConnectorTest.cpp index 7e3754f0551..d3006793acb 100644 --- a/src/common/encryption/test/LicenseManagerConnectorTest.cpp +++ b/src/common/encryption/test/LicenseManagerConnectorTest.cpp @@ -24,7 +24,7 @@ auto LMCIns = nebula::LicenseManagerConnector::getInstance(); TEST(LicenseManagerConnectorTest, getLMIdTest) { auto res = LMCIns->getLMId(); EXPECT_TRUE(res.ok()); - EXPECT_EQ(9, res.value().size()); + EXPECT_EQ(9, LMCIns->LMId_.size()); } TEST(LicenseManagerConnectorTest, buildValidateBodyTest) { diff --git a/src/common/encryption/test/LicenseTest.cpp b/src/common/encryption/test/LicenseTest.cpp deleted file mode 100644 index 8cb27724aa4..00000000000 --- a/src/common/encryption/test/LicenseTest.cpp +++ /dev/null @@ -1,292 +0,0 @@ -/* Copyright (c) 2020 vesoft inc. All rights reserved. - * - * This source code is licensed under Apache 2.0 License. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "common/encryption/License.h" -#include "common/network/NetworkUtils.h" - -namespace nebula { -namespace encryption { -// Dummy mac addresses -const char macAddr1[] = "92:BD:91:50:5E:75"; -const char macAddr2[] = "9D:B6:8C:91:1F:11"; -const char macAddr3[] = "DE:94:46:FD:73:C1"; -const char macAddr4[] = "DE:94:46:4D:73:C1"; - -// using encryption::License; -TEST(LicenseGeneratorTool, BloomFilterTest) { - std::vector keyVec{"adasdadasdadasd", - "fsafljfiogerklio9)nf", - "akdodsgjiowoo87*&7hb3eb fsdf 3", - "wqqq", - "nebula::encryption::License::genBloomFil(keyVec);", - "ne231bula::encryption::License::genBloomter(keyVec);", - "ne231bu2314la::encryption::License::genBmFilter(keyVec);", - "ne231bu2314la::encryption::License::genBmFilter;", - "qwefjgpwejp"}; - - LOG(INFO) << "Building bit vector..."; - auto bitVec = License::genBitVector(keyVec); - - LOG(INFO) << "bitVec binary: " << bitVec << " size: " << bitVec.size(); - - auto base64 = proxygen::base64Encode(folly::StringPiece((bitVec))); - LOG(INFO) << "bitVec base64: " << base64 << " length: " << base64.size(); - - LOG(INFO) << "Looking for existing keys..."; - for (auto& ele : keyVec) { - EXPECT_TRUE(License::lookupKey(ele, bitVec)); - } - - LOG(INFO) << "Looking for non-existing keys..."; - int falsePositiveCount = 0; - for (auto i = 0; i < 100; i++) { - if (License::lookupKey(std::string(i, 'b'), bitVec)) { - ++falsePositiveCount; - } - } - double falsePositiveRate = falsePositiveCount / 100.0; - LOG(INFO) << "False positive rate: " << falsePositiveRate; - EXPECT_LT(falsePositiveRate, 0.15); -} - -TEST(LicenseGeneratorTool, HardwareCheckTest) { - // Generate 2 machine codes from dummy mac addresses - auto encodedMacAddrs = folly::join(",", {macAddr1, macAddr2}); - auto machineCode1 = License::genMachineCode(encodedMacAddrs); - - encodedMacAddrs = folly::join(",", {macAddr3, macAddr4}); - auto machineCode2 = License::genMachineCode(encodedMacAddrs); - - // Generate cluster code - const std::string clusterCode = License::genClusterCode({machineCode1, machineCode2}); - LOG(INFO) << "Cluster code: " << clusterCode; - - // Validate authorized machine codes - EXPECT_EQ(Status::OK(), License::checkMachineCode(machineCode1, clusterCode)); - EXPECT_EQ(Status::OK(), License::checkMachineCode(machineCode2, clusterCode)); - - // Check unauthorized machine code - std::string machineCode3 = "d6QqwqCHJK0j0LasdugfuweSNiCaXu3rdfy6rJKF213A=%"; - EXPECT_EQ(Status::Error(), License::checkMachineCode("machineCode", clusterCode)); -} - -// Simulate the case: -// 3 machines with 50 network interfaces each -TEST(LicenseGeneratorTool, MultipleMacAddrTest) { - auto machineCode1 = License::genMachineCode( - "5a:21:f5:08:e2:c6,4a:d9:ca:31:ba:74,4a:d9:ca:31:ba:74,67:A8:3B:70:60:03,5F:C1:43:08:8A:E4," - "ED:3B:37:F4:73:38,6C:77:EC:34:F2:2D,CA:D6:02:92:B9:D1,75:42:C5:E6:E0:21,09:03:F0:5D:9C:74," - "34:73:FE:D4:75:E1,DC:2B:5F:8F:91:EA,65:23:C7:36:95:87,6C:F2:AD:C1:C9:FB,8E:47:3B:36:E8:81," - "37:37:1C:1A:D0:2B,7A:A2:B2:CB:0B:DC,91:67:DB:BA:D6:73,3D:B4:B3:3A:9F:48,3C:50:C3:62:88:06," - "1B:C1:C1:0D:36:F6,A5:E5:0F:86:44:2B,DC:8C:84:A4:D4:1C,C0:A0:93:2B:63:C7,0A:5F:CF:38:CD:E5," - "08:D6:36:23:08:87,23:CC:71:CE:55:B8,E1:77:B6:D1:9A:2B,1A:62:A3:11:D7:EB,44:E2:68:86:3B:60," - "F5:9B:0E:3B:0A:1A,C5:00:D5:CB:EF:0F,AF:20:67:06:AC:CB,C2:31:D1:66:A6:1F,48:81:7C:69:C9:87," - "4C:DB:FD:BC:EB:28,09:5A:25:1F:86:B9,27:41:67:FE:26:98,77:90:84:BD:77:E1,E5:8C:8C:65:2D:4B," - "3F:59:35:C2:E7:86,32:A4:F9:A8:39:87,D8:59:8C:EB:BE:FD,7C:86:EB:70:1E:CE,71:AC:55:24:80:27," - "97:18:82:24:E4:80,44:FB:36:D2:CC:60,21:58:41:39:34:3E,3C:8C:14:E9:CD:34,54:AC:BE:C7:99:4B"); - LOG(INFO) << "Machine code 1: " << machineCode1; - - auto machineCode2 = License::genMachineCode( - "02:42:1e:0e:97:1a,5a:21:f5:08:e2:c6,4a:d9:ca:31:ba:74,9e:fb:23:43:af:63,EA:47:DA:5B:21:4A," - "E1:8A:14:E6:97:8E,E8:ED:36:83:DB:8D,02:22:C1:BB:DD:8F,23:DD:3C:60:7E:43,DB:F5:C1:D1:95:9D," - "D3:A7:21:7D:25:CC,B9:FE:DE:49:A5:9C,57:26:89:C7:FE:BE,FE:A9:4E:E2:FB:36,95:43:FD:13:88:75," - "C9:33:B0:2C:64:C5,6F:E2:79:E7:FE:23,36:83:3C:7F:73:C7,57:46:95:B8:FB:43,48:26:BE:2B:83:EA," - "7B:61:39:22:7F:79,D2:42:38:0B:E5:AE,84:9D:43:DC:08:FB,F7:83:4F:93:1F:0E,42:39:EB:7B:58:20," - "53:29:51:31:E2:68,16:6A:36:89:18:91,E2:8F:59:E9:33:4D,39:EF:C9:3B:21:5A,39:E8:EB:89:9A:CA," - "24:5D:63:98:14:2B,02:A0:BE:E2:F6:3F,83:2A:C8:4D:11:21,64:73:AB:8E:47:CD,D6:09:79:5F:A9:D9," - "65:C2:70:13:18:4D,B9:02:C9:11:14:D9,BB:4E:E7:D0:20:8E,1E:B4:4A:50:4A:67,2E:E2:27:94:5E:FA," - "A6:B6:45:17:DC:02,1A:04:9F:93:06:93,20:83:58:A1:E4:72,FE:20:3D:B8:DB:B5,54:53:46:51:0F:33," - "F8:7F:EE:DD:14:BD,E8:AD:B9:52:52:B2,12:E8:3E:65:22:55,A5:75:72:A1:86:6C,55:B1:1F:1C:0D:02"); - LOG(INFO) << "Machine code 2: " << machineCode2; - - auto machineCode3 = License::genMachineCode( - "40:61:C4:B6:A3:35,18:7A:05:95:72:AF,3C:75:FD:E2:32:0D,13:C6:F0:AC:22:F1,79:6F:1D:94:68:E3," - "3E:2B:BC:C6:E4:3F,43:F9:B7:29:01:69,EC:1D:DE:2B:D7:B2,13:35:EA:87:D7:C2,53:0F:31:C3:93:81," - "31:F3:80:20:54:63,17:F3:8F:22:79:11,23:7C:76:75:26:C9,13:88:0B:3F:98:0E,E9:82:0E:08:14:53," - "89:3F:2E:03:BF:A8,80:96:7B:AB:6D:11,B3:9E:58:F7:B6:98,13:BF:ED:83:27:4A,FE:9A:D4:29:98:86," - "FD:84:1D:E7:60:D0,03:4D:A0:F9:4E:E7,6A:00:93:2D:B5:DF,E2:84:25:E6:9C:6A,57:9D:4B:7C:57:4D," - "04:F2:DC:61:F5:44,03:F5:5F:8B:A4:62,DF:78:67:22:90:EF,94:CE:61:7A:A9:43,4F:96:9E:E8:92:43," - "73:30:3E:67:74:3B,4F:29:90:33:A5:AA,5A:36:8B:7A:E4:40,16:49:3F:F0:6A:40,F1:EC:85:61:3A:4A," - "69:AC:56:B4:D8:D6,6C:AF:D1:4D:D8:F3,19:5F:5A:16:B9:FB,9C:D1:A0:33:89:FD,46:DB:B5:2D:0A:95," - "88:44:00:6D:01:E9,90:A2:BF:15:2D:83,D7:42:C4:27:29:D3,0E:C1:1B:E3:AF:69,52:E4:24:23:04:AB," - "95:77:C1:2C:BC:94,37:87:08:4D:3E:41,D7:C3:9D:B1:75:36,97:69:D9:49:6A:0E,58:6D:91:F1:34:58"); - LOG(INFO) << "Machine code 3: " << machineCode3; - - // Generate cluster code - const std::string clusterCode = - License::genClusterCode({machineCode1, machineCode2, machineCode3}); - LOG(INFO) << "Cluster code: " << clusterCode; - - // Validate authorized machine codes - EXPECT_EQ(Status::OK(), License::checkMachineCode(machineCode1, clusterCode)); - EXPECT_EQ(Status::OK(), License::checkMachineCode(machineCode2, clusterCode)); - EXPECT_EQ(Status::OK(), License::checkMachineCode(machineCode3, clusterCode)); - EXPECT_EQ(Status::OK(), License::checkMachineCode("19:5F:5A:16:B9:FB", clusterCode)); - - // Validate unauthorized machine code - EXPECT_EQ(Status::Error(), License::checkMachineCode("19:5F:5A:16:9B:FB", clusterCode)); -} - -std::string gen_random(const int len) { - static const char alphanum[] = - "0123456789" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz"; - std::string tmp_s; - tmp_s.reserve(len); - - for (int i = 0; i < len; ++i) { - tmp_s += alphanum[rand() % (sizeof(alphanum) - 1)]; - } - - return tmp_s; -} - -// 5 machines, each has 5 mac address -TEST(LicenseGeneratorTool, ClusterCodeLengthTest) { - std::vector keyVec; - keyVec.reserve(5); - for (int i = 0; i < 5; i++) { - std::vector macs; - macs.reserve(5); - for (int j = 0; j < 5; j++) { - macs.push_back(gen_random(10)); - } - auto encodedMacAddrs = folly::join(",", macs); - keyVec.push_back(License::genMachineCode(encodedMacAddrs)); - } - - const std::string clusterCode = License::genClusterCode(keyVec); - // 52 chars(v3.3) vs 12 chars(v3.2) - DLOG(INFO) << "Cluster code: " << clusterCode; -} - -// To test the previous version of license still works -// Last updated: 2022-10-26 (release v3.3) -TEST(LicenseGeneratorTool, CompatibilityTest) { - // Check previous license( $ $ - $ $ $ ) diff --git a/src/graph/context/test/CMakeLists.txt b/src/graph/context/test/CMakeLists.txt index cf73acd214a..797519c9b2c 100644 --- a/src/graph/context/test/CMakeLists.txt +++ b/src/graph/context/test/CMakeLists.txt @@ -19,8 +19,6 @@ SET(CONTEXT_TEST_LIBS $ $ $ - $ - $ $ $ $ diff --git a/src/graph/executor/test/CMakeLists.txt b/src/graph/executor/test/CMakeLists.txt index eac4bfce740..26f051acd96 100644 --- a/src/graph/executor/test/CMakeLists.txt +++ b/src/graph/executor/test/CMakeLists.txt @@ -4,7 +4,6 @@ SET(EXEC_QUERY_TEST_OBJS $ - $ $ $ $ diff --git a/src/graph/optimizer/test/CMakeLists.txt b/src/graph/optimizer/test/CMakeLists.txt index 10248d3ddd0..5c6ebd71361 100644 --- a/src/graph/optimizer/test/CMakeLists.txt +++ b/src/graph/optimizer/test/CMakeLists.txt @@ -16,7 +16,6 @@ set(OPTIMIZER_TEST_LIB $ $ $ - $ $ $ $ diff --git a/src/graph/planner/test/CMakeLists.txt b/src/graph/planner/test/CMakeLists.txt index a486572c113..eab01937c44 100644 --- a/src/graph/planner/test/CMakeLists.txt +++ b/src/graph/planner/test/CMakeLists.txt @@ -39,7 +39,6 @@ nebula_add_test( $ $ $ - $ $ $ $ diff --git a/src/graph/service/GraphFlags.cpp b/src/graph/service/GraphFlags.cpp index 461e71f434f..85f7499591a 100644 --- a/src/graph/service/GraphFlags.cpp +++ b/src/graph/service/GraphFlags.cpp @@ -116,9 +116,6 @@ DEFINE_string(ldap_searchfilter, "", "Use search filter, more flexible than sear DEFINE_int32(num_rows_to_check_memory, 1024, "number rows to check memory"); -// License file path -DEFINE_string(license_path, "/nebula.license", "File path to license file"); - // audit DEFINE_bool(enable_audit, false, "Whether to enable the audit log."); DEFINE_string(audit_log_handler, "file", "Where to write the audit log. Optional: [ file | es ]"); diff --git a/src/graph/service/GraphFlags.h b/src/graph/service/GraphFlags.h index c7c73b6189b..419cddbccb5 100644 --- a/src/graph/service/GraphFlags.h +++ b/src/graph/service/GraphFlags.h @@ -80,8 +80,6 @@ DECLARE_bool(enable_client_white_list); DECLARE_string(client_white_list); DECLARE_int32(num_rows_to_check_memory); -// License file -DECLARE_string(license_path); // audit DECLARE_bool(enable_audit); diff --git a/src/graph/util/test/CMakeLists.txt b/src/graph/util/test/CMakeLists.txt index 64584d0109a..8ec346efe20 100644 --- a/src/graph/util/test/CMakeLists.txt +++ b/src/graph/util/test/CMakeLists.txt @@ -40,8 +40,6 @@ nebula_add_test( $ $ $ - $ - $ $ $ $ diff --git a/src/graph/validator/test/CMakeLists.txt b/src/graph/validator/test/CMakeLists.txt index d2973ce1f0b..5809183f534 100644 --- a/src/graph/validator/test/CMakeLists.txt +++ b/src/graph/validator/test/CMakeLists.txt @@ -46,7 +46,6 @@ set(VALIDATOR_TEST_LIBS $ $ $ - $ $ $ $ diff --git a/src/graph/visitor/test/CMakeLists.txt b/src/graph/visitor/test/CMakeLists.txt index d54aa5e27c0..57ff999dcb7 100644 --- a/src/graph/visitor/test/CMakeLists.txt +++ b/src/graph/visitor/test/CMakeLists.txt @@ -63,7 +63,6 @@ nebula_add_test( $ $ $ - $ $ $ $ diff --git a/src/kvstore/cache/test/CMakeLists.txt b/src/kvstore/cache/test/CMakeLists.txt index dc2c69367d2..fd8ce713656 100644 --- a/src/kvstore/cache/test/CMakeLists.txt +++ b/src/kvstore/cache/test/CMakeLists.txt @@ -31,7 +31,6 @@ set(cache_test_deps $ $ $ - $ $ $ $ diff --git a/src/kvstore/listener/test/CMakeLists.txt b/src/kvstore/listener/test/CMakeLists.txt index c753d286675..7c2c7911e95 100644 --- a/src/kvstore/listener/test/CMakeLists.txt +++ b/src/kvstore/listener/test/CMakeLists.txt @@ -16,7 +16,6 @@ set(LISTENER_TEST_LIBS $ $ $ - $ $ $ $ diff --git a/src/kvstore/raftex/test/CMakeLists.txt b/src/kvstore/raftex/test/CMakeLists.txt index 13cec52ec60..09772065508 100644 --- a/src/kvstore/raftex/test/CMakeLists.txt +++ b/src/kvstore/raftex/test/CMakeLists.txt @@ -7,7 +7,6 @@ set(RAFTEX_TEST_LIBS $ $ $ - $ $ $ $ diff --git a/src/kvstore/test/CMakeLists.txt b/src/kvstore/test/CMakeLists.txt index b115066e84c..7ddc682d469 100644 --- a/src/kvstore/test/CMakeLists.txt +++ b/src/kvstore/test/CMakeLists.txt @@ -16,7 +16,6 @@ set(KVSTORE_TEST_LIBS $ $ $ - $ $ $ $ diff --git a/src/meta/CMakeLists.txt b/src/meta/CMakeLists.txt index aba7356fc7e..2c2f0e6b0d2 100644 --- a/src/meta/CMakeLists.txt +++ b/src/meta/CMakeLists.txt @@ -55,7 +55,6 @@ nebula_add_library( processors/admin/GetMetaDirInfoProcessor.cpp processors/admin/VerifyClientVersionProcessor.cpp processors/admin/SaveGraphVersionProcessor.cpp - processors/admin/GetLicenseProcessor.cpp processors/admin/VariableProcessor.cpp processors/config/RegConfigProcessor.cpp processors/config/GetConfigProcessor.cpp @@ -176,7 +175,6 @@ set(meta_test_deps $ $ $ - $ $ $ $ diff --git a/src/meta/MetaServiceHandler.cpp b/src/meta/MetaServiceHandler.cpp index 438b07209b5..19347cf7917 100644 --- a/src/meta/MetaServiceHandler.cpp +++ b/src/meta/MetaServiceHandler.cpp @@ -12,7 +12,6 @@ #include "meta/processors/admin/CreateBackupProcessor.h" #include "meta/processors/admin/CreateSnapshotProcessor.h" #include "meta/processors/admin/DropSnapshotProcessor.h" -#include "meta/processors/admin/GetLicenseProcessor.h" #include "meta/processors/admin/GetMetaDirInfoProcessor.h" #include "meta/processors/admin/ListClusterInfoProcessor.h" #include "meta/processors/admin/ListSnapshotsProcessor.h" @@ -673,12 +672,6 @@ folly::Future MetaServiceHandler::future_getSegmentId( RETURN_FUTURE(processor); } -folly::Future MetaServiceHandler::future_getLicense( - const cpp2::GetLicenseReq& req) { - auto* processor = GetLicenseProcessor::instance(kvstore_); - RETURN_FUTURE(processor); -} - folly::Future MetaServiceHandler::future_getMetaSyncProgress( const cpp2::GetSyncProgressReq& req) { auto* processor = GetSyncProgressProcessor::instance(kvstore_); diff --git a/src/meta/MetaServiceHandler.h b/src/meta/MetaServiceHandler.h index b1aeef10439..27dfa441d78 100644 --- a/src/meta/MetaServiceHandler.h +++ b/src/meta/MetaServiceHandler.h @@ -280,10 +280,6 @@ class MetaServiceHandler final : public cpp2::MetaServiceSvIf { folly::Future future_saveGraphVersion( const cpp2::SaveGraphVersionReq& req) override; - // Enterprise exclusive - // Requests license from meta - folly::Future future_getLicense(const cpp2::GetLicenseReq& req) override; - folly::Future future_getWorkerId(const cpp2::GetWorkerIdReq& req) override; folly::Future future_getSegmentId( diff --git a/src/meta/processors/admin/GetLicenseProcessor.cpp b/src/meta/processors/admin/GetLicenseProcessor.cpp deleted file mode 100644 index 3657e817177..00000000000 --- a/src/meta/processors/admin/GetLicenseProcessor.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/* Copyright (c) 2022 vesoft inc. All rights reserved. - * - * This source code is licensed under Apache 2.0 License. - */ - -#include "meta/processors/admin/GetLicenseProcessor.h" - -#include "common/encryption/License.h" - -namespace nebula { -namespace meta { -void GetLicenseProcessor::process(const cpp2::GetLicenseReq& req) { - UNUSED(req); - LOG(INFO) << "[License] Received GetLicense request"; - std::string licenseContent = ""; - std::string licenseKey = ""; - - // Get singleton - auto licenseIns = encryption::License::getInstance(); - - // Parse license file to get license content - auto contentCheckStatus = encryption::License::parseLicenseContent(licenseIns->getLicensePath()); - if (!contentCheckStatus.ok()) { - LOG(ERROR) << "[License] Failed to parse the license file: " << contentCheckStatus.status(); - } else { - licenseContent = std::move(contentCheckStatus).value(); - } - - // Parse license file to get license key - auto parseLicenseKeyStatus = encryption::License::parseLicenseKey(licenseIns->getLicensePath()); - if (!parseLicenseKeyStatus.ok()) { - LOG(ERROR) << "[License] Failed to parse the license file: " << parseLicenseKeyStatus.status(); - } else { - licenseKey = parseLicenseKeyStatus.value(); - } - - // Fill license into response - // We don't check whether the license is valid or not here, the content will be send back to - // graph/storage side to check - resp_.licenseContent_ref() = licenseContent; - resp_.licenseKey_ref() = licenseKey; - resp_.code_ref() = nebula::cpp2::ErrorCode::SUCCEEDED; - - onFinished(); -} -} // namespace meta -} // namespace nebula diff --git a/src/meta/processors/admin/GetLicenseProcessor.h b/src/meta/processors/admin/GetLicenseProcessor.h deleted file mode 100644 index 0f6b2d35ab1..00000000000 --- a/src/meta/processors/admin/GetLicenseProcessor.h +++ /dev/null @@ -1,30 +0,0 @@ -/* Copyright (c) 2022 vesoft inc. All rights reserved. - * - * This source code is licensed under Apache 2.0 License. - */ - -#ifndef META_GETLICENSEPROCESSOR_H_ -#define META_GETLICENSEPROCESSOR_H_ - -#include "meta/processors/BaseProcessor.h" - -namespace nebula { -namespace meta { -class GetLicenseProcessor final : public BaseProcessor { - public: - static GetLicenseProcessor* instance(kvstore::KVStore* kvstore) { - return new GetLicenseProcessor(kvstore); - } - - // This interface is enterprise exclusive - // This processor should return the license content and key. - // The parameter is unused. - void process(const cpp2::GetLicenseReq& req); - - private: - explicit GetLicenseProcessor(kvstore::KVStore* kvstore) - : BaseProcessor(kvstore) {} -}; -} // namespace meta -} // namespace nebula -#endif // META_GETLICENSEPROCESSOR_H_ diff --git a/src/meta/processors/admin/HBProcessor.cpp b/src/meta/processors/admin/HBProcessor.cpp index 9b20aaeb764..087a846d644 100644 --- a/src/meta/processors/admin/HBProcessor.cpp +++ b/src/meta/processors/admin/HBProcessor.cpp @@ -5,7 +5,6 @@ #include "meta/processors/admin/HBProcessor.h" -#include "common/base/Base.h" #include "common/encryption/LicenseManagerConnector.h" #include "common/time/WallClock.h" #include "meta/ActiveHostsMan.h" @@ -40,7 +39,7 @@ void HBProcessor::process(const cpp2::HBReq& req) { auto LMCIns = LicenseManagerConnector::getInstance(); if (!LMCIns->isMockingForTest()) { - // check whether meta should accept the heartbeat + // Check whether meta should accept the heartbeat if (LMCIns->dropAllHosts_) { LOG(INFO) << "License is not valid, reject heartbeat from " << host; handleErrorCode(nebula::cpp2::ErrorCode::E_INVALID_LICENSE_MANAGER_STATUS); @@ -48,7 +47,6 @@ void HBProcessor::process(const cpp2::HBReq& req) { return; } - // Check whether resource usage exceeds the limit auto ret = checkResourceUsage(role, host, cpuCore); if (ret != nebula::cpp2::ErrorCode::SUCCEEDED) { handleErrorCode(ret); @@ -151,104 +149,94 @@ void HBProcessor::process(const cpp2::HBReq& req) { // Checks the active node number of the given role // Rejects heartbeat if number reaches the max value -// The license only limits the number of graph and storage nodes, other role types won't be checked. +// The license only limits the number of graph and storage nodes, other role types won't be nebula::cpp2::ErrorCode HBProcessor::checkNodeNumber(const cpp2::HostRole role, - const HostAddr& host) { - // Only check the number of graph and storage hosts - if (role != cpp2::HostRole::GRAPH && role != cpp2::HostRole::STORAGE) { - return nebula::cpp2::ErrorCode::SUCCEEDED; - } - - // Get active hosts - auto activeHostsRet = ActiveHostsMan::getActiveHosts(kvstore_, 0, role); - if (!nebula::ok(activeHostsRet)) { - return nebula::error(activeHostsRet); - } - auto activeHosts = nebula::value(activeHostsRet); - auto activeHostsNum = activeHosts.size(); - - VLOG(2) << fmt::format("[License Manager] Active {} hosts number: {}", - apache::thrift::util::enumNameSafe(role), - activeHostsNum); - - // Get available nodes specified in license - auto LMCIns = LicenseManagerConnector::getInstance(); - std::atomic& availableNodesNum = (role == cpp2::HostRole::GRAPH) - ? LMCIns->resourceUsage_.availableGraphVal - : LMCIns->resourceUsage_.availableStorageVal; - - std::atomic& appliedNodesNum = (role == cpp2::HostRole::GRAPH) - ? LMCIns->resourceUsage_.approvedGraphVal - : LMCIns->resourceUsage_.approvedStorageVal; - // if the current host is registered and the number of active hosts is less than the max value, - // skip the check - if (std::find(activeHosts.begin(), activeHosts.end(), host) != activeHosts.end() && - availableNodesNum > 0) { - return nebula::cpp2::ErrorCode::SUCCEEDED; + const HostAddr& host, + const uint32_t activeHostsNum, + const uint32_t resourceCap, + bool isHostRegistered) { + bool pass = true; + // Reject the registered heartbeat + if (isHostRegistered) { + if (activeHostsNum > resourceCap) { // No available nodes left + pass = false; + } + } else { + // Reject the incoming heartbeat + if (activeHostsNum >= resourceCap) { // No available nodes left + pass = false; + } } - if (availableNodesNum.fetch_sub(1) <= 0) { // No available nodes left + if (!pass) { LOG(ERROR) << fmt::format( - "[License Manager] No available {} hosts left, heartbeat from {} is " - "rejected, total active {} hosts number applied: {}", + "The number of {} node has reached the maximum, the max number of {} node in the cluster " + "is {}, heartbeat from {} is rejected", apache::thrift::util::enumNameSafe(role), - host.toString(), apache::thrift::util::enumNameSafe(role), - appliedNodesNum); + resourceCap, + host.toString()); return nebula::cpp2::ErrorCode::E_NODE_NUMBER_EXCEED_LIMIT; } VLOG(2) << fmt::format("[License Manager] Available {} hosts number: {}", apache::thrift::util::enumNameSafe(role), - availableNodesNum); + resourceCap); + DLOG(INFO) << fmt::format( "[License Manager] Current the number of active {} nodes is {}, heartbeat from {} is " "accepted", apache::thrift::util::enumNameSafe(role), - availableNodesNum, + resourceCap, host.toString()); - DLOG(INFO) << "LMCIns->availableResource_: " << LMCIns->resourceUsage_.availableGraphVal << " " - << LMCIns->resourceUsage_.availableStorageVal; - return nebula::cpp2::ErrorCode::SUCCEEDED; } nebula::cpp2::ErrorCode HBProcessor::checkNodeCpu(const cpp2::HostRole role, const HostAddr& host, - const unsigned int cpuNum) { - // Only check the number of graph and storage hosts - if (role != cpp2::HostRole::GRAPH && role != cpp2::HostRole::STORAGE) { - return nebula::cpp2::ErrorCode::SUCCEEDED; + const unsigned int incomingCPUNum, + const unsigned int resourceCap, + bool isHostRegistered) { + // Get total cpu cores + auto res = meta::ActiveHostsMan::getHostInfoByRole(kvstore_, role); + if (!nebula::ok(res)) { + return nebula::error(res); } - - unsigned availableCpuCores = 0; - auto LMCIns = LicenseManagerConnector::getInstance(); - if (role == cpp2::HostRole::GRAPH) { - availableCpuCores = LMCIns->resourceUsage_.availableGraphVal.load(); - } else if (role == cpp2::HostRole::STORAGE) { - availableCpuCores = LMCIns->resourceUsage_.availableStorageVal.load(); - } else { // No need to check other role types - return nebula::cpp2::ErrorCode::SUCCEEDED; + uint32_t totalHostsNum = nebula::value(res).size(); + DLOG(INFO) << fmt::format("[License Manager] Total active {} nodes number: {}", + apache::thrift::util::enumNameSafe(role), + totalHostsNum); + uint32_t totalCPU = 0; + for (auto& hostInfo : nebula::value(res)) { + totalCPU += hostInfo.cpuNum_; + } + DLOG(INFO) << fmt::format("[License Manager] Total {} cpu cores: {}", + apache::thrift::util::enumNameSafe(role), + totalCPU); + + bool pass = true; + // Reject the registered heartbeat + if (isHostRegistered) { + if (totalCPU > resourceCap) { // No available cpu cores left + pass = false; + } + } else { + // If current total + coming host's cpu cores > resource cap, reject the heartbeat + if (totalCPU > resourceCap - incomingCPUNum) { + pass = false; + } } - if (cpuNum > availableCpuCores) { + if (!pass) { LOG(ERROR) << fmt::format( - "[License Manager] Current the number of cpu cores {} has reach the maximum cpu cores " - "allowed {}, " - "heartbeat from {} is rejected", - cpuNum, - availableCpuCores, + "[License Manager] The number of {} node CPU cores has reached the maximum, CPU core " + "maximum: {}, heartbeat from {} is rejected", + apache::thrift::util::enumNameSafe(role), + resourceCap, host.toString()); return nebula::cpp2::ErrorCode::E_TOTAL_CPU_CORE_EXCEED_LIMIT; } - // Reduce the available cpu cores - if (role == cpp2::HostRole::GRAPH) { - LMCIns->resourceUsage_.availableGraphVal.fetch_sub(cpuNum); - } else if (role == cpp2::HostRole::STORAGE) { - LMCIns->resourceUsage_.availableStorageVal.fetch_sub(cpuNum); - } - return nebula::cpp2::ErrorCode::SUCCEEDED; } @@ -261,80 +249,46 @@ nebula::cpp2::ErrorCode HBProcessor::checkResourceUsage(const cpp2::HostRole rol return nebula::cpp2::ErrorCode::SUCCEEDED; } - // Get active hosts + auto LMCIns = LicenseManagerConnector::getInstance(); + + // Get all alive hosts auto activeHostsRet = ActiveHostsMan::getActiveHosts(kvstore_, 0, role); if (!nebula::ok(activeHostsRet)) { return nebula::error(activeHostsRet); } auto activeHosts = nebula::value(activeHostsRet); - auto activeHostsNum = activeHosts.size(); - VLOG(2) << fmt::format("[License Manager] Active {} hosts number: {}", - apache::thrift::util::enumNameSafe(role), - activeHostsNum); - - // if the current host has been registered, no need to pull from LM - if (std::find(activeHosts.begin(), activeHosts.end(), host) != activeHosts.end()) { + // If the current host has been registered, and LM's status is normal, there is no need to pull + // from the LM + bool isHostRegistered = + std::find(activeHosts.begin(), activeHosts.end(), host) != activeHosts.end(); + if (isHostRegistered && !LMCIns->isOverLimit_) { return nebula::cpp2::ErrorCode::SUCCEEDED; } - // Check the resource usage via license manager - auto LMCIns = LicenseManagerConnector::getInstance(); + DLOG(INFO) << "[License Manager] Current host is not registered or license manager is over limit"; + // Pull resource usage from license manager auto validateRes = LMCIns->validateLicense(); - if (validateRes != LMStatus::Ready) { + if (!LMStatusHelper::isStatusNormal(validateRes)) { LOG(ERROR) << "[License Manager] Failed to validate license: " << LMStatusHelper::statusToString(validateRes); return nebula::cpp2::ErrorCode::E_INVALID_LICENSE_MANAGER_STATUS; } - // Get available resource specified in license - std::atomic& availableResource = (role == cpp2::HostRole::GRAPH) - ? LMCIns->resourceUsage_.availableGraphVal - : LMCIns->resourceUsage_.availableStorageVal; + // Get resource capacity + std::atomic& resourceCap = (role == cpp2::HostRole::GRAPH) + ? LMCIns->resourceUsage_.availableGraphVal + : LMCIns->resourceUsage_.availableStorageVal; auto resourceType = LMCIns->resourceUsage_.kind; - if (resourceType == "CPU") { - if (cpuNum > availableResource) { - LOG(ERROR) << fmt::format( - "[License Manager] The number of CPU cores {} has reached the maximum, " - "heartbeat from {} is rejected", - cpuNum, - availableResource, - host.toString()); - return nebula::cpp2::ErrorCode::E_TOTAL_CPU_CORE_EXCEED_LIMIT; - } - - // Reduce the available cpu cores - if (role == cpp2::HostRole::GRAPH) { - LMCIns->resourceUsage_.availableGraphVal.fetch_sub(cpuNum); - } else if (role == cpp2::HostRole::STORAGE) { - LMCIns->resourceUsage_.availableStorageVal.fetch_sub(cpuNum); - } - return nebula::cpp2::ErrorCode::SUCCEEDED; + DLOG(INFO) << "[License Manager] Resource type: " << resourceType + << ", graph resource cap: " << LMCIns->resourceUsage_.availableGraphVal + << ", storage resource cap: " << LMCIns->resourceUsage_.availableStorageVal; + if (resourceType == "CPU") { + return checkNodeCpu(role, host, cpuNum, resourceCap, isHostRegistered); } else if (resourceType == "NODE") { - if (availableResource.fetch_sub(1) <= 0) { // No available nodes left - LOG(ERROR) << fmt::format( - "The number of {} node has reached the maximum, heartbeat from {} is rejected", - apache::thrift::util::enumNameSafe(role), - host.toString()); - return nebula::cpp2::ErrorCode::E_NODE_NUMBER_EXCEED_LIMIT; - } - - VLOG(2) << fmt::format("[License Manager] Available {} hosts number: {}", - apache::thrift::util::enumNameSafe(role), - availableResource); - - DLOG(INFO) << fmt::format( - "[License Manager] Current the number of active {} nodes is {}, heartbeat from {} is " - "accepted", - apache::thrift::util::enumNameSafe(role), - availableResource, - host.toString()); - DLOG(INFO) << "LMCIns->availableResource_: " << LMCIns->resourceUsage_.availableGraphVal << " " - << LMCIns->resourceUsage_.availableStorageVal; - - return nebula::cpp2::ErrorCode::SUCCEEDED; + return checkNodeNumber(role, host, activeHosts.size(), resourceCap, isHostRegistered); } else { LOG(ERROR) << "[License Manager] Unknown limit resource type: " << resourceType; return nebula::cpp2::ErrorCode::E_UNKNOWN; diff --git a/src/meta/processors/admin/HBProcessor.h b/src/meta/processors/admin/HBProcessor.h index 300c437b4aa..d8e0f33665f 100644 --- a/src/meta/processors/admin/HBProcessor.h +++ b/src/meta/processors/admin/HBProcessor.h @@ -66,9 +66,15 @@ class HBProcessor : public BaseProcessor { nebula::cpp2::ErrorCode checkNodeCpu(const cpp2::HostRole role, const HostAddr& host, - const unsigned int cpuNum); - - nebula::cpp2::ErrorCode checkNodeNumber(const cpp2::HostRole role, const HostAddr& host); + const unsigned int incomingCPUNum, + const unsigned int resourceCap, + bool isHostRegistered); + + nebula::cpp2::ErrorCode checkNodeNumber(const cpp2::HostRole role, + const HostAddr& host, + const uint32_t activeHostsNum, + const uint32_t resourceCap, + bool isHostRegistered); void setLeaderInfo(); diff --git a/src/mock/MockCluster.cpp b/src/mock/MockCluster.cpp index 213fb8eef8a..464b5d6c96f 100644 --- a/src/mock/MockCluster.cpp +++ b/src/mock/MockCluster.cpp @@ -18,7 +18,6 @@ #include "storage/transaction/TransactionManager.h" DECLARE_int32(heartbeat_interval_secs); -DEFINE_string(license_path, "tests/secrets/nebula.license", "File path to license file"); namespace nebula { namespace mock { diff --git a/src/parser/test/CMakeLists.txt b/src/parser/test/CMakeLists.txt index 80f44dd5e0d..fd8a40d67ad 100644 --- a/src/parser/test/CMakeLists.txt +++ b/src/parser/test/CMakeLists.txt @@ -26,7 +26,6 @@ set(PARSER_TEST_LIBS $ $ $ - $ $ $ $ diff --git a/src/storage/test/CMakeLists.txt b/src/storage/test/CMakeLists.txt index 43adffa0749..86eed1edef6 100644 --- a/src/storage/test/CMakeLists.txt +++ b/src/storage/test/CMakeLists.txt @@ -28,7 +28,6 @@ set(storage_test_deps $ $ $ - $ $ $ $ diff --git a/src/tools/CMakeLists.txt b/src/tools/CMakeLists.txt index fd9617453fe..f87a5ab6903 100644 --- a/src/tools/CMakeLists.txt +++ b/src/tools/CMakeLists.txt @@ -63,7 +63,6 @@ set(tools_test_deps $ $ $ - $ $ $ $ @@ -82,8 +81,4 @@ nebula_add_subdirectory(meta-dump) nebula_add_subdirectory(db-dump) nebula_add_subdirectory(db-upgrade) nebula_add_subdirectory(meta-upgrade) - -# We don't want expose cluster-code-generator in the installation package -# nebula_add_subdirectory(cluster-code-generator) -nebula_add_subdirectory(machine-code-generator) nebula_add_subdirectory(db-playback) diff --git a/src/tools/cluster-code-generator/CMakeLists.txt b/src/tools/cluster-code-generator/CMakeLists.txt deleted file mode 100644 index 0ec3b538128..00000000000 --- a/src/tools/cluster-code-generator/CMakeLists.txt +++ /dev/null @@ -1,30 +0,0 @@ -# Copyright (c) 2022 vesoft inc. All rights reserved. -# -# This source code is licensed under Apache 2.0 License. - -nebula_add_executable( - NAME - cluster-code-generator - SOURCES - ClusterCodeGeneratorTool.cpp - OBJECTS - $ - $ - $ - $ - LIBRARIES - ${PROXYGEN_LIBRARIES} -) - -install( - TARGETS - cluster-code-generator - PERMISSIONS - OWNER_EXECUTE OWNER_WRITE OWNER_READ - GROUP_EXECUTE GROUP_READ - WORLD_EXECUTE WORLD_READ - DESTINATION - bin - COMPONENT - tool -) diff --git a/src/tools/cluster-code-generator/ClusterCodeGeneratorTool.cpp b/src/tools/cluster-code-generator/ClusterCodeGeneratorTool.cpp deleted file mode 100644 index 41e565fb424..00000000000 --- a/src/tools/cluster-code-generator/ClusterCodeGeneratorTool.cpp +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright (c) 2022 vesoft inc. All rights reserved. -// -// This source code is licensed under Apache 2.0 License. -// - -#include /* printf */ -#include /* exit */ - -#include "common/encryption/License.h" - -using nebula::encryption::License; - -DEFINE_string(code, - "", - "A list of machine codes has to be given. Each code should be separated by `,` and " - "no space included."); - -int main(int argc, char* argv[]) { - folly::init(&argc, &argv, true); - google::SetStderrLogging(google::INFO); - - // Currently we only support one option: code - if (FLAGS_code.empty()) { - LOG(INFO) << "Please specify the machine codes, each code should be separated by `,` and no " - "space included.\nUsage: --code="; - return -1; - } - - // Split machine codes from the input - std::vector machineCodes; - folly::split(",", FLAGS_code.c_str(), machineCodes, true); - - printf("Machine codes: "); - for (auto& ele : machineCodes) { - printf("%s ", ele.c_str()); - } - printf("\n"); - printf("********* Generating Cluster Code... *********\n"); - auto clusterCode = License::genClusterCode(machineCodes); - - if (clusterCode.empty()) { - printf("Failed to generate the Cluster Code\n"); - return EXIT_FAILURE; - } - - printf("********* Cluster Code Generation Finished *********\n"); - printf("Cluster Code:\n%s\n", clusterCode.c_str()); - - return 0; -} diff --git a/src/tools/machine-code-generator/CMakeLists.txt b/src/tools/machine-code-generator/CMakeLists.txt deleted file mode 100644 index 5be65951984..00000000000 --- a/src/tools/machine-code-generator/CMakeLists.txt +++ /dev/null @@ -1,31 +0,0 @@ -# Copyright (c) 2022 vesoft inc. All rights reserved. -# -# This source code is licensed under Apache 2.0 License. - - nebula_add_executable( - NAME - machine-code-generator - SOURCES - machineCodeGeneratorTool.cpp - OBJECTS - $ - $ - $ - $ - LIBRARIES - ${THRIFT_LIBRARIES} - ${PROXYGEN_LIBRARIES} -) - -install( - TARGETS - machine-code-generator - PERMISSIONS - OWNER_EXECUTE OWNER_WRITE OWNER_READ - GROUP_EXECUTE GROUP_READ - WORLD_EXECUTE WORLD_READ - DESTINATION - bin - COMPONENT - tool -) diff --git a/src/tools/machine-code-generator/machineCodeGeneratorTool.cpp b/src/tools/machine-code-generator/machineCodeGeneratorTool.cpp deleted file mode 100644 index 21b2ad61ee1..00000000000 --- a/src/tools/machine-code-generator/machineCodeGeneratorTool.cpp +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) 2022 vesoft inc. All rights reserved. -// -// This source code is licensed under Apache 2.0 License. -// - -#include - -#include "common/encryption/License.h" -#include "common/network/NetworkUtils.h" - -int main(int argc, char* argv[]) { - using nebula::encryption::License; - folly::init(&argc, &argv, true); - google::SetStderrLogging(google::INFO); - - printf("********* Generating Machine Code... *********\n"); - auto machineCode = License::genMachineCode(); - if (machineCode.empty()) { - printf("Failed to generate the Machine Code\n"); - return -1; - } - printf("********* Machine Code Generation Finished *********\n"); - printf("Machine Code:\n%s\n", machineCode.c_str()); - return 0; -} diff --git a/src/webservice/CMakeLists.txt b/src/webservice/CMakeLists.txt index 09534310809..5edcb65d439 100644 --- a/src/webservice/CMakeLists.txt +++ b/src/webservice/CMakeLists.txt @@ -11,7 +11,6 @@ nebula_add_library( GetStatsHandler.cpp Router.cpp StatusHandler.cpp - GetLicenseHandler.cpp SlowQueryHandler.cpp ) diff --git a/src/webservice/GetLicenseHandler.cpp b/src/webservice/GetLicenseHandler.cpp deleted file mode 100644 index d1d9bda1f30..00000000000 --- a/src/webservice/GetLicenseHandler.cpp +++ /dev/null @@ -1,72 +0,0 @@ -/* Copyright (c) 2022 vesoft inc. All rights reserved. - * - * This source code is licensed under Apache 2.0 License. - */ - -#include "webservice/GetLicenseHandler.h" - -#include -#include -#include - -#include "common/encryption/License.h" - -namespace nebula { - -using proxygen::HTTPMessage; -using proxygen::HTTPMethod; -using proxygen::ProxygenError; -using proxygen::ResponseBuilder; -using proxygen::UpgradeProtocol; - -void GetLicenseHandler::onRequest(std::unique_ptr headers) noexcept { - if (headers->getMethod().value() != HTTPMethod::GET) { - // Unsupported method - err_ = HttpCode::E_UNSUPPORTED_METHOD; - return; - } -} - -void GetLicenseHandler::onBody(std::unique_ptr) noexcept { - // Do nothing, we only support GET -} - -void GetLicenseHandler::onEOM() noexcept { - switch (err_) { - case HttpCode::E_UNSUPPORTED_METHOD: - ResponseBuilder(downstream_) - .status(WebServiceUtils::to(HttpStatusCode::METHOD_NOT_ALLOWED), - WebServiceUtils::toString(HttpStatusCode::METHOD_NOT_ALLOWED)) - .sendWithEOM(); - return; - default: - break; - } - - folly::dynamic vals = getLicense(); - ResponseBuilder(downstream_) - .status(WebServiceUtils::to(HttpStatusCode::OK), - WebServiceUtils::toString(HttpStatusCode::OK)) - .body(folly::toJson(vals)) - .sendWithEOM(); -} - -void GetLicenseHandler::onUpgrade(UpgradeProtocol) noexcept { - // Do nothing -} - -void GetLicenseHandler::requestComplete() noexcept { - delete this; -} - -void GetLicenseHandler::onError(ProxygenError error) noexcept { - LOG(ERROR) << "Web service StorageHttpHandler got error: " << proxygen::getErrorString(error); -} - -const folly::dynamic GetLicenseHandler::getLicense() const { - auto licenseIns = encryption::License::getInstance(); - auto licenseContent = licenseIns->getContent(); - return licenseContent; -} - -} // namespace nebula diff --git a/src/webservice/GetLicenseHandler.h b/src/webservice/GetLicenseHandler.h deleted file mode 100644 index 12837a6c5b6..00000000000 --- a/src/webservice/GetLicenseHandler.h +++ /dev/null @@ -1,43 +0,0 @@ -/* Copyright (c) 2022 vesoft inc. All rights reserved. - * - * This source code is licensed under Apache 2.0 License. - */ - -#ifndef WEBSERVICE_GETLICENSEHANDLER_H_ -#define WEBSERVICE_GETLICENSEHANDLER_H_ - -#include -#include - -#include "common/base/Base.h" -#include "webservice/Common.h" - -namespace nebula { - -class GetLicenseHandler : public proxygen::RequestHandler { - public: - GetLicenseHandler() = default; - - void onRequest(std::unique_ptr headers) noexcept override; - - void onBody(std::unique_ptr body) noexcept override; - - void onEOM() noexcept override; - - void onUpgrade(proxygen::UpgradeProtocol proto) noexcept override; - - void requestComplete() noexcept override; - - void onError(proxygen::ProxygenError err) noexcept override; - - protected: - const folly::dynamic getLicense() const; - - protected: - HttpCode err_{HttpCode::SUCCEEDED}; - bool returnJson_{false}; - std::vector statNames_; -}; - -} // namespace nebula -#endif // WEBSERVICE_GETLICENSEHANDLER_H_ diff --git a/src/webservice/WebService.cpp b/src/webservice/WebService.cpp index 3d9434bb2b7..36f528344f2 100644 --- a/src/webservice/WebService.cpp +++ b/src/webservice/WebService.cpp @@ -12,7 +12,6 @@ #include "common/thread/NamedThread.h" #include "kvstore/RecvFilesHandler.h" #include "webservice/GetFlagsHandler.h" -#include "webservice/GetLicenseHandler.h" #include "webservice/GetStatsHandler.h" #include "webservice/NotFoundHandler.h" #include "webservice/Router.h" @@ -90,11 +89,6 @@ Status WebService::start(uint16_t httpPort) { DCHECK(params.empty()); return new StatusHandler(); }); - // License - router().get("/license").handler([](web::PathParams&& params) { - DCHECK(params.empty()); - return new GetLicenseHandler(); - }); router().get("/slow_query").handler([](web::PathParams&& params) { DCHECK(params.empty()); return new SlowQueryHandler(); diff --git a/src/webservice/test/CMakeLists.txt b/src/webservice/test/CMakeLists.txt index 86e7ce7ba82..f65f244e5fe 100644 --- a/src/webservice/test/CMakeLists.txt +++ b/src/webservice/test/CMakeLists.txt @@ -14,8 +14,6 @@ set(ws_test_deps $ $ $ - $ - $ ) nebula_add_test( @@ -70,17 +68,3 @@ nebula_add_test( ${PROXYGEN_LIBRARIES} gtest ) - -nebula_add_test( - NAME - http_license_test - SOURCES - LicenseHandlerTest.cpp - OBJECTS - ${ws_test_deps} - $ - LIBRARIES - ${PROXYGEN_LIBRARIES} - gtest - curl -) diff --git a/src/webservice/test/LicenseHandlerTest.cpp b/src/webservice/test/LicenseHandlerTest.cpp deleted file mode 100644 index 467e5e1e53c..00000000000 --- a/src/webservice/test/LicenseHandlerTest.cpp +++ /dev/null @@ -1,77 +0,0 @@ -/* Copyright (c) 2019 vesoft inc. All rights reserved. - * - * This source code is licensed under Apache 2.0 License. - */ - -#include -#include - -#include "common/base/Base.h" -#include "common/encryption/License.h" -#include "common/fs/TempDir.h" -#include "common/http/HttpClient.h" -#include "version/Version.h" -#include "webservice/WebService.h" - -namespace nebula { - -using nebula::fs::TempDir; - -class LicenseHandlerTestEnv : public ::testing::Environment { - public: - void SetUp() override { - FLAGS_ws_http_port = 0; - VLOG(1) << "Starting web service..."; - - webSvc_ = std::make_unique(); - auto status = webSvc_->start(); - getDummyLicense(); - ASSERT_TRUE(status.ok()) << status; - } - - void getDummyLicense() { - auto licenseIns = encryption::License::getInstance(); - folly::dynamic dummyContent = folly::dynamic::object(); - dummyContent["vendor"] = "vesoft"; - dummyContent["graphdSpec"] = folly::dynamic::object("nodes", 100); - dummyContent["storagedSpec"] = folly::dynamic::object("nodes", 100); - dummyContent["storagedSpec"] = folly::dynamic::object("nodes", 100); - dummyContent["expirationDate"] = "2021-11-30T15:59:59.000Z"; - licenseIns->setContent(dummyContent); - } - - void TearDown() override { - webSvc_.reset(); - VLOG(1) << "Web service stopped"; - } - - protected: - std::unique_ptr webSvc_; -}; - -TEST(LicenseHandlerTest, SimpleTest) { - { - auto url = "/license"; - auto request = - folly::stringPrintf("http://%s:%d%s", FLAGS_ws_ip.c_str(), FLAGS_ws_http_port, url); - auto resp = HttpClient::instance().get(request); - ASSERT_EQ(resp.curlCode, 0); - auto json = folly::parseJson(resp.body); - LOG(INFO) << folly::toPrettyJson(json); - - ASSERT_EQ("vesoft", json["vendor"]); - ASSERT_EQ("{\"nodes\":100}", folly::toJson(json["graphdSpec"])); - ASSERT_EQ(100, json["storagedSpec"]["nodes"]); - ASSERT_EQ("2021-11-30T15:59:59.000Z", json["expirationDate"].asString()); - } -} - -} // namespace nebula - -int main(int argc, char** argv) { - ::testing::InitGoogleTest(&argc, argv); - folly::init(&argc, &argv, true); - google::SetStderrLogging(google::INFO); - ::testing::AddGlobalTestEnvironment(new nebula::LicenseHandlerTestEnv()); - return RUN_ALL_TESTS(); -} diff --git a/tests/common/nebula_service.py b/tests/common/nebula_service.py index b6b500f25eb..42b87dbf552 100644 --- a/tests/common/nebula_service.py +++ b/tests/common/nebula_service.py @@ -459,9 +459,6 @@ def get_log_file_path(self, process_name, process_index=0): else: raise Exception('not support process name: {}'.format(process_name)) - def get_license_file_path(self): - return self.work_dir + '/share/resources/nebula.license' - def update_graphd_param(self, config): self.graphd_param.update(config) @@ -495,9 +492,6 @@ def _copy_nebula_conf(self): shutil.copy(self.src_dir + '/tests/cert/test.derive.key', resources_dir) shutil.copy(self.src_dir + '/tests/cert/test.derive.crt', resources_dir) - # license - shutil.copy(self.src_dir + '/tests/secrets/nebula.license', resources_dir) - def _copy_standalone_conf(self): bin_path = self.build_dir + '/bin/' conf_path = self.src_dir + '/conf/' @@ -524,9 +518,6 @@ def _copy_standalone_conf(self): shutil.copy(self.src_dir + '/tests/cert/test.derive.key', resources_dir) shutil.copy(self.src_dir + '/tests/cert/test.derive.crt', resources_dir) - # license - shutil.copy(self.src_dir + '/tests/secrets/nebula.license', resources_dir) - @staticmethod def is_port_in_use(port): with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as s: diff --git a/tests/secrets/nebula_test.license.gpg b/tests/secrets/nebula_test.license.gpg deleted file mode 100644 index 5997a0e0f21d18d94baeead5df058d3e2b673640..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 958 zcmV;v13~sMP0jw<|EZ_P_wES_NIe2-A*?z~ZH#_*XpOZSq zn@x%vT8X=O4PG!W%!-y%B#H1+)=XH?HYkNEfu20fJDF5>aG2Zw7wW^?qZx_MdB!16 zSgH}JTS*6^PjjQNLRME5kvzg%Y>EYP7X!M@VxevfOtkF_OpXT4tu(+>Ld zDaU0lNgyCn=8=}zoa+6aag-Cm!wR9AZW2Uy(_DIuNf!HM=5JO;brKq zg@jrpD6{?(GF~I#es_{O!$>uX)?nKa{-=UB@K)5>-L!@v9 zs7|a_@9(GoR&7#6fXA|!1n}~L1(>u013nVMRy}3Suf(nqWU%EoHpLRj69T)o?D>s- z@f`ckrI$grrz(_dsmt3Oilk`@>ewUT1IhG+FV$PCm~m{^hpzn~<3v!rqxZJRF_FYg zzR~dD9!g)+?3a`XHFeR*!0XG9d=x+BHHra1;qKEt$o#T>j zPmV`s@@d^&7eyDI>JDs5lQ9Zl_>_af-8bO< zY0L99HKOtU7LtyJkri@3SXT|*+*hUy^xNB~*XLO8vt0M&ROCN+Dak;Zp6h(Rh z)5yUvN>s})ztRy)^cyi8_fD&m!}~j8kpt}Ou;>U{ zmRv2Ns(n|e6UJkAp(>m~^}G@!y46HvnSZd-oMgh8$Wqiz=>OX+$>}@hCtsn2X?8e$ zM$}7sqfh? g?iSt=Z-;hGXNzeWjoJCD*YDUZ0pE;yM{neUi`jSK-T(jq