diff --git a/src/cm/CMakeLists.txt b/src/cm/CMakeLists.txt index 5a8789974..1471917f6 100644 --- a/src/cm/CMakeLists.txt +++ b/src/cm/CMakeLists.txt @@ -8,7 +8,15 @@ # Dependencies # ###################################################################################################################### -find_package(Poco REQUIRED Util) +find_package( + Poco + REQUIRED + Crypto + DataSQLite + Net + NetSSL + Util +) # ###################################################################################################################### # Target properties @@ -24,7 +32,9 @@ set(TARGET_PREFIX ${TARGET_PREFIX}_cm) add_subdirectory(app) add_subdirectory(communication) add_subdirectory(config) -# add_subdirectory(database) +add_subdirectory(database) add_subdirectory(iamclient) add_subdirectory(networkmanager) add_subdirectory(smcontroller) +add_subdirectory(unitconfig) +add_subdirectory(utils) diff --git a/src/cm/app/CMakeLists.txt b/src/cm/app/CMakeLists.txt index 281c2b918..ea34be1cd 100644 --- a/src/cm/app/CMakeLists.txt +++ b/src/cm/app/CMakeLists.txt @@ -14,14 +14,40 @@ set(TARGET_NAME app) # Sources # ###################################################################################################################### -set(SOURCES app.cpp main.cpp) +set(SOURCES aoscore.cpp app.cpp main.cpp) # ###################################################################################################################### # Libraries # ###################################################################################################################### -set(LIBRARIES aos::common::logger aos::common::utils aos::common::version aos::core::common::version - aos::core::cm::storagestate Poco::Util +set(LIBRARIES + aos::cm::communication + aos::cm::config + aos::cm::database + aos::cm::iamclient + aos::cm::networkmanager + aos::cm::smcontroller + aos::cm::unitconfig + aos::cm::utils + aos::common::downloader + aos::common::fileserver + aos::common::logger + aos::common::ocispec + aos::common::utils + aos::common::version + aos::core::cm::alerts + aos::core::cm::imagemanager + aos::core::cm::launcher + aos::core::cm::monitoring + aos::core::cm::nodeinfoprovider + aos::core::cm::storagestate + aos::core::cm::unitconfig + aos::core::cm::updatemanager + aos::core::common::crypto + aos::core::common::pkcs11 + aos::core::common::spaceallocator + aos::core::common::version + Poco::Util ) # ###################################################################################################################### @@ -38,6 +64,8 @@ add_exec( ${SOURCES} LIBRARIES ${LIBRARIES} + LINK_OPTIONS + -rdynamic ) # ###################################################################################################################### diff --git a/src/cm/app/aoscore.cpp b/src/cm/app/aoscore.cpp new file mode 100644 index 000000000..4d0b6431c --- /dev/null +++ b/src/cm/app/aoscore.cpp @@ -0,0 +1,280 @@ +/* + * Copyright (C) 2025 EPAM Systems, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include + +#include "aoscore.hpp" +#include "envvarhandler.hpp" + +namespace aos::cm::app { + +/*********************************************************************************************************************** + * Public + **********************************************************************************************************************/ + +void AosCore::Init(const std::string& configFile) +{ + auto err = mLogger.Init(); + AOS_ERROR_CHECK_AND_THROW(err, "can't initialize logger"); + + LOG_DBG() << "Aos core size" << Log::Field("size", sizeof(AosCore)); + + // Initialize Aos modules + + err = config::ParseConfig(configFile.empty() ? cDefaultConfigFile : configFile, mConfig); + AOS_ERROR_CHECK_AND_THROW(err, "can't parse config"); + + // Initialize crypto provider + + err = mCryptoProvider.Init(); + AOS_ERROR_CHECK_AND_THROW(err, "can't initialize crypto provider"); + + // Initialize cert loader + + err = mCertLoader.Init(mCryptoProvider, mPKCS11Manager); + AOS_ERROR_CHECK_AND_THROW(err, "can't initialize cert loader"); + + // Initialize crypto helper + + err = mCryptoHelper.Init( + mIAMClient, mCryptoProvider, mCertLoader, mConfig.mServiceDiscoveryURL.c_str(), mConfig.mCACert.c_str()); + AOS_ERROR_CHECK_AND_THROW(err, "can't initialize crypto helper"); + + // Initialize file info provider + + err = mFileInfoProvider.Init(mCryptoProvider); + AOS_ERROR_CHECK_AND_THROW(err, "can't initialize file info provider"); + + // Initialize TLS credentials + + err = mTLSCredentials.Init(mConfig.mCACert, mIAMClient, mCertLoader, mCryptoProvider); + AOS_ERROR_CHECK_AND_THROW(err, "can't initialize TLS credentials"); + + // Initialize IAM client + + err = mIAMClient.Init(mConfig.mIAMProtectedServerURL, mConfig.mIAMPublicServerURL, mConfig.mCertStorage, + mTLSCredentials, mConfig.mCertStorage.c_str(), false); + AOS_ERROR_CHECK_AND_THROW(err, "can't initialize IAM client"); + + // Initialize communication + + err = mCommunication.Init(mConfig, mIAMClient, mIAMClient, mIAMClient, mCertLoader, mCryptoProvider, mCryptoHelper, + mCryptoProvider, mUpdateManager, mStorageState, mSMController, mLauncher, mIAMClient, mIAMClient); + AOS_ERROR_CHECK_AND_THROW(err, "can't initialize communication"); + + InitDatabase(); + InitStorageState(); + InitSMController(); + + err = mAlerts.Init(mConfig.mAlerts, mCommunication, mCommunication); + AOS_ERROR_CHECK_AND_THROW(err, "can't initialize alerts"); + + err = mDownloadSpaceAllocator.Init(mConfig.mImageManager.mInstallPath, mPlatformFS, 0, &mImageManager); + AOS_ERROR_CHECK_AND_THROW(err, "can't initialize download space allocator"); + + err = mInstallSpaceAllocator.Init(mConfig.mImageManager.mInstallPath, mPlatformFS, 0, &mImageManager); + AOS_ERROR_CHECK_AND_THROW(err, "can't initialize install space allocator"); + + err = mDownloader.Init(&mAlerts); + AOS_ERROR_CHECK_AND_THROW(err, "can't initialize downloader"); + + err = mFileServer.Init(mConfig.mFileServerURL, mConfig.mImageManager.mInstallPath.CStr()); + AOS_ERROR_CHECK_AND_THROW(err, "can't initialize file server"); + + err = mImageManager.Init(mConfig.mImageManager, mDatabase, mCommunication, mDownloadSpaceAllocator, + mInstallSpaceAllocator, mDownloader, mFileServer, mCryptoHelper, mFileInfoProvider, mOCISpec); + AOS_ERROR_CHECK_AND_THROW(err, "can't initialize image manager"); + + err = mNodeInfoProvider.Init(mConfig.mNodeInfoProvider, mIAMClient); + AOS_ERROR_CHECK_AND_THROW(err, "can't initialize node info provider"); + + err = mMonitoring.Init(mConfig.mMonitoring, mCommunication, mCommunication, mLauncher, mNodeInfoProvider); + AOS_ERROR_CHECK_AND_THROW(err, "can't initialize monitoring"); + + err = mUnitConfig.Init({mConfig.mUnitConfigFile.c_str()}, mNodeInfoProvider, mSMController, mJSONProvider); + AOS_ERROR_CHECK_AND_THROW(err, "can't initialize unit config"); + + err = mLauncher.Init(mConfig.mLauncher, mNodeInfoProvider, mSMController, mImageManager, mOCISpec, mUnitConfig, + mStorageState, mNetworkManager, mSMController, mAlerts, mIAMClient, utils::IsUIDValid, utils::IsGIDValid, + mDatabase); + AOS_ERROR_CHECK_AND_THROW(err, "can't initialize launcher"); + + err = mUpdateManager.Init({mConfig.mUnitStatusSendTimeout}, mIAMClient, mIAMClient, mUnitConfig, mNodeInfoProvider, + mImageManager, mLauncher, mCommunication, mCommunication); + AOS_ERROR_CHECK_AND_THROW(err, "can't initialize update manager"); + + mDNSServer.Init(mConfig.mDNSStoragePath, mConfig.mDNSIP); + + err = mNetworkManager.Init(mDatabase, mCryptoProvider, mSMController, mDNSServer); + AOS_ERROR_CHECK_AND_THROW(err, "can't initialize network manager"); +} + +void AosCore::Start() +{ + auto err = mFSWatcher.Start(); + AOS_ERROR_CHECK_AND_THROW(err, "can't start FS watcher"); + + mCleanupManager.AddCleanup([this]() { + if (auto err = mFSWatcher.Stop(); !err.IsNone()) { + LOG_ERR() << "Can't stop FS watcher" << Log::Field(err); + } + }); + + err = mFileServer.Start(); + AOS_ERROR_CHECK_AND_THROW(err, "can't start file server"); + + mCleanupManager.AddCleanup([this]() { + if (auto err = mFileServer.Stop(); !err.IsNone()) { + LOG_ERR() << "Can't stop file server" << Log::Field(err); + } + }); + + err = mStorageState.Start(); + AOS_ERROR_CHECK_AND_THROW(err, "can't start storage state"); + + mCleanupManager.AddCleanup([this]() { + if (auto err = mStorageState.Stop(); !err.IsNone()) { + LOG_ERR() << "Can't stop storage state" << Log::Field(err); + } + }); + + err = mAlerts.Start(); + AOS_ERROR_CHECK_AND_THROW(err, "can't start alerts"); + + mCleanupManager.AddCleanup([this]() { + if (auto err = mAlerts.Stop(); !err.IsNone()) { + LOG_ERR() << "Can't stop alerts" << Log::Field(err); + } + }); + + err = mNodeInfoProvider.Start(); + AOS_ERROR_CHECK_AND_THROW(err, "can't start node info provider"); + + mCleanupManager.AddCleanup([this]() { + if (auto err = mNodeInfoProvider.Stop(); !err.IsNone()) { + LOG_ERR() << "Can't stop node info provider" << Log::Field(err); + } + }); + + err = mMonitoring.Start(); + AOS_ERROR_CHECK_AND_THROW(err, "can't start monitoring"); + + mCleanupManager.AddCleanup([this]() { + if (auto err = mMonitoring.Stop(); !err.IsNone()) { + LOG_ERR() << "Can't stop monitoring" << Log::Field(err); + } + }); + + err = mImageManager.Start(); + AOS_ERROR_CHECK_AND_THROW(err, "can't start image manager"); + + mCleanupManager.AddCleanup([this]() { + if (auto err = mImageManager.Stop(); !err.IsNone()) { + LOG_ERR() << "Can't stop image manager" << Log::Field(err); + } + }); + + err = mLauncher.Start(); + AOS_ERROR_CHECK_AND_THROW(err, "can't start launcher"); + + mCleanupManager.AddCleanup([this]() { + if (auto err = mLauncher.Stop(); !err.IsNone()) { + LOG_ERR() << "Can't stop launcher" << Log::Field(err); + } + }); + + err = mSMController.Start(); + AOS_ERROR_CHECK_AND_THROW(err, "can't start SM controller"); + + mCleanupManager.AddCleanup([this]() { + if (auto err = mSMController.Stop(); !err.IsNone()) { + LOG_ERR() << "Can't stop SM controller" << Log::Field(err); + } + }); + + err = mUpdateManager.Start(); + AOS_ERROR_CHECK_AND_THROW(err, "can't start update manager"); + + mCleanupManager.AddCleanup([this]() { + if (auto err = mUpdateManager.Stop(); !err.IsNone()) { + LOG_ERR() << "Can't stop update manager" << Log::Field(err); + } + }); + + err = mCommunication.Start(); + AOS_ERROR_CHECK_AND_THROW(err, "can't start communication"); + + mCleanupManager.AddCleanup([this]() { + if (auto err = mCommunication.Stop(); !err.IsNone()) { + LOG_ERR() << "Can't stop communication" << Log::Field(err); + } + }); +} + +void AosCore::Stop() +{ + mCleanupManager.ExecuteCleanups(); +} + +void AosCore::SetLogBackend(common::logger::Logger::Backend backend) +{ + mLogger.SetBackend(backend); +} + +void AosCore::SetLogLevel(LogLevel level) +{ + mLogger.SetLogLevel(level); +} + +/*********************************************************************************************************************** + * Private + **********************************************************************************************************************/ + +void AosCore::InitDatabase() +{ + database::Config config; + + config.mWorkingDir = mConfig.mWorkingDir; + config.mMigrationPath = mConfig.mMigration.mMigrationPath; + config.mMergedMigrationPath = mConfig.mMigration.mMergedMigrationPath; + + auto err = mDatabase.Init(config); + AOS_ERROR_CHECK_AND_THROW(err, "can't initialize database"); +} + +void AosCore::InitStorageState() +{ + mFSWatcher.Init(Time::cMinutes, 10 * Time::cSeconds, {fs::FSEventEnum::eModify}); + + storagestate::Config config; + + auto err = config.mStateDir.Assign(mConfig.mStateDir.c_str()); + AOS_ERROR_CHECK_AND_THROW(err, "can't assign state dir to storage state config"); + + err = config.mStorageDir.Assign(mConfig.mStorageDir.c_str()); + AOS_ERROR_CHECK_AND_THROW(err, "can't assign storage dir to storage state config"); + + err = mStorageState.Init(config, mDatabase, mCommunication, mPlatformFS, mFSWatcher, mCryptoProvider); + AOS_ERROR_CHECK_AND_THROW(err, "can't initialize storage state"); +} + +void AosCore::InitSMController() +{ + smcontroller::Config config; + + config.mCACert = mConfig.mCACert; + config.mCertStorage = mConfig.mCertStorage; + config.mCMServerURL = mConfig.mCMServerURL; + + auto err = mSMController.Init(config, mCommunication, mIAMClient, mCertLoader, mCryptoProvider, mCommunication, + mAlerts, mCommunication, mCommunication, mMonitoring, mLauncher, mNodeInfoProvider); + AOS_ERROR_CHECK_AND_THROW(err, "can't initialize SM controller"); +} + +} // namespace aos::cm::app diff --git a/src/cm/app/aoscore.hpp b/src/cm/app/aoscore.hpp new file mode 100644 index 000000000..fc095aaef --- /dev/null +++ b/src/cm/app/aoscore.hpp @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2025 EPAM Systems, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef AOS_CM_APP_AOSCORE_HPP_ +#define AOS_CM_APP_AOSCORE_HPP_ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace aos::cm::app { + +/** + * Aos core instance. + */ +class AosCore { +public: + /** + * Initializes Aos core. + */ + void Init(const std::string& configFile); + + /** + * Starts Aos core. + */ + void Start(); + + /** + * Stops Aos core. + */ + void Stop(); + + /** + * Sets log backend. + * + * @param backend log backend. + */ + void SetLogBackend(aos::common::logger::Logger::Backend backend); + + /** + * Sets log level. + * + * @param level log level. + */ + void SetLogLevel(aos::LogLevel level); + +private: + void InitDatabase(); + void InitStorageState(); + void InitSMController(); + + config::Config mConfig = {}; + aos::crypto::CertLoader mCertLoader; + aos::crypto::DefaultCryptoProvider mCryptoProvider; + aos::crypto::CryptoHelper mCryptoHelper; + aos::pkcs11::PKCS11Manager mPKCS11Manager; + aos::spaceallocator::SpaceAllocator mDownloadSpaceAllocator; + aos::spaceallocator::SpaceAllocator mInstallSpaceAllocator; + aos::common::downloader::Downloader mDownloader; + aos::common::utils::FSPlatform mPlatformFS; + aos::common::utils::FSBufferedWatcher mFSWatcher; + aos::fs::FileInfoProvider mFileInfoProvider; + aos::common::oci::OCISpec mOCISpec; + common::fileserver::Fileserver mFileServer; + common::iamclient::TLSCredentials mTLSCredentials; + cm::alerts::Alerts mAlerts; + cm::imagemanager::ImageManager mImageManager; + cm::launcher::Launcher mLauncher; + cm::monitoring::Monitoring mMonitoring; + cm::networkmanager::NetworkManager mNetworkManager; + cm::networkmanager::DNSServer mDNSServer; + cm::nodeinfoprovider::NodeInfoProvider mNodeInfoProvider; + cm::smcontroller::SMController mSMController; + cm::storagestate::StorageState mStorageState; + cm::unitconfig::JSONProvider mJSONProvider; + cm::unitconfig::UnitConfig mUnitConfig; + cm::updatemanager::UpdateManager mUpdateManager; + communication::Communication mCommunication; + database::Database mDatabase; + iamclient::IAMClient mIAMClient; + common::logger::Logger mLogger; + aos::common::utils::CleanupManager mCleanupManager; + +private: + static constexpr auto cDefaultConfigFile = "aos_cm.cfg"; +}; + +} // namespace aos::cm::app + +#endif diff --git a/src/cm/app/app.cpp b/src/cm/app/app.cpp index 3d1b353af..99d599fc4 100644 --- a/src/cm/app/app.cpp +++ b/src/cm/app/app.cpp @@ -12,9 +12,9 @@ #include #include +#include #include -#include #include #include @@ -91,25 +91,41 @@ void App::initialize(Application& self) RegisterErrorSignals(); - auto err = mLogger.Init(); - AOS_ERROR_CHECK_AND_THROW(err, "can't initialize logger"); + try { - Application::initialize(self); - Init(); - Start(); + auto err = mLogger.Init(); + AOS_ERROR_CHECK_AND_THROW(err, "can't initialize logger"); + + Application::initialize(self); + + mAosCore = std::make_unique(); + + mAosCore->Init(mConfigFile); + + mInitialized = true; + + mAosCore->Start(); + } catch (const std::exception& e) { + LOG_ERR() << "Initialization failed" << Log::Field(common::utils::ToAosError(e)); + + throw; + } // Notify systemd - auto ret = sd_notify(0, cSDNotifyReady); - if (ret < 0) { + if (auto ret = sd_notify(0, cSDNotifyReady); ret < 0) { AOS_ERROR_CHECK_AND_THROW(ret, "can't notify systemd"); } } void App::uninitialize() { - Stop(); - Application::uninitialize(); + + if (!mInitialized) { + return; + } + + mAosCore->Stop(); } void App::reinitialize(Application& self) @@ -156,7 +172,8 @@ void App::defineOptions(Poco::Util::OptionSet& options) void App::Init() { - LOG_INF() << "Initialize CM" << Log::Field("version", AOS_CORE_CPP_VERSION); + LOG_INF() << "Init CM" << Log::Field("version", AOS_CORE_CPP_VERSION); + LOG_DBG() << "Aos core size" << Log::Field("size", sizeof(AosCore)); } void App::Start() diff --git a/src/cm/app/app.hpp b/src/cm/app/app.hpp index 374a03956..8e38fd90a 100644 --- a/src/cm/app/app.hpp +++ b/src/cm/app/app.hpp @@ -12,6 +12,8 @@ #include +#include "aoscore.hpp" + namespace aos::cm::app { /** @@ -45,10 +47,11 @@ class App : public Poco::Util::ServerApplication { void Start(); void Stop(); - common::logger::Logger mLogger; - bool mStopProcessing = false; - bool mProvisioning = false; - std::string mConfigFile; + std::unique_ptr mAosCore; + common::logger::Logger mLogger; + bool mStopProcessing {}; + bool mInitialized {}; + std::string mConfigFile; }; } // namespace aos::cm::app diff --git a/src/cm/app/envvarhandler.hpp b/src/cm/app/envvarhandler.hpp new file mode 100644 index 000000000..66161a2c3 --- /dev/null +++ b/src/cm/app/envvarhandler.hpp @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2025 EPAM Systems, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef AOS_CM_APP_ENVVARHANDLER_HPP_ +#define AOS_CM_APP_ENVVARHANDLER_HPP_ + +#include + +namespace aos::cm::launcher { + +/** @addtogroup cm Communication Manager + * @{ + */ + +/** + * Environment variable handler interface. + */ +class EnvVarHandler : public EnvVarHandlerItf { +public: + /** + * Overrides environment variables. + * + * @param envVars environment variables. + * @return Error. + */ + Error OverrideEnvVars(const OverrideEnvVarsRequest& envVars) override + { + (void)envVars; + + return ErrorEnum::eNotSupported; + } +}; + +} // namespace aos::cm::launcher + +#endif diff --git a/src/cm/communication/CMakeLists.txt b/src/cm/communication/CMakeLists.txt index 3bc3f6830..edc66c1c6 100644 --- a/src/cm/communication/CMakeLists.txt +++ b/src/cm/communication/CMakeLists.txt @@ -30,6 +30,7 @@ set(LIBRARIES aos::common::utils aos::common::config aos::core::common::crypto + aos::cm::communication::cloudprotocol Poco::Crypto Poco::Foundation Poco::Net diff --git a/src/cm/communication/cloudprotocol/blobs.cpp b/src/cm/communication/cloudprotocol/blobs.cpp index 2bd4f74b2..3e054108a 100644 --- a/src/cm/communication/cloudprotocol/blobs.cpp +++ b/src/cm/communication/cloudprotocol/blobs.cpp @@ -90,8 +90,17 @@ void BlobInfoFromJSON(const common::utils::CaseInsensitiveObjectWrapper& json, B blobURLInfo.mSize = json.GetValue("size"); - DecryptInfoFromJSON(json.GetObject("decryptInfo"), blobURLInfo.mDecryptInfo); - SignInfoFromJSON(json.GetObject("signInfo"), blobURLInfo.mSignInfo); + if (json.Has("decryptInfo")) { + blobURLInfo.mDecryptInfo.EmplaceValue(); + + DecryptInfoFromJSON(json.GetObject("decryptInfo"), *blobURLInfo.mDecryptInfo); + } + + if (json.Has("signInfo")) { + blobURLInfo.mSignInfo.EmplaceValue(); + + SignInfoFromJSON(json.GetObject("signInfo"), *blobURLInfo.mSignInfo); + } } } // namespace diff --git a/src/cm/communication/cloudprotocol/common.cpp b/src/cm/communication/cloudprotocol/common.cpp index 9190503a7..6b8b1d667 100644 --- a/src/cm/communication/cloudprotocol/common.cpp +++ b/src/cm/communication/cloudprotocol/common.cpp @@ -172,7 +172,9 @@ Error FromJSON(const common::utils::CaseInsensitiveObjectWrapper& json, Instance Error ToJSON(const Protocol& protocol, Poco::JSON::Object& json) { try { - json.set("correlationID", protocol.mCorrelationID.CStr()); + if (!protocol.mCorrelationID.IsEmpty()) { + json.set("correlationId", protocol.mCorrelationID.CStr()); + } } catch (const std::exception& e) { return common::utils::ToAosError(e); } @@ -182,8 +184,8 @@ Error ToJSON(const Protocol& protocol, Poco::JSON::Object& json) Error FromJSON(const common::utils::CaseInsensitiveObjectWrapper& json, Protocol& protocol) { - if (auto err = protocol.mCorrelationID.Assign(json.GetValue("correlationID").c_str()); !err.IsNone()) { - return AOS_ERROR_WRAP(Error(err, "can't parse correlationID")); + if (auto err = protocol.mCorrelationID.Assign(json.GetValue("correlationId").c_str()); !err.IsNone()) { + return AOS_ERROR_WRAP(Error(err, "can't parse correlationId")); } return ErrorEnum::eNone; diff --git a/src/cm/communication/cloudprotocol/desiredstatus.cpp b/src/cm/communication/cloudprotocol/desiredstatus.cpp index 7d5092c09..53cd3675b 100644 --- a/src/cm/communication/cloudprotocol/desiredstatus.cpp +++ b/src/cm/communication/cloudprotocol/desiredstatus.cpp @@ -233,6 +233,12 @@ void UpdateItemInfoFromJSON(const common::utils::CaseInsensitiveObjectWrapper& j err = updateItemInfo.mItemID.Assign(identity.mID->c_str()); AOS_ERROR_CHECK_AND_THROW(err, "can't parse itemID"); + + if (!identity.mType.has_value()) { + AOS_ERROR_THROW(ErrorEnum::eNotFound, "item type is missing"); + } + + updateItemInfo.mType = *identity.mType; } auto err = updateItemInfo.mVersion.Assign(json.GetValue("version").c_str()); @@ -301,11 +307,11 @@ void SubjectInfoFromJSON(const common::utils::CaseInsensitiveObjectWrapper& json auto err = ParseAosIdentity(json.GetObject("identity"), identity); AOS_ERROR_CHECK_AND_THROW(err, "can't parse subject identity"); - if (!identity.mCodename.has_value()) { - AOS_ERROR_THROW(ErrorEnum::eNotFound, "subject codename is missing"); + if (!identity.mID.has_value()) { + AOS_ERROR_THROW(ErrorEnum::eNotFound, "subject ID is missing"); } - err = subject.mSubjectID.Assign(identity.mCodename->c_str()); + err = subject.mSubjectID.Assign(identity.mID->c_str()); AOS_ERROR_CHECK_AND_THROW(err, "can't parse subjectID"); err = subject.mSubjectType.FromString(json.GetValue("type").c_str()); diff --git a/src/cm/communication/cloudprotocol/tests/alerts.cpp b/src/cm/communication/cloudprotocol/tests/alerts.cpp index 3fbe2d4fe..7b1f2ac77 100644 --- a/src/cm/communication/cloudprotocol/tests/alerts.cpp +++ b/src/cm/communication/cloudprotocol/tests/alerts.cpp @@ -154,7 +154,7 @@ class CloudProtocolAlerts : public Test { TEST_F(CloudProtocolAlerts, AlertsArray) { constexpr auto cJSON - = R"({"messageType":"alerts","correlationID":"id","items":[)" + = R"({"messageType":"alerts","correlationId":"id","items":[)" R"({"timestamp":"1970-01-01T00:00:00Z","tag":"coreAlert","node":{"codename":"test_node"},)" R"("coreComponent":"CM","message":"Test core alert message"},)" R"({"timestamp":"1970-01-01T00:00:00Z","tag":"resourceAllocateAlert","item":{"id":"itemID"},)" diff --git a/src/cm/communication/cloudprotocol/tests/blobs.cpp b/src/cm/communication/cloudprotocol/tests/blobs.cpp index 01c939223..852867410 100644 --- a/src/cm/communication/cloudprotocol/tests/blobs.cpp +++ b/src/cm/communication/cloudprotocol/tests/blobs.cpp @@ -38,7 +38,7 @@ class CloudProtocolBlobs : public Test { TEST_F(CloudProtocolBlobs, BlobURLsRequest) { - constexpr auto cExpectedMessage = R"({"messageType":"requestBlobUrls","correlationID":"id",)" + constexpr auto cExpectedMessage = R"({"messageType":"requestBlobUrls","correlationId":"id",)" R"("digests":[)" R"("sha256:3c3a4604a545cdc127456d94e421cd355bca5b528f4a9c1905b15da2eb4a4c6b",)" R"("sha256:1c3a4604a545cdc127456d94e421cd355bca5b528f4a9c1905b15da2eb4a4c6b"]})"; @@ -60,7 +60,7 @@ TEST_F(CloudProtocolBlobs, BlobURLsInfo) { constexpr auto cJSON = R"({ "messageType": "blobUrls", - "correlationID": "id", + "correlationId": "id", "items": [ { "digest": "sha256:3c3a4604a545cdc127456d94e421cd355bca5b528f4a9c1905b15da2eb4a4c6b", @@ -115,17 +115,19 @@ TEST_F(CloudProtocolBlobs, BlobURLsInfo) EXPECT_EQ(image.mSHA256, expectedSHA256); EXPECT_EQ(image.mSize, 1000); - EXPECT_STREQ(image.mDecryptInfo.mBlockAlg.CStr(), "AES256/CBC/pkcs7"); - EXPECT_EQ(image.mDecryptInfo.mBlockIV, String("blockIv").AsByteArray()); - EXPECT_EQ(image.mDecryptInfo.mBlockKey, String("blockKey").AsByteArray()); - - EXPECT_STREQ(image.mSignInfo.mChainName.CStr(), "chainName"); - EXPECT_STREQ(image.mSignInfo.mAlg.CStr(), "RSA/SHA256"); - EXPECT_EQ(image.mSignInfo.mValue, String("value").AsByteArray()); - EXPECT_EQ(image.mSignInfo.mTrustedTimestamp, Time::UTC("2023-10-01T12:00:00Z").mValue); - ASSERT_EQ(image.mSignInfo.mOCSPValues.Size(), 2); - EXPECT_STREQ(image.mSignInfo.mOCSPValues[0].CStr(), "ocspValue1"); - EXPECT_STREQ(image.mSignInfo.mOCSPValues[1].CStr(), "ocspValue2"); + ASSERT_TRUE(image.mDecryptInfo.HasValue()); + EXPECT_STREQ(image.mDecryptInfo->mBlockAlg.CStr(), "AES256/CBC/pkcs7"); + EXPECT_EQ(image.mDecryptInfo->mBlockIV, String("blockIv").AsByteArray()); + EXPECT_EQ(image.mDecryptInfo->mBlockKey, String("blockKey").AsByteArray()); + + ASSERT_TRUE(image.mSignInfo.HasValue()); + EXPECT_STREQ(image.mSignInfo->mChainName.CStr(), "chainName"); + EXPECT_STREQ(image.mSignInfo->mAlg.CStr(), "RSA/SHA256"); + EXPECT_EQ(image.mSignInfo->mValue, String("value").AsByteArray()); + EXPECT_EQ(image.mSignInfo->mTrustedTimestamp, Time::UTC("2023-10-01T12:00:00Z").mValue); + ASSERT_EQ(image.mSignInfo->mOCSPValues.Size(), 2); + EXPECT_STREQ(image.mSignInfo->mOCSPValues[0].CStr(), "ocspValue1"); + EXPECT_STREQ(image.mSignInfo->mOCSPValues[1].CStr(), "ocspValue2"); } } // namespace aos::cm::communication::cloudprotocol diff --git a/src/cm/communication/cloudprotocol/tests/certificates.cpp b/src/cm/communication/cloudprotocol/tests/certificates.cpp index ed88f0ade..72749ea97 100644 --- a/src/cm/communication/cloudprotocol/tests/certificates.cpp +++ b/src/cm/communication/cloudprotocol/tests/certificates.cpp @@ -32,7 +32,7 @@ TEST_F(CloudProtocolCertificates, RenewCertsNotification) { constexpr auto cJSON = R"({ "messageType": "renewCertificatesNotification", - "correlationID": "id", + "correlationId": "id", "certificates": [ { "type": "iam", @@ -118,7 +118,7 @@ TEST_F(CloudProtocolCertificates, IssuedUnitCerts) { constexpr auto cJSON = R"({ "messageType": "issuedUnitCertificates", - "correlationID": "id", + "correlationId": "id", "certificates": [ { "type": "iam", @@ -173,7 +173,7 @@ TEST_F(CloudProtocolCertificates, IssuedUnitCerts) TEST_F(CloudProtocolCertificates, IssueUnitCerts) { - constexpr auto cJSON = R"({"messageType":"issueUnitCertificates","correlationID":"id","requests":[)" + constexpr auto cJSON = R"({"messageType":"issueUnitCertificates","correlationId":"id","requests":[)" R"({"type":"iam","node":{"codename":"node1"},"csr":"csr_1"},)" R"({"type":"offline","node":{"codename":"node2"},"csr":"csr_2"}]})"; @@ -201,7 +201,7 @@ TEST_F(CloudProtocolCertificates, IssueUnitCerts) TEST_F(CloudProtocolCertificates, InstallUnitCertsConfirmation) { constexpr auto cJSON - = R"({"messageType":"installUnitCertificatesConfirmation","correlationID":"id","certificates":[)" + = R"({"messageType":"installUnitCertificatesConfirmation","correlationId":"id","certificates":[)" R"({"type":"iam","node":{"codename":"node1"},"serial":"serial_1",)" R"("errorInfo":{"aosCode":1,"exitCode":0,"message":"error_msg"}},)" R"({"type":"offline","node":{"codename":"node2"},"serial":"serial_2"}]})"; diff --git a/src/cm/communication/cloudprotocol/tests/common.cpp b/src/cm/communication/cloudprotocol/tests/common.cpp index d5f134775..1d98e66ff 100644 --- a/src/cm/communication/cloudprotocol/tests/common.cpp +++ b/src/cm/communication/cloudprotocol/tests/common.cpp @@ -228,7 +228,7 @@ TEST_F(CloudProtocolCommon, InstanceFilterNoFilterTags) TEST_F(CloudProtocolCommon, ProtocolToJSON) { const auto cProtocol = Protocol {"corr-id"}; - constexpr auto cJSON = R"({"correlationID":"corr-id"})"; + constexpr auto cJSON = R"({"correlationId":"corr-id"})"; auto json = Poco::makeShared(Poco::JSON_PRESERVE_KEY_ORDER); ASSERT_EQ(ToJSON(cProtocol, *json), ErrorEnum::eNone); @@ -238,7 +238,7 @@ TEST_F(CloudProtocolCommon, ProtocolToJSON) TEST_F(CloudProtocolCommon, ProtocolFromJSON) { - constexpr auto cJSON = R"({"correlationID":"corr-id"})"; + constexpr auto cJSON = R"({"correlationId":"corr-id"})"; auto [jsonVar, err] = common::utils::ParseJson(cJSON); ASSERT_TRUE(err.IsNone()) << tests::utils::ErrorToStr(err); diff --git a/src/cm/communication/cloudprotocol/tests/desiredstatus.cpp b/src/cm/communication/cloudprotocol/tests/desiredstatus.cpp index 03723a923..abcd3bb94 100644 --- a/src/cm/communication/cloudprotocol/tests/desiredstatus.cpp +++ b/src/cm/communication/cloudprotocol/tests/desiredstatus.cpp @@ -40,7 +40,7 @@ TEST_F(CloudProtocolDesiredStatus, Nodes) { constexpr auto cJSON = R"({ "messageType": "desiredStatus", - "correlationID": "id", + "correlationId": "id", "nodes": [ { "item": {"codename": "node-1"}, @@ -77,7 +77,7 @@ TEST_F(CloudProtocolDesiredStatus, UnitConfig) { constexpr auto cJSON = R"({ "messageType": "desiredStatus", - "correlationID": "id", + "correlationId": "id", "unitConfig": { "version": "v1.0.0", "formatVersion": "1.0", @@ -232,7 +232,8 @@ TEST_F(CloudProtocolDesiredStatus, Items) "items": [ { "item": { - "id": "item1" + "id": "item1", + "type": "service" }, "version": "0.0.1", "owner": { @@ -242,7 +243,8 @@ TEST_F(CloudProtocolDesiredStatus, Items) }, { "item": { - "id": "item2" + "id": "item2", + "type": "component" }, "version": "1.2.3", "owner": { @@ -267,12 +269,14 @@ TEST_F(CloudProtocolDesiredStatus, Items) const auto& item0 = desiredStatus->mUpdateItems[0]; EXPECT_STREQ(item0.mItemID.CStr(), "item1"); + EXPECT_STREQ(item0.mType.ToString().CStr(), "service"); EXPECT_STREQ(item0.mOwnerID.CStr(), "owner1"); EXPECT_STREQ(item0.mVersion.CStr(), "0.0.1"); EXPECT_STREQ(item0.mIndexDigest.CStr(), "sha256:36f028580bb02cc8272a9a020f4200e346e276ae664e45ee80745574e2f5ab80"); const auto& item1 = desiredStatus->mUpdateItems[1]; EXPECT_STREQ(item1.mItemID.CStr(), "item2"); + EXPECT_STREQ(item1.mType.ToString().CStr(), "component"); EXPECT_STREQ(item1.mOwnerID.CStr(), "owner2"); EXPECT_STREQ(item1.mVersion.CStr(), "1.2.3"); EXPECT_STREQ(item1.mIndexDigest.CStr(), "sha256:abcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcd"); @@ -342,13 +346,13 @@ TEST_F(CloudProtocolDesiredStatus, Subjects) "subjects": [ { "identity": { - "codename": "subjectId1" + "id": "subjectId1" }, "type": "group" }, { "identity": { - "codename": "subjectId2" + "id": "subjectId2" }, "type": "user" } diff --git a/src/cm/communication/cloudprotocol/tests/envvars.cpp b/src/cm/communication/cloudprotocol/tests/envvars.cpp index 78abbb53b..ec862fc0f 100644 --- a/src/cm/communication/cloudprotocol/tests/envvars.cpp +++ b/src/cm/communication/cloudprotocol/tests/envvars.cpp @@ -33,7 +33,7 @@ TEST_F(CloudProtocolEnvVars, OverrideEnvVarsRequest) { const auto cJSON = R"({ "messageType": "overrideEnvVarsStatus", - "correlationID": "id", + "correlationId": "id", "items": [ { "item": { @@ -99,7 +99,7 @@ TEST_F(CloudProtocolEnvVars, OverrideEnvVarsRequest) TEST_F(CloudProtocolEnvVars, OverrideEnvVarsStatuses) { - constexpr auto cJSON = R"({"messageType":"overrideEnvVarsStatus","correlationID":"id",)" + constexpr auto cJSON = R"({"messageType":"overrideEnvVarsStatus","correlationId":"id",)" R"("statuses":[{"item":{"id":"itemID"},)" R"("subject":{"id":"subjectID"},"instance":0,"name":"var0","errorInfo":{"aosCode":1,)" R"("exitCode":0,"message":""}},{"item":{"id":"itemID"},"subject":{"id":"subjectID"},)" diff --git a/src/cm/communication/cloudprotocol/tests/log.cpp b/src/cm/communication/cloudprotocol/tests/log.cpp index e210e3b42..0cae2070e 100644 --- a/src/cm/communication/cloudprotocol/tests/log.cpp +++ b/src/cm/communication/cloudprotocol/tests/log.cpp @@ -33,7 +33,7 @@ TEST_F(CloudProtocolLog, RequestLog) { constexpr auto cJSON = R"({ "messageType": "requestLog", - "correlationID": "logID", + "correlationId": "logID", "logType": "systemLog", "filter": { "from": "2024-01-01T12:00:00Z", @@ -82,7 +82,7 @@ TEST_F(CloudProtocolLog, RequestLog) TEST_F(CloudProtocolLog, PushLog) { - constexpr auto cJSON = R"({"messageType":"pushLog","correlationID":"logID","node":{"codename":"nodeID"},)" + constexpr auto cJSON = R"({"messageType":"pushLog","correlationId":"logID","node":{"codename":"nodeID"},)" R"("part":1,"partsCount":10,"content":"log content","status":"error",)" R"("errorInfo":{"aosCode":1,"exitCode":0,"message":""}})"; diff --git a/src/cm/communication/cloudprotocol/tests/monitoring.cpp b/src/cm/communication/cloudprotocol/tests/monitoring.cpp index 7141ba70c..d5d734bcc 100644 --- a/src/cm/communication/cloudprotocol/tests/monitoring.cpp +++ b/src/cm/communication/cloudprotocol/tests/monitoring.cpp @@ -81,7 +81,7 @@ void AddInstanceStateInfo(const Time& time, InstanceState state, InstanceStateIn TEST_F(CloudProtocolMonitoring, Monitoring) { - constexpr auto cJSON = R"({"messageType":"monitoringData","correlationID":"id",)" + constexpr auto cJSON = R"({"messageType":"monitoringData","correlationId":"id",)" R"("nodes":[{"node":{"codename":"node1"},"nodeStates":[)" R"({"timestamp":"2024-01-31T12:00:00Z","state":"provisioned","isConnected":true},)" R"({"timestamp":"2024-01-31T12:01:00Z","state":"unprovisioned","isConnected":true}],)" @@ -143,7 +143,7 @@ TEST_F(CloudProtocolMonitoring, Monitoring) TEST_F(CloudProtocolMonitoring, MonitoringNoInstances) { - constexpr auto cJSON = R"({"messageType":"monitoringData","correlationID":"id",)" + constexpr auto cJSON = R"({"messageType":"monitoringData","correlationId":"id",)" R"("nodes":[{"node":{"codename":"node1"},"nodeStates":[)" R"({"timestamp":"2024-01-31T12:00:00Z","state":"provisioned","isConnected":true},)" R"({"timestamp":"2024-01-31T12:01:00Z","state":"provisioned","isConnected":false}],)" diff --git a/src/cm/communication/cloudprotocol/tests/provisioning.cpp b/src/cm/communication/cloudprotocol/tests/provisioning.cpp index 5c46fecea..556251b49 100644 --- a/src/cm/communication/cloudprotocol/tests/provisioning.cpp +++ b/src/cm/communication/cloudprotocol/tests/provisioning.cpp @@ -32,7 +32,7 @@ class CloudProtocolProvisioning : public Test { TEST_F(CloudProtocolProvisioning, StartProvisioningRequest) { const auto cJSON = R"({ - "correlationID": "id", + "correlationId": "id", "node": { "codename": "node1" }, @@ -56,7 +56,7 @@ TEST_F(CloudProtocolProvisioning, StartProvisioningRequest) TEST_F(CloudProtocolProvisioning, StartProvisioningResponseWithoutError) { - constexpr auto cJSON = R"({"messageType":"startProvisioningResponse","correlationID":"id",)" + constexpr auto cJSON = R"({"messageType":"startProvisioningResponse","correlationId":"id",)" R"("node":{"codename":"node1"},)" R"("csrs":[{"type":"cm","csr":"cm scr"},)" R"({"type":"iam","csr":"iam csr"}]})"; @@ -83,7 +83,7 @@ TEST_F(CloudProtocolProvisioning, StartProvisioningResponseWithoutError) TEST_F(CloudProtocolProvisioning, StartProvisioningResponseWithError) { - constexpr auto cJSON = R"({"messageType":"startProvisioningResponse","correlationID":"id",)" + constexpr auto cJSON = R"({"messageType":"startProvisioningResponse","correlationId":"id",)" R"("node":{"codename":"node1"},"errorInfo":)" R"({"aosCode":1,"exitCode":0,"message":""},"csrs":[{"type":"cm","csr":"cm scr"},)" R"({"type":"iam","csr":"iam csr"}]})"; @@ -113,7 +113,7 @@ TEST_F(CloudProtocolProvisioning, StartProvisioningResponseWithError) TEST_F(CloudProtocolProvisioning, FinishProvisioningRequest) { const auto cJSON = R"({ - "correlationID": "id", + "correlationId": "id", "node": { "codename": "node1" }, @@ -157,7 +157,7 @@ TEST_F(CloudProtocolProvisioning, FinishProvisioningRequest) TEST_F(CloudProtocolProvisioning, FinishProvisioningResponseWithoutError) { constexpr auto cJSON - = R"({"messageType":"finishProvisioningResponse","correlationID":"id","node":{"codename":"node1"}})"; + = R"({"messageType":"finishProvisioningResponse","correlationId":"id","node":{"codename":"node1"}})"; auto response = std::make_unique(); response->mCorrelationID = "id"; @@ -173,7 +173,7 @@ TEST_F(CloudProtocolProvisioning, FinishProvisioningResponseWithoutError) TEST_F(CloudProtocolProvisioning, FinishProvisioningResponseWithError) { - constexpr auto cJSON = R"({"messageType":"finishProvisioningResponse","correlationID":"id",)" + constexpr auto cJSON = R"({"messageType":"finishProvisioningResponse","correlationId":"id",)" R"("node":{"codename":"node1"},"errorInfo":)" R"({"aosCode":1,"exitCode":0,"message":""}})"; @@ -193,7 +193,7 @@ TEST_F(CloudProtocolProvisioning, FinishProvisioningResponseWithError) TEST_F(CloudProtocolProvisioning, DeprovisioningRequest) { const auto cJSON = R"({ - "correlationID": "id", + "correlationId": "id", "node": { "codename": "node1" }, @@ -218,7 +218,7 @@ TEST_F(CloudProtocolProvisioning, DeprovisioningRequest) TEST_F(CloudProtocolProvisioning, DeprovisioningResponseWithoutError) { constexpr auto cJSON - = R"({"messageType":"deprovisioningResponse","correlationID":"id","node":{"codename":"node1"}})"; + = R"({"messageType":"deprovisioningResponse","correlationId":"id","node":{"codename":"node1"}})"; auto response = std::make_unique(); response->mCorrelationID = "id"; @@ -234,7 +234,7 @@ TEST_F(CloudProtocolProvisioning, DeprovisioningResponseWithoutError) TEST_F(CloudProtocolProvisioning, DeprovisioningResponseWithError) { - constexpr auto cJSON = R"({"messageType":"deprovisioningResponse","correlationID":"id",)" + constexpr auto cJSON = R"({"messageType":"deprovisioningResponse","correlationId":"id",)" R"("node":{"codename":"node1"},"errorInfo":)" R"({"aosCode":1,"exitCode":0,"message":""}})"; diff --git a/src/cm/communication/cloudprotocol/tests/state.cpp b/src/cm/communication/cloudprotocol/tests/state.cpp index 94832f82f..15b31cb03 100644 --- a/src/cm/communication/cloudprotocol/tests/state.cpp +++ b/src/cm/communication/cloudprotocol/tests/state.cpp @@ -54,7 +54,7 @@ TEST_F(CloudProtocolState, StateAcceptance) "subject": { "id": "subject1" }, - "correlationID": "correlation1", + "correlationId": "correlation1", "instance": "10", "checksum": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08", "result": "accepted", @@ -89,7 +89,7 @@ TEST_F(CloudProtocolState, UpdateState) "subject": { "id": "subject1" }, - "correlationID": "correlation1", + "correlationId": "correlation1", "instance": "10", "stateChecksum": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08", "state": "test" @@ -116,7 +116,7 @@ TEST_F(CloudProtocolState, UpdateState) TEST_F(CloudProtocolState, NewState) { const auto cExpectedJSON - = R"({"messageType":"newState","correlationID":"correlation1","item":{"id":"item1"},"subject":{"id":"subject1"},)" + = R"({"messageType":"newState","correlationId":"correlation1","item":{"id":"item1"},"subject":{"id":"subject1"},)" R"("instance":10,"stateChecksum":"9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08",)" R"("state":"test"})"; @@ -139,7 +139,7 @@ TEST_F(CloudProtocolState, NewState) TEST_F(CloudProtocolState, StateRequest) { const auto cExpectedJSON - = R"({"messageType":"stateRequest","correlationID":"correlation1","item":{"id":"item1"},"subject":{"id":"subject1"},)" + = R"({"messageType":"stateRequest","correlationId":"correlation1","item":{"id":"item1"},"subject":{"id":"subject1"},)" R"("instance":10,"default":true})"; auto state = std::make_unique(); diff --git a/src/cm/communication/cloudprotocol/tests/status.cpp b/src/cm/communication/cloudprotocol/tests/status.cpp index 1980ad09d..5560704d5 100644 --- a/src/cm/communication/cloudprotocol/tests/status.cpp +++ b/src/cm/communication/cloudprotocol/tests/status.cpp @@ -38,7 +38,7 @@ class CloudProtocolStatus : public Test { TEST_F(CloudProtocolStatus, AckToJSON) { - constexpr auto cExpectedMessage = R"({"messageType":"ack","correlationID":"id"})"; + constexpr auto cExpectedMessage = R"({"messageType":"ack","correlationId":"id"})"; auto ack = std::make_unique(); ack->mCorrelationID = "id"; @@ -53,7 +53,7 @@ TEST_F(CloudProtocolStatus, AckToJSON) TEST_F(CloudProtocolStatus, AckFromJSON) { - constexpr auto cJSON = R"({"messageType":"ack","correlationID":"id"})"; + constexpr auto cJSON = R"({"messageType":"ack","correlationId":"id"})"; auto [jsonVar, err] = common::utils::ParseJson(cJSON); ASSERT_TRUE(err.IsNone()) << tests::utils::ErrorToStr(err); @@ -70,7 +70,7 @@ TEST_F(CloudProtocolStatus, AckFromJSON) TEST_F(CloudProtocolStatus, NackToJSON) { - constexpr auto cExpectedMessage = R"({"messageType":"nack","correlationID":"id","retryAfter":100})"; + constexpr auto cExpectedMessage = R"({"messageType":"nack","correlationId":"id","retryAfter":100})"; auto nack = std::make_unique(); nack->mCorrelationID = "id"; @@ -86,7 +86,7 @@ TEST_F(CloudProtocolStatus, NackToJSON) TEST_F(CloudProtocolStatus, NackFromJSONUsesDefaultRetryAfter) { - constexpr auto cJSON = R"({"messageType":"nack","correlationID":"id"})"; + constexpr auto cJSON = R"({"messageType":"nack","correlationId":"id"})"; auto [jsonVar, err] = common::utils::ParseJson(cJSON); ASSERT_TRUE(err.IsNone()) << tests::utils::ErrorToStr(err); @@ -104,7 +104,7 @@ TEST_F(CloudProtocolStatus, NackFromJSONUsesDefaultRetryAfter) TEST_F(CloudProtocolStatus, NackFromJSONCustomRetryAfter) { - constexpr auto cJSON = R"({"messageType":"nack","correlationID":"id","retryAfter":224})"; + constexpr auto cJSON = R"({"messageType":"nack","correlationId":"id","retryAfter":224})"; auto [jsonVar, err] = common::utils::ParseJson(cJSON); ASSERT_TRUE(err.IsNone()) << tests::utils::ErrorToStr(err); diff --git a/src/cm/communication/cloudprotocol/tests/unitstatus.cpp b/src/cm/communication/cloudprotocol/tests/unitstatus.cpp index 52036aca2..125f95439 100644 --- a/src/cm/communication/cloudprotocol/tests/unitstatus.cpp +++ b/src/cm/communication/cloudprotocol/tests/unitstatus.cpp @@ -63,7 +63,7 @@ class CloudProtocolUnitStatus : public Test { TEST_F(CloudProtocolUnitStatus, UnitConfig) { - constexpr auto cJSON = R"({"messageType":"unitStatus","correlationID":"id","isDeltaInfo":false,"unitConfig":[)" + constexpr auto cJSON = R"({"messageType":"unitStatus","correlationId":"id","isDeltaInfo":false,"unitConfig":[)" R"({"version":"0.0.1","state":"failed","errorInfo":{"aosCode":1,"exitCode":0,)" R"("message":"error message"}},)" R"({"version":"0.0.2","state":"installed"}]})"; @@ -93,7 +93,7 @@ TEST_F(CloudProtocolUnitStatus, UnitConfig) TEST_F(CloudProtocolUnitStatus, Nodes) { constexpr auto cJSON - = R"({"messageType":"unitStatus","correlationID":"id","isDeltaInfo":false,"nodes":[)" + = R"({"messageType":"unitStatus","correlationId":"id","isDeltaInfo":false,"nodes":[)" R"({"identity":{"codename":"nodeID1","title":"title1"},"nodeGroupSubject":{"codename":"type1"},)" R"("maxDmips":10000,"physicalRam":8096,"totalRam":16384,"osInfo":{"os":"Linux",)" R"("version":"5.10","features":["feature1","feature2"]},"cpus":[{"modelName":)" @@ -189,7 +189,7 @@ TEST_F(CloudProtocolUnitStatus, Nodes) TEST_F(CloudProtocolUnitStatus, Items) { constexpr auto cJSON - = R"({"messageType":"unitStatus","correlationID":"id","isDeltaInfo":false,"items":[)" + = R"({"messageType":"unitStatus","correlationId":"id","isDeltaInfo":false,"items":[)" R"({"item":{"id":"itemID1"},"version":"version1","state":"downloading"},)" R"({"item":{"id":"itemID2"},"version":"version1","state":"installed"},)" R"({"item":{"id":"itemID3"},"version":"version1","state":"failed","errorInfo":{"aosCode":1,"exitCode":0,"message":"test error"}}]})"; @@ -226,7 +226,7 @@ TEST_F(CloudProtocolUnitStatus, Items) TEST_F(CloudProtocolUnitStatus, Instances) { constexpr auto cJSON - = R"({"messageType":"unitStatus","correlationID":"id","isDeltaInfo":false,"instances":[)" + = R"({"messageType":"unitStatus","correlationId":"id","isDeltaInfo":false,"instances":[)" R"({"item":{"id":"itemID1"},"subject":{"id":"subjectID1"},"version":"version1","instances":[)" R"({"node":{"codename":"nodeID1"},"runtime":{"codename":"runtimeID1"},"instance":1,"stateChecksum":"12345678","state":"active"},)" R"({"node":{"codename":"nodeID1"},"runtime":{"codename":"runtimeID1"},"instance":2,"state":"failed","errorInfo":{"aosCode":1,"exitCode":0,"message":""}}]},)" @@ -279,7 +279,7 @@ TEST_F(CloudProtocolUnitStatus, Instances) TEST_F(CloudProtocolUnitStatus, PreinstalledInstances) { constexpr auto cJSON - = R"({"messageType":"unitStatus","correlationID":"id","isDeltaInfo":false,"instances":[)" + = R"({"messageType":"unitStatus","correlationId":"id","isDeltaInfo":false,"instances":[)" R"({"item":{"id":"itemID1"},"subject":{"id":"subjectID1"},"version":"version1","instances":[)" R"({"node":{"codename":"nodeID1"},"runtime":{"codename":"runtimeID1"},"instance":1,"stateChecksum":"12345678","state":"active"},)" R"({"node":{"codename":"nodeID1"},"runtime":{"codename":"runtimeID1"},"instance":2,"state":"failed","errorInfo":{"aosCode":1,"exitCode":0,"message":""}}]},)" @@ -332,7 +332,7 @@ TEST_F(CloudProtocolUnitStatus, PreinstalledInstances) TEST_F(CloudProtocolUnitStatus, Subjects) { - constexpr auto cJSON = R"({"messageType":"unitStatus","correlationID":"id","isDeltaInfo":false,)" + constexpr auto cJSON = R"({"messageType":"unitStatus","correlationId":"id","isDeltaInfo":false,)" R"("subjects":[{"codename":"subject1"},{"codename":"subject2"}]})"; auto unitStatus = std::make_unique(); diff --git a/src/cm/communication/communication.cpp b/src/cm/communication/communication.cpp index 878a975e9..90566308f 100644 --- a/src/cm/communication/communication.cpp +++ b/src/cm/communication/communication.cpp @@ -10,7 +10,8 @@ #include #include -#include +#include + #include #include #include @@ -181,12 +182,12 @@ std::unique_ptr ParseMessage(const common::utils::CaseIn Error Communication::Init(const cm::config::Config& config, iamclient::CurrentNodeInfoProviderItf& currentNodeInfoProvider, iamclient::IdentProviderItf& identityProvider, iamclient::CertProviderItf& certProvider, crypto::CertLoaderItf& certLoader, - crypto::x509::ProviderItf& cryptoProvider, crypto::UUIDItf& uuidProvider, + crypto::x509::ProviderItf& cryptoProvider, crypto::CryptoHelper& cryptoHelper, crypto::UUIDItf& uuidProvider, updatemanager::UpdateManagerItf& updateManager, storagestate::StateHandlerItf& stateHandler, smcontroller::LogProviderItf& logProvider, launcher::EnvVarHandlerItf& envVarHandler, iamclient::CertHandlerItf& certHandler, iamclient::ProvisioningItf& provisioningHandler) { - LOG_DBG() << "Initializing communication"; + LOG_DBG() << "Init communication"; Poco::Net::initializeSSL(); @@ -196,6 +197,7 @@ Error Communication::Init(const cm::config::Config& config, mCertProvider = &certProvider; mCertLoader = &certLoader; mCryptoProvider = &cryptoProvider; + mCryptoHelper = &cryptoHelper; mUUIDProvider = &uuidProvider; mUpdateManager = &updateManager; mStateHandler = &stateHandler; @@ -210,6 +212,12 @@ Error Communication::Init(const cm::config::Config& config, mCloudHttpRequest.set("Connection", "Upgrade"); mCloudHttpRequest.set("Upgrade", "websocket"); + try { + mConfigServiceDiscoveryURI = Poco::URI(mConfig->mServiceDiscoveryURL); + } catch (const std::exception& e) { + return AOS_ERROR_WRAP(common::utils::ToAosError(e)); + } + return ErrorEnum::eNone; } @@ -217,7 +225,7 @@ Error Communication::Start() { std::lock_guard lock {mMutex}; - LOG_DBG() << "Starting communication"; + LOG_DBG() << "Start communication"; if (mIsRunning) { return AOS_ERROR_WRAP(ErrorEnum::eWrongState); @@ -344,7 +352,8 @@ Error Communication::GetBlobsInfos(const Array>& d ResponseMessageVariantPtr response; - if (auto err = SendAndWaitResponse(Message(txn, payload, request->mCorrelationID.CStr()), response); + if (auto err + = SendAndWaitResponse(Message(txn, payload, SendPollicy::eExpectAck, request->mCorrelationID.CStr()), response); !err.IsNone()) { return AOS_ERROR_WRAP(err); } @@ -435,7 +444,7 @@ Error Communication::SendUnitStatus(const UnitStatus& unitStatus) Error Communication::SubscribeListener(cloudconnection::ConnectionListenerItf& listener) { - std::lock_guard lock {mMutex}; + std::lock_guard lock {mSubscribersMutex}; LOG_DBG() << "Subscribing connection listener"; @@ -450,7 +459,7 @@ Error Communication::SubscribeListener(cloudconnection::ConnectionListenerItf& l Error Communication::UnsubscribeListener(cloudconnection::ConnectionListenerItf& listener) { - std::lock_guard lock {mMutex}; + std::lock_guard lock {mSubscribersMutex}; LOG_DBG() << "Unsubscribing connection listener"; @@ -480,13 +489,13 @@ std::unique_ptr Communication::CreateSession(const auto certInfo = std::make_unique(); - auto err = mCertProvider->GetCert(mConfig->mCertStorage.c_str(), {}, {}, *certInfo); + auto err = mCertProvider->GetCert(cOnlineCertificate, {}, {}, *certInfo); AOS_ERROR_CHECK_AND_THROW(err); auto context = Poco::makeAuto(Poco::Net::Context::TLS_CLIENT_USE, ""); - err = common::utils::ConfigureSSLContext(mConfig->mCertStorage.c_str(), mConfig->mCrypt.mCACert.c_str(), - *mCertProvider, *mCertLoader, *mCryptoProvider, context->sslContext()); + err = common::utils::ConfigureSSLContext(cOnlineCertificate, mConfig->mCACert.c_str(), *mCertProvider, *mCertLoader, + *mCryptoProvider, context->sslContext()); AOS_ERROR_CHECK_AND_THROW(err); return std::make_unique(uri.getHost(), uri.getPort(), context); @@ -523,33 +532,42 @@ void Communication::ReceiveDiscoveryResponse( Poco::StreamCopier::copyToString(session.receiveResponse(httpResponse), responseBody); if (httpResponse.getStatus() != Poco::Net::HTTPResponse::HTTP_OK) { + LOG_ERR() << "Discovery request failed" << Log::Field("status", httpResponse.getStatus()) + << Log::Field("reason", httpResponse.getReason().c_str()); + AOS_ERROR_THROW(ErrorEnum::eRuntime, "Discovery request failed"); } + LOG_DBG() << "Received discovery response" << Log::Field("content", responseBody.c_str()); + mDiscoveryResponse.emplace(); auto err = cloudprotocol::FromJSON(responseBody, *mDiscoveryResponse); AOS_ERROR_CHECK_AND_THROW(err, "Failed to convert discovery response from JSON"); } -Error Communication::SendDiscoveryRequest() +Error Communication::SendDiscoveryRequest(const String& url) { try { - auto session = CreateSession(Poco::URI(mConfig->mServiceDiscoveryURL)); + auto session = CreateSession(Poco::URI(url.CStr())); auto clearSession = DeferRelease(session.get(), [](auto* session) { if (session) { session->reset(); } }); - LOG_DBG() << "Send discovery request"; + LOG_DBG() << "Send discovery request" << Log::Field("url", url.CStr()); const auto requestBody = CreateDiscoveryRequestBody(); + auto postURI = Poco::URI(url.CStr()); + postURI.setPath(mConfigServiceDiscoveryURI.getPath()); + Poco::Net::HTTPRequest httpRequest; httpRequest.setMethod(Poco::Net::HTTPRequest::HTTP_POST); httpRequest.setVersion(Poco::Net::HTTPMessage::HTTP_1_1); + httpRequest.setURI(postURI.getPathEtc().empty() ? "/" : postURI.getPathEtc()); httpRequest.setKeepAlive(false); httpRequest.set("Accept", "application/json"); httpRequest.setContentType("application/json"); @@ -557,10 +575,12 @@ Error Communication::SendDiscoveryRequest() Poco::Net::HTTPResponse httpResponse; httpRequest.setContentLength64(static_cast(requestBody.length())); + LOG_DBG() << "Connect to service discovery server" << Log::Field("url", postURI.toString().c_str()) + << Log::Field("content", requestBody.c_str()); + session->sendRequest(httpRequest) << requestBody; ReceiveDiscoveryResponse(*session, httpResponse); - } catch (const std::exception& e) { return common::utils::ToAosError(e); } @@ -578,41 +598,67 @@ Error Communication::SendDiscoveryRequest() Error Communication::ConnectToCloud() { - std::lock_guard lock {mMutex}; + auto serviceDiscoveryURLs = std::make_unique, cMaxServiceDiscoveryURLs>>(); - LOG_DBG() << "Connect to cloud web socket server"; + if (auto err = mCryptoHelper->GetServiceDiscoveryURLs(*serviceDiscoveryURLs); !err.IsNone()) { + return AOS_ERROR_WRAP(err); + } - if (!ConnectionInfoIsSet()) { - if (auto err = SendDiscoveryRequest(); !err.IsNone()) { + if (!mConfig->mOverrideServiceDiscoveryURL.empty()) { + serviceDiscoveryURLs->Clear(); + if (auto err + = serviceDiscoveryURLs->PushBack(StaticString(mConfig->mOverrideServiceDiscoveryURL.c_str())); + !err.IsNone()) { return AOS_ERROR_WRAP(err); } + } - mCloudHttpRequest.set("Authorization", std::string("Bearer ").append(mDiscoveryResponse->mAuthToken.CStr())); + if (serviceDiscoveryURLs->IsEmpty()) { + return AOS_ERROR_WRAP(Error(ErrorEnum::eRuntime, "no service discovery URLs available")); } - auto it = mDiscoveryResponse->mConnectionInfo.begin(); - try { - mClientSession = CreateSession(Poco::URI(it->CStr())); + { + std::lock_guard lock {mMutex}; - mWebSocket.emplace(Poco::Net::WebSocket(*mClientSession, mCloudHttpRequest, mCloudHttpResponse)); + LOG_DBG() << "Connect to cloud web socket server"; - mWebSocket->setKeepAlive(true); - mWebSocket->setReceiveTimeout(0); - } catch (const Poco::Net::NetException& e) { - if (e.code() == Poco::Net::WebSocket::WS_ERR_UNAUTHORIZED) { - LOG_WRN() << "Authorization failed, clearing discovery response"; + if (!ConnectionInfoIsSet()) { + if (auto err = SendDiscoveryRequest(serviceDiscoveryURLs->Front()); !err.IsNone()) { + return AOS_ERROR_WRAP(err); + } - mDiscoveryResponse.reset(); + mCloudHttpRequest.set( + "Authorization", std::string("Bearer ").append(mDiscoveryResponse->mAuthToken.CStr())); } - mDiscoveryResponse->mConnectionInfo.Erase(it); + auto it = mDiscoveryResponse->mConnectionInfo.begin(); + try { + auto uri = Poco::URI(it->CStr()); - mWebSocket.reset(); + mClientSession = CreateSession(uri); - mClientSession->reset(); - mClientSession.reset(); + mCloudHttpRequest.setURI(uri.getPathEtc().empty() ? "/" : uri.getPathEtc()); - return common::utils::ToAosError(e); + mWebSocket.emplace(Poco::Net::WebSocket(*mClientSession, mCloudHttpRequest, mCloudHttpResponse)); + + mWebSocket->setKeepAlive(true); + mWebSocket->setReceiveTimeout(0); + } catch (const Poco::Net::NetException& e) { + if (e.code() == Poco::Net::WebSocket::WS_ERR_UNAUTHORIZED) { + LOG_WRN() << "Authorization failed, clearing discovery response"; + + mDiscoveryResponse.reset(); + } + + mDiscoveryResponse->mConnectionInfo.Erase(it); + + mWebSocket.reset(); + + mClientSession->reset(); + mClientSession.reset(); + + return common::utils::ToAosError(e); + } } NotifyConnectionEstablished(); @@ -663,6 +709,8 @@ Error Communication::Disconnect() void Communication::NotifyConnectionEstablished() { + std::lock_guard lock {mSubscribersMutex}; + LOG_INF() << "Notifying connection established" << Log::Field("subscribersCount", mSubscribers.size()); for (auto& subscriber : mSubscribers) { @@ -672,6 +720,8 @@ void Communication::NotifyConnectionEstablished() void Communication::NotifyConnectionLost() { + std::lock_guard lock {mSubscribersMutex}; + LOG_INF() << "Notifying connection lost" << Log::Field("subscribersCount", mSubscribers.size()); for (auto& subscriber : mSubscribers) { @@ -718,18 +768,37 @@ Error Communication::ReceiveFrames() do { n = mWebSocket->receiveFrame(buffer, flags); - if ((flags & Poco::Net::WebSocket::FRAME_OP_BITMASK) == Poco::Net::WebSocket::FRAME_OP_CLOSE) { + const auto opcodes = flags & Poco::Net::WebSocket::FRAME_OP_BITMASK; + + LOG_DBG() << "WebSocket frame received" << Log::Field("size", n) << Log::Field("opcodes", opcodes); + + if (opcodes == Poco::Net::WebSocket::FRAME_OP_CLOSE) { LOG_DBG() << "Received close frame, disconnecting"; break; } - LOG_DBG() << "Received WebSocket frame" << Log::Field("size", n) << Log::Field("flags", flags); + if (opcodes == Poco::Net::WebSocket::FRAME_OP_PING) { + std::lock_guard lock {mMutex}; + + const auto sentBytes = mWebSocket->sendFrame( + buffer.begin(), n, Poco::Net::WebSocket::FRAME_OP_PONG | Poco::Net::WebSocket::FRAME_FLAG_FIN); - if (n > 0) { + LOG_DBG() << "Sent pong frame" << Log::Field("sentBytes", sentBytes); + + buffer.resize(0); + + continue; + } + + if (n > 0 && (opcodes == Poco::Net::WebSocket::FRAME_OP_BINARY)) { std::lock_guard lock {mMutex}; - mReceiveQueue.emplace(buffer.begin(), buffer.end()); + std::string message(buffer.begin(), buffer.begin() + n); + + LOG_DBG() << "Received message" << Log::Field("message", message.c_str()); + + mReceiveQueue.emplace(std::move(message)); mCondVar.notify_all(); } @@ -799,13 +868,15 @@ void Communication::HandleSendQueue() } try { - auto data = it->Payload(); + const auto data = it->Payload(); - const auto sentBytes = mWebSocket->sendFrame(data.data(), data.size(), Poco::Net::WebSocket::FRAME_TEXT); + const auto sentBytes = mWebSocket->sendFrame(data.data(), data.size(), Poco::Net::WebSocket::FRAME_BINARY); LOG_DBG() << "Sent message" << Log::Field("sentBytes", sentBytes) << Log::Field("message", data.c_str()); - mSentMessages.emplace(it->Txn(), *it); + if (it->Pollicy() == SendPollicy::eExpectAck) { + mSentMessages.emplace(it->Txn(), *it); + } mSendQueue.erase(it); } catch (const std::exception& e) { @@ -840,12 +911,12 @@ void Communication::HandleUnacknowledgedMessages() if (!it->second.RetryAllowed()) { LOG_ERR() << "Message delivery failed, max retries reached" << Log::Field("txn", it->first.c_str()) - << Log::Field("correlationID", it->second.CorrelationID().c_str()); + << Log::Field("correlationId", it->second.CorrelationID().c_str()); mResponseHandlers.erase(it->second.CorrelationID()); } else { LOG_WRN() << "Message not acknowledged, re-enqueueing" << Log::Field("txn", it->first.c_str()) - << Log::Field("correlationID", it->second.CorrelationID().c_str()); + << Log::Field("correlationId", it->second.CorrelationID().c_str()); it->second.ResetTimestamp(now); it->second.IncrementTries(); @@ -889,7 +960,7 @@ void Communication::HandleReceivedMessage() Error Communication::HandleMessage(const std::string& message) { - LOG_DBG() << "Handle receive queue"; + LOG_DBG() << "Handle cloud message" << Log::Field("message", message.c_str()); auto parseResult = common::utils::ParseJson(message); if (!parseResult.mError.IsNone()) { @@ -974,6 +1045,9 @@ Error Communication::EnqueueMessage(const Message& msg, OnResponseReceivedFunc o { std::unique_lock lock {mMutex}; + LOG_DBG() << "Enqueue message" << Log::Field("txn", msg.Txn().c_str()) + << Log::Field("correlationId", msg.CorrelationID().c_str()); + if (onResponseReceived) { mResponseHandlers.emplace(msg.CorrelationID(), onResponseReceived); } @@ -988,6 +1062,10 @@ Error Communication::DequeueMessage(const Message& msg) { std::lock_guard lock {mMutex}; + mSendQueue.erase(std::remove_if(mSendQueue.begin(), mSendQueue.end(), + [&msg](const Message& queuedMsg) { return queuedMsg.Txn() == msg.Txn(); }), + mSendQueue.end()); + mSentMessages.erase(msg.Txn()); mResponseHandlers.erase(msg.CorrelationID()); @@ -996,11 +1074,11 @@ Error Communication::DequeueMessage(const Message& msg) void Communication::HandleMessage(const ResponseInfo& info, const cloudprotocol::Ack& ack) { - LOG_DBG() << "Received ack message" << Log::Field("txn", info.mTxn.c_str()) - << Log::Field("correlationID", ack.mCorrelationID); - std::lock_guard lock {mMutex}; + LOG_DBG() << "Received ack message" << Log::Field("txn", info.mTxn.c_str()) + << Log::Field("correlationId", ack.mCorrelationID); + mSentMessages.erase(info.mTxn); } @@ -1015,7 +1093,7 @@ void Communication::HandleMessage(const ResponseInfo& info, const cloudprotocol: } LOG_DBG() << "Received nack message" << Log::Field("txn", info.mTxn.c_str()) - << Log::Field("correlationID", info.mCorrelationID.c_str()) + << Log::Field("correlationId", info.mCorrelationID.c_str()) << Log::Field("retryAfter", nack.mRetryAfter.Milliseconds()); auto it = mSentMessages.find(info.mTxn); @@ -1036,7 +1114,7 @@ void Communication::HandleMessage(const ResponseInfo& info, const cloudprotocol: void Communication::HandleMessage(const ResponseInfo& info, const BlobURLsInfo& urls) { LOG_DBG() << "Received blob URLs info message" << Log::Field("txn", info.mTxn.c_str()) - << Log::Field("correlationID", info.mCorrelationID.c_str()) << Log::Field("count", urls.mItems.Size()); + << Log::Field("correlationId", info.mCorrelationID.c_str()) << Log::Field("count", urls.mItems.Size()); if (auto err = SendAck(info.mTxn); !err.IsNone()) { LOG_ERR() << "Send ack failed" << Log::Field("txn", info.mTxn.c_str()) << Log::Field(err); @@ -1318,7 +1396,7 @@ Error Communication::SendAck(const std::string& txn) return common::utils::ToAosError(e); } - return EnqueueMessage(Message(txn, std::move(msg))); + return EnqueueMessage(Message(txn, std::move(msg), SendPollicy::eSendOnly)); } Error Communication::SendIssueUnitCerts(const IssueUnitCerts& certs) @@ -1326,7 +1404,7 @@ Error Communication::SendIssueUnitCerts(const IssueUnitCerts& certs) LOG_DBG() << "Send issue unit certs"; try { - if (auto err = EnqueueMessage(CreateMessageData(certs), true); !err.IsNone()) { + if (auto err = EnqueueMessage(CreateMessageData(certs)); !err.IsNone()) { return AOS_ERROR_WRAP(err); } } catch (const std::exception& e) { @@ -1361,7 +1439,7 @@ void Communication::OnResponseReceived(const ResponseInfo& info, ResponseMessage auto it = mResponseHandlers.find(info.mCorrelationID); if (it == mResponseHandlers.end()) { LOG_DBG() << "Message handler not found" << Log::Field("txn", info.mTxn.c_str()) - << Log::Field("correlationID", info.mCorrelationID.c_str()); + << Log::Field("correlationId", info.mCorrelationID.c_str()); return; } diff --git a/src/cm/communication/communication.hpp b/src/cm/communication/communication.hpp index 826660381..276c6282f 100644 --- a/src/cm/communication/communication.hpp +++ b/src/cm/communication/communication.hpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -25,6 +26,10 @@ #include #include +#include +#include +#include +#include #include #include #include @@ -36,11 +41,6 @@ #include #include -#include -#include -#include -#include - #include #include @@ -64,6 +64,7 @@ class Communication : public cm::communication::CommunicationItf, private NonCop * @param certProvider certificate provider. * @param certLoader certificate loader. * @param cryptoProvider crypto provider. + * @param cryptoHelper crypto helper. * @param uuidProvider UUID provider. * @param updateManager update manager. * @param stateHandler storage state handler. @@ -75,7 +76,8 @@ class Communication : public cm::communication::CommunicationItf, private NonCop */ Error Init(const cm::config::Config& config, iamclient::CurrentNodeInfoProviderItf& currentNodeInfoProvider, iamclient::IdentProviderItf& identityProvider, iamclient::CertProviderItf& certProvider, - crypto::CertLoaderItf& certLoader, crypto::x509::ProviderItf& cryptoProvider, crypto::UUIDItf& uuidProvider, + crypto::CertLoaderItf& certLoader, crypto::x509::ProviderItf& cryptoProvider, + crypto::CryptoHelper& cryptoHelper, crypto::UUIDItf& uuidProvider, updatemanager::UpdateManagerItf& updateManager, storagestate::StateHandlerItf& stateHandler, smcontroller::LogProviderItf& logProvider, launcher::EnvVarHandlerItf& envVarHandler, iamclient::CertHandlerItf& certHandler, iamclient::ProvisioningItf& provisioningHandler @@ -176,24 +178,33 @@ class Communication : public cm::communication::CommunicationItf, private NonCop Error UnsubscribeListener(cloudconnection::ConnectionListenerItf& listener) override; private: - static constexpr auto cProtocolVersion = 7; - static constexpr auto cReconnectTries = 5; - static constexpr auto cReconnectTimeout = Time::cSeconds * 1; - static constexpr auto cMaxReconnectTimeout = 10 * Time::cMinutes; - static constexpr auto cMessageHandlerThreads = 4; + static constexpr auto cProtocolVersion = 7; + static constexpr auto cReconnectTries = 5; + static constexpr auto cReconnectTimeout = Time::cSeconds * 1; + static constexpr auto cMaxReconnectTimeout = 10 * Time::cMinutes; + static constexpr auto cMessageHandlerThreads = 4; + static constexpr auto cOnlineCertificate = "online"; + static constexpr auto cMaxServiceDiscoveryURLs = 1; using SessionPtr = std::unique_ptr; using ResponseMessageVariant = std::variant; using ResponseMessageVariantPtr = std::shared_ptr; using OnResponseReceivedFunc = std::function; + enum class SendPollicy { + eExpectAck, + eSendOnly, + }; + class Message { public: - Message(const std::string& txn, Poco::JSON::Object::Ptr payload, const std::string& correlationID = {}, + Message(const std::string& txn, Poco::JSON::Object::Ptr payload, + SendPollicy sendPollicy = SendPollicy::eExpectAck, const std::string& correlationId = {}, const Time& timestamp = Time::Now()) : mTxn(txn) , mPayload(std::move(payload)) - , mCorrelationID(correlationID) + , mSendPollicy(sendPollicy) + , mCorrelationID(correlationId) , mTimestamp(timestamp) { } @@ -201,6 +212,7 @@ class Communication : public cm::communication::CommunicationItf, private NonCop const std::string& Txn() const { return mTxn; } const std::string& CorrelationID() const { return mCorrelationID; } std::string Payload() const { return common::utils::Stringify(mPayload); } + SendPollicy Pollicy() const { return mSendPollicy; } const Time& Timestamp() const { return mTimestamp; } void ResetTimestamp(const Time& time) { mTimestamp = time; } bool RetryAllowed() const { return mTries < cMaxTries; } @@ -211,6 +223,7 @@ class Communication : public cm::communication::CommunicationItf, private NonCop std::string mTxn; Poco::JSON::Object::Ptr mPayload; + SendPollicy mSendPollicy {SendPollicy::eExpectAck}; std::string mCorrelationID; Time mTimestamp {Time::Now()}; size_t mTries {}; @@ -225,7 +238,7 @@ class Communication : public cm::communication::CommunicationItf, private NonCop std::string CreateDiscoveryRequestBody() const; void ReceiveDiscoveryResponse(Poco::Net::HTTPClientSession& session, Poco::Net::HTTPResponse& httpResponse); bool ConnectionInfoIsSet() const; - Error SendDiscoveryRequest(); + Error SendDiscoveryRequest(const String& url); Error ConnectToCloud(); Error CloseConnection(); Error Disconnect(); @@ -261,7 +274,7 @@ class Communication : public cm::communication::CommunicationItf, private NonCop void HandleMessage(const ResponseInfo& info, const RenewCertsNotification& notification); void HandleMessage(const ResponseInfo& info, const IssuedUnitCerts& certs); Error SendAndWaitResponse(const Message& msg, ResponseMessageVariantPtr& response); - Error SendAck(const std::string& correlationID); + Error SendAck(const std::string& correlationId); Error SendIssueUnitCerts(const IssueUnitCerts& certs); Error SendInstallUnitCertsConfirmation(const InstallUnitCertsConfirmation& confirmation); void OnResponseReceived(const ResponseInfo& info, ResponseMessageVariantPtr message); @@ -272,6 +285,7 @@ class Communication : public cm::communication::CommunicationItf, private NonCop iamclient::CertProviderItf* mCertProvider {}; crypto::CertLoaderItf* mCertLoader {}; crypto::x509::ProviderItf* mCryptoProvider {}; + crypto::CryptoHelper* mCryptoHelper {}; crypto::UUIDItf* mUUIDProvider {}; updatemanager::UpdateManagerItf* mUpdateManager {}; storagestate::StateHandlerItf* mStateHandler {}; @@ -281,12 +295,14 @@ class Communication : public cm::communication::CommunicationItf, private NonCop iamclient::ProvisioningItf* mProvisioningHandler {}; std::atomic_bool mIsRunning {}; SystemInfo mSystemInfo; + std::mutex mSubscribersMutex; std::vector mSubscribers; std::optional mDiscoveryResponse; std::mutex mMutex; std::condition_variable mCondVar; StaticString mMainNodeID; Duration mReconnectTimeout {cReconnectTimeout}; + Poco::URI mConfigServiceDiscoveryURI; SessionPtr mClientSession; std::optional mWebSocket; diff --git a/src/cm/communication/tests/communication.cpp b/src/cm/communication/tests/communication.cpp index 64cb220ba..627924228 100644 --- a/src/cm/communication/tests/communication.cpp +++ b/src/cm/communication/tests/communication.cpp @@ -13,8 +13,11 @@ #include #include #include +#include #include #include +#include +#include #include #include #include @@ -28,6 +31,10 @@ #include #include +#include "mocks/launchermock.hpp" +#include "mocks/smcontrollermock.hpp" +#include "mocks/storagestatemock.hpp" +#include "mocks/updatemanagermock.hpp" #include "stubs/certprovider.hpp" #include "stubs/connectionsubscriber.hpp" #include "stubs/httpserver.hpp" @@ -48,58 +55,12 @@ constexpr auto cDiscoveryServerPort = 3344; constexpr auto cDiscoveryServerURL = "https://localhost:3344"; constexpr auto cWebSocketServiceURL = "wss://localhost:3345"; constexpr auto cCloudServerPort = 3345; +constexpr auto cCertificate = "online"; /*********************************************************************************************************************** * Mocks **********************************************************************************************************************/ -class IdentityProviderMock : public iamclient::IdentProviderItf { -public: - MOCK_METHOD(Error, GetSystemInfo, (SystemInfo & info), (override)); - MOCK_METHOD(Error, GetSubjects, (Array> & subjects), (override)); - MOCK_METHOD(Error, SubscribeListener, (iamclient::SubjectsListenerItf & subjectsListener), (override)); - MOCK_METHOD(Error, UnsubscribeListener, (iamclient::SubjectsListenerItf & subjectsListener), (override)); -}; - -class UpdateManagerMock : public updatemanager::UpdateManagerItf { -public: - MOCK_METHOD(Error, ProcessDesiredStatus, (const DesiredStatus& desiredStatus), (override)); -}; - -class StateHandlerMock : public storagestate::StateHandlerItf { -public: - MOCK_METHOD(Error, UpdateState, (const aos::UpdateState& state), (override)); - MOCK_METHOD(Error, AcceptState, (const StateAcceptance& state), (override)); -}; - -class LogProviderMock : public smcontroller::LogProviderItf { -public: - MOCK_METHOD(Error, RequestLog, (const aos::RequestLog& log), (override)); -}; - -class EnvVarHandlerMock : public launcher::EnvVarHandlerItf { -public: - MOCK_METHOD(Error, OverrideEnvVars, (const OverrideEnvVarsRequest& envVars), (override)); -}; - -class CertHandlerMock : public iamclient::CertHandlerItf { -public: - MOCK_METHOD(Error, CreateKey, - (const String& nodeID, const String& certType, const String& subject, const String& password, String& csr), - (override)); - MOCK_METHOD(Error, ApplyCert, - (const String& nodeID, const String& certType, const String& pemCert, CertInfo& certInfo), (override)); -}; - -class ProvisioningMock : public iamclient::ProvisioningItf { -public: - MOCK_METHOD( - Error, GetCertTypes, (const String& nodeID, Array>& certTypes), (const, override)); - MOCK_METHOD(Error, StartProvisioning, (const String& nodeID, const String& password), (override)); - MOCK_METHOD(Error, FinishProvisioning, (const String& nodeID, const String& password), (override)); - MOCK_METHOD(Error, Deprovision, (const String& nodeID, const String& password), (override)); -}; - class UUIDItfStub : public crypto::UUIDItf { public: void SetUUID(const uuid::UUID& uuid) @@ -180,11 +141,10 @@ class CMCommunicationTest : public Test { tests::utils::InitLog(); mConfig.mServiceDiscoveryURL = cDiscoveryServerURL; - mConfig.mCrypt.mCACert = CERTIFICATES_CM_DIR "/ca.cer"; - mConfig.mCertStorage = "client"; + mConfig.mCACert = CERTIFICATES_CM_DIR "/ca.cer"; mConfig.mCloudResponseWaitTimeout = Time::cSeconds * 5; - EXPECT_CALL(mIdentityProvider, GetSystemInfo).WillRepeatedly(Invoke([this](SystemInfo& info) { + EXPECT_CALL(mIdentProviderMock, GetSystemInfo).WillRepeatedly(Invoke([this](SystemInfo& info) { info.mSystemID = mSystemID; return ErrorEnum::eNone; })); @@ -200,24 +160,28 @@ class CMCommunicationTest : public Test { err = mCertLoader.Init(mCryptoProvider, mSOFTHSMEnv.GetManager()); ASSERT_TRUE(err.IsNone()) << "Failed to initialize certificate loader: " << tests::utils::ErrorToStr(err); - RegisterPKCS11Module(mConfig.mCertStorage.c_str()); - ASSERT_TRUE(mCertHandler.SetOwner(mConfig.mCertStorage.c_str(), cPIN).IsNone()); + RegisterPKCS11Module(cCertificate); + ASSERT_TRUE(mCertHandler.SetOwner(cCertificate, cPIN).IsNone()); RegisterPKCS11Module("server"); - ApplyCertificate(mConfig.mCertStorage.c_str(), mConfig.mCertStorage.c_str(), - CERTIFICATES_CM_DIR "/client_int.key", CERTIFICATES_CM_DIR "/client_int.cer", 0x3333444, mClientInfo); + ApplyCertificate(cCertificate, cCertificate, CERTIFICATES_CM_DIR "/client_int.key", + CERTIFICATES_CM_DIR "/client_int.cer", 0x3333444, mClientInfo); ApplyCertificate("server", "localhost", CERTIFICATES_CM_DIR "/server_int.key", CERTIFICATES_CM_DIR "/server_int.cer", 0x3333333, mServerInfo); CertInfo certInfo; - mCertHandler.GetCert("client", {}, {}, certInfo); + mCertHandler.GetCert(cCertificate, {}, {}, certInfo); auto [keyURI, errPkcs] = common::utils::CreatePKCS11URL(certInfo.mKeyURL); EXPECT_EQ(errPkcs, ErrorEnum::eNone); auto [certPEM, err2] = common::utils::LoadPEMCertificates(certInfo.mCertURL, mCertLoader, mCryptoProvider); EXPECT_EQ(err2, ErrorEnum::eNone); + err = mCryptoHelper.Init(mCertProviderStub, mCryptoProvider, mCertLoader, mConfig.mServiceDiscoveryURL.c_str(), + mConfig.mCACert.c_str()); + ASSERT_TRUE(err.IsNone()) << "Failed to initialize crypto helper: " << tests::utils::ErrorToStr(err); + StartHTTPServer(); } @@ -255,24 +219,24 @@ class CMCommunicationTest : public Test { void SubscribeAndWaitConnected() { - EXPECT_CALL(mCurrentNodeInfoProvider, GetCurrentNodeInfo).WillRepeatedly(Invoke([this](NodeInfo& info) { + EXPECT_CALL(mCurrentNodeInfoProviderMock, GetCurrentNodeInfo).WillRepeatedly(Invoke([this](NodeInfo& info) { info.mNodeID = mNodeID; return ErrorEnum::eNone; })); - auto err = mCommunication.Init(mConfig, mCurrentNodeInfoProvider, mIdentityProvider, mCertProvider, mCertLoader, - mCryptoProvider, mUUIDProvider, mUpdateManager, mStateHandler, mLogProvider, mEnvVarHandler, - mCertHandlerMock, mProvisioningMock); + auto err = mCommunication.Init(mConfig, mCurrentNodeInfoProviderMock, mIdentProviderMock, mCertProviderStub, + mCertLoader, mCryptoProvider, mCryptoHelper, mUUIDProvider, mUpdateManagerMock, mStateHandlerMock, + mLogProviderMock, mEnvVarHandlerMock, mCertHandlerMock, mProvisioningMock); ASSERT_TRUE(err.IsNone()) << tests::utils::ErrorToStr(err); - err = mCommunication.SubscribeListener(mConnectionSubscriber); + err = mCommunication.SubscribeListener(mConnectionSubscriberStub); ASSERT_TRUE(err.IsNone()) << tests::utils::ErrorToStr(err); err = mCommunication.Start(); ASSERT_TRUE(err.IsNone()) << tests::utils::ErrorToStr(err); - err = mConnectionSubscriber.WaitEvent(cConnectedEvent); + err = mConnectionSubscriberStub.WaitEvent(cConnectedEvent); EXPECT_TRUE(err.IsNone()) << tests::utils::ErrorToStr(err); } @@ -365,15 +329,15 @@ class CMCommunicationTest : public Test { StaticString mSystemID = "test_system_id"; StaticString mNodeID = "node0"; config::Config mConfig; - ConnectionSubscriberStub mConnectionSubscriber; - iamclient::CurrentNodeInfoProviderMock mCurrentNodeInfoProvider; - IdentityProviderMock mIdentityProvider; - UpdateManagerMock mUpdateManager; - StateHandlerMock mStateHandler; - LogProviderMock mLogProvider; - EnvVarHandlerMock mEnvVarHandler; - CertHandlerMock mCertHandlerMock; - ProvisioningMock mProvisioningMock; + ConnectionSubscriberStub mConnectionSubscriberStub; + iamclient::CurrentNodeInfoProviderMock mCurrentNodeInfoProviderMock; + iamclient::IdentProviderMock mIdentProviderMock; + updatemanager::UpdateManagerMock mUpdateManagerMock; + storagestate::StateHandlerMock mStateHandlerMock; + smcontroller::LogProviderMock mLogProviderMock; + launcher::EnvVarHandlerMock mEnvVarHandlerMock; + iamclient::CertHandlerMock mCertHandlerMock; + iamclient::ProvisioningMock mProvisioningMock; std::optional mDiscoveryServer; std::optional mCloudServer; @@ -381,8 +345,9 @@ class CMCommunicationTest : public Test { CertInfo mClientInfo; CertInfo mServerInfo; crypto::DefaultCryptoProvider mCryptoProvider; + crypto::CryptoHelper mCryptoHelper; UUIDItfStub mUUIDProvider; - iamclient::CertProviderStub mCertProvider {mCertHandler}; + iamclient::CertProviderStub mCertProviderStub {mCertHandler}; crypto::CertLoader mCertLoader; Communication mCommunication; @@ -415,21 +380,21 @@ TEST_F(CMCommunicationTest, Reconnect) StopHTTPServer(); - auto err = mConnectionSubscriber.WaitEvent(cDisconnectedEvent, std::chrono::seconds(15)); + auto err = mConnectionSubscriberStub.WaitEvent(cDisconnectedEvent, std::chrono::seconds(15)); EXPECT_TRUE(err.IsNone()) << tests::utils::ErrorToStr(err); StartHTTPServer(); - err = mConnectionSubscriber.WaitEvent(cConnectedEvent); + err = mConnectionSubscriberStub.WaitEvent(cConnectedEvent); EXPECT_TRUE(err.IsNone()) << tests::utils::ErrorToStr(err); err = mCommunication.Stop(); ASSERT_TRUE(err.IsNone()) << tests::utils::ErrorToStr(err); - err = mConnectionSubscriber.WaitEvent(cDisconnectedEvent); + err = mConnectionSubscriberStub.WaitEvent(cDisconnectedEvent); EXPECT_TRUE(err.IsNone()) << tests::utils::ErrorToStr(err); - err = mCommunication.UnsubscribeListener(mConnectionSubscriber); + err = mCommunication.UnsubscribeListener(mConnectionSubscriberStub); EXPECT_TRUE(err.IsNone()) << tests::utils::ErrorToStr(err); } @@ -437,19 +402,19 @@ TEST_F(CMCommunicationTest, SubscribeUnsubscribe) { SubscribeAndWaitConnected(); - auto err = mCommunication.SubscribeListener(mConnectionSubscriber); + auto err = mCommunication.SubscribeListener(mConnectionSubscriberStub); ASSERT_TRUE(err.Is(ErrorEnum::eAlreadyExist)) << tests::utils::ErrorToStr(err); err = mCommunication.Stop(); ASSERT_TRUE(err.IsNone()) << tests::utils::ErrorToStr(err); - err = mConnectionSubscriber.WaitEvent(cDisconnectedEvent); + err = mConnectionSubscriberStub.WaitEvent(cDisconnectedEvent); EXPECT_TRUE(err.IsNone()) << tests::utils::ErrorToStr(err); - err = mCommunication.UnsubscribeListener(mConnectionSubscriber); + err = mCommunication.UnsubscribeListener(mConnectionSubscriberStub); EXPECT_TRUE(err.IsNone()) << tests::utils::ErrorToStr(err); - err = mCommunication.UnsubscribeListener(mConnectionSubscriber); + err = mCommunication.UnsubscribeListener(mConnectionSubscriberStub); EXPECT_TRUE(err.Is(ErrorEnum::eNotFound)) << tests::utils::ErrorToStr(err); } @@ -460,7 +425,7 @@ TEST_F(CMCommunicationTest, MessageIsRecentIfAckNotReceived) const auto cExpectedMessage = std::regex(R"(^\{"header":\{"version":7,"systemId":"test_system_id","createdAt":"[^"]+",)" R"("txn":"fb6e8461-2601-4f9a-8957-7ab4e52f304c"\},)" - R"("data":\{"messageType":"alerts","correlationID":"id","items":\[\]\}\}$)"); + R"("data":\{"messageType":"alerts","correlationId":"id","items":\[\]\}\}$)"); SubscribeAndWaitConnected(); @@ -492,7 +457,7 @@ TEST_F(CMCommunicationTest, SendAlerts) const auto cExpectedMessage = std::regex(R"(^\{"header":\{"version":7,"systemId":"test_system_id","createdAt":"[^"]+",)" R"("txn":"fb6e8461-2601-4f9a-8957-7ab4e52f304c"\},)" - R"("data":\{"messageType":"alerts","correlationID":"id","items":\[\]\}\}$)"); + R"("data":\{"messageType":"alerts","correlationId":"id","items":\[\]\}\}$)"); SubscribeAndWaitConnected(); @@ -516,7 +481,7 @@ TEST_F(CMCommunicationTest, SendOverrideEnvsStatuses) const auto cExpectedMessage = std::regex(R"(^\{"header":\{"version":7,"systemId":"test_system_id","createdAt":"[^"]+",)" R"("txn":"fb6e8461-2601-4f9a-8957-7ab4e52f304c"\},)" - R"("data":\{"messageType":"overrideEnvVarsStatus","correlationID":"","statuses":\[\]\}\}$)"); + R"("data":\{"messageType":"overrideEnvVarsStatus","statuses":\[\]\}\}$)"); SubscribeAndWaitConnected(); @@ -549,6 +514,13 @@ TEST_F(CMCommunicationTest, GetBlobsInfosTimeout) auto err = mCommunication.GetBlobsInfos(digests, *blobsInfo); EXPECT_TRUE(err.Is(ErrorEnum::eTimeout)) << tests::utils::ErrorToStr(err); + // make sure get blobs info message is not sent one more time after timeout + + auto result + = mCloudSendMessageQueue.Pop(std::chrono::milliseconds(2 * mConfig.mCloudResponseWaitTimeout.Milliseconds())); + + EXPECT_FALSE(result.has_value()) << "No more messages expected, but received: " << result.value(); + err = mCommunication.Stop(); ASSERT_TRUE(err.IsNone()) << tests::utils::ErrorToStr(err); } @@ -561,7 +533,7 @@ TEST_F(CMCommunicationTest, GetBlobsInfos) const auto cExpectedMessage = std::regex( R"(^\{"header":\{"version":7,"systemId":"test_system_id","createdAt":"[^"]+",)" R"("txn":"fb6e8461-2601-4f9a-8957-7ab4e52f304c"\},)" - R"("data":\{"messageType":"requestBlobUrls","correlationID":"2a05b9cc-32fb-41b6-a099-0fca3bb39ce2",)" + R"("data":\{"messageType":"requestBlobUrls","correlationId":"2a05b9cc-32fb-41b6-a099-0fca3bb39ce2",)" R"("digests":\["sha256:3c3a4604a545cdc127456d94e421cd355bca5b528f4a9c1905b15da2eb4a4c6b"\]\}\}$)"); constexpr auto cCloudAck = R"({ "header": { @@ -581,7 +553,7 @@ TEST_F(CMCommunicationTest, GetBlobsInfos) }, "data": { "messageType": "blobUrls", - "correlationID": "2a05b9cc-32fb-41b6-a099-0fca3bb39ce2", + "correlationId": "2a05b9cc-32fb-41b6-a099-0fca3bb39ce2", "items": [ { "digest": "sha256:3c3a4604a545cdc127456d94e421cd355bca5b528f4a9c1905b15da2eb4a4c6b", @@ -613,7 +585,7 @@ TEST_F(CMCommunicationTest, GetBlobsInfos) const auto cExpectedAckMsg = std::regex(R"(^\{"header":\{"version":7,"systemId":"test_system_id","createdAt":"[^"]+",)" R"("txn":"f2df3016-de31-46e6-9ce8-9cde4ed7849f"\},)" - R"("data":\{"messageType":"ack","correlationID":""\}\}$)"); + R"("data":\{"messageType":"ack"\}\}$)"); SubscribeAndWaitConnected(); @@ -655,7 +627,7 @@ TEST_F(CMCommunicationTest, SendMonitoring) const auto cExpectedMessage = std::regex(R"(^\{"header":\{"version":7,"systemId":"test_system_id","createdAt":"[^"]+",)" R"("txn":"fb6e8461-2601-4f9a-8957-7ab4e52f304c"\},)" - R"("data":\{"messageType":"monitoringData","correlationID":"","nodes":\[\]\}\}$)"); + R"("data":\{"messageType":"monitoringData","nodes":\[\]\}\}$)"); SubscribeAndWaitConnected(); @@ -677,7 +649,7 @@ TEST_F(CMCommunicationTest, SendLog) const auto cExpectedMessage = std::regex(R"(^\{"header":\{"version":7,"systemId":"test_system_id","createdAt":"[^"]+",)" R"("txn":"fb6e8461-2601-4f9a-8957-7ab4e52f304c"\},)" - R"("data":\{"messageType":"pushLog","correlationID":"","node":\{"codename":""\},)" + R"("data":\{"messageType":"pushLog","node":\{"codename":""\},)" R"("part":0,"partsCount":0,"content":"","status":"ok"\}\}$)"); SubscribeAndWaitConnected(); @@ -701,7 +673,7 @@ TEST_F(CMCommunicationTest, SendStateRequest) const auto cExpectedMessage = std::regex(R"(^\{"header":\{"version":7,"systemId":"test_system_id","createdAt":"[^"]+",)" R"("txn":"fb6e8461-2601-4f9a-8957-7ab4e52f304c"\},)" - R"("data":\{"messageType":"stateRequest","correlationID":"","item":\{"id":""\},)" + R"("data":\{"messageType":"stateRequest","item":\{"id":""\},)" R"("subject":\{"id":""\},"instance":0,"default":false\}\}$)"); SubscribeAndWaitConnected(); @@ -725,7 +697,7 @@ TEST_F(CMCommunicationTest, SendNewState) const auto cExpectedMessage = std::regex(R"(^\{"header":\{"version":7,"systemId":"test_system_id","createdAt":"[^"]+",)" R"("txn":"fb6e8461-2601-4f9a-8957-7ab4e52f304c"\},)" - R"("data":\{"messageType":"newState","correlationID":"","item":\{"id":""\},)" + R"("data":\{"messageType":"newState","item":\{"id":""\},)" R"("subject":\{"id":""\},"instance":0,"stateChecksum":"","state":""\}\}$)"); SubscribeAndWaitConnected(); @@ -770,7 +742,7 @@ TEST_F(CMCommunicationTest, ReceiveUpdateStateMessage) std::promise messageHandled; - EXPECT_CALL(mStateHandler, UpdateState).WillOnce(Invoke([&messageHandled](const UpdateState& state) { + EXPECT_CALL(mStateHandlerMock, UpdateState).WillOnce(Invoke([&messageHandled](const UpdateState& state) { EXPECT_STREQ(state.mItemID.CStr(), "itemID"); EXPECT_STREQ(state.mSubjectID.CStr(), "subjectID"); EXPECT_EQ(state.mInstance, 0); @@ -816,7 +788,7 @@ TEST_F(CMCommunicationTest, ReceiveStateAcceptanceMessage) std::promise messageHandled; - EXPECT_CALL(mStateHandler, AcceptState).WillOnce(Invoke([&messageHandled](const StateAcceptance& state) { + EXPECT_CALL(mStateHandlerMock, AcceptState).WillOnce(Invoke([&messageHandled](const StateAcceptance& state) { EXPECT_STREQ(state.mItemID.CStr(), "itemID"); EXPECT_STREQ(state.mSubjectID.CStr(), "subjectID"); EXPECT_EQ(state.mInstance, 0); @@ -884,11 +856,11 @@ TEST_F(CMCommunicationTest, ReceiveRenewCertsNotification) const auto cExpectedAckMsg = std::regex(R"(^\{"header":\{"version":7,"systemId":"test_system_id","createdAt":"[^"]+",)" R"("txn":"fb6e8461-2601-4f9a-8957-7ab4e52f304c"\},)" - R"("data":\{"messageType":"ack","correlationID":""\}\}$)"); + R"("data":\{"messageType":"ack"\}\}$)"); const auto cExpectedIssuedCertsRequestMsg = std::regex(R"(^\{"header":\{"version":7,"systemId":"test_system_id","createdAt":"[^"]+",)" R"("txn":"180d54e5-0bac-4d4e-a144-68de544cb3d8"\},)" - R"("data":\{"messageType":"issueUnitCertificates","correlationID":"","requests":\[)" + R"("data":\{"messageType":"issueUnitCertificates","requests":\[)" R"(\{"type":"iam","node":\{"codename":"node0"\},"csr":"csr_result_0"\},)" R"(\{"type":"iam","node":\{"codename":"node1"\},"csr":"csr_result_1"\}]\}\}$)"); @@ -993,17 +965,17 @@ TEST_F(CMCommunicationTest, ReceiveIssuedUnitCerts) const auto cExpectedAckMsg = std::regex(R"(^\{"header":\{"version":7,"systemId":"test_system_id","createdAt":"[^"]+",)" R"("txn":"fb6e8461-2601-4f9a-8957-7ab4e52f304c"\},)" - R"("data":\{"messageType":"ack","correlationID":""\}\}$)"); - const auto cExpectedIssuedCertsRequestMsg = std::regex( - R"(^\{"header":\{"version":7,"systemId":"test_system_id","createdAt":"[^"]+",)" - R"("txn":"180d54e5-0bac-4d4e-a144-68de544cb3d8"\},)" - R"("data":\{"messageType":"installUnitCertificatesConfirmation","correlationID":"","certificates":\[)" - R"(\{"type":"cm","node":\{"codename":"node1"\},"serial":"00"\},)" - R"(\{"type":"iam","node":\{"codename":"node1"\},"serial":"01"\},)" - R"(\{"type":"cm","node":\{"codename":"node2"\},"serial":"02"\},)" - R"(\{"type":"iam","node":\{"codename":"node2"\},"serial":"03"\},)" - R"(\{"type":"cm","node":\{"codename":"node0"\},"serial":"04"\},)" - R"(\{"type":"iam","node":\{"codename":"node0"\},"serial":"05"\}]\}\}$)"); + R"("data":\{"messageType":"ack"\}\}$)"); + const auto cExpectedIssuedCertsRequestMsg + = std::regex(R"(^\{"header":\{"version":7,"systemId":"test_system_id","createdAt":"[^"]+",)" + R"("txn":"180d54e5-0bac-4d4e-a144-68de544cb3d8"\},)" + R"("data":\{"messageType":"installUnitCertificatesConfirmation","certificates":\[)" + R"(\{"type":"cm","node":\{"codename":"node1"\},"serial":"00"\},)" + R"(\{"type":"iam","node":\{"codename":"node1"\},"serial":"01"\},)" + R"(\{"type":"cm","node":\{"codename":"node2"\},"serial":"02"\},)" + R"(\{"type":"iam","node":\{"codename":"node2"\},"serial":"03"\},)" + R"(\{"type":"cm","node":\{"codename":"node0"\},"serial":"04"\},)" + R"(\{"type":"iam","node":\{"codename":"node0"\},"serial":"05"\}]\}\}$)"); SubscribeAndWaitConnected(); @@ -1042,4 +1014,62 @@ TEST_F(CMCommunicationTest, ReceiveIssuedUnitCerts) ASSERT_TRUE(err.IsNone()) << tests::utils::ErrorToStr(err); } +TEST_F(CMCommunicationTest, ReceivedAckIsNotRecent) +{ + mConfig.mCloudResponseWaitTimeout = Time::cMilliseconds; + + constexpr auto cJSON = R"({ + "header": { + "version": 7, + "systemId": "test_system_id", + "txn": "fb6e8461-2601-4f9a-8957-7ab4e52f304c" + }, + "data": { + "messageType": "requestLog", + "correlationId": "logID", + "logType": "systemLog", + "filter": { + "from": "2024-01-01T12:00:00Z", + "till": "2024-01-31T12:00:00Z", + "nodeIds": [ + { + "codename": "node1" + }, + { + "codename": "node2" + } + ], + "item": { + "id": "itemID" + }, + "subject": { + "id": "subjectID" + }, + "instance": 1 + } + } + })"; + const auto cExpectedAckMsg + = std::regex(R"(^\{"header":\{"version":7,"systemId":"test_system_id","createdAt":"[^"]+",)" + R"("txn":"fb6e8461-2601-4f9a-8957-7ab4e52f304c"\},)" + R"("data":\{"messageType":"ack"\}\}$)"); + + SubscribeAndWaitConnected(); + + mUUIDProvider.SetUUID("00008461-2601-4f9a-8957-7ab4e52f304c"); + + mCloudSendMessageQueue.Push(cJSON); + + const auto cReceivedMessage = mCloudReceivedMessages.Pop().value_or(""); + EXPECT_TRUE(std::regex_match(cReceivedMessage, cExpectedAckMsg)) << "Received message: " << cReceivedMessage; + + const auto recievedCloudMessage = mCloudReceivedMessages.Pop(std::chrono::seconds(1)); + + EXPECT_FALSE(recievedCloudMessage.has_value()) + << "No more messages expected, but received: " << recievedCloudMessage.value(); + + auto err = mCommunication.Stop(); + ASSERT_TRUE(err.IsNone()) << tests::utils::ErrorToStr(err); +} + } // namespace aos::cm::communication diff --git a/src/cm/communication/tests/mocks/launchermock.hpp b/src/cm/communication/tests/mocks/launchermock.hpp new file mode 100644 index 000000000..53cda123e --- /dev/null +++ b/src/cm/communication/tests/mocks/launchermock.hpp @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2025 EPAM Systems, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef AOS_CM_COMMUNICATION_TESTS_MOCKS_LAUNCHERMOCK_HPP_ +#define AOS_CM_COMMUNICATION_TESTS_MOCKS_LAUNCHERMOCK_HPP_ + +#include + +#include + +namespace aos::cm::launcher { + +/** + * Env var handler mock. + */ +class EnvVarHandlerMock : public EnvVarHandlerItf { +public: + MOCK_METHOD(Error, OverrideEnvVars, (const OverrideEnvVarsRequest& envVars), (override)); +}; + +} // namespace aos::cm::launcher + +#endif diff --git a/src/cm/communication/tests/mocks/smcontrollermock.hpp b/src/cm/communication/tests/mocks/smcontrollermock.hpp new file mode 100644 index 000000000..e6a45702f --- /dev/null +++ b/src/cm/communication/tests/mocks/smcontrollermock.hpp @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2025 EPAM Systems, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef AOS_CM_COMMUNICATION_TESTS_MOCKS_SMCONTROLLERMOCK_HPP_ +#define AOS_CM_COMMUNICATION_TESTS_MOCKS_SMCONTROLLERMOCK_HPP_ + +#include + +#include + +namespace aos::cm::smcontroller { + +/** + * Log provider mock. + */ +class LogProviderMock : public LogProviderItf { +public: + MOCK_METHOD(Error, RequestLog, (const aos::RequestLog&), (override)); +}; + +} // namespace aos::cm::smcontroller + +#endif diff --git a/src/cm/communication/tests/mocks/storagestatemock.hpp b/src/cm/communication/tests/mocks/storagestatemock.hpp new file mode 100644 index 000000000..00eed5245 --- /dev/null +++ b/src/cm/communication/tests/mocks/storagestatemock.hpp @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2025 EPAM Systems, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef AOS_CM_COMMUNICATION_TESTS_MOCKS_STORAGESTATEMOCK_HPP_ +#define AOS_CM_COMMUNICATION_TESTS_MOCKS_STORAGESTATEMOCK_HPP_ + +#include + +#include + +namespace aos::cm::storagestate { + +/** + * State handler mock. + */ +class StateHandlerMock : public StateHandlerItf { +public: + MOCK_METHOD(Error, UpdateState, (const aos::UpdateState&), (override)); + MOCK_METHOD(Error, AcceptState, (const StateAcceptance&), (override)); +}; + +} // namespace aos::cm::storagestate + +#endif diff --git a/src/cm/communication/tests/mocks/updatemanagermock.hpp b/src/cm/communication/tests/mocks/updatemanagermock.hpp new file mode 100644 index 000000000..8431ea75b --- /dev/null +++ b/src/cm/communication/tests/mocks/updatemanagermock.hpp @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2025 EPAM Systems, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef AOS_CM_COMMUNICATION_TESTS_MOCKS_UPDATEMANAGERMOCK_HPP_ +#define AOS_CM_COMMUNICATION_TESTS_MOCKS_UPDATEMANAGERMOCK_HPP_ + +#include + +#include + +namespace aos::cm::updatemanager { + +/** + * Update manager mock. + */ +class UpdateManagerMock : public UpdateManagerItf { +public: + MOCK_METHOD(Error, ProcessDesiredStatus, (const DesiredStatus&), (override)); +}; + +} // namespace aos::cm::updatemanager + +#endif diff --git a/src/cm/communication/tests/stubs/httpserver.hpp b/src/cm/communication/tests/stubs/httpserver.hpp index 15277200b..ce8e82348 100644 --- a/src/cm/communication/tests/stubs/httpserver.hpp +++ b/src/cm/communication/tests/stubs/httpserver.hpp @@ -24,7 +24,8 @@ #include #include -#include +#include + #include namespace aos::cm::communication { @@ -174,18 +175,23 @@ class WebSocketRequestHandler : public Poco::Net::HTTPRequestHandler { do { n = mWebSocket->receiveFrame(buffer, flags); - if (n == 0) { - continue; - } else if ((flags & Poco::Net::WebSocket::FRAME_OP_BITMASK) == Poco::Net::WebSocket::FRAME_OP_CLOSE) { + const auto opts = (flags & Poco::Net::WebSocket::FRAME_OP_BITMASK); + + LOG_DBG() << "Received WebSocket frame" << aos::Log::Field("size", n) << aos::Log::Field("flags", opts); + + if (opts == Poco::Net::WebSocket::FRAME_OP_CLOSE) { mWebSocket->sendFrame(nullptr, 0, flags); break; + } else if (opts == Poco::Net::WebSocket::FRAME_OP_PONG) { + LOG_DBG() << "Received WebSocket pong frame"; + continue; + } else if (n > 0 && (opts == Poco::Net::WebSocket::FRAME_OP_BINARY)) { + mReceivedMessages.Push(std::string(buffer.begin(), buffer.end())); } - mReceivedMessages.Push(std::string(buffer.begin(), buffer.end())); - buffer.resize(0); - } while (n > 0 && (flags & Poco::Net::WebSocket::FRAME_OP_BITMASK) != Poco::Net::WebSocket::FRAME_OP_CLOSE); + } while (n >= 0); } catch (const std::exception& e) { LOG_ERR() << "WebSocket receiver failed" << aos::Log::Field(common::utils::ToAosError(e)); @@ -206,7 +212,10 @@ class WebSocketRequestHandler : public Poco::Net::HTTPRequestHandler { try { while (mRunning) { if (auto messageOpt = mSendMessageQueue.Pop(std::chrono::milliseconds(100)); messageOpt.has_value()) { - mWebSocket->sendFrame(messageOpt->c_str(), messageOpt->length(), Poco::Net::WebSocket::FRAME_TEXT); + LOG_DBG() << "Sending WebSocket message" << aos::Log::Field("message", messageOpt->c_str()); + + mWebSocket->sendFrame( + messageOpt->c_str(), messageOpt->length(), Poco::Net::WebSocket::FRAME_BINARY); continue; } diff --git a/src/cm/config/config.cpp b/src/cm/config/config.cpp index 891df7c6a..4e6865c53 100644 --- a/src/cm/config/config.cpp +++ b/src/cm/config/config.cpp @@ -9,6 +9,8 @@ #include +#include + #include #include @@ -20,23 +22,18 @@ namespace aos::cm::config { * Constants **********************************************************************************************************************/ -constexpr auto cDefaultServiceTTL = "30d"; -constexpr auto cDefaultLayerTTL = "30d"; -constexpr auto cDefaultUnitStatusSendTimeout = "30s"; -constexpr auto cDefaultCloudResponseWaitTimeout = "10s"; -constexpr auto cDefaultMaxConcurrentDownloads = 4; -constexpr auto cDefaultRetryDelay = "1m"; -constexpr auto cDefaultMaxRetryDelay = "30m"; -constexpr auto cDefaultDownloadPartLimit = 100; -constexpr auto cDefaultUMControllerUpdateTTL = "30d"; -constexpr auto cDefaultNodesConnectionTimeout = "10m"; -constexpr auto cDefaultSMControllerUpdateTTL = "30d"; -constexpr auto cDefaultAlertsSendPeriod = "10s"; -constexpr auto cDefaultAlertsMaxMessageSize = 65536; -constexpr auto cDefaultAlertsMaxOfflineMessages = 25; -constexpr auto cDefaultMonitoringSendPeriod = "1m"; -constexpr auto cDefaultMigrationPath = "/usr/share/aos/communicationmanager/migration"; -constexpr auto cDefaultCertStorage = "/var/aos/crypt/cm/"; +constexpr auto cDefaultAlertsSendPeriod = "10s"; +constexpr auto cDefaultCloudResponseWaitTimeout = "10s"; +constexpr auto cDefaultLauncherInstanceTTL = "30d"; +constexpr auto cDefaultLauncherNodesConnectionTimeout = "10m"; +constexpr auto cDefaultMonitoringSendPeriod = "1m"; +constexpr auto cDefaultSMConnectionTimeout = "1m"; +constexpr auto cDefaultUnitStatusSendTimeout = "30s"; +constexpr auto cDefaultUpdateItemTTL = "30d"; +constexpr auto cDefaultRemoveOutdatedPeriod = "24h"; +constexpr auto cDefaultMigrationPath = "/usr/share/aos/communicationmanager/migration"; +constexpr auto cDefaultCertStorage = "/var/aos/crypt/cm/"; +constexpr auto cDefaultDNSStoragePath = "/var/aos/dns"; /*********************************************************************************************************************** * Static @@ -44,81 +41,67 @@ constexpr auto cDefaultCertStorage = "/var/aos/crypt/cm/"; namespace { -void ParseCryptConfig(const common::utils::CaseInsensitiveObjectWrapper& object, Crypt& config) -{ - config.mCACert = object.GetValue("caCert"); - config.mTpmDevice = object.GetValue("tpmDevice"); - config.mPkcs11Library = object.GetValue("pkcs11Library"); -} - -void ParseUMControllerConfig(const common::utils::CaseInsensitiveObjectWrapper& object, UMController& config) +void ParseMonitoringConfig(const common::utils::CaseInsensitiveObjectWrapper& object, Monitoring& config) { - config.mFileServerURL = object.GetValue("fileServerUrl"); - config.mCMServerURL = object.GetValue("cmServerUrl"); + common::config::ParseMonitoringConfig(object, config); - Error err = ErrorEnum::eNone; + Error err; - Tie(config.mUpdateTTL, err) - = common::utils::ParseDuration(object.GetValue("updateTtl", cDefaultUMControllerUpdateTTL)); - AOS_ERROR_CHECK_AND_THROW(err, "error parsing updateTtl tag"); + Tie(config.mSendPeriod, err) + = common::utils::ParseDuration(object.GetValue("sendPeriod", cDefaultMonitoringSendPeriod)); + AOS_ERROR_CHECK_AND_THROW(err, "error parsing sendPeriod tag"); } -void ParseMonitoringConfig(const common::utils::CaseInsensitiveObjectWrapper& object, Monitoring& config) +void ParseNodeInfoProviderConfig( + const common::utils::CaseInsensitiveObjectWrapper& object, nodeinfoprovider::Config& config) { - auto err = common::config::ParseMonitoringConfig(object.GetObject("monitorConfig"), config); - AOS_ERROR_CHECK_AND_THROW(err, "error parsing monitoring config"); + Error err; - Tie(config.mSendPeriod, err) - = common::utils::ParseDuration(object.GetValue("sendPeriod", cDefaultMonitoringSendPeriod)); - AOS_ERROR_CHECK_AND_THROW(err, "error parsing sendPeriod tag"); + Tie(config.mSMConnectionTimeout, err) = common::utils::ParseDuration( + object.GetValue("smConnectionTimeout", cDefaultSMConnectionTimeout)); + AOS_ERROR_CHECK_AND_THROW(err, "error parsing smConnectionTimeout tag"); } -void ParseAlertsConfig(const common::utils::CaseInsensitiveObjectWrapper& object, Alerts& config) +void ParseAlertsConfig(const common::utils::CaseInsensitiveObjectWrapper& object, alerts::Config& config) { - auto err = common::config::ParseJournalAlertsConfig(object.GetObject("journalAlerts"), config.mJournalAlerts); - AOS_ERROR_CHECK_AND_THROW(err, "error parsing journal alerts config"); + Error err; Tie(config.mSendPeriod, err) = common::utils::ParseDuration(object.GetValue("sendPeriod", cDefaultAlertsSendPeriod)); AOS_ERROR_CHECK_AND_THROW(err, "error parsing sendPeriod tag"); - - config.mMaxMessageSize = object.GetValue("maxMessageSize", cDefaultAlertsMaxMessageSize); - config.mMaxOfflineMessages = object.GetValue("maxOfflineMessages", cDefaultAlertsMaxOfflineMessages); } -void ParseDownloaderConfig( - const common::utils::CaseInsensitiveObjectWrapper& object, const std::string& workingDir, Downloader& config) +void ParseImageManagerConfig(const common::utils::CaseInsensitiveObjectWrapper& object, const std::string& workingDir, + imagemanager::Config& config) { - config.mDownloadDir = object.GetValue("downloadDir", std::filesystem::path(workingDir) / "download"); - config.mMaxConcurrentDownloads = object.GetValue("maxConcurrentDownloads", cDefaultMaxConcurrentDownloads); - - Error err = ErrorEnum::eNone; + auto err = config.mInstallPath.Assign( + object.GetValue("installPath", std::filesystem::path(workingDir) / "install").c_str()); + AOS_ERROR_CHECK_AND_THROW(err, "error parsing installPath tag"); - Tie(config.mRetryDelay, err) - = common::utils::ParseDuration(object.GetValue("retryDelay", cDefaultRetryDelay)); - AOS_ERROR_CHECK_AND_THROW(err, "error parsing retryDelay tag"); + err = config.mDownloadPath.Assign( + object.GetValue("downloadPath", std::filesystem::path(workingDir) / "download").c_str()); + AOS_ERROR_CHECK_AND_THROW(err, "error parsing downloadPath tag"); - Tie(config.mMaxRetryDelay, err) - = common::utils::ParseDuration(object.GetValue("maxRetryDelay", cDefaultMaxRetryDelay)); - AOS_ERROR_CHECK_AND_THROW(err, "error parsing maxRetryDelay tag"); + Tie(config.mUpdateItemTTL, err) + = common::utils::ParseDuration(object.GetValue("updateItemTtl", cDefaultUpdateItemTTL)); + AOS_ERROR_CHECK_AND_THROW(err, "error parsing updateItemTtl tag"); - config.mDownloadPartLimit = object.GetValue("downloadPartLimit", cDefaultDownloadPartLimit); + Tie(config.mRemoveOutdatedPeriod, err) = common::utils::ParseDuration( + object.GetValue("removeOutdatedPeriod", cDefaultRemoveOutdatedPeriod)); + AOS_ERROR_CHECK_AND_THROW(err, "error parsing removeOutdatedPeriod tag"); } -void ParseSMControllerConfig(const common::utils::CaseInsensitiveObjectWrapper& object, SMController& config) +void ParseLauncherConfig(const common::utils::CaseInsensitiveObjectWrapper& object, launcher::Config& config) { - config.mFileServerURL = object.GetValue("fileServerUrl"); - config.mCMServerURL = object.GetValue("cmServerUrl"); - - Error err = ErrorEnum::eNone; + Error err; Tie(config.mNodesConnectionTimeout, err) = common::utils::ParseDuration( - object.GetValue("nodesConnectionTimeout", cDefaultNodesConnectionTimeout)); + object.GetValue("nodesConnectionTimeout", cDefaultLauncherNodesConnectionTimeout)); AOS_ERROR_CHECK_AND_THROW(err, "error parsing nodesConnectionTimeout tag"); - Tie(config.mUpdateTTL, err) - = common::utils::ParseDuration(object.GetValue("updateTtl", cDefaultSMControllerUpdateTTL)); - AOS_ERROR_CHECK_AND_THROW(err, "error parsing updateTtl tag"); + Tie(config.mInstanceTTL, err) + = common::utils::ParseDuration(object.GetValue("instanceTtl", cDefaultLauncherInstanceTTL)); + AOS_ERROR_CHECK_AND_THROW(err, "error parsing instanceTtl tag"); } } // namespace @@ -129,6 +112,8 @@ void ParseSMControllerConfig(const common::utils::CaseInsensitiveObjectWrapper& Error ParseConfig(const std::string& filename, Config& config) { + LOG_DBG() << "Parsing config file" << Log::Field("file", filename.c_str()); + std::ifstream file(filename); if (!file.is_open()) { @@ -141,54 +126,40 @@ Error ParseConfig(const std::string& filename, Config& config) common::utils::CaseInsensitiveObjectWrapper object(result); auto empty = common::utils::CaseInsensitiveObjectWrapper(Poco::makeShared()); + config.mCACert = object.GetValue("caCert"); config.mWorkingDir = object.GetValue("workingDir"); - ParseCryptConfig(object.Has("fcrypt") ? object.GetObject("fcrypt") : empty, config.mCrypt); - ParseUMControllerConfig( - object.Has("umController") ? object.GetObject("umController") : empty, config.mUMController); ParseMonitoringConfig(object.Has("monitoring") ? object.GetObject("monitoring") : empty, config.mMonitoring); + ParseNodeInfoProviderConfig( + object.Has("nodeInfoProvider") ? object.GetObject("nodeInfoProvider") : empty, config.mNodeInfoProvider); ParseAlertsConfig(object.Has("alerts") ? object.GetObject("alerts") : empty, config.mAlerts); - ParseDownloaderConfig( - object.Has("downloader") ? object.GetObject("downloader") : empty, config.mWorkingDir, config.mDownloader); - ParseSMControllerConfig( - object.Has("smController") ? object.GetObject("smController") : empty, config.mSMController); + ParseImageManagerConfig(object.Has("imageManager") ? object.GetObject("imageManager") : empty, + config.mWorkingDir, config.mImageManager); + ParseLauncherConfig(object.Has("launcher") ? object.GetObject("launcher") : empty, config.mLauncher); - if (auto err - = common::config::ParseMigrationConfig(object.Has("migration") ? object.GetObject("migration") : empty, - cDefaultMigrationPath, std::filesystem::path(config.mWorkingDir) / "migration", config.mMigration); - err != ErrorEnum::eNone) { - return AOS_ERROR_WRAP(err); - } + common::config::ParseMigrationConfig(object.Has("migration") ? object.GetObject("migration") : empty, + cDefaultMigrationPath, std::filesystem::path(config.mWorkingDir) / "migration", config.mMigration); - config.mDNSIP = object.GetValue("dnsIp"); + config.mDNSStoragePath = object.GetValue("dnsStoragePath", cDefaultDNSStoragePath); + config.mDNSIP = object.GetValue("dnsIp"); config.mCertStorage = object.GetValue("certStorage", cDefaultCertStorage); - config.mServiceDiscoveryURL = object.GetValue("serviceDiscoveryUrl"); - config.mIAMProtectedServerURL = object.GetValue("iamProtectedServerUrl"); - config.mIAMPublicServerURL = object.GetValue("iamPublicServerUrl"); - config.mCMServerURL = object.GetValue("cmServerUrl"); + config.mServiceDiscoveryURL = object.GetValue("serviceDiscoveryUrl"); + config.mOverrideServiceDiscoveryURL = object.GetValue("overrideServiceDiscoveryUrl", ""); + config.mIAMProtectedServerURL = object.GetValue("iamProtectedServerUrl"); + config.mIAMPublicServerURL = object.GetValue("iamPublicServerUrl"); + config.mFileServerURL = object.GetValue("fileServerUrl"); + config.mCMServerURL = object.GetValue("cmServerUrl"); config.mStorageDir = object.GetValue("storageDir", std::filesystem::path(config.mWorkingDir) / "storages"); config.mStateDir = object.GetValue("stateDir", std::filesystem::path(config.mWorkingDir) / "states"); - config.mImageStoreDir - = object.GetValue("imageStoreDir", std::filesystem::path(config.mWorkingDir) / "imagestore"); - config.mComponentsDir - = object.GetValue("componentsDir", std::filesystem::path(config.mWorkingDir) / "components"); config.mUnitConfigFile = object.GetValue( "unitConfigFile", std::filesystem::path(config.mWorkingDir) / "aos_unit.cfg"); Error err = ErrorEnum::eNone; - Tie(config.mServiceTTL, err) - = common::utils::ParseDuration(object.GetValue("serviceTtlDays", cDefaultServiceTTL)); - AOS_ERROR_CHECK_AND_THROW(err, "error parsing serviceTtlDays tag"); - - Tie(config.mLayerTTL, err) - = common::utils::ParseDuration(object.GetValue("layerTtlDays", cDefaultLayerTTL)); - AOS_ERROR_CHECK_AND_THROW(err, "error parsing layerTtlDays tag"); - Tie(config.mUnitStatusSendTimeout, err) = common::utils::ParseDuration( object.GetValue("unitStatusSendTimeout", cDefaultUnitStatusSendTimeout)); AOS_ERROR_CHECK_AND_THROW(err, "error parsing unitStatusSendTimeout tag"); diff --git a/src/cm/config/config.hpp b/src/cm/config/config.hpp index c39bcdd83..61ac076f7 100644 --- a/src/cm/config/config.hpp +++ b/src/cm/config/config.hpp @@ -10,7 +10,11 @@ #include #include +#include +#include +#include #include +#include #include #include @@ -23,85 +27,35 @@ namespace aos::cm::config { * Types **********************************************************************************************************************/ -/* - * Crypt configuration. - */ -struct Crypt { - std::string mCACert; - std::string mTpmDevice; - std::string mPkcs11Library; -}; - -/* - * UM controller configuration. - */ -struct UMController { - std::string mFileServerURL; - std::string mCMServerURL; - Duration mUpdateTTL; -}; - /* * Monitoring configuration. */ struct Monitoring : public aos::monitoring::Config, public aos::cm::monitoring::Config { }; -/* - * Alerts configuration. - */ -struct Alerts { - common::config::JournalAlerts mJournalAlerts; - Duration mSendPeriod; - int mMaxMessageSize; - int mMaxOfflineMessages; -}; - -/* - * Downloader configuration. - */ -struct Downloader { - std::string mDownloadDir; - int mMaxConcurrentDownloads; - Duration mRetryDelay; - Duration mMaxRetryDelay; - int mDownloadPartLimit; -}; - -/* - * SM controller configuration. - */ -struct SMController { - std::string mFileServerURL; - std::string mCMServerURL; - Duration mNodesConnectionTimeout; - Duration mUpdateTTL; -}; - /* * Config structure. */ struct Config { - Crypt mCrypt; - UMController mUMController; + std::string mCACert; Monitoring mMonitoring; - Alerts mAlerts; common::config::Migration mMigration; - Downloader mDownloader; - SMController mSMController; + alerts::Config mAlerts; + imagemanager::Config mImageManager; + launcher::Config mLauncher; + nodeinfoprovider::Config mNodeInfoProvider; + std::string mDNSStoragePath; std::string mDNSIP; std::string mCertStorage; std::string mServiceDiscoveryURL; + std::string mOverrideServiceDiscoveryURL; std::string mIAMProtectedServerURL; std::string mIAMPublicServerURL; + std::string mFileServerURL; std::string mCMServerURL; std::string mStorageDir; std::string mStateDir; std::string mWorkingDir; - std::string mImageStoreDir; - std::string mComponentsDir; std::string mUnitConfigFile; - Duration mServiceTTL; - Duration mLayerTTL; Duration mUnitStatusSendTimeout; Duration mCloudResponseWaitTimeout; }; diff --git a/src/cm/config/tests/config.cpp b/src/cm/config/tests/config.cpp index 89865cc8e..c9559e81b 100644 --- a/src/cm/config/tests/config.cpp +++ b/src/cm/config/tests/config.cpp @@ -24,89 +24,52 @@ using namespace testing; namespace { constexpr auto cFullTestConfigJSON = R"({ - "fcrypt" : { - "CACert" : "CACert", - "tpmDevice": "/dev/tpmrm0", - "pkcs11Library": "/path/to/pkcs11/library" - }, + "CACert": "CACert", "certStorage": "/var/aos/crypt/cm/", - "storageDir" : "/var/aos/storage", - "stateDir" : "/var/aos/state", - "serviceDiscoveryUrl" : "www.aos.com", - "iamProtectedServerUrl" : "localhost:8089", - "iamPublicServerUrl" : "localhost:8090", + "storageDir": "/var/aos/storage", + "stateDir": "/var/aos/state", + "serviceDiscoveryUrl": "www.aos.com", + "iamProtectedServerUrl": "localhost:8089", + "iamPublicServerUrl": "localhost:8090", "cmServerUrl":"localhost:8094", - "workingDir" : "workingDir", - "imageStoreDir": "imagestoreDir", - "componentsDir": "componentDir", - "serviceTtlDays": "720h", - "layerTtlDays": "720h", - "unitConfigFile" : "/var/aos/aos_unit.cfg", + "fileServerUrl":"localhost:8080", + "workingDir": "workingDir", + "unitConfigFile": "/var/aos/aos_unit.cfg", "cloudResponseWaitTimeout": "3d", - "downloader": { - "downloadDir": "/path/to/download", - "maxConcurrentDownloads": 10, - "retryDelay": "10s", - "maxRetryDelay": "30s", - "downloadPartLimit": 57 - }, "monitoring": { - "monitorConfig": { - "pollPeriod": "1s" - }, "sendPeriod": "5m" }, - "alerts": { - "sendPeriod": "20s", - "maxMessageSize": 1024, - "maxOfflineMessages": 32, - "journalAlerts": { - "filter": ["test", "regexp"] - } + "nodeinfoprovider": { + "smConnectionTimeout": "10m" }, - "migration" : { - "migrationPath" : "/usr/share/aos_communicationmanager/migration", - "mergedMigrationPath" : "/var/aos/communicationmanager/migration" + "alerts": { + "sendPeriod": "13m" }, - "smController" : { - "fileServerUrl" : "localhost:8094", - "cmServerUrl" : "localhost:8093", - "nodesConnectionTimeout" : "100s", - "updateTtl" : "30h" + "imageManager": { + "installPath": "/path/to/install", + "downloadPath": "/path/to/download", + "updateItemTtl": "30d", + "removeOutdatedPeriod": "1h" }, - "umController": { - "fileServerUrl" : "localhost:8092", - "cmServerUrl" : "localhost:8091", - "updateTtl" : "100h" - } + "launcher": { + "nodesConnectionTimeout": "1m", + "instanceTtl": "1d" + }, + "migration": { + "migrationPath": "/usr/share/aos_communicationmanager/migration", + "mergedMigrationPath": "/var/aos/communicationmanager/migration" + }, + "dnsStoragePath": "/var/aos/dnsstorage", + "dnsIp": "0.0.0.0:5353" })"; constexpr auto cMinimalTestConfigJSON = R"({ - "fcrypt" : { - "CACert" : "CACert", - "tpmDevice": "/dev/tpmrm0", - "pkcs11Library": "/path/to/pkcs11/library" - }, - "workingDir" : "workingDir", - "serviceDiscoveryUrl" : "www.aos.com", - "iamProtectedServerUrl" : "localhost:8089", - "iamPublicServerUrl" : "localhost:8090", - "cmServerUrl":"localhost:8094", - "monitoring": { - "monitorConfig": { - "pollPeriod": "1s" - } - }, - "alerts": { - "journalAlerts": { - "filter": ["test", "regexp"] - } - }, - "smController" : {"fileServerUrl" : "localhost:8094", "cmServerUrl" : "localhost:8093"}, - "umController": { - "fileServerUrl" : "localhost:8092", - "cmServerUrl" : "localhost:8091" - } + "CACert" : "CACert", + "workingDir" : "workingDir", + "serviceDiscoveryUrl" : "www.aos.com", + "iamProtectedServerUrl" : "localhost:8089", + "iamPublicServerUrl" : "localhost:8090", + "cmServerUrl":"localhost:8094" })"; } // namespace @@ -151,52 +114,37 @@ TEST_F(CMConfigTest, ParseFullConfig) ASSERT_EQ(err, aos::ErrorEnum::eNone); - EXPECT_EQ(config.mCrypt.mTpmDevice, "/dev/tpmrm0"); - EXPECT_EQ(config.mCrypt.mCACert, "CACert"); - EXPECT_EQ(config.mCrypt.mPkcs11Library, "/path/to/pkcs11/library"); - + EXPECT_EQ(config.mCACert, "CACert"); EXPECT_EQ(config.mServiceDiscoveryURL, "www.aos.com"); - EXPECT_EQ(config.mImageStoreDir, "imagestoreDir"); EXPECT_EQ(config.mStorageDir, "/var/aos/storage"); EXPECT_EQ(config.mStateDir, "/var/aos/state"); EXPECT_EQ(config.mWorkingDir, "workingDir"); EXPECT_EQ(config.mUnitConfigFile, "/var/aos/aos_unit.cfg"); EXPECT_EQ(config.mIAMProtectedServerURL, "localhost:8089"); EXPECT_EQ(config.mIAMPublicServerURL, "localhost:8090"); + EXPECT_EQ(config.mFileServerURL, "localhost:8080"); EXPECT_EQ(config.mCMServerURL, "localhost:8094"); EXPECT_EQ(config.mCertStorage, "/var/aos/crypt/cm/"); - EXPECT_EQ(config.mComponentsDir, "componentDir"); - EXPECT_EQ(config.mServiceTTL, aos::Time::cHours * 24 * 30); - EXPECT_EQ(config.mLayerTTL, aos::Time::cHours * 24 * 30); EXPECT_EQ(config.mCloudResponseWaitTimeout, aos::Time::cDay * 3); - EXPECT_EQ(config.mDownloader.mDownloadDir, "/path/to/download"); - EXPECT_EQ(config.mDownloader.mMaxConcurrentDownloads, 10); - EXPECT_EQ(config.mDownloader.mRetryDelay, aos::Time::cSeconds * 10); - EXPECT_EQ(config.mDownloader.mMaxRetryDelay, aos::Time::cSeconds * 30); - EXPECT_EQ(config.mDownloader.mDownloadPartLimit, 57); - EXPECT_EQ(config.mMonitoring.mSendPeriod, aos::Time::cMinutes * 5); + EXPECT_EQ(config.mNodeInfoProvider.mSMConnectionTimeout, aos::Time::cMinutes * 10); + EXPECT_EQ(config.mAlerts.mSendPeriod, aos::Time::cMinutes * 13); - EXPECT_EQ(config.mAlerts.mSendPeriod, aos::Time::cSeconds * 20); - EXPECT_EQ(config.mAlerts.mMaxMessageSize, 1024); - EXPECT_EQ(config.mAlerts.mMaxOfflineMessages, 32); - - std::vector expectedFilter = {"test", "regexp"}; - EXPECT_EQ(config.mAlerts.mJournalAlerts.mFilter, expectedFilter); - - EXPECT_EQ(config.mUMController.mFileServerURL, "localhost:8092"); - EXPECT_EQ(config.mUMController.mCMServerURL, "localhost:8091"); - EXPECT_EQ(config.mUMController.mUpdateTTL, aos::Time::cHours * 100); + EXPECT_STREQ(config.mImageManager.mInstallPath.CStr(), "/path/to/install"); + EXPECT_STREQ(config.mImageManager.mDownloadPath.CStr(), "/path/to/download"); + EXPECT_EQ(config.mImageManager.mUpdateItemTTL, aos::Time::cDay * 30); + EXPECT_EQ(config.mImageManager.mRemoveOutdatedPeriod, aos::Time::cHours * 1); - EXPECT_EQ(config.mSMController.mFileServerURL, "localhost:8094"); - EXPECT_EQ(config.mSMController.mCMServerURL, "localhost:8093"); - EXPECT_EQ(config.mSMController.mNodesConnectionTimeout, aos::Time::cSeconds * 100); - EXPECT_EQ(config.mSMController.mUpdateTTL, aos::Time::cHours * 30); + EXPECT_EQ(config.mLauncher.mNodesConnectionTimeout, aos::Time::cMinutes * 1); + EXPECT_EQ(config.mLauncher.mInstanceTTL, aos::Time::cDay * 1); EXPECT_EQ(config.mMigration.mMigrationPath, "/usr/share/aos_communicationmanager/migration"); EXPECT_EQ(config.mMigration.mMergedMigrationPath, "/var/aos/communicationmanager/migration"); + + EXPECT_EQ(config.mDNSStoragePath, "/var/aos/dnsstorage"); + EXPECT_EQ(config.mDNSIP, "0.0.0.0:5353"); } TEST_F(CMConfigTest, ParseMinimalConfigWithDefaults) @@ -207,9 +155,7 @@ TEST_F(CMConfigTest, ParseMinimalConfigWithDefaults) ASSERT_EQ(err, aos::ErrorEnum::eNone); - EXPECT_EQ(config.mCrypt.mTpmDevice, "/dev/tpmrm0"); - EXPECT_EQ(config.mCrypt.mCACert, "CACert"); - EXPECT_EQ(config.mCrypt.mPkcs11Library, "/path/to/pkcs11/library"); + EXPECT_EQ(config.mCACert, "CACert"); EXPECT_EQ(config.mServiceDiscoveryURL, "www.aos.com"); EXPECT_EQ(config.mWorkingDir, "workingDir"); @@ -220,39 +166,21 @@ TEST_F(CMConfigTest, ParseMinimalConfigWithDefaults) EXPECT_EQ(config.mCertStorage, "/var/aos/crypt/cm/"); EXPECT_EQ(config.mStorageDir, (std::filesystem::path("workingDir") / "storages").string()); EXPECT_EQ(config.mStateDir, (std::filesystem::path("workingDir") / "states").string()); - EXPECT_EQ(config.mImageStoreDir, (std::filesystem::path("workingDir") / "imagestore").string()); - EXPECT_EQ(config.mComponentsDir, (std::filesystem::path("workingDir") / "components").string()); EXPECT_EQ(config.mUnitConfigFile, (std::filesystem::path("workingDir") / "aos_unit.cfg").string()); - EXPECT_EQ(config.mServiceTTL, aos::Time::cHours * 24 * 30); - EXPECT_EQ(config.mLayerTTL, aos::Time::cHours * 24 * 30); EXPECT_EQ(config.mUnitStatusSendTimeout, aos::Time::cSeconds * 30); EXPECT_EQ(config.mCloudResponseWaitTimeout, aos::Time::cSeconds * 10); - EXPECT_EQ(config.mDownloader.mDownloadDir, (std::filesystem::path("workingDir") / "download").string()); - EXPECT_EQ(config.mDownloader.mMaxConcurrentDownloads, 4); - EXPECT_EQ(config.mDownloader.mRetryDelay, aos::Time::cMinutes * 1); - EXPECT_EQ(config.mDownloader.mMaxRetryDelay, aos::Time::cMinutes * 30); - EXPECT_EQ(config.mDownloader.mDownloadPartLimit, 100); - EXPECT_EQ(config.mMonitoring.mSendPeriod, aos::Time::cMinutes * 1); - + EXPECT_EQ(config.mNodeInfoProvider.mSMConnectionTimeout, aos::Time::cMinutes * 1); EXPECT_EQ(config.mAlerts.mSendPeriod, aos::Time::cSeconds * 10); - EXPECT_EQ(config.mAlerts.mMaxMessageSize, 65536); - EXPECT_EQ(config.mAlerts.mMaxOfflineMessages, 25); - std::vector expectedFilter = {"test", "regexp"}; - EXPECT_EQ(config.mAlerts.mJournalAlerts.mFilter, expectedFilter); - - EXPECT_EQ(config.mUMController.mFileServerURL, "localhost:8092"); - EXPECT_EQ(config.mUMController.mCMServerURL, "localhost:8091"); - EXPECT_EQ(config.mUMController.mUpdateTTL, aos::Time::cHours * 720); - - EXPECT_EQ(config.mSMController.mFileServerURL, "localhost:8094"); - EXPECT_EQ(config.mSMController.mCMServerURL, "localhost:8093"); - EXPECT_EQ(config.mSMController.mNodesConnectionTimeout, aos::Time::cMinutes * 10); - EXPECT_EQ(config.mSMController.mUpdateTTL, aos::Time::cHours * 720); + EXPECT_STREQ(config.mImageManager.mInstallPath.CStr(), (std::filesystem::path("workingDir") / "install").c_str()); + EXPECT_STREQ(config.mImageManager.mDownloadPath.CStr(), (std::filesystem::path("workingDir") / "download").c_str()); + EXPECT_EQ(config.mImageManager.mUpdateItemTTL, aos::Time::cDay * 30); EXPECT_EQ(config.mMigration.mMigrationPath, "/usr/share/aos/communicationmanager/migration"); EXPECT_EQ(config.mMigration.mMergedMigrationPath, (std::filesystem::path("workingDir") / "migration").string()); + + EXPECT_EQ(config.mDNSStoragePath, "/var/aos/dns"); } diff --git a/src/cm/database/database.cpp b/src/cm/database/database.cpp index 4fe46d016..080926cf9 100644 --- a/src/cm/database/database.cpp +++ b/src/cm/database/database.cpp @@ -13,7 +13,8 @@ #include #include -#include +#include + #include #include @@ -103,142 +104,6 @@ void DeserializeDNSServers(const std::string& jsonStr, Array("architecture").c_str())); - - if (src.has("variant")) { - dst.mArchInfo.mVariant.SetValue(src.getValue("variant").c_str()); - } - - AOS_ERROR_CHECK_AND_THROW(dst.mOSInfo.mOS.Assign(src.getValue("os").c_str())); - - if (src.has("osVersion")) { - dst.mOSInfo.mVersion.SetValue(src.getValue("osVersion").c_str()); - } - - if (src.has("features")) { - auto featuresArray = src.getArray("features"); - - for (const auto& featureJson : *featuresArray) { - AOS_ERROR_CHECK_AND_THROW( - dst.mOSInfo.mFeatures.PushBack(featureJson.convert().c_str()), "can't add feature"); - } - } -} - -void SerializeAosImageInfo(const aos::ImageInfo& src, Poco::JSON::Object& dst) -{ - dst.set("imageID", src.mImageID.CStr()); - SerializePlatformInfo(src, dst); -} - -void DeserializeAosImageInfo(const Poco::JSON::Object& src, aos::ImageInfo& dst) -{ - AOS_ERROR_CHECK_AND_THROW(dst.mImageID.Assign(src.getValue("imageID").c_str())); - DeserializePlatformInfo(src, dst); -} - -std::string SerializeImages(const Array& images) -{ - Poco::JSON::Array imagesJSON; - auto sha256Hex = std::make_unique>(); - - for (const auto& image : images) { - Poco::JSON::Object imageObj; - - imageObj.set("url", image.mURL.CStr()); - imageObj.set("path", image.mPath.CStr()); - imageObj.set("size", static_cast(image.mSize)); - - sha256Hex->Clear(); - AOS_ERROR_CHECK_AND_THROW(sha256Hex->ByteArrayToHex(image.mSHA256), "failed to convert SHA256 to hex"); - imageObj.set("sha256", sha256Hex->CStr()); - - Poco::JSON::Array metadataArray; - - for (const auto& metadata : image.mMetadata) { - metadataArray.add(metadata.CStr()); - } - - imageObj.set("metadata", metadataArray); - - SerializeAosImageInfo(image, imageObj); - - imagesJSON.add(imageObj); - } - - return common::utils::Stringify(imagesJSON); -} - -void DeserializeImages(const std::string& json, Array& images) -{ - Poco::JSON::Parser parser; - - auto imagesJSON = parser.parse(json).extract(); - if (imagesJSON == nullptr) { - AOS_ERROR_CHECK_AND_THROW(AOS_ERROR_WRAP(ErrorEnum::eFailed), "failed to parse images array"); - } - - auto imageInfo = std::make_unique(); - auto metadata = std::make_unique>(); - - images.Clear(); - - for (const auto& imageJson : *imagesJSON) { - const auto imageObj = imageJson.extract(); - if (imageObj == nullptr) { - AOS_ERROR_CHECK_AND_THROW(AOS_ERROR_WRAP(ErrorEnum::eFailed), "failed to parse image object"); - } - - imageInfo->mURL = imageObj->getValue("url").c_str(); - imageInfo->mPath = imageObj->getValue("path").c_str(); - imageInfo->mSize = imageObj->getValue("size"); - - auto sha256Hex = imageObj->getValue("sha256"); - AOS_ERROR_CHECK_AND_THROW( - String(sha256Hex.c_str()).HexToByteArray(imageInfo->mSHA256), "failed to convert hex to SHA256"); - - auto metadataArray = imageObj->getArray("metadata"); - if (metadataArray == nullptr) { - AOS_ERROR_CHECK_AND_THROW(AOS_ERROR_WRAP(ErrorEnum::eFailed), "failed to parse metadata array"); - } - - for (const auto& metadataJson : *metadataArray) { - AOS_ERROR_CHECK_AND_THROW( - metadata->Assign(metadataJson.convert().c_str()), "can't assign metadata"); - AOS_ERROR_CHECK_AND_THROW(imageInfo->mMetadata.PushBack(*metadata), "can't add metadata"); - } - - DeserializeAosImageInfo(*imageObj, *imageInfo); - - AOS_ERROR_CHECK_AND_THROW(images.PushBack(*imageInfo), "can't add image info"); - } -} - } // namespace /*********************************************************************************************************************** @@ -303,8 +168,8 @@ Error Database::AddStorageStateInfo(const storagestate::InstanceInfo& info) StorageStateInstanceInfoRow row; FromAos(info, row); - *mSession << "INSERT INTO storagestate (itemID, subjectID, instance, storageQuota, " - "stateQuota, stateChecksum) VALUES (?, ?, ?, ?, ?, ?);", + *mSession << "INSERT INTO storagestate (itemID, subjectID, instance, type, storageQuota, " + "stateQuota, stateChecksum) VALUES (?, ?, ?, ?, ?, ?, ?);", bind(row), now; } catch (const std::exception& e) { return AOS_ERROR_WRAP(common::utils::ToAosError(e)); @@ -320,8 +185,9 @@ Error Database::RemoveStorageStateInfo(const InstanceIdent& instanceIdent) try { Poco::Data::Statement statement {*mSession}; - statement << "DELETE FROM storagestate WHERE itemID = ? AND subjectID = ? AND instance = ?;", - bind(instanceIdent.mItemID.CStr()), bind(instanceIdent.mSubjectID.CStr()), bind(instanceIdent.mInstance); + statement << "DELETE FROM storagestate WHERE itemID = ? AND subjectID = ? AND instance = ? AND type = ?;", + bind(instanceIdent.mItemID.CStr()), bind(instanceIdent.mSubjectID.CStr()), bind(instanceIdent.mInstance), + bind(instanceIdent.mType.ToString().CStr()); if (statement.execute() != 1) { return ErrorEnum::eNotFound; @@ -339,7 +205,7 @@ Error Database::GetAllStorageStateInfo(Array& info) try { std::vector rows; - *mSession << "SELECT itemID, subjectID, instance, storageQuota, stateQuota, stateChecksum FROM " + *mSession << "SELECT itemID, subjectID, instance, type, storageQuota, stateQuota, stateChecksum FROM " "storagestate;", into(rows), now; @@ -365,10 +231,10 @@ Error Database::GetStorageStateInfo(const InstanceIdent& instanceIdent, storages StorageStateInstanceInfoRow row; Poco::Data::Statement statement {*mSession}; - statement << "SELECT itemID, subjectID, instance, storageQuota, stateQuota, stateChecksum FROM " - "storagestate WHERE itemID = ? AND subjectID = ? AND instance = ?;", + statement << "SELECT itemID, subjectID, instance, type, storageQuota, stateQuota, stateChecksum FROM " + "storagestate WHERE itemID = ? AND subjectID = ? AND instance = ? AND type = ?;", bind(instanceIdent.mItemID.CStr()), bind(instanceIdent.mSubjectID.CStr()), bind(instanceIdent.mInstance), - into(row); + bind(instanceIdent.mType.ToString().CStr()), into(row); if (statement.execute() == 0) { return ErrorEnum::eNotFound; @@ -391,10 +257,10 @@ Error Database::UpdateStorageStateInfo(const storagestate::InstanceInfo& info) Poco::Data::BLOB checksumBlob(info.mStateChecksum.begin(), info.mStateChecksum.Size()); statement << "UPDATE storagestate SET storageQuota = ?, stateQuota = ?, stateChecksum = ? WHERE " - "itemID = ? AND subjectID = ? AND instance = ?;", + "itemID = ? AND subjectID = ? AND instance = ? AND type = ?;", bind(info.mStorageQuota), bind(info.mStateQuota), bind(checksumBlob), bind(info.mInstanceIdent.mItemID.CStr()), bind(info.mInstanceIdent.mSubjectID.CStr()), - bind(info.mInstanceIdent.mInstance); + bind(info.mInstanceIdent.mInstance), bind(info.mInstanceIdent.mType.ToString().CStr()); if (statement.execute() == 0) { return ErrorEnum::eNotFound; @@ -406,116 +272,6 @@ Error Database::UpdateStorageStateInfo(const storagestate::InstanceInfo& info) return ErrorEnum::eNone; } -/*********************************************************************************************************************** - * imagemanager::storage::StorageItf implementation - **********************************************************************************************************************/ - -Error Database::SetItemState(const String& id, const String& version, imagemanager::storage::ItemState state) -{ - std::lock_guard lock {mMutex}; - - try { - Poco::Data::Statement statement {*mSession}; - - statement << "UPDATE imagemanager SET state = ? WHERE id = ? AND version = ?;", bind(state.ToString().CStr()), - bind(id.CStr()), bind(version.CStr()); - - if (statement.execute() != 1) { - return ErrorEnum::eNotFound; - } - } catch (const std::exception& e) { - return AOS_ERROR_WRAP(common::utils::ToAosError(e)); - } - - return ErrorEnum::eNone; -} - -Error Database::RemoveItem(const String& id, const String& version) -{ - std::lock_guard lock {mMutex}; - - try { - Poco::Data::Statement statement {*mSession}; - - statement << "DELETE FROM imagemanager WHERE id = ? AND version = ?;", bind(id.CStr()), bind(version.CStr()); - - if (statement.execute() != 1) { - return ErrorEnum::eNotFound; - } - } catch (const std::exception& e) { - return AOS_ERROR_WRAP(common::utils::ToAosError(e)); - } - - return ErrorEnum::eNone; -} - -Error Database::GetItemsInfo(Array& items) -{ - std::lock_guard lock {mMutex}; - - try { - std::vector rows; - - *mSession << "SELECT id, type, version, state, path, totalSize, gid, timestamp, images FROM imagemanager;", - into(rows), now; - - auto itemInfo = std::make_unique(); - items.Clear(); - - for (const auto& row : rows) { - ToAos(row, *itemInfo); - AOS_ERROR_CHECK_AND_THROW(items.PushBack(*itemInfo), "can't add item info"); - } - } catch (const std::exception& e) { - return AOS_ERROR_WRAP(common::utils::ToAosError(e)); - } - - return ErrorEnum::eNone; -} - -Error Database::GetItemVersionsByID(const String& id, Array& items) -{ - std::lock_guard lock {mMutex}; - - try { - std::vector rows; - - *mSession << "SELECT id, type, version, state, path, totalSize, gid, timestamp, images FROM imagemanager WHERE " - "id = ?;", - bind(id.CStr()), into(rows), now; - - auto itemInfo = std::make_unique(); - items.Clear(); - - for (const auto& row : rows) { - ToAos(row, *itemInfo); - AOS_ERROR_CHECK_AND_THROW(items.PushBack(*itemInfo), "can't add item info"); - } - } catch (const std::exception& e) { - return AOS_ERROR_WRAP(common::utils::ToAosError(e)); - } - - return ErrorEnum::eNone; -} - -Error Database::AddItem(const imagemanager::storage::ItemInfo& item) -{ - std::lock_guard lock {mMutex}; - - try { - ImageManagerItemInfoRow row; - - FromAos(item, row); - *mSession << "INSERT INTO imagemanager (id, type, version, state, path, totalSize, gid, timestamp, images) " - "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?);", - bind(row), now; - } catch (const std::exception& e) { - return AOS_ERROR_WRAP(common::utils::ToAosError(e)); - } - - return ErrorEnum::eNone; -} - /*********************************************************************************************************************** * networkmanager::StorageItf implementation **********************************************************************************************************************/ @@ -560,8 +316,8 @@ Error Database::AddInstance(const networkmanager::Instance& instance) NetworkManagerInstanceRow row; FromAos(instance, row); - *mSession << "INSERT INTO networkmanager_instances (itemID, subjectID, instance, networkID, nodeID, ip, " - "exposedPorts, dnsServers) VALUES (?, ?, ?, ?, ?, ?, ?, ?);", + *mSession << "INSERT INTO networkmanager_instances (itemID, subjectID, instance, type, networkID, nodeID, ip, " + "exposedPorts, dnsServers) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?);", bind(row), now; } catch (const std::exception& e) { return AOS_ERROR_WRAP(common::utils::ToAosError(e)); @@ -626,7 +382,7 @@ Error Database::GetInstances(const String& networkID, const String& nodeID, Arra try { std::vector rows; - *mSession << "SELECT itemID, subjectID, instance, networkID, nodeID, ip, exposedPorts, dnsServers FROM " + *mSession << "SELECT itemID, subjectID, instance, type, networkID, nodeID, ip, exposedPorts, dnsServers FROM " "networkmanager_instances WHERE networkID = ? AND nodeID = ?;", bind(networkID.CStr()), bind(nodeID.CStr()), into(rows), now; @@ -691,8 +447,10 @@ Error Database::RemoveNetworkInstance(const InstanceIdent& instanceIdent) try { Poco::Data::Statement statement {*mSession}; - statement << "DELETE FROM networkmanager_instances WHERE itemID = ? AND subjectID = ? AND instance = ?;", - bind(instanceIdent.mItemID.CStr()), bind(instanceIdent.mSubjectID.CStr()), bind(instanceIdent.mInstance); + statement + << "DELETE FROM networkmanager_instances WHERE itemID = ? AND subjectID = ? AND instance = ? AND type = ?;", + bind(instanceIdent.mItemID.CStr()), bind(instanceIdent.mSubjectID.CStr()), bind(instanceIdent.mInstance), + bind(instanceIdent.mType.ToString().CStr()); if (statement.execute() != 1) { return ErrorEnum::eNotFound; @@ -716,8 +474,9 @@ Error Database::AddInstance(const launcher::InstanceInfo& info) LauncherInstanceInfoRow row; FromAos(info, row); - *mSession << "INSERT INTO launcher_instances (itemID, subjectID, instance, imageID, updateItemType, nodeID, " - "prevNodeID, runtimeID, uid, timestamp, cached) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);", + *mSession << "INSERT INTO launcher_instances (itemID, subjectID, instance, type, manifestDigest, " + "nodeID, prevNodeID, runtimeID, uid, gid, timestamp, state, isUnitSubject, version) " + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);", bind(row), now; } catch (const std::exception& e) { return AOS_ERROR_WRAP(common::utils::ToAosError(e)); @@ -733,13 +492,14 @@ Error Database::UpdateInstance(const launcher::InstanceInfo& info) try { Poco::Data::Statement statement {*mSession}; - statement - << "UPDATE launcher_instances SET imageID = ?, updateItemType = ?, nodeID = ?, prevNodeID = ?, " - "runtimeID = ?, uid = ?, timestamp = ?, cached = ? WHERE itemID = ? AND subjectID = ? AND instance = ?;", - bind(info.mImageID.CStr()), bind(info.mUpdateItemType.ToString().CStr()), bind(info.mNodeID.CStr()), - bind(info.mPrevNodeID.CStr()), bind(info.mRuntimeID.CStr()), bind(info.mUID), - bind(info.mTimestamp.UnixNano()), bind(info.mCached), bind(info.mInstanceIdent.mItemID.CStr()), - bind(info.mInstanceIdent.mSubjectID.CStr()), bind(info.mInstanceIdent.mInstance); + statement << "UPDATE launcher_instances SET manifestDigest = ?, nodeID = ?, prevNodeID = " + "?, runtimeID = ?, uid = ?, gid = ?, timestamp = ?, state = ?, isUnitSubject = ? " + "WHERE itemID = ? AND subjectID = ? AND instance = ? AND type = ? AND version = ?;", + bind(info.mManifestDigest.CStr()), bind(info.mNodeID.CStr()), bind(info.mPrevNodeID.CStr()), + bind(info.mRuntimeID.CStr()), bind(info.mUID), bind(info.mGID), bind(info.mTimestamp.UnixNano()), + bind(info.mState.ToString().CStr()), bind(info.mIsUnitSubject), bind(info.mInstanceIdent.mItemID.CStr()), + bind(info.mInstanceIdent.mSubjectID.CStr()), bind(info.mInstanceIdent.mInstance), + bind(info.mInstanceIdent.mType.ToString().CStr()), bind(info.mVersion.CStr()); if (statement.execute() != 1) { return ErrorEnum::eNotFound; @@ -758,10 +518,11 @@ Error Database::GetInstance(const InstanceIdent& instanceID, launcher::InstanceI try { std::vector rows; - *mSession << "SELECT itemID, subjectID, instance, imageID, updateItemType, nodeID, prevNodeID, runtimeID, uid, " - "timestamp, cached FROM launcher_instances WHERE itemID = ? AND subjectID = ? AND instance = ?;", - bind(instanceID.mItemID.CStr()), bind(instanceID.mSubjectID.CStr()), bind(instanceID.mInstance), into(rows), - now; + *mSession << "SELECT itemID, subjectID, instance, type, manifestDigest, nodeID, prevNodeID, " + "runtimeID, uid, gid, timestamp, state, isUnitSubject, version " + "FROM launcher_instances WHERE itemID = ? AND subjectID = ? AND instance = ? AND type = ?;", + bind(instanceID.mItemID.CStr()), bind(instanceID.mSubjectID.CStr()), bind(instanceID.mInstance), + bind(instanceID.mType.ToString().CStr()), into(rows), now; if (rows.size() != 1) { return ErrorEnum::eNotFound; @@ -782,8 +543,8 @@ Error Database::GetActiveInstances(Array& instances) con try { std::vector rows; - *mSession << "SELECT itemID, subjectID, instance, imageID, updateItemType, nodeID, prevNodeID, runtimeID, uid, " - "timestamp, cached FROM launcher_instances;", + *mSession << "SELECT itemID, subjectID, instance, type, manifestDigest, nodeID, prevNodeID, " + "runtimeID, uid, gid, timestamp, state, isUnitSubject, version FROM launcher_instances;", into(rows), now; auto instanceInfo = std::make_unique(); @@ -808,8 +569,9 @@ Error Database::RemoveInstance(const InstanceIdent& instanceIdent) Poco::Data::Statement statement {*mSession}; statement.reset(*mSession); - statement << "DELETE FROM launcher_instances WHERE itemID = ? AND subjectID = ? AND instance = ?;", - bind(instanceIdent.mItemID.CStr()), bind(instanceIdent.mSubjectID.CStr()), bind(instanceIdent.mInstance); + statement << "DELETE FROM launcher_instances WHERE itemID = ? AND subjectID = ? AND instance = ? AND type = ?;", + bind(instanceIdent.mItemID.CStr()), bind(instanceIdent.mSubjectID.CStr()), bind(instanceIdent.mInstance), + bind(instanceIdent.mType.ToString().CStr()); if (statement.execute() != 1) { return ErrorEnum::eNotFound; @@ -821,6 +583,117 @@ Error Database::RemoveInstance(const InstanceIdent& instanceIdent) return ErrorEnum::eNone; } +/*********************************************************************************************************************** + * imagemanager::StorageItf implementation + **********************************************************************************************************************/ + +Error Database::AddItem(const imagemanager::ItemInfo& item) +{ + std::lock_guard lock {mMutex}; + + try { + ImageManagerItemInfoRow row; + + FromAos(item, row); + *mSession + << "INSERT INTO imagemanager (itemID, version, indexDigest, state, timestamp) VALUES (?, ?, ?, ?, ?);", + bind(row), now; + } catch (const std::exception& e) { + return AOS_ERROR_WRAP(common::utils::ToAosError(e)); + } + + return ErrorEnum::eNone; +} + +Error Database::RemoveItem(const String& id, const String& version) +{ + std::lock_guard lock {mMutex}; + + try { + Poco::Data::Statement statement {*mSession}; + + statement << "DELETE FROM imagemanager WHERE itemID = ? AND version = ?;", bind(id.CStr()), + bind(version.CStr()); + + if (statement.execute() != 1) { + return ErrorEnum::eNotFound; + } + } catch (const std::exception& e) { + return AOS_ERROR_WRAP(common::utils::ToAosError(e)); + } + + return ErrorEnum::eNone; +} + +Error Database::UpdateItemState(const String& id, const String& version, ItemState state, Time timestamp) +{ + std::lock_guard lock {mMutex}; + + try { + Poco::Data::Statement statement {*mSession}; + + statement << "UPDATE imagemanager SET state = ?, timestamp = ? WHERE itemID = ? AND version = ?;", + bind(static_cast(state)), bind(timestamp.UnixNano()), bind(id.CStr()), bind(version.CStr()); + + if (statement.execute() != 1) { + return ErrorEnum::eNotFound; + } + } catch (const std::exception& e) { + return AOS_ERROR_WRAP(common::utils::ToAosError(e)); + } + + return ErrorEnum::eNone; +} + +Error Database::GetItemsInfo(Array& items) +{ + std::lock_guard lock {mMutex}; + + try { + std::vector rows; + + *mSession << "SELECT itemID, version, indexDigest, state, timestamp FROM imagemanager;", into(rows), now; + + auto itemInfo = std::make_unique(); + + items.Clear(); + + for (const auto& row : rows) { + ToAos(row, *itemInfo); + AOS_ERROR_CHECK_AND_THROW(items.PushBack(*itemInfo), "can't add item info"); + } + } catch (const std::exception& e) { + return AOS_ERROR_WRAP(common::utils::ToAosError(e)); + } + + return ErrorEnum::eNone; +} + +Error Database::GetItemsInfos(const String& itemID, Array& items) +{ + std::lock_guard lock {mMutex}; + + try { + std::vector rows; + + *mSession << "SELECT itemID, version, indexDigest, state, timestamp FROM imagemanager WHERE itemID = ?;", + bind(itemID.CStr()), into(rows), now; + + auto itemInfo = std::make_unique(); + + items.Clear(); + + for (const auto& row : rows) { + ToAos(row, *itemInfo); + AOS_ERROR_CHECK_AND_THROW(items.PushBack(*itemInfo), "can't add item info"); + } + } catch (const std::exception& e) { + return AOS_ERROR_WRAP(common::utils::ToAosError(e)); + } + + return ErrorEnum::eNone; +} + /*********************************************************************************************************************** * Private **********************************************************************************************************************/ @@ -833,26 +706,23 @@ void Database::CreateTables() "itemID TEXT," "subjectID TEXT," "instance INTEGER," + "type TEXT," "storageQuota INTEGER," "stateQuota INTEGER," "stateChecksum BLOB," - "PRIMARY KEY(itemID,subjectID,instance)" + "PRIMARY KEY(itemID,subjectID,instance,type)" ");", now; LOG_INF() << "Create imagemanager table"; *mSession << "CREATE TABLE IF NOT EXISTS imagemanager (" - "id TEXT," - "type TEXT," + "itemID TEXT," "version TEXT," - "state TEXT," - "path TEXT," - "totalSize INTEGER," - "gid INTEGER," + "indexDigest TEXT," + "state INTEGER," "timestamp INTEGER," - "images TEXT," - "PRIMARY KEY(id,version)" + "PRIMARY KEY(itemID,version)" ");", now; @@ -883,12 +753,13 @@ void Database::CreateTables() "itemID TEXT," "subjectID TEXT," "instance INTEGER," + "type TEXT," "networkID TEXT," "nodeID TEXT," "ip TEXT," "exposedPorts TEXT," "dnsServers TEXT," - "PRIMARY KEY(itemID,subjectID,instance)," + "PRIMARY KEY(itemID,subjectID,instance,type)," "FOREIGN KEY(networkID) REFERENCES networks(networkID)," "FOREIGN KEY(networkID,nodeID) REFERENCES hosts(networkID,nodeID)" ");", @@ -900,15 +771,18 @@ void Database::CreateTables() "itemID TEXT," "subjectID TEXT," "instance INTEGER," - "imageID TEXT," - "updateItemType TEXT," + "type TEXT," + "manifestDigest TEXT," "nodeID TEXT," "prevNodeID TEXT," "runtimeID TEXT," "uid INTEGER," + "gid INTEGER," "timestamp INTEGER," - "cached INTEGER," - "PRIMARY KEY(itemID,subjectID,instance)" + "state TEXT," + "isUnitSubject INTEGER," + "version TEXT," + "PRIMARY KEY(itemID,subjectID,instance,type,version)" ");", now; } @@ -923,6 +797,7 @@ void Database::FromAos(const storagestate::InstanceInfo& src, StorageStateInstan dst.set(src.mInstanceIdent.mItemID.CStr()); dst.set(src.mInstanceIdent.mSubjectID.CStr()); dst.set(src.mInstanceIdent.mInstance); + dst.set(src.mInstanceIdent.mType.ToString().CStr()); dst.set(src.mStorageQuota); dst.set(src.mStateQuota); dst.set( @@ -938,45 +813,12 @@ void Database::ToAos(const StorageStateInstanceInfoRow& src, storagestate::Insta dst.mInstanceIdent.mInstance = src.get(); dst.mStorageQuota = src.get(); dst.mStateQuota = src.get(); + AOS_ERROR_CHECK_AND_THROW( + dst.mInstanceIdent.mType.FromString(src.get().c_str()), + "failed to parse instance type"); AOS_ERROR_CHECK_AND_THROW(dst.mStateChecksum.Assign(Array(blob.rawContent(), blob.size()))); } -void Database::FromAos(const imagemanager::storage::ItemInfo& src, ImageManagerItemInfoRow& dst) -{ - dst.set(src.mID.CStr()); - dst.set(src.mType.ToString().CStr()); - dst.set(src.mVersion.CStr()); - dst.set(src.mState.ToString().CStr()); - dst.set(src.mPath.CStr()); - dst.set(src.mTotalSize); - dst.set(src.mGID); - dst.set(src.mTimestamp.UnixNano()); - dst.set(SerializeImages(src.mImages)); -} - -void Database::ToAos(const ImageManagerItemInfoRow& src, imagemanager::storage::ItemInfo& dst) -{ - dst.mID = src.get().c_str(); - dst.mVersion = src.get().c_str(); - dst.mPath = src.get().c_str(); - dst.mTotalSize = src.get(); - dst.mGID = src.get(); - dst.mTimestamp - = Time::Unix(src.get() / Time::cSeconds.Nanoseconds(), - src.get() % Time::cSeconds.Nanoseconds()); - - if (auto err = dst.mType.FromString(src.get().c_str()); !err.IsNone()) { - AOS_ERROR_CHECK_AND_THROW(err, "failed to parse item type"); - } - - if (auto err = dst.mState.FromString(src.get().c_str()); - !err.IsNone()) { - AOS_ERROR_CHECK_AND_THROW(err, "failed to parse item state"); - } - - DeserializeImages(src.get(), dst.mImages); -} - void Database::FromAos(const networkmanager::Network& src, NetworkManagerNetworkRow& dst) { dst.set(src.mNetworkID.CStr()); @@ -1009,6 +851,7 @@ void Database::FromAos(const networkmanager::Instance& src, NetworkManagerInstan dst.set(src.mInstanceIdent.mItemID.CStr()); dst.set(src.mInstanceIdent.mSubjectID.CStr()); dst.set(src.mInstanceIdent.mInstance); + dst.set(src.mInstanceIdent.mType.ToString().CStr()); dst.set(src.mNetworkID.CStr()); dst.set(src.mNodeID.CStr()); dst.set(src.mIP.CStr()); @@ -1021,9 +864,12 @@ void Database::ToAos(const NetworkManagerInstanceRow& src, networkmanager::Insta dst.mInstanceIdent.mItemID = src.get().c_str(); dst.mInstanceIdent.mSubjectID = src.get().c_str(); dst.mInstanceIdent.mInstance = src.get(); - dst.mNetworkID = src.get().c_str(); - dst.mNodeID = src.get().c_str(); - dst.mIP = src.get().c_str(); + AOS_ERROR_CHECK_AND_THROW( + dst.mInstanceIdent.mType.FromString(src.get().c_str()), + "failed to parse instance type"); + dst.mNetworkID = src.get().c_str(); + dst.mNodeID = src.get().c_str(); + dst.mIP = src.get().c_str(); DeserializeExposedPorts(src.get(), dst.mExposedPorts); DeserializeDNSServers(src.get(), dst.mDNSServers); @@ -1034,34 +880,62 @@ void Database::FromAos(const launcher::InstanceInfo& src, LauncherInstanceInfoRo dst.set(src.mInstanceIdent.mItemID.CStr()); dst.set(src.mInstanceIdent.mSubjectID.CStr()); dst.set(src.mInstanceIdent.mInstance); - dst.set(src.mImageID.CStr()); - dst.set(src.mUpdateItemType.ToString().CStr()); + dst.set(src.mInstanceIdent.mType.ToString().CStr()); + dst.set(src.mManifestDigest.CStr()); dst.set(src.mNodeID.CStr()); dst.set(src.mPrevNodeID.CStr()); dst.set(src.mRuntimeID.CStr()); dst.set(src.mUID); + dst.set(src.mGID); dst.set(src.mTimestamp.UnixNano()); - dst.set(src.mCached); + dst.set(src.mState.ToString().CStr()); + dst.set(src.mIsUnitSubject); + dst.set(src.mVersion.CStr()); } void Database::ToAos(const LauncherInstanceInfoRow& src, launcher::InstanceInfo& dst) { - auto timestamp = src.get(); - auto updateItemType = src.get(); - dst.mInstanceIdent.mItemID = src.get().c_str(); dst.mInstanceIdent.mSubjectID = src.get().c_str(); dst.mInstanceIdent.mInstance = src.get(); - dst.mImageID = src.get().c_str(); - dst.mNodeID = src.get().c_str(); - dst.mPrevNodeID = src.get().c_str(); - dst.mRuntimeID = src.get().c_str(); - dst.mUID = src.get(); + AOS_ERROR_CHECK_AND_THROW( + dst.mInstanceIdent.mType.FromString(src.get().c_str()), + "failed to parse instance type"); + dst.mManifestDigest = src.get().c_str(); + dst.mNodeID = src.get().c_str(); + dst.mPrevNodeID = src.get().c_str(); + dst.mRuntimeID = src.get().c_str(); + dst.mUID = src.get(); + dst.mGID = src.get(); + + auto timestamp = src.get(); dst.mTimestamp = Time::Unix(timestamp / Time::cSeconds.Nanoseconds(), timestamp % Time::cSeconds.Nanoseconds()); - dst.mCached = src.get(); - AOS_ERROR_CHECK_AND_THROW( - dst.mUpdateItemType.FromString(updateItemType.c_str()), "failed to parse update item type"); + dst.mIsUnitSubject = src.get(); + dst.mVersion = src.get().c_str(); + + const auto& stateStr = src.get(); + AOS_ERROR_CHECK_AND_THROW(dst.mState.FromString(stateStr.c_str()), "failed to parse instance state"); +} + +void Database::FromAos(const imagemanager::ItemInfo& src, ImageManagerItemInfoRow& dst) +{ + dst.set(src.mItemID.CStr()); + dst.set(src.mVersion.CStr()); + dst.set(src.mIndexDigest.CStr()); + dst.set(static_cast(src.mState)); + dst.set(src.mTimestamp.UnixNano()); +} + +void Database::ToAos(const ImageManagerItemInfoRow& src, imagemanager::ItemInfo& dst) +{ + dst.mItemID = src.get().c_str(); + dst.mVersion = src.get().c_str(); + dst.mIndexDigest = src.get().c_str(); + dst.mState = static_cast(src.get()); + + auto timestamp = src.get(); + dst.mTimestamp = Time::Unix(timestamp / Time::cSeconds.Nanoseconds(), timestamp % Time::cSeconds.Nanoseconds()); } } // namespace aos::cm::database diff --git a/src/cm/database/database.hpp b/src/cm/database/database.hpp index e7431294a..2a35dd727 100644 --- a/src/cm/database/database.hpp +++ b/src/cm/database/database.hpp @@ -30,9 +30,9 @@ namespace aos::cm::database { * Database class. */ class Database : public storagestate::StorageItf, - public imagemanager::storage::StorageItf, public networkmanager::StorageItf, - public launcher::StorageItf { + public launcher::StorageItf, + public imagemanager::StorageItf { public: /** * Creates database instance. @@ -97,54 +97,6 @@ class Database : public storagestate::StorageItf, */ Error UpdateStorageStateInfo(const storagestate::InstanceInfo& info) override; - // - // imagemanager::storage::StorageItf interface - // - - /** - * Sets item state. - * - * @param id ID. - * @param version Version. - * @param state Item state. - * @return Error. - */ - Error SetItemState(const String& id, const String& version, imagemanager::storage::ItemState state) override; - - /** - * Removes item. - * - * @param id ID. - * @param version Version. - * @return Error. - */ - Error RemoveItem(const String& id, const String& version) override; - - /** - * Gets items info. - * - * @param items Items info. - * @return Error. - */ - Error GetItemsInfo(Array& items) override; - - /** - * Gets item versions by ID. - * - * @param id ID. - * @param items Items info. - * @return Error. - */ - Error GetItemVersionsByID(const String& id, Array& items) override; - - /** - * Adds item. - * - * @param item Item info. - * @return Error. - */ - Error AddItem(const imagemanager::storage::ItemInfo& item) override; - // // networkmanager::StorageItf interface // @@ -272,6 +224,55 @@ class Database : public storagestate::StorageItf, */ Error RemoveInstance(const InstanceIdent& instanceIdent) override; + // + // imagemanager::StorageItf interface + // + + /** + * Adds item. + * + * @param item Item info. + * @return Error. + */ + Error AddItem(const imagemanager::ItemInfo& item) override; + + /** + * Removes item. + * + * @param id ID. + * @param version Version. + * @return Error. + */ + Error RemoveItem(const String& id, const String& version) override; + + /** + * Updates item state. + * + * @param id ID. + * @param version Version. + * @param state Item state. + * @param timestamp Timestamp. + * @return Error. + */ + Error UpdateItemState(const String& id, const String& version, ItemState state, Time timestamp = {}) override; + + /** + * Gets items info. + * + * @param items Items info. + * @return Error. + */ + Error GetItemsInfo(Array& items) override; + + /** + * Gets items info by ID. + * + * @param itemID Item ID. + * @param items Items info. + * @return Error. + */ + Error GetItemsInfos(const String& itemID, Array& items) override; + private: static constexpr int cVersion = 0; static constexpr auto cDBFileName = "cm.db"; @@ -280,26 +281,13 @@ class Database : public storagestate::StorageItf, eItemID = 0, eSubjectID, eInstance, + eType, eStorageQuota, eStateQuota, eStateChecksum }; using StorageStateInstanceInfoRow - = Poco::Tuple; - - enum class ImageManagerItemInfoColumns : int { - eID = 0, - eType, - eVersion, - eState, - ePath, - eTotalSize, - eGID, - eTimestamp, - eImages - }; - using ImageManagerItemInfoRow = Poco::Tuple; + = Poco::Tuple; enum class NetworkManagerNetworkColumns : int { eNetworkID = 0, eSubnet, eVlanID }; using NetworkManagerNetworkRow = Poco::Tuple; @@ -311,6 +299,7 @@ class Database : public storagestate::StorageItf, eItemID = 0, eSubjectID, eInstance, + eType, eNetworkID, eNodeID, eIP, @@ -318,23 +307,29 @@ class Database : public storagestate::StorageItf, eDNSServers }; using NetworkManagerInstanceRow = Poco::Tuple; + std::string, std::string, std::string, std::string>; enum class LauncherInstanceInfoColumns : int { eItemID = 0, eSubjectID, eInstance, - eImageID, - eUpdateItemType, + eType, + eManifestDigest, eNodeID, ePrevNodeID, eRuntimeID, eUID, + eGID, eTimestamp, - eCached + eState, + eIsUnitSubject, + eVersion }; using LauncherInstanceInfoRow = Poco::Tuple; + std::string, std::string, std::string, uint32_t, uint32_t, uint64_t, std::string, bool, std::string>; + + enum class ImageManagerItemInfoColumns : int { eItemID = 0, eVersion, eIndexDigest, eState, eTimestamp }; + using ImageManagerItemInfoRow = Poco::Tuple; // make virtual for unit tests virtual int GetVersion() const; @@ -343,9 +338,6 @@ class Database : public storagestate::StorageItf, static void FromAos(const storagestate::InstanceInfo& src, StorageStateInstanceInfoRow& dst); static void ToAos(const StorageStateInstanceInfoRow& src, storagestate::InstanceInfo& dst); - static void FromAos(const imagemanager::storage::ItemInfo& src, ImageManagerItemInfoRow& dst); - static void ToAos(const ImageManagerItemInfoRow& src, imagemanager::storage::ItemInfo& dst); - static void FromAos(const networkmanager::Network& src, NetworkManagerNetworkRow& dst); static void ToAos(const NetworkManagerNetworkRow& src, networkmanager::Network& dst); @@ -358,6 +350,9 @@ class Database : public storagestate::StorageItf, static void FromAos(const launcher::InstanceInfo& src, LauncherInstanceInfoRow& dst); static void ToAos(const LauncherInstanceInfoRow& src, launcher::InstanceInfo& dst); + static void FromAos(const imagemanager::ItemInfo& src, ImageManagerItemInfoRow& dst); + static void ToAos(const ImageManagerItemInfoRow& src, imagemanager::ItemInfo& dst); + std::unique_ptr mSession; std::optional mDatabase; mutable std::mutex mMutex; diff --git a/src/cm/database/tests/database.cpp b/src/cm/database/tests/database.cpp index 6cf897904..ab2e795bf 100644 --- a/src/cm/database/tests/database.cpp +++ b/src/cm/database/tests/database.cpp @@ -25,13 +25,15 @@ std::vector ToVector(const Array& src) return std::vector(src.begin(), src.end()); } -InstanceIdent CreateInstanceIdent(const char* itemID, const char* subjectID, uint64_t instance) +InstanceIdent CreateInstanceIdent(const char* itemID, const char* subjectID, uint64_t instance, + UpdateItemType itemType = UpdateItemTypeEnum::eService) { InstanceIdent ident; ident.mItemID = itemID; ident.mSubjectID = subjectID; ident.mInstance = instance; + ident.mType = itemType; return ident; } @@ -50,44 +52,6 @@ storagestate::InstanceInfo CreateStorageStateInstanceInfo( return info; } -imagemanager::storage::ItemInfo CreateImageManagerItemInfo( - const char* id, const char* version, imagemanager::storage::ItemStateEnum state, size_t totalSize) -{ - imagemanager::storage::ItemInfo item; - - item.mID = id; - item.mVersion = version; - item.mTotalSize = totalSize; - item.mGID = 1000; - item.mPath = "/path/to/item"; - item.mTimestamp = Time::Now(); - - item.mType = UpdateItemTypeEnum::eComponent; - item.mState = state; - - // Add a sample image - imagemanager::storage::ImageInfo imageInfo; - imageInfo.mURL = "http://example.com/image.tar"; - imageInfo.mPath = "/path/to/image"; - imageInfo.mSize = 1024 * 1024; - - // SHA256 hash (magic number) - static const std::vector cSHA256MagicNumber = {0xde, 0xad, 0xbe, 0xef}; - - imageInfo.mSHA256 = Array(cSHA256MagicNumber.data(), cSHA256MagicNumber.size()); - - // Platform info - imageInfo.mImageID = "image1"; - imageInfo.mArchInfo.mArchitecture = "amd64"; - imageInfo.mArchInfo.mVariant.SetValue("v8"); - imageInfo.mOSInfo.mOS = "linux"; - imageInfo.mOSInfo.mVersion.SetValue("5.10"); - - AOS_ERROR_CHECK_AND_THROW(item.mImages.PushBack(imageInfo), "can't add image"); - - return item; -} - networkmanager::Network CreateNetwork(const char* networkID, const char* subnet, uint64_t vlanID) { networkmanager::Network network; @@ -110,11 +74,11 @@ networkmanager::Host CreateHost(const char* nodeID, const char* ip) } networkmanager::Instance CreateInstance(const char* itemID, const char* subjectID, uint64_t instance, - const char* networkID, const char* nodeID, const char* ip) + const char* networkID, const char* nodeID, const char* ip, UpdateItemType itemType = UpdateItemTypeEnum::eService) { networkmanager::Instance inst; - inst.mInstanceIdent = CreateInstanceIdent(itemID, subjectID, instance); + inst.mInstanceIdent = CreateInstanceIdent(itemID, subjectID, instance, itemType); inst.mNetworkID = networkID; inst.mNodeID = nodeID; inst.mIP = ip; @@ -137,20 +101,38 @@ networkmanager::Instance CreateInstance(const char* itemID, const char* subjectI return inst; } -launcher::InstanceInfo CreateLauncherInstanceInfo( - const char* itemID, const char* subjectID, uint64_t instance, const char* imageID, const char* nodeID) +launcher::InstanceInfo CreateLauncherInstanceInfo(const char* itemID, const char* subjectID, uint64_t instance, + const char* manifestDigest, const char* nodeID, UpdateItemType itemType = UpdateItemTypeEnum::eService, + launcher::InstanceStateEnum state = launcher::InstanceStateEnum::eCached, bool isUnitSubject = false, + const char* version = "1.0.0") { launcher::InstanceInfo info; - info.mInstanceIdent = CreateInstanceIdent(itemID, subjectID, instance); - info.mImageID = imageID; - info.mUpdateItemType = UpdateItemTypeEnum::eService; + info.mInstanceIdent = CreateInstanceIdent(itemID, subjectID, instance, itemType); + info.mManifestDigest = manifestDigest; info.mNodeID = nodeID; info.mPrevNodeID = "prevNode"; info.mRuntimeID = "runc"; info.mUID = 1000; + info.mGID = 2000; info.mTimestamp = Time::Now(); - info.mCached = true; + info.mState = state; + info.mIsUnitSubject = isUnitSubject; + info.mVersion = version; + + return info; +} + +imagemanager::ItemInfo CreateImageManagerItemInfo( + const char* itemID, const char* version, const char* indexDigest, ItemState state) +{ + imagemanager::ItemInfo info; + + info.mItemID = itemID; + info.mVersion = version; + info.mIndexDigest = indexDigest; + info.mState = state; + info.mTimestamp = Time::Now(); return info; } @@ -315,112 +297,6 @@ TEST_F(CMDatabaseTest, StateStorageUpdateStorageStateInfo) ASSERT_FALSE(mDB.UpdateStorageStateInfo(nonExistentInfo).IsNone()); } -/*********************************************************************************************************************** - * imagemanager::storage::StorageItf tests - **********************************************************************************************************************/ - -TEST_F(CMDatabaseTest, ImageManagerAddItem) -{ - ASSERT_TRUE(mDB.Init(mDatabaseConfig).IsNone()); - - auto item - = CreateImageManagerItemInfo("item1", "1.0.0", imagemanager::storage::ItemStateEnum::eCached, 1024 * 1024); - - ASSERT_TRUE(mDB.AddItem(item).IsNone()); - - // Verify the item was added by retrieving all items - StaticArray allItems; - ASSERT_TRUE(mDB.GetItemsInfo(allItems).IsNone()); - EXPECT_THAT(ToVector(allItems), UnorderedElementsAre(item)); -} - -TEST_F(CMDatabaseTest, ImageManagerSetItemState) -{ - ASSERT_TRUE(mDB.Init(mDatabaseConfig).IsNone()); - - // Set state for non-existent item - auto err = mDB.SetItemState( - "nonexistent", "1.0.0", imagemanager::storage::ItemState(imagemanager::storage::ItemStateEnum::eActive)); - ASSERT_EQ(err, ErrorEnum::eNotFound); - - // Add an item with state "cached" - auto item - = CreateImageManagerItemInfo("item1", "1.0.0", imagemanager::storage::ItemStateEnum::eCached, 1024 * 1024); - ASSERT_TRUE(mDB.AddItem(item).IsNone()); - - StaticArray allItems; - ASSERT_TRUE(mDB.GetItemsInfo(allItems).IsNone()); - ASSERT_EQ(allItems.Size(), 1); - EXPECT_EQ(allItems[0].mState, imagemanager::storage::ItemStateEnum::eCached); - - // Set state to "active" - ASSERT_TRUE(mDB.SetItemState(item.mID, item.mVersion, imagemanager::storage::ItemStateEnum::eActive).IsNone()); - - ASSERT_TRUE(mDB.GetItemsInfo(allItems).IsNone()); - ASSERT_EQ(allItems.Size(), 1); - EXPECT_EQ(allItems[0].mState, imagemanager::storage::ItemStateEnum::eActive); -} - -TEST_F(CMDatabaseTest, ImageManagerRemoveItem) -{ - ASSERT_TRUE(mDB.Init(mDatabaseConfig).IsNone()); - - // Remove non-existent item - EXPECT_EQ(mDB.RemoveItem("nonexistent", "1.0.0"), ErrorEnum::eNotFound); - - // Add items - auto item1 - = CreateImageManagerItemInfo("item1", "1.0.0", imagemanager::storage::ItemStateEnum::eCached, 1024 * 1024); - auto item2 - = CreateImageManagerItemInfo("item2", "2.0.0", imagemanager::storage::ItemStateEnum::eActive, 2048 * 1024); - - ASSERT_TRUE(mDB.AddItem(item1).IsNone()); - ASSERT_TRUE(mDB.AddItem(item2).IsNone()); - - // Remove item2 - ASSERT_TRUE(mDB.RemoveItem(item2.mID, item2.mVersion).IsNone()); - - StaticArray allItems; - ASSERT_TRUE(mDB.GetItemsInfo(allItems).IsNone()); - EXPECT_THAT(ToVector(allItems), UnorderedElementsAre(item1)); - - // Remove item2 again - EXPECT_EQ(mDB.RemoveItem(item2.mID, item2.mVersion), ErrorEnum::eNotFound); -} - -TEST_F(CMDatabaseTest, ImageManagerGetItemVersionsByID) -{ - ASSERT_TRUE(mDB.Init(mDatabaseConfig).IsNone()); - - // Get versions for non-existent item - should return empty - StaticArray versions; - ASSERT_TRUE(mDB.GetItemVersionsByID("nonexistent", versions).IsNone()); - EXPECT_EQ(versions.Size(), 0); - - // Add items - auto item1v1 - = CreateImageManagerItemInfo("item1", "1.0.0", imagemanager::storage::ItemStateEnum::eCached, 1024 * 1024); - auto item1v2 - = CreateImageManagerItemInfo("item1", "2.0.0", imagemanager::storage::ItemStateEnum::eActive, 2048 * 1024); - auto item1v3 - = CreateImageManagerItemInfo("item1", "3.0.0", imagemanager::storage::ItemStateEnum::eCached, 3072 * 1024); - auto item2v1 - = CreateImageManagerItemInfo("item2", "1.0.0", imagemanager::storage::ItemStateEnum::eActive, 512 * 1024); - - ASSERT_TRUE(mDB.AddItem(item1v1).IsNone()); - ASSERT_TRUE(mDB.AddItem(item1v2).IsNone()); - ASSERT_TRUE(mDB.AddItem(item1v3).IsNone()); - ASSERT_TRUE(mDB.AddItem(item2v1).IsNone()); - - // Get all versions of item1 - ASSERT_TRUE(mDB.GetItemVersionsByID("item1", versions).IsNone()); - EXPECT_THAT(ToVector(versions), UnorderedElementsAre(item1v1, item1v2, item1v3)); - - // Get all versions of item2 - ASSERT_TRUE(mDB.GetItemVersionsByID("item2", versions).IsNone()); - EXPECT_THAT(ToVector(versions), UnorderedElementsAre(item2v1)); -} - /*********************************************************************************************************************** * networkmanager::StorageItf tests **********************************************************************************************************************/ @@ -493,7 +369,8 @@ TEST_F(CMDatabaseTest, NetworkManagerAddInstance) auto instance1 = CreateInstance("service1", "subject1", 0, "network1", "node1", "172.17.0.10"); auto instance2 = CreateInstance("service1", "subject1", 1, "network1", "node1", "172.17.0.11"); - auto instance3 = CreateInstance("service2", "subject2", 0, "network1", "node1", "172.17.0.12"); + auto instance3 + = CreateInstance("service2", "subject2", 0, "network1", "node1", "172.17.0.12", UpdateItemTypeEnum::eComponent); // Add instances ASSERT_TRUE(mDB.AddInstance(instance1).IsNone()); @@ -621,49 +498,62 @@ TEST_F(CMDatabaseTest, LauncherAddInstance) { ASSERT_TRUE(mDB.Init(mDatabaseConfig).IsNone()); - auto instance1 = CreateLauncherInstanceInfo("service1", "subject1", 0, "image1", "node1"); - auto instance2 = CreateLauncherInstanceInfo("service1", "subject1", 1, "image1", "node1"); - auto instance3 = CreateLauncherInstanceInfo("service2", "subject2", 0, "image2", "node2"); + auto instance1 = CreateLauncherInstanceInfo("service1", "subject1", 0, "image1", "node1", + UpdateItemTypeEnum::eService, launcher::InstanceStateEnum::eActive, false, "1.0.0"); + auto instance2 = CreateLauncherInstanceInfo("service1", "subject1", 1, "image1", "node1", + UpdateItemTypeEnum::eService, launcher::InstanceStateEnum::eCached, true, "1.0.0"); + auto instance3 = CreateLauncherInstanceInfo("service2", "subject2", 0, "image2", "node2", + UpdateItemTypeEnum::eComponent, launcher::InstanceStateEnum::eDisabled, false, "2.0.0"); // Add instances ASSERT_TRUE(mDB.AddInstance(instance1).IsNone()); ASSERT_TRUE(mDB.AddInstance(instance2).IsNone()); ASSERT_TRUE(mDB.AddInstance(instance3).IsNone()); - // Add duplicate instance - auto duplicateInstance = CreateLauncherInstanceInfo("service1", "subject1", 0, "image99", "node99"); + // Add duplicate instance (same primary key including version) + auto duplicateInstance = CreateLauncherInstanceInfo("service1", "subject1", 0, "image99", "node99", + UpdateItemTypeEnum::eService, launcher::InstanceStateEnum::eCached, false, "1.0.0"); ASSERT_FALSE(mDB.AddInstance(duplicateInstance).IsNone()); + // Add instance with same InstanceIdent but different version (should succeed) + auto instance1v2 = CreateLauncherInstanceInfo("service1", "subject1", 0, "image1", "node1", + UpdateItemTypeEnum::eService, launcher::InstanceStateEnum::eActive, false, "2.0.0"); + ASSERT_TRUE(mDB.AddInstance(instance1v2).IsNone()); + // Verify instances - StaticArray instances; + StaticArray instances; ASSERT_TRUE(mDB.GetActiveInstances(instances).IsNone()); - EXPECT_THAT(ToVector(instances), UnorderedElementsAre(instance1, instance2, instance3)); + EXPECT_THAT(ToVector(instances), UnorderedElementsAre(instance1, instance2, instance3, instance1v2)); } TEST_F(CMDatabaseTest, LauncherUpdateInstance) { ASSERT_TRUE(mDB.Init(mDatabaseConfig).IsNone()); - auto instance1 = CreateLauncherInstanceInfo("service1", "subject1", 0, "image1", "node1"); - auto instance2 = CreateLauncherInstanceInfo("service2", "subject2", 0, "image2", "node2"); + auto instance1 = CreateLauncherInstanceInfo("service1", "subject1", 0, "image1", "node1", + UpdateItemTypeEnum::eService, launcher::InstanceStateEnum::eCached, false, "1.0.0"); + auto instance2 = CreateLauncherInstanceInfo("service2", "subject2", 0, "image2", "node2", + UpdateItemTypeEnum::eService, launcher::InstanceStateEnum::eActive, true, "1.0.0"); // Add instances ASSERT_TRUE(mDB.AddInstance(instance1).IsNone()); ASSERT_TRUE(mDB.AddInstance(instance2).IsNone()); // Update instance - instance1.mImageID = "image1-updated"; - instance1.mNodeID = "node1-updated"; - instance1.mPrevNodeID = "node1"; - instance1.mRuntimeID = "crun"; - instance1.mUID = 2000; - instance1.mCached = false; + instance1.mManifestDigest = "image1-updated"; + instance1.mNodeID = "node1-updated"; + instance1.mPrevNodeID = "node1"; + instance1.mRuntimeID = "crun"; + instance1.mUID = 2000; + instance1.mState = launcher::InstanceStateEnum::eActive; + instance1.mIsUnitSubject = true; ASSERT_TRUE(mDB.UpdateInstance(instance1).IsNone()); // Update non-existent instance - auto nonExistentInstance = CreateLauncherInstanceInfo("nonexistent", "subject", 99, "image99", "node99"); + auto nonExistentInstance = CreateLauncherInstanceInfo("nonexistent", "subject", 99, "image99", "node99", + UpdateItemTypeEnum::eService, launcher::InstanceStateEnum::eCached, false, "1.0.0"); ASSERT_FALSE(mDB.UpdateInstance(nonExistentInstance).IsNone()); // Verify updated instance @@ -682,8 +572,10 @@ TEST_F(CMDatabaseTest, LauncherGetInstance) { ASSERT_TRUE(mDB.Init(mDatabaseConfig).IsNone()); - auto instance1 = CreateLauncherInstanceInfo("service1", "subject1", 0, "image1", "node1"); - auto instance2 = CreateLauncherInstanceInfo("service2", "subject2", 0, "image2", "node2"); + auto instance1 = CreateLauncherInstanceInfo("service1", "subject1", 0, "image1", "node1", + UpdateItemTypeEnum::eService, launcher::InstanceStateEnum::eActive, false, "1.0.0"); + auto instance2 = CreateLauncherInstanceInfo("service2", "subject2", 0, "image2", "node2", + UpdateItemTypeEnum::eService, launcher::InstanceStateEnum::eCached, true, "2.0.0"); // Add instances ASSERT_TRUE(mDB.AddInstance(instance1).IsNone()); @@ -694,9 +586,11 @@ TEST_F(CMDatabaseTest, LauncherGetInstance) ASSERT_TRUE(mDB.GetInstance(instance1.mInstanceIdent, retrievedInstance).IsNone()); EXPECT_EQ(retrievedInstance, instance1); + EXPECT_EQ(retrievedInstance.mVersion, "1.0.0"); ASSERT_TRUE(mDB.GetInstance(instance2.mInstanceIdent, retrievedInstance).IsNone()); EXPECT_EQ(retrievedInstance, instance2); + EXPECT_EQ(retrievedInstance.mVersion, "2.0.0"); // Get non-existent instance auto nonExistentIdent = CreateInstanceIdent("nonexistent", "subject", 99); @@ -712,8 +606,10 @@ TEST_F(CMDatabaseTest, LauncherGetActiveInstances) ASSERT_TRUE(mDB.GetActiveInstances(emptyInstances).IsNone()); EXPECT_EQ(emptyInstances.Size(), 0); - auto instance1 = CreateLauncherInstanceInfo("service1", "subject1", 0, "image1", "node1"); - auto instance2 = CreateLauncherInstanceInfo("service2", "subject2", 0, "image2", "node2"); + auto instance1 = CreateLauncherInstanceInfo("service1", "subject1", 0, "image1", "node1", + UpdateItemTypeEnum::eService, launcher::InstanceStateEnum::eActive, false, "1.0.0"); + auto instance2 = CreateLauncherInstanceInfo("service2", "subject2", 0, "image2", "node2", + UpdateItemTypeEnum::eService, launcher::InstanceStateEnum::eDisabled, true, "2.0.0"); // Add instances ASSERT_TRUE(mDB.AddInstance(instance1).IsNone()); @@ -730,8 +626,10 @@ TEST_F(CMDatabaseTest, LauncherRemoveInstance) { ASSERT_TRUE(mDB.Init(mDatabaseConfig).IsNone()); - auto instance1 = CreateLauncherInstanceInfo("service1", "subject1", 0, "image1", "node1"); - auto instance2 = CreateLauncherInstanceInfo("service2", "subject2", 0, "image2", "node2"); + auto instance1 = CreateLauncherInstanceInfo("service1", "subject1", 0, "image1", "node1", + UpdateItemTypeEnum::eService, launcher::InstanceStateEnum::eCached, true, "1.0.0"); + auto instance2 = CreateLauncherInstanceInfo("service2", "subject2", 0, "image2", "node2", + UpdateItemTypeEnum::eService, launcher::InstanceStateEnum::eActive, false, "2.0.0"); ASSERT_TRUE(mDB.AddInstance(instance1).IsNone()); ASSERT_TRUE(mDB.AddInstance(instance2).IsNone()); @@ -744,4 +642,134 @@ TEST_F(CMDatabaseTest, LauncherRemoveInstance) ASSERT_FALSE(mDB.RemoveInstance(nonExistentIdent).IsNone()); } +/*********************************************************************************************************************** + * imagemanager::StorageItf tests + **********************************************************************************************************************/ + +TEST_F(CMDatabaseTest, ImageManagerAddItem) +{ + ASSERT_TRUE(mDB.Init(mDatabaseConfig).IsNone()); + + auto item1 = CreateImageManagerItemInfo("service1", "1.0.0", "sha256:abc123", ItemStateEnum::eInstalled); + auto item2 = CreateImageManagerItemInfo("service1", "2.0.0", "sha256:def456", ItemStateEnum::eInstalled); + auto item3 = CreateImageManagerItemInfo("service2", "1.0.0", "sha256:ghi789", ItemStateEnum::ePending); + + ASSERT_TRUE(mDB.AddItem(item1).IsNone()); + ASSERT_TRUE(mDB.AddItem(item2).IsNone()); + ASSERT_TRUE(mDB.AddItem(item3).IsNone()); + + auto duplicateItem = CreateImageManagerItemInfo("service1", "1.0.0", "sha256:xyz999", ItemStateEnum::eInstalled); + ASSERT_FALSE(mDB.AddItem(duplicateItem).IsNone()); + + StaticArray items; + + ASSERT_TRUE(mDB.GetItemsInfo(items).IsNone()); + + EXPECT_THAT(ToVector(items), UnorderedElementsAre(item1, item2, item3)); +} + +TEST_F(CMDatabaseTest, ImageManagerRemoveItem) +{ + ASSERT_TRUE(mDB.Init(mDatabaseConfig).IsNone()); + + auto item1 = CreateImageManagerItemInfo("service1", "1.0.0", "sha256:abc123", ItemStateEnum::eInstalled); + auto item2 = CreateImageManagerItemInfo("service1", "2.0.0", "sha256:def456", ItemStateEnum::eInstalled); + auto item3 = CreateImageManagerItemInfo("service2", "1.0.0", "sha256:ghi789", ItemStateEnum::ePending); + + ASSERT_TRUE(mDB.AddItem(item1).IsNone()); + ASSERT_TRUE(mDB.AddItem(item2).IsNone()); + ASSERT_TRUE(mDB.AddItem(item3).IsNone()); + + ASSERT_TRUE(mDB.RemoveItem("service1", "1.0.0").IsNone()); + + ASSERT_FALSE(mDB.RemoveItem("nonexistent", "1.0.0").IsNone()); + + StaticArray items; + + ASSERT_TRUE(mDB.GetItemsInfo(items).IsNone()); + + EXPECT_THAT(ToVector(items), UnorderedElementsAre(item2, item3)); +} + +TEST_F(CMDatabaseTest, ImageManagerUpdateItemState) +{ + ASSERT_TRUE(mDB.Init(mDatabaseConfig).IsNone()); + + auto item1 = CreateImageManagerItemInfo("service1", "1.0.0", "sha256:abc123", ItemStateEnum::ePending); + auto item2 = CreateImageManagerItemInfo("service2", "1.0.0", "sha256:def456", ItemStateEnum::ePending); + + ASSERT_TRUE(mDB.AddItem(item1).IsNone()); + ASSERT_TRUE(mDB.AddItem(item2).IsNone()); + + auto newTimestamp = Time::Now(); + ASSERT_TRUE(mDB.UpdateItemState("service1", "1.0.0", ItemStateEnum::eInstalled, newTimestamp).IsNone()); + + ASSERT_FALSE(mDB.UpdateItemState("nonexistent", "1.0.0", ItemStateEnum::eInstalled).IsNone()); + + StaticArray items; + + ASSERT_TRUE(mDB.GetItemsInfos("service1", items).IsNone()); + ASSERT_EQ(items.Size(), 1); + EXPECT_EQ(items[0].mState, ItemStateEnum::eInstalled); + EXPECT_EQ(items[0].mTimestamp, newTimestamp); + + StaticArray items2; + + ASSERT_TRUE(mDB.GetItemsInfos("service2", items2).IsNone()); + ASSERT_EQ(items2.Size(), 1); + EXPECT_EQ(items2[0].mState, ItemStateEnum::ePending); +} + +TEST_F(CMDatabaseTest, ImageManagerGetItemsInfo) +{ + ASSERT_TRUE(mDB.Init(mDatabaseConfig).IsNone()); + + StaticArray emptyItems; + + ASSERT_TRUE(mDB.GetItemsInfo(emptyItems).IsNone()); + EXPECT_EQ(emptyItems.Size(), 0); + + auto item1 = CreateImageManagerItemInfo("service1", "1.0.0", "sha256:abc123", ItemStateEnum::eInstalled); + auto item2 = CreateImageManagerItemInfo("service1", "2.0.0", "sha256:def456", ItemStateEnum::eInstalled); + auto item3 = CreateImageManagerItemInfo("service2", "1.0.0", "sha256:ghi789", ItemStateEnum::ePending); + + ASSERT_TRUE(mDB.AddItem(item1).IsNone()); + ASSERT_TRUE(mDB.AddItem(item2).IsNone()); + ASSERT_TRUE(mDB.AddItem(item3).IsNone()); + + StaticArray items; + + ASSERT_TRUE(mDB.GetItemsInfo(items).IsNone()); + + EXPECT_THAT(ToVector(items), UnorderedElementsAre(item1, item2, item3)); +} + +TEST_F(CMDatabaseTest, ImageManagerGetItemsInfos) +{ + ASSERT_TRUE(mDB.Init(mDatabaseConfig).IsNone()); + + auto item1 = CreateImageManagerItemInfo("service1", "1.0.0", "sha256:abc123", ItemStateEnum::eInstalled); + auto item2 = CreateImageManagerItemInfo("service1", "2.0.0", "sha256:def456", ItemStateEnum::eInstalled); + auto item3 = CreateImageManagerItemInfo("service2", "1.0.0", "sha256:ghi789", ItemStateEnum::ePending); + + ASSERT_TRUE(mDB.AddItem(item1).IsNone()); + ASSERT_TRUE(mDB.AddItem(item2).IsNone()); + ASSERT_TRUE(mDB.AddItem(item3).IsNone()); + + StaticArray service1Items; + + ASSERT_TRUE(mDB.GetItemsInfos("service1", service1Items).IsNone()); + EXPECT_THAT(ToVector(service1Items), UnorderedElementsAre(item1, item2)); + + StaticArray service2Items; + + ASSERT_TRUE(mDB.GetItemsInfos("service2", service2Items).IsNone()); + EXPECT_THAT(ToVector(service2Items), UnorderedElementsAre(item3)); + + StaticArray nonExistentItems; + + ASSERT_TRUE(mDB.GetItemsInfos("nonexistent", nonExistentItems).IsNone()); + EXPECT_EQ(nonExistentItems.Size(), 0); +} + } // namespace aos::cm::database diff --git a/src/cm/iamclient/iamclient.cpp b/src/cm/iamclient/iamclient.cpp index 0cb01d5e0..b2db88901 100644 --- a/src/cm/iamclient/iamclient.cpp +++ b/src/cm/iamclient/iamclient.cpp @@ -19,24 +19,24 @@ Error IAMClient::Init(const std::string& iamProtectedServerURL, const std::strin const std::string& certStorage, aos::common::iamclient::TLSCredentialsItf& tlsCredentials, const String& certType, bool insecureConnection) { - LOG_INF() << "Initializing IAM client"; + LOG_DBG() << "Init IAM client"; - auto err = CertificateService::Init(iamProtectedServerURL, certStorage, tlsCredentials, insecureConnection); + auto err = PublicCertService::Init(iamPublicServerURL, tlsCredentials, insecureConnection); if (!err.IsNone()) { return err; } - err = NodesService::Init(iamProtectedServerURL, certStorage, tlsCredentials, insecureConnection); + err = CertificateService::Init(iamProtectedServerURL, certStorage, tlsCredentials, insecureConnection); if (!err.IsNone()) { return err; } - err = ProvisioningService::Init(iamProtectedServerURL, certStorage, tlsCredentials, insecureConnection); + err = NodesService::Init(iamProtectedServerURL, certStorage, tlsCredentials, insecureConnection); if (!err.IsNone()) { return err; } - err = PublicCertService::Init(iamPublicServerURL, tlsCredentials, insecureConnection); + err = ProvisioningService::Init(iamProtectedServerURL, certStorage, tlsCredentials, insecureConnection); if (!err.IsNone()) { return err; } @@ -51,6 +51,16 @@ Error IAMClient::Init(const std::string& iamProtectedServerURL, const std::strin return err; } + err = PublicCurrentNodeService::Init(iamPublicServerURL, tlsCredentials, insecureConnection); + if (!err.IsNone()) { + return err; + } + + err = PublicIdentityService::Init(iamPublicServerURL, tlsCredentials, insecureConnection); + if (!err.IsNone()) { + return err; + } + LOG_INF() << "IAM client initialized successfully"; return ErrorEnum::eNone; @@ -84,6 +94,16 @@ void IAMClient::OnCertChanged([[maybe_unused]] const CertInfo& info) if (!err.IsNone()) { LOG_ERR() << "Failed to reconnect public nodes service" << Log::Field(err); } + + err = PublicCurrentNodeService::Reconnect(); + if (!err.IsNone()) { + LOG_ERR() << "Failed to reconnect public current node service" << Log::Field(err); + } + + err = PublicIdentityService::Reconnect(); + if (!err.IsNone()) { + LOG_ERR() << "Failed to reconnect public identity service" << Log::Field(err); + } } } // namespace aos::cm::iamclient diff --git a/src/cm/iamclient/iamclient.hpp b/src/cm/iamclient/iamclient.hpp index fac46f285..01c8dd07b 100644 --- a/src/cm/iamclient/iamclient.hpp +++ b/src/cm/iamclient/iamclient.hpp @@ -11,6 +11,8 @@ #include #include #include +#include +#include #include #include @@ -26,6 +28,8 @@ class IAMClient : public aos::common::iamclient::CertificateService, public aos::common::iamclient::ProvisioningService, public aos::common::iamclient::PublicCertService, public aos::common::iamclient::PublicNodesService, + public aos::common::iamclient::PublicCurrentNodeService, + public aos::common::iamclient::PublicIdentityService, public aos::iamclient::CertListenerItf { public: /** diff --git a/src/cm/networkmanager/CMakeLists.txt b/src/cm/networkmanager/CMakeLists.txt index 1c9e03549..e5dc302e8 100644 --- a/src/cm/networkmanager/CMakeLists.txt +++ b/src/cm/networkmanager/CMakeLists.txt @@ -26,8 +26,14 @@ set(INCLUDES ${Libnl_INCLUDE_DIRS}) # Libraries # ###################################################################################################################### -set(LIBRARIES aos::core::common::tools aos::common::network aos::common::utils ${Libnl_LIBRARIES} Poco::Foundation - Poco::Util +set(LIBRARIES + aos::core::cm::networkmanager + aos::core::common::tools + aos::common::network + aos::common::utils + ${Libnl_LIBRARIES} + Poco::Foundation + Poco::Util ) # ###################################################################################################################### diff --git a/src/cm/networkmanager/ipsubnet.cpp b/src/cm/networkmanager/ipsubnet.cpp index 2fb7e9589..2f4e88aae 100644 --- a/src/cm/networkmanager/ipsubnet.cpp +++ b/src/cm/networkmanager/ipsubnet.cpp @@ -106,7 +106,7 @@ std::string IpSubnet::RequestIPNetPool(const std::string& networkID) std::string IpSubnet::FindUnusedIPSubnet() { - StaticArray routes; + std::vector routes; auto err = common::network::GetRouteList(routes); AOS_ERROR_CHECK_AND_THROW(err, "failed to get routes"); diff --git a/src/cm/networkmanager/itf/sender.hpp b/src/cm/networkmanager/itf/sender.hpp deleted file mode 100644 index 0fae2642d..000000000 --- a/src/cm/networkmanager/itf/sender.hpp +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) 2025 EPAM Systems, Inc. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef AOS_CM_NETWORKMANAGER_ITF_SENDER_HPP_ -#define AOS_CM_NETWORKMANAGER_ITF_SENDER_HPP_ - -#include - -#include - -namespace aos::cm::networkmanager { - -/** - * Sender interface. - */ -class SenderItf { -public: - /** - * Destructor. - */ - virtual ~SenderItf() = default; - - /** - * Sends network. - * - * @param nodeID Node ID. - * @param networkParameters Network parameters. - * @return Error. - */ - virtual Error SendNetwork(const std::string& nodeID, const std::vector& networkParameters) = 0; -}; - -} // namespace aos::cm::networkmanager - -#endif // AOS_CM_NETWORKMANAGER_ITF_SENDER_HPP_ diff --git a/src/cm/networkmanager/networkmanager.cpp b/src/cm/networkmanager/networkmanager.cpp index 2f914a59b..75cfd9ed2 100644 --- a/src/cm/networkmanager/networkmanager.cpp +++ b/src/cm/networkmanager/networkmanager.cpp @@ -29,19 +29,20 @@ constexpr int cExposedPortConfigExpectedLen = 2; * Public **********************************************************************************************************************/ -Error NetworkManager::Init(StorageItf& storage, crypto::RandomItf& random, SenderItf& sender, DNSServerItf& dnsServer) +Error NetworkManager::Init( + StorageItf& storage, crypto::RandomItf& random, NodeNetworkItf& nodeNetwork, DNSServerItf& dnsServer) { - mStorage = &storage; - mRandom = &random; - mSender = &sender; - mDNSServer = &dnsServer; + mStorage = &storage; + mRandom = &random; + mNodeNetwork = &nodeNetwork; + mDNSServer = &dnsServer; mIpSubnet.Init(); auto networks = std::make_unique>(); if (auto err = mStorage->GetNetworks(*networks); !err.IsNone()) { - return err; + return AOS_ERROR_WRAP(err); } for (const auto& network : *networks) { @@ -51,7 +52,7 @@ Error NetworkManager::Init(StorageItf& storage, crypto::RandomItf& random, Sende auto hosts = std::make_unique>(); if (auto err = mStorage->GetHosts(network.mNetworkID, *hosts); !err.IsNone()) { - return err; + return AOS_ERROR_WRAP(err); } for (const auto& host : *hosts) { @@ -61,7 +62,7 @@ Error NetworkManager::Init(StorageItf& storage, crypto::RandomItf& random, Sende auto instances = std::make_unique>(); if (auto err = mStorage->GetInstances(network.mNetworkID, host.mNodeID, *instances); !err.IsNone()) { - return err; + return AOS_ERROR_WRAP(err); } for (const auto& instance : *instances) { @@ -85,7 +86,7 @@ Error NetworkManager::GetInstances(Array& instances) const for (const auto& [__, hostInstances] : networkState.mHostInstances) { for (const auto& [instanceIdent, ___] : hostInstances.mInstances) { if (auto err = instances.PushBack(instanceIdent); !err.IsNone()) { - return err; + return AOS_ERROR_WRAP(err); } } } @@ -120,7 +121,7 @@ Error NetworkManager::RemoveInstanceNetworkParameters(const InstanceIdent& insta << Log::Field("instanceIdent", instanceIdent); } } catch (const std::exception& e) { - return common::utils::ToAosError(e); + return AOS_ERROR_WRAP(common::utils::ToAosError(e)); } LOG_WRN() << "Instance network parameters not found" << Log::Field("instanceIdent", instanceIdent); @@ -132,25 +133,25 @@ Error NetworkManager::UpdateProviderNetwork(const Array>& p { LOG_DBG() << "Updating provider network" << Log::Field("nodeID", nodeID); - std::vector networkParametersList; + StaticArray networkParametersList; try { RemoveProviderNetworks(providers, nodeID); for (const auto& provider : providers) { - std::unique_ptr networkParameters = std::make_unique(); + UpdateNetworkParameters networkParameters; - AddProviderNetwork(provider, nodeID, *networkParameters); + AddProviderNetwork(provider, nodeID, networkParameters); - networkParametersList.push_back(*networkParameters); + networkParametersList.PushBack(networkParameters); } } catch (const std::exception& e) { - return common::utils::ToAosError(e); + return AOS_ERROR_WRAP(common::utils::ToAosError(e)); } LOG_DBG() << "Updated provider network" << Log::Field("nodeID", nodeID); - return mSender->SendNetwork(nodeID.CStr(), networkParametersList); + return mNodeNetwork->UpdateNetworks(nodeID, networkParametersList); } Error NetworkManager::PrepareInstanceNetworkParameters(const InstanceIdent& instanceIdent, const String& networkID, @@ -224,7 +225,7 @@ Error NetworkManager::PrepareInstanceNetworkParameters(const InstanceIdent& inst } if (auto err = mStorage->AddInstance(instance); !err.IsNone()) { - return err; + return AOS_ERROR_WRAP(err); } LOG_DBG() << "Prepared instance network parameters" << Log::Field("networkID", networkID) @@ -232,7 +233,7 @@ Error NetworkManager::PrepareInstanceNetworkParameters(const InstanceIdent& inst << Log::Field("IP", result.mIP); } catch (const std::exception& e) { - return common::utils::ToAosError(e); + return AOS_ERROR_WRAP(common::utils::ToAosError(e)); } return ErrorEnum::eNone; @@ -241,7 +242,7 @@ Error NetworkManager::PrepareInstanceNetworkParameters(const InstanceIdent& inst Error NetworkManager::RestartDNSServer() { if (auto err = mDNSServer->UpdateHostsFile(mHosts); !err.IsNone()) { - return err; + return AOS_ERROR_WRAP(err); } mHosts.clear(); @@ -259,11 +260,11 @@ Error NetworkManager::ParseExposedPorts(const Array, cExposedPortConfigExpectedLen> portConfig; if (auto err = exposedPort.Split(portConfig, '/'); !err.IsNone()) { - return err; + return AOS_ERROR_WRAP(err); } if (portConfig.Size() == 0) { - return Error(ErrorEnum::eRuntime, "unsupported ExposedPorts format"); + return AOS_ERROR_WRAP(Error(ErrorEnum::eRuntime, "unsupported ExposedPorts format")); } ExposedPort exposedPortInfo; @@ -354,7 +355,7 @@ Error NetworkManager::PrepareFirewallRules(const std::string& subnet, const Stri result.mFirewallRules.PushBack(rule); } } catch (const std::exception& e) { - return Error(aos::ErrorEnum::eRuntime, e.what()); + return AOS_ERROR_WRAP(common::utils::ToAosError(e)); } return ErrorEnum::eNone; @@ -410,7 +411,7 @@ bool NetworkManager::IsHostExist(const std::string& hostName) const } void NetworkManager::AddProviderNetwork( - const String& networkID, const String& nodeID, NetworkParameters& networkParameters) + const String& networkID, const String& nodeID, UpdateNetworkParameters& networkParameters) { LOG_DBG() << "Adding provider network" << Log::Field("networkID", networkID) << Log::Field("nodeID", nodeID); @@ -454,7 +455,7 @@ void NetworkManager::AddProviderNetwork( } void NetworkManager::CreateProviderNetwork( - const String& networkID, const String& nodeID, NetworkParameters& networkParameters) + const String& networkID, const String& nodeID, UpdateNetworkParameters& networkParameters) { LOG_DBG() << "Creating provider network" << Log::Field("networkID", networkID) << Log::Field("nodeID", nodeID); diff --git a/src/cm/networkmanager/networkmanager.hpp b/src/cm/networkmanager/networkmanager.hpp index c1e1f8c57..08ad55df3 100644 --- a/src/cm/networkmanager/networkmanager.hpp +++ b/src/cm/networkmanager/networkmanager.hpp @@ -11,12 +11,12 @@ #include #include +#include #include #include #include "ipsubnet.hpp" #include "itf/dnsserver.hpp" -#include "itf/sender.hpp" #include "itf/storage.hpp" namespace aos::cm::networkmanager { @@ -33,11 +33,11 @@ class NetworkManager : public NetworkManagerItf { * * @param storage Storage interface. * @param random Random interface. - * @param sender Sender interface. + * @param nodeNetwork Node network interface. * @param dnsServer DNS server interface. * @return Error. */ - Error Init(StorageItf& storage, crypto::RandomItf& random, SenderItf& sender, DNSServerItf& dnsServer); + Error Init(StorageItf& storage, crypto::RandomItf& random, NodeNetworkItf& nodeNetwork, DNSServerItf& dnsServer); /** * Gets instances. @@ -91,13 +91,14 @@ class NetworkManager : public NetworkManagerItf { void RemoveExistedNetworks(); void RemoveProviderNetworks(const Array>& providers, const String& nodeID); - void AddProviderNetwork(const String& networkID, const String& nodeID, NetworkParameters& networkParameters); + void AddProviderNetwork(const String& networkID, const String& nodeID, UpdateNetworkParameters& networkParameters); void RemoveInstanceNetwork(const std::string& networkID, const std::string& IP, const InstanceIdent& instanceIdent); - void CreateProviderNetwork(const String& networkID, const String& nodeID, NetworkParameters& networkParameters); - bool ShouldRemoveNetwork(const NetworkState& networkState, const Array>& providers) const; - void CleanupHostFromNetwork(NetworkState& networkState, const String& nodeID); - bool IsNetworkEmpty(const NetworkState& networkState) const; - void CleanupEmptyNetwork(const NetworkState& networkState); + void CreateProviderNetwork( + const String& networkID, const String& nodeID, UpdateNetworkParameters& networkParameters); + bool ShouldRemoveNetwork(const NetworkState& networkState, const Array>& providers) const; + void CleanupHostFromNetwork(NetworkState& networkState, const String& nodeID); + bool IsNetworkEmpty(const NetworkState& networkState) const; + void CleanupEmptyNetwork(const NetworkState& networkState); uint64_t GenerateVlanID(); void PrepareInstanceIdentHosts( const InstanceIdent& instanceIdent, const String& networkID, std::vector& hosts) const; @@ -115,7 +116,7 @@ class NetworkManager : public NetworkManagerItf { StorageItf* mStorage {}; crypto::RandomItf* mRandom {}; - SenderItf* mSender {}; + NodeNetworkItf* mNodeNetwork {}; DNSServerItf* mDNSServer {}; IpSubnet mIpSubnet; diff --git a/src/cm/networkmanager/tests/mocks/dnsservermock.hpp b/src/cm/networkmanager/tests/mocks/dnsservermock.hpp index b1b8eea24..7698fd713 100644 --- a/src/cm/networkmanager/tests/mocks/dnsservermock.hpp +++ b/src/cm/networkmanager/tests/mocks/dnsservermock.hpp @@ -11,7 +11,7 @@ #include -namespace aos::cm::networkmanager::tests { +namespace aos::cm::networkmanager { class MockDNSServer : public DNSServerItf { public: @@ -20,6 +20,6 @@ class MockDNSServer : public DNSServerItf { MOCK_METHOD(std::string, GetIP, (), (const, override)); }; -} // namespace aos::cm::networkmanager::tests +} // namespace aos::cm::networkmanager #endif // AOS_CM_NETWORKMANAGER_TESTS_MOCKS_DNSSERVERMOCK_HPP_ diff --git a/src/cm/networkmanager/tests/mocks/nodenetworkmock.hpp b/src/cm/networkmanager/tests/mocks/nodenetworkmock.hpp new file mode 100644 index 000000000..6477fe78e --- /dev/null +++ b/src/cm/networkmanager/tests/mocks/nodenetworkmock.hpp @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2025 EPAM Systems, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef AOS_CM_NETWORKMANAGER_TESTS_MOCKS_NODENETWORKMOCK_HPP_ +#define AOS_CM_NETWORKMANAGER_TESTS_MOCKS_NODENETWORKMOCK_HPP_ + +#include + +#include + +namespace aos::cm::networkmanager { + +class MockNodeNetwork : public NodeNetworkItf { +public: + MOCK_METHOD(Error, UpdateNetworks, (const String& nodeID, const Array& networkParameters), + (override)); +}; + +} // namespace aos::cm::networkmanager + +#endif diff --git a/src/cm/networkmanager/tests/mocks/sendermock.hpp b/src/cm/networkmanager/tests/mocks/sendermock.hpp deleted file mode 100644 index 4874f27cc..000000000 --- a/src/cm/networkmanager/tests/mocks/sendermock.hpp +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (C) 2025 EPAM Systems, Inc. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef AOS_CM_NETWORKMANAGER_TESTS_MOCKS_SENDERMOCK_HPP_ -#define AOS_CM_NETWORKMANAGER_TESTS_MOCKS_SENDERMOCK_HPP_ - -#include - -#include - -namespace aos::cm::networkmanager::tests { - -class MockSender : public SenderItf { -public: - MOCK_METHOD(Error, SendNetwork, - (const std::string& nodeID, const std::vector& networkParameters), (override)); -}; - -} // namespace aos::cm::networkmanager::tests - -#endif diff --git a/src/cm/networkmanager/tests/mocks/storagemock.hpp b/src/cm/networkmanager/tests/mocks/storagemock.hpp index 0ede9f6b3..cc32f7e28 100644 --- a/src/cm/networkmanager/tests/mocks/storagemock.hpp +++ b/src/cm/networkmanager/tests/mocks/storagemock.hpp @@ -11,7 +11,7 @@ #include -namespace aos::cm::networkmanager::tests { +namespace aos::cm::networkmanager { class MockStorage : public StorageItf { public: @@ -27,6 +27,6 @@ class MockStorage : public StorageItf { MOCK_METHOD(Error, RemoveNetworkInstance, (const InstanceIdent& instanceIdent), (override)); }; -} // namespace aos::cm::networkmanager::tests +} // namespace aos::cm::networkmanager #endif diff --git a/src/cm/networkmanager/tests/networkmanager.cpp b/src/cm/networkmanager/tests/networkmanager.cpp index 3a38211fa..38a024335 100644 --- a/src/cm/networkmanager/tests/networkmanager.cpp +++ b/src/cm/networkmanager/tests/networkmanager.cpp @@ -4,19 +4,22 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include + #include +#include + #include #include #include #include #include -#include #include "mocks/dnsservermock.hpp" +#include "mocks/nodenetworkmock.hpp" #include "mocks/randommock.hpp" -#include "mocks/sendermock.hpp" #include "mocks/storagemock.hpp" using namespace testing; @@ -25,7 +28,7 @@ using namespace testing; * Suite **********************************************************************************************************************/ -namespace aos::cm::networkmanager::tests { +namespace aos::cm::networkmanager { class CMNetworkManagerTest : public Test { public: @@ -36,7 +39,7 @@ class CMNetworkManagerTest : public Test { mNetworkManager = std::make_unique(); mStorage = std::make_unique>(); mRandom = std::make_unique>(); - mSender = std::make_unique>(); + mNodeNetwork = std::make_unique>(); mDNSServer = std::make_unique>(); } @@ -46,7 +49,7 @@ class CMNetworkManagerTest : public Test { std::unique_ptr mNetworkManager; std::unique_ptr> mStorage; std::unique_ptr> mRandom; - std::unique_ptr> mSender; + std::unique_ptr> mNodeNetwork; std::unique_ptr> mDNSServer; }; @@ -62,7 +65,7 @@ TEST_F(CMNetworkManagerTest, UpdateProviderNetwork_Success) String nodeID = "node1"; - std::vector capturedNetworkParams; + StaticArray capturedNetworkParams; EXPECT_CALL(*mStorage, GetNetworks(_)).WillOnce(Return(ErrorEnum::eNone)); EXPECT_CALL(*mStorage, GetHosts(_, _)).WillRepeatedly(Return(ErrorEnum::eNone)); @@ -76,17 +79,22 @@ TEST_F(CMNetworkManagerTest, UpdateProviderNetwork_Success) EXPECT_CALL(*mStorage, AddHost(_, _)).WillOnce(Return(ErrorEnum::eNone)).WillOnce(Return(ErrorEnum::eNone)); - EXPECT_CALL(*mSender, SendNetwork(_, _)) - .WillOnce(DoAll(SaveArg<1>(&capturedNetworkParams), Return(ErrorEnum::eNone))); + EXPECT_CALL(*mNodeNetwork, UpdateNetworks(_, _)) + .WillOnce(Invoke([&](const String&, const Array& params) -> Error { + for (const auto& p : params) { + capturedNetworkParams.PushBack(p); + } + return ErrorEnum::eNone; + })); - auto err = mNetworkManager->Init(*mStorage, *mRandom, *mSender, *mDNSServer); + auto err = mNetworkManager->Init(*mStorage, *mRandom, *mNodeNetwork, *mDNSServer); ASSERT_TRUE(err.IsNone()); err = mNetworkManager->UpdateProviderNetwork(providers, nodeID); EXPECT_TRUE(err.IsNone()); - EXPECT_EQ(capturedNetworkParams.size(), 2); + EXPECT_EQ(capturedNetworkParams.Size(), 2); for (const auto& networkParams : capturedNetworkParams) { EXPECT_FALSE(networkParams.mSubnet.IsEmpty()); @@ -104,11 +112,11 @@ TEST_F(CMNetworkManagerTest, UpdateProviderNetwork_Success) EXPECT_CALL(*mStorage, RemoveHost(String("provider1"), nodeID)).WillOnce(Return(ErrorEnum::eNone)); EXPECT_CALL(*mStorage, RemoveNetwork(String("provider1"))).WillOnce(Return(ErrorEnum::eNone)); - EXPECT_CALL(*mSender, SendNetwork(_, _)) - .WillOnce(Invoke([&](const std::string&, const std::vector& params) -> Error { - EXPECT_EQ(params.size(), 1); + EXPECT_CALL(*mNodeNetwork, UpdateNetworks(_, _)) + .WillOnce(Invoke([&](const String&, const Array& params) -> Error { + EXPECT_EQ(params.Size(), 1); auto it = std::find_if(capturedNetworkParams.begin(), capturedNetworkParams.end(), - [](const NetworkParameters& np) { return np.mNetworkID == "provider2"; }); + [](const UpdateNetworkParameters& np) { return np.mNetworkID == "provider2"; }); EXPECT_NE(it, capturedNetworkParams.end()); EXPECT_EQ(params[0].mSubnet, it->mSubnet); EXPECT_EQ(params[0].mIP, it->mIP); @@ -125,9 +133,9 @@ TEST_F(CMNetworkManagerTest, UpdateProviderNetwork_Success) EXPECT_CALL(*mStorage, RemoveHost(String("provider2"), nodeID)).WillOnce(Return(ErrorEnum::eNone)); EXPECT_CALL(*mStorage, RemoveNetwork(String("provider2"))).WillOnce(Return(ErrorEnum::eNone)); - EXPECT_CALL(*mSender, SendNetwork(_, _)) - .WillOnce(Invoke([&](const std::string&, const std::vector& params) -> Error { - EXPECT_EQ(params.size(), 0); + EXPECT_CALL(*mNodeNetwork, UpdateNetworks(_, _)) + .WillOnce(Invoke([&](const String&, const Array& params) -> Error { + EXPECT_EQ(params.Size(), 0); return ErrorEnum::eNone; })); @@ -150,7 +158,7 @@ TEST_F(CMNetworkManagerTest, UpdateProviderNetwork_StorageError) EXPECT_CALL(*mStorage, AddNetwork(_)).WillOnce(Return(Error(ErrorEnum::eRuntime, "Storage error"))); - auto err = mNetworkManager->Init(*mStorage, *mRandom, *mSender, *mDNSServer); + auto err = mNetworkManager->Init(*mStorage, *mRandom, *mNodeNetwork, *mDNSServer); ASSERT_TRUE(err.IsNone()); err = mNetworkManager->UpdateProviderNetwork(providers, nodeID); @@ -171,7 +179,7 @@ TEST_F(CMNetworkManagerTest, UpdateProviderNetwork_RandomError) EXPECT_CALL(*mRandom, RandInt(_)) .WillOnce(Return(RetWithError(0u, Error(ErrorEnum::eRuntime, "Random error")))); - auto err = mNetworkManager->Init(*mStorage, *mRandom, *mSender, *mDNSServer); + auto err = mNetworkManager->Init(*mStorage, *mRandom, *mNodeNetwork, *mDNSServer); ASSERT_TRUE(err.IsNone()); err = mNetworkManager->UpdateProviderNetwork(providers, nodeID); @@ -195,9 +203,9 @@ TEST_F(CMNetworkManagerTest, UpdateProviderNetwork_SenderError) EXPECT_CALL(*mStorage, AddHost(_, _)).WillOnce(Return(ErrorEnum::eNone)); - EXPECT_CALL(*mSender, SendNetwork(_, _)).WillOnce(Return(Error(ErrorEnum::eRuntime, "Sender error"))); + EXPECT_CALL(*mNodeNetwork, UpdateNetworks(_, _)).WillOnce(Return(Error(ErrorEnum::eRuntime, "Sender error"))); - auto err = mNetworkManager->Init(*mStorage, *mRandom, *mSender, *mDNSServer); + auto err = mNetworkManager->Init(*mStorage, *mRandom, *mNodeNetwork, *mDNSServer); ASSERT_TRUE(err.IsNone()); err = mNetworkManager->UpdateProviderNetwork(providers, nodeID); @@ -232,9 +240,9 @@ TEST_F(CMNetworkManagerTest, UpdateProviderNetwork_ExistingNetwork) EXPECT_CALL(*mStorage, GetInstances(String("existing_provider"), String("node1"), _)) .WillOnce(Return(ErrorEnum::eNone)); - EXPECT_CALL(*mSender, SendNetwork(_, _)) - .WillOnce(Invoke([&](const std::string&, const std::vector& params) -> Error { - EXPECT_EQ(params.size(), 1); + EXPECT_CALL(*mNodeNetwork, UpdateNetworks(_, _)) + .WillOnce(Invoke([&](const String&, const Array& params) -> Error { + EXPECT_EQ(params.Size(), 1); EXPECT_EQ(params[0].mNetworkID, "existing_provider"); EXPECT_EQ(params[0].mSubnet, "172.17.0.0/16"); EXPECT_EQ(params[0].mIP, "172.17.0.1"); @@ -242,7 +250,7 @@ TEST_F(CMNetworkManagerTest, UpdateProviderNetwork_ExistingNetwork) return ErrorEnum::eNone; })); - auto err = mNetworkManager->Init(*mStorage, *mRandom, *mSender, *mDNSServer); + auto err = mNetworkManager->Init(*mStorage, *mRandom, *mNodeNetwork, *mDNSServer); ASSERT_TRUE(err.IsNone()); err = mNetworkManager->UpdateProviderNetwork(providers, nodeID); @@ -287,7 +295,7 @@ TEST_F(CMNetworkManagerTest, PrepareInstanceNetworkParameters_NewInstance_Succes EXPECT_CALL(*mDNSServer, GetIP()).WillOnce(Return("8.8.8.8")).WillOnce(Return("1.1.1.1")); - auto err = mNetworkManager->Init(*mStorage, *mRandom, *mSender, *mDNSServer); + auto err = mNetworkManager->Init(*mStorage, *mRandom, *mNodeNetwork, *mDNSServer); ASSERT_TRUE(err.IsNone()); err = mNetworkManager->PrepareInstanceNetworkParameters(instanceIdent, networkID, nodeID, instanceData, result1); @@ -357,7 +365,7 @@ TEST_F(CMNetworkManagerTest, PrepareInstanceNetworkParameters_ExistingInstance_S return ErrorEnum::eNone; })); - auto err = mNetworkManager->Init(*mStorage, *mRandom, *mSender, *mDNSServer); + auto err = mNetworkManager->Init(*mStorage, *mRandom, *mNodeNetwork, *mDNSServer); ASSERT_TRUE(err.IsNone()); err = mNetworkManager->PrepareInstanceNetworkParameters(instanceIdent, networkID, nodeID, instanceData, result); @@ -385,7 +393,7 @@ TEST_F(CMNetworkManagerTest, PrepareInstanceNetworkParameters_NetworkNotFound_Er EXPECT_CALL(*mStorage, GetHosts(_, _)).WillRepeatedly(Return(ErrorEnum::eNone)); EXPECT_CALL(*mStorage, GetInstances(_, _, _)).WillRepeatedly(Return(ErrorEnum::eNone)); - auto err = mNetworkManager->Init(*mStorage, *mRandom, *mSender, *mDNSServer); + auto err = mNetworkManager->Init(*mStorage, *mRandom, *mNodeNetwork, *mDNSServer); ASSERT_TRUE(err.IsNone()); err = mNetworkManager->PrepareInstanceNetworkParameters(instanceIdent, networkID, nodeID, instanceData, result); @@ -425,7 +433,7 @@ TEST_F(CMNetworkManagerTest, PrepareInstanceNetworkParameters_NodeNotFound_Error EXPECT_CALL(*mStorage, GetInstances(String("network1"), String("node1"), _)).WillOnce(Return(ErrorEnum::eNone)); - auto err = mNetworkManager->Init(*mStorage, *mRandom, *mSender, *mDNSServer); + auto err = mNetworkManager->Init(*mStorage, *mRandom, *mNodeNetwork, *mDNSServer); ASSERT_TRUE(err.IsNone()); err = mNetworkManager->PrepareInstanceNetworkParameters(instanceIdent, networkID, nodeID, instanceData, result); @@ -472,7 +480,7 @@ TEST_F(CMNetworkManagerTest, RemoveInstanceNetworkParameters_Success) EXPECT_CALL(*mStorage, RemoveNetworkInstance(instanceIdent)).WillOnce(Return(ErrorEnum::eNone)); - auto err = mNetworkManager->Init(*mStorage, *mRandom, *mSender, *mDNSServer); + auto err = mNetworkManager->Init(*mStorage, *mRandom, *mNodeNetwork, *mDNSServer); ASSERT_TRUE(err.IsNone()); err = mNetworkManager->RemoveInstanceNetworkParameters(instanceIdent, nodeID); @@ -544,7 +552,7 @@ TEST_F(CMNetworkManagerTest, GetInstances_Success) return ErrorEnum::eNone; })); - auto err = mNetworkManager->Init(*mStorage, *mRandom, *mSender, *mDNSServer); + auto err = mNetworkManager->Init(*mStorage, *mRandom, *mNodeNetwork, *mDNSServer); ASSERT_TRUE(err.IsNone()); StaticArray instances; @@ -618,7 +626,7 @@ TEST_F(CMNetworkManagerTest, RestartDNSServer_Success) EXPECT_CALL(*mDNSServer, GetIP()).WillOnce(Return("8.8.8.8")).WillOnce(Return("1.1.1.1")); - auto err = mNetworkManager->Init(*mStorage, *mRandom, *mSender, *mDNSServer); + auto err = mNetworkManager->Init(*mStorage, *mRandom, *mNodeNetwork, *mDNSServer); ASSERT_TRUE(err.IsNone()); err = mNetworkManager->PrepareInstanceNetworkParameters(instanceIdent1, networkID, nodeID, instanceData1, result1); @@ -718,7 +726,7 @@ TEST_F(CMNetworkManagerTest, PrepareInstanceNetworkParameters_CrossNetworkFirewa EXPECT_CALL(*mDNSServer, GetIP()).WillOnce(Return("8.8.8.8")).WillOnce(Return("1.1.1.1")); - auto err = mNetworkManager->Init(*mStorage, *mRandom, *mSender, *mDNSServer); + auto err = mNetworkManager->Init(*mStorage, *mRandom, *mNodeNetwork, *mDNSServer); ASSERT_TRUE(err.IsNone()); err = mNetworkManager->PrepareInstanceNetworkParameters(instanceIdent1, networkID1, nodeID, instanceData1, result1); @@ -757,4 +765,4 @@ TEST_F(CMNetworkManagerTest, PrepareInstanceNetworkParameters_CrossNetworkFirewa } } -} // namespace aos::cm::networkmanager::tests +} // namespace aos::cm::networkmanager diff --git a/src/cm/smcontroller/smcontroller.cpp b/src/cm/smcontroller/smcontroller.cpp index 999c4f28b..4ae7afb16 100644 --- a/src/cm/smcontroller/smcontroller.cpp +++ b/src/cm/smcontroller/smcontroller.cpp @@ -9,7 +9,8 @@ #include #include -#include +#include + #include #include #include @@ -29,7 +30,7 @@ Error SMController::Init(const Config& config, cloudconnection::CloudConnectionI monitoring::ReceiverItf& monitoringReceiver, launcher::InstanceStatusReceiverItf& instanceStatusReceiver, nodeinfoprovider::SMInfoReceiverItf& smInfoReceiver, bool insecureConn) { - LOG_INF() << "Initialize SM Controller"; + LOG_DBG() << "Init SM controller"; mConfig = config; mCloudConnection = &cloudConnection; @@ -45,10 +46,6 @@ Error SMController::Init(const Config& config, cloudconnection::CloudConnectionI mSMInfoReceiver = &smInfoReceiver; mInsecureConn = insecureConn; - if (auto err = CreateServerCredentials(); !err.IsNone()) { - return AOS_ERROR_WRAP(err); - } - return ErrorEnum::eNone; } @@ -56,6 +53,10 @@ Error SMController::Start() { LOG_INF() << "Start SM Controller"; + if (auto err = CreateServerCredentials(); !err.IsNone()) { + return AOS_ERROR_WRAP(err); + } + if (auto err = StartServer(); !err.IsNone()) { return AOS_ERROR_WRAP(err); } @@ -148,7 +149,7 @@ Error SMController::GetNodeConfigStatus(const String& nodeID, NodeConfigStatus& Error SMController::RequestLog(const aos::RequestLog& log) { - LOG_DBG() << "Requesting log" << Log::Field("correlationID", log.mCorrelationID); + LOG_DBG() << "Requesting log" << Log::Field("correlationId", log.mCorrelationID); for (const auto& nodeID : log.mFilter.mNodes) { SMHandler* handler = FindNode(nodeID); @@ -427,6 +428,8 @@ Error SMController::StartServer() return AOS_ERROR_WRAP(Error(ErrorEnum::eFailed, "failed to start CM server")); } + LOG_INF() << "CM server started on: " << correctedAddress.c_str(); + return ErrorEnum::eNone; } diff --git a/src/cm/smcontroller/smcontroller.hpp b/src/cm/smcontroller/smcontroller.hpp index 9fa1ef71d..4fdea4c2f 100644 --- a/src/cm/smcontroller/smcontroller.hpp +++ b/src/cm/smcontroller/smcontroller.hpp @@ -38,7 +38,7 @@ namespace aos::cm::smcontroller { class SMController : public SMControllerItf, private cloudconnection::ConnectionListenerItf, private NodeConnectionStatusListenerItf, - private iamclient::CertListenerItf, + private aos::iamclient::CertListenerItf, private servicemanager::v5::SMService::Service { public: /** @@ -60,7 +60,7 @@ class SMController : public SMControllerItf, * @return Error. */ Error Init(const Config& config, cloudconnection::CloudConnectionItf& cloudConnection, - iamclient::CertProviderItf& certProvider, crypto::CertLoaderItf& certLoader, + aos::iamclient::CertProviderItf& certProvider, crypto::CertLoaderItf& certLoader, crypto::x509::ProviderItf& cryptoProvider, imagemanager::BlobInfoProviderItf& blobInfoProvider, alerts::ReceiverItf& alertsReceiver, SenderItf& logSender, launcher::SenderItf& envVarsStatusSender, monitoring::ReceiverItf& monitoringReceiver, launcher::InstanceStatusReceiverItf& instanceStatusReceiver, @@ -201,7 +201,7 @@ class SMController : public SMControllerItf, cloudconnection::CloudConnectionItf* mCloudConnection {}; crypto::CertLoaderItf* mCertLoader {}; crypto::x509::ProviderItf* mCryptoProvider {}; - iamclient::CertProviderItf* mCertProvider {}; + aos::iamclient::CertProviderItf* mCertProvider {}; imagemanager::BlobInfoProviderItf* mBlobInfoProvider {}; alerts::ReceiverItf* mAlertsReceiver {}; SenderItf* mLogSender {}; diff --git a/src/cm/smcontroller/smhandler.cpp b/src/cm/smcontroller/smhandler.cpp index fd26beb3a..53366dbe2 100644 --- a/src/cm/smcontroller/smhandler.cpp +++ b/src/cm/smcontroller/smhandler.cpp @@ -6,7 +6,8 @@ #include -#include +#include + #include #include @@ -146,7 +147,7 @@ Error SMHandler::UpdateNodeConfig(const NodeConfig& config) Error SMHandler::RequestLog(const aos::RequestLog& log) { - LOG_DBG() << "Request log" << Log::Field("correlationID", log.mCorrelationID) << Log::Field("nodeID", GetNodeID()); + LOG_DBG() << "Request log" << Log::Field("correlationId", log.mCorrelationID) << Log::Field("nodeID", GetNodeID()); servicemanager::v5::SMIncomingMessages inMsg; servicemanager::v5::SMOutgoingMessages outMsg; @@ -332,7 +333,7 @@ Error SMHandler::ProcessNodeInstancesStatus(const servicemanager::v5::NodeInstan Error SMHandler::ProcessLogData(const servicemanager::v5::LogData& logData) { LOG_DBG() << "Process log data" << Log::Field("nodeID", GetNodeID()) - << Log::Field("correlationID", logData.correlation_id().c_str()) << Log::Field("part", logData.part()) + << Log::Field("correlationId", logData.correlation_id().c_str()) << Log::Field("part", logData.part()) << Log::Field("partCount", logData.part_count()); auto pushLog = std::make_unique(); diff --git a/src/cm/smcontroller/tests/stubs/instancestatusreceiverstub.hpp b/src/cm/smcontroller/tests/stubs/instancestatusreceiverstub.hpp index c8ee584ae..a8ad4430f 100644 --- a/src/cm/smcontroller/tests/stubs/instancestatusreceiverstub.hpp +++ b/src/cm/smcontroller/tests/stubs/instancestatusreceiverstub.hpp @@ -50,14 +50,6 @@ class InstanceStatusReceiverStub : public InstanceStatusReceiverItf { return ErrorEnum::eNone; } - Error OnEnvVarsStatusesReceived(const String& nodeID, const Array& statuses) override - { - (void)nodeID; - (void)statuses; - - return ErrorEnum::eNone; - } - Error WaitInstanceStatus(const String& nodeID, const InstanceIdent& instanceIdent) { std::unique_lock lock {mMutex}; diff --git a/src/cm/smcontroller/tests/stubs/smcontrollersenderstub.hpp b/src/cm/smcontroller/tests/stubs/smcontrollersenderstub.hpp index 8244009d8..556df2467 100644 --- a/src/cm/smcontroller/tests/stubs/smcontrollersenderstub.hpp +++ b/src/cm/smcontroller/tests/stubs/smcontrollersenderstub.hpp @@ -32,13 +32,13 @@ class SenderStub : public SenderItf { return ErrorEnum::eNone; } - Error WaitLog(const String& correlationID, uint64_t part) + Error WaitLog(const String& correlationId, uint64_t part) { std::unique_lock lock {mMutex}; - auto hasLog = [this, &correlationID, part]() { - auto it = std::find_if(mLogs.begin(), mLogs.end(), [&correlationID, part](const PushLog& log) { - return log.mCorrelationID == correlationID && log.mPart == part; + auto hasLog = [this, &correlationId, part]() { + auto it = std::find_if(mLogs.begin(), mLogs.end(), [&correlationId, part](const PushLog& log) { + return log.mCorrelationID == correlationId && log.mPart == part; }); return it != mLogs.end(); @@ -53,12 +53,12 @@ class SenderStub : public SenderItf { return ErrorEnum::eNone; } - bool HasLog(const String& correlationID, uint64_t part) const + bool HasLog(const String& correlationId, uint64_t part) const { std::lock_guard lock {mMutex}; - auto it = std::find_if(mLogs.begin(), mLogs.end(), [&correlationID, part](const PushLog& log) { - return log.mCorrelationID == correlationID && log.mPart == part; + auto it = std::find_if(mLogs.begin(), mLogs.end(), [&correlationId, part](const PushLog& log) { + return log.mCorrelationID == correlationId && log.mPart == part; }); return it != mLogs.end(); diff --git a/src/sm/runner/CMakeLists.txt b/src/cm/unitconfig/CMakeLists.txt similarity index 88% rename from src/sm/runner/CMakeLists.txt rename to src/cm/unitconfig/CMakeLists.txt index 29c0a7aa0..56da42d4e 100644 --- a/src/sm/runner/CMakeLists.txt +++ b/src/cm/unitconfig/CMakeLists.txt @@ -1,22 +1,22 @@ # -# Copyright (C) 2024 EPAM Systems, Inc. +# Copyright (C) 2025 EPAM Systems, Inc. # # SPDX-License-Identifier: Apache-2.0 # -set(TARGET_NAME runner) +set(TARGET_NAME unitconfig) # ###################################################################################################################### # Sources # ###################################################################################################################### -set(SOURCES runner.cpp) +set(SOURCES jsonprovider.cpp) # ###################################################################################################################### # Libraries # ###################################################################################################################### -set(LIBRARIES aos::common::utils aos::sm::utils Poco::JSON) +set(LIBRARIES aos::common::jsonprovider aos::common::utils Poco::JSON) # ###################################################################################################################### # Target diff --git a/src/cm/unitconfig/jsonprovider.cpp b/src/cm/unitconfig/jsonprovider.cpp new file mode 100644 index 000000000..2266a9342 --- /dev/null +++ b/src/cm/unitconfig/jsonprovider.cpp @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2025 EPAM Systems, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include +#include +#include + +#include "jsonprovider.hpp" + +namespace aos::cm::unitconfig { + +/*********************************************************************************************************************** + * Public + **********************************************************************************************************************/ + +Error JSONProvider::UnitConfigFromJSON(const String& json, aos::UnitConfig& unitConfig) const +{ + try { + Poco::JSON::Parser parser; + auto result = parser.parse(json.CStr()); + common::utils::CaseInsensitiveObjectWrapper object(result.extract()); + + auto err = unitConfig.mVersion.Assign(object.GetValue("version").c_str()); + AOS_ERROR_CHECK_AND_THROW(err, "parsed version length exceeds application limit"); + + err = unitConfig.mFormatVersion.Assign(object.GetValue("formatVersion").c_str()); + AOS_ERROR_CHECK_AND_THROW(err, "parsed format version length exceeds application limit"); + + if (object.Has("nodes")) { + common::utils::ForEach(object, "nodes", [&unitConfig](const Poco::Dynamic::Var& value) { + common::utils::CaseInsensitiveObjectWrapper nodeObject(value); + + NodeConfig nodeConfig = {}; + + auto err = common::jsonprovider::NodeConfigFromJSONObject(nodeObject, nodeConfig); + AOS_ERROR_CHECK_AND_THROW(err, "node config parsing error"); + + err = unitConfig.mNodes.PushBack(nodeConfig); + AOS_ERROR_CHECK_AND_THROW(err, "parsed nodes count exceeds application limit"); + }); + } + } catch (const std::exception& e) { + return AOS_ERROR_WRAP(common::utils::ToAosError(e)); + } + + return ErrorEnum::eNone; +} + +Error JSONProvider::UnitConfigToJSON(const aos::UnitConfig& unitConfig, String& json) const +{ + try { + auto object = Poco::makeShared(Poco::JSON_PRESERVE_KEY_ORDER); + + object->set("version", unitConfig.mVersion.CStr()); + object->set("formatVersion", unitConfig.mFormatVersion.CStr()); + object->set( + "nodes", common::utils::ToJsonArray(unitConfig.mNodes, common::jsonprovider::NodeConfigToJSONObject)); + + json = common::utils::Stringify(object).c_str(); + } catch (const std::exception& e) { + return AOS_ERROR_WRAP(common::utils::ToAosError(e)); + } + + return ErrorEnum::eNone; +} + +} // namespace aos::cm::unitconfig diff --git a/src/cm/unitconfig/jsonprovider.hpp b/src/cm/unitconfig/jsonprovider.hpp new file mode 100644 index 000000000..b771fe556 --- /dev/null +++ b/src/cm/unitconfig/jsonprovider.hpp @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2025 EPAM Systems, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef AOS_CM_UNITCONFIG_JSONPROVIDER_HPP_ +#define AOS_CM_UNITCONFIG_JSONPROVIDER_HPP_ + +#include + +namespace aos::cm::unitconfig { + +/** + * JSON provider for UnitConfig. + */ +class JSONProvider : public unitconfig::JSONProviderItf { +public: + /** + * Creates unit config object from a JSON string. + * + * @param json JSON string. + * @param[out] unitConfig unit config object. + * @return Error. + */ + Error UnitConfigFromJSON(const String& json, aos::UnitConfig& unitConfig) const override; + + /** + * Creates unit config JSON string from a unit config object. + * + * @param unitConfig unit config object. + * @param[out] json JSON string. + * @return Error. + */ + Error UnitConfigToJSON(const aos::UnitConfig& unitConfig, String& json) const override; +}; + +} // namespace aos::cm::unitconfig + +#endif diff --git a/src/cm/unitconfig/tests/CMakeLists.txt b/src/cm/unitconfig/tests/CMakeLists.txt new file mode 100644 index 000000000..816438554 --- /dev/null +++ b/src/cm/unitconfig/tests/CMakeLists.txt @@ -0,0 +1,33 @@ +# +# Copyright (C) 2025 EPAM Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +set(TARGET_NAME unitconfig_test) + +# ###################################################################################################################### +# Sources +# ###################################################################################################################### + +set(SOURCES jsonprovider.cpp) + +# ###################################################################################################################### +# Libraries +# ###################################################################################################################### + +set(LIBRARIES aos::cm::unitconfig GTest::gmock_main) + +# ###################################################################################################################### +# Target +# ###################################################################################################################### + +add_test( + TARGET_NAME + ${TARGET_NAME} + LOG_MODULE + SOURCES + ${SOURCES} + LIBRARIES + ${LIBRARIES} +) diff --git a/src/cm/unitconfig/tests/jsonprovider.cpp b/src/cm/unitconfig/tests/jsonprovider.cpp new file mode 100644 index 000000000..f0127dd9e --- /dev/null +++ b/src/cm/unitconfig/tests/jsonprovider.cpp @@ -0,0 +1,300 @@ +/* + * Copyright (C) 2025 EPAM Systems, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include + +#include + +#include + +using namespace testing; + +namespace aos::cm::unitconfig { + +namespace { + +/*********************************************************************************************************************** + * Consts + **********************************************************************************************************************/ + +constexpr auto cTestUnitConfigJSON = R"({ + "version": "2.0.0", + "formatVersion": "7", + "nodes": [ + { + "nodeId": "node-1", + "nodeType": "mainType", + "version": "1.0.0", + "alertRules": { + "ram": { + "minTimeout": "PT1S", + "minThreshold": 0.1, + "maxThreshold": 0.2 + }, + "cpu": { + "minTimeout": "PT2S", + "minThreshold": 0.3, + "maxThreshold": 0.4 + }, + "partitions": [ + { + "name": "partition1", + "minTimeout": "PT3S", + "minThreshold": 0.5, + "maxThreshold": 0.6 + } + ], + "download": { + "minTimeout": "PT5S", + "minThreshold": 100, + "maxThreshold": 200 + }, + "upload": { + "minTimeout": "PT6S", + "minThreshold": 300, + "maxThreshold": 400 + } + }, + "resourceRatios": { + "cpu": 50, + "ram": 51, + "storage": 52, + "state": 53 + }, + "labels": [ + "mainNode" + ], + "priority": 1 + }, + { + "nodeId": "node-2", + "nodeType": "secondaryType", + "version": "1.0.0", + "labels": [ + "secondaryNode" + ], + "priority": 2 + } + ] +})"; + +constexpr auto cTestUnitConfigEmptyNodesJSON = R"({ + "version": "1.0.0", + "formatVersion": "7", + "nodes": [] +})"; + +constexpr auto cTestUnitConfigMinimalJSON = R"({ + "version": "1.0.0", + "formatVersion": "7", + "nodes": [ + { + "nodeId": "node-1", + "nodeType": "type1", + "version": "1.0.0", + "priority": 0 + } + ] +})"; + +/*********************************************************************************************************************** + * Static + **********************************************************************************************************************/ + +AlertRules CreateAlerts() +{ + AlertRules alerts; + + alerts.mRAM.SetValue(AlertRulePercents {aos::Time::cSeconds, 0.1, 0.2}); + alerts.mCPU.SetValue(AlertRulePercents {2 * aos::Time::cSeconds, 0.3, 0.4}); + alerts.mPartitions.EmplaceBack(PartitionAlertRule {3 * aos::Time::cSeconds, 0.5, 0.6, "partition1"}); + alerts.mDownload.SetValue(AlertRulePoints {5 * aos::Time::cSeconds, 100, 200}); + alerts.mUpload.SetValue(AlertRulePoints {6 * aos::Time::cSeconds, 300, 400}); + + return alerts; +} + +aos::ResourceRatios CreateResourceRatios() +{ + aos::ResourceRatios ratios; + + ratios.mCPU.SetValue(50); + ratios.mRAM.SetValue(51); + ratios.mStorage.SetValue(52); + ratios.mState.SetValue(53); + + return ratios; +} + +UnitConfig CreateUnitConfig() +{ + UnitConfig unitConfig; + + unitConfig.mVersion = "2.0.0"; + unitConfig.mFormatVersion = "7"; + + NodeConfig node1; + node1.mNodeID = "node-1"; + node1.mNodeType = "mainType"; + node1.mVersion = "1.0.0"; + node1.mAlertRules.SetValue(CreateAlerts()); + node1.mResourceRatios.SetValue(CreateResourceRatios()); + node1.mLabels.PushBack("mainNode"); + node1.mPriority = 1; + unitConfig.mNodes.PushBack(node1); + + NodeConfig node2; + node2.mNodeID = "node-2"; + node2.mNodeType = "secondaryType"; + node2.mVersion = "1.0.0"; + node2.mLabels.PushBack("secondaryNode"); + node2.mPriority = 2; + unitConfig.mNodes.PushBack(node2); + + return unitConfig; +} + +void CompareNodeConfig(const NodeConfig& nodeConfig, const NodeConfig& expectedNodeConfig) +{ + EXPECT_EQ(nodeConfig.mNodeID, expectedNodeConfig.mNodeID) << "Node ID mismatch"; + EXPECT_EQ(nodeConfig.mVersion, expectedNodeConfig.mVersion) << "Version mismatch"; + EXPECT_EQ(nodeConfig.mNodeType, expectedNodeConfig.mNodeType) << "Node type mismatch"; + EXPECT_EQ(nodeConfig.mPriority, expectedNodeConfig.mPriority) << "Priority mismatch"; + EXPECT_EQ(nodeConfig.mLabels, expectedNodeConfig.mLabels) << "Node labels mismatch"; + + // Compare alert rules + EXPECT_EQ(nodeConfig.mAlertRules.HasValue(), expectedNodeConfig.mAlertRules.HasValue()) + << "Alert rules presence mismatch"; + + if (nodeConfig.mAlertRules.HasValue() && expectedNodeConfig.mAlertRules.HasValue()) { + EXPECT_EQ(nodeConfig.mAlertRules->mRAM, expectedNodeConfig.mAlertRules->mRAM) << "Alert rules ram mismatch"; + EXPECT_EQ(nodeConfig.mAlertRules->mCPU, expectedNodeConfig.mAlertRules->mCPU) << "Alert rules cpu mismatch"; + EXPECT_EQ(nodeConfig.mAlertRules->mPartitions, expectedNodeConfig.mAlertRules->mPartitions) + << "Alert rules partitions mismatch"; + EXPECT_EQ(nodeConfig.mAlertRules->mDownload, expectedNodeConfig.mAlertRules->mDownload) + << "Alert rules download mismatch"; + EXPECT_EQ(nodeConfig.mAlertRules->mUpload, expectedNodeConfig.mAlertRules->mUpload) + << "Alert rules upload mismatch"; + } + + EXPECT_EQ(nodeConfig.mResourceRatios.HasValue(), expectedNodeConfig.mResourceRatios.HasValue()) + << "Resource ratios presence mismatch"; + + if (nodeConfig.mResourceRatios.HasValue() && expectedNodeConfig.mResourceRatios.HasValue()) { + EXPECT_EQ(nodeConfig.mResourceRatios->mCPU, expectedNodeConfig.mResourceRatios->mCPU) + << "Resource ratios cpu mismatch"; + EXPECT_EQ(nodeConfig.mResourceRatios->mRAM, expectedNodeConfig.mResourceRatios->mRAM) + << "Resource ratios ram mismatch"; + EXPECT_EQ(nodeConfig.mResourceRatios->mStorage, expectedNodeConfig.mResourceRatios->mStorage) + << "Resource ratios storage mismatch"; + EXPECT_EQ(nodeConfig.mResourceRatios->mState, expectedNodeConfig.mResourceRatios->mState) + << "Resource ratios state mismatch"; + } +} + +void CompareUnitConfig(const UnitConfig& unitConfig, const UnitConfig& expectedUnitConfig) +{ + EXPECT_EQ(unitConfig.mVersion, expectedUnitConfig.mVersion) << "Unit config version mismatch"; + EXPECT_EQ(unitConfig.mFormatVersion, expectedUnitConfig.mFormatVersion) << "Unit config format version mismatch"; + ASSERT_EQ(unitConfig.mNodes.Size(), expectedUnitConfig.mNodes.Size()) << "Nodes count mismatch"; + + for (size_t i = 0; i < unitConfig.mNodes.Size(); ++i) { + CompareNodeConfig(unitConfig.mNodes[i], expectedUnitConfig.mNodes[i]); + } +} + +} // namespace + +/*********************************************************************************************************************** + * Suite + **********************************************************************************************************************/ + +class JSONProviderTest : public Test { +public: + void SetUp() override { tests::utils::InitLog(); } + + JSONProvider mProvider; +}; + +/*********************************************************************************************************************** + * Tests + **********************************************************************************************************************/ + +TEST_F(JSONProviderTest, UnitConfigFromJSONSucceeds) +{ + UnitConfig parsedUnitConfig; + + ASSERT_EQ(mProvider.UnitConfigFromJSON(cTestUnitConfigJSON, parsedUnitConfig), ErrorEnum::eNone); + + CompareUnitConfig(parsedUnitConfig, CreateUnitConfig()); +} + +TEST_F(JSONProviderTest, UnitConfigFromJSONEmptyNodes) +{ + UnitConfig parsedUnitConfig; + + ASSERT_EQ(mProvider.UnitConfigFromJSON(cTestUnitConfigEmptyNodesJSON, parsedUnitConfig), ErrorEnum::eNone); + + EXPECT_EQ(parsedUnitConfig.mVersion, "1.0.0"); + EXPECT_EQ(parsedUnitConfig.mFormatVersion, "7"); + EXPECT_TRUE(parsedUnitConfig.mNodes.IsEmpty()); +} + +TEST_F(JSONProviderTest, UnitConfigFromJSONMinimal) +{ + UnitConfig parsedUnitConfig; + + ASSERT_EQ(mProvider.UnitConfigFromJSON(cTestUnitConfigMinimalJSON, parsedUnitConfig), ErrorEnum::eNone); + + EXPECT_EQ(parsedUnitConfig.mVersion, "1.0.0"); + EXPECT_EQ(parsedUnitConfig.mFormatVersion, "7"); + ASSERT_EQ(parsedUnitConfig.mNodes.Size(), 1); + EXPECT_EQ(parsedUnitConfig.mNodes[0].mNodeID, "node-1"); + EXPECT_EQ(parsedUnitConfig.mNodes[0].mNodeType, "type1"); + EXPECT_EQ(parsedUnitConfig.mNodes[0].mPriority, 0); + EXPECT_FALSE(parsedUnitConfig.mNodes[0].mAlertRules.HasValue()); + EXPECT_FALSE(parsedUnitConfig.mNodes[0].mResourceRatios.HasValue()); +} + +TEST_F(JSONProviderTest, UnitConfigToJSON) +{ + const UnitConfig unitConfig = CreateUnitConfig(); + auto unitConfigJSON = std::make_unique>(); + UnitConfig parsedUnitConfig; + + ASSERT_EQ(mProvider.UnitConfigToJSON(unitConfig, *unitConfigJSON), ErrorEnum::eNone); + ASSERT_EQ(mProvider.UnitConfigFromJSON(*unitConfigJSON, parsedUnitConfig), ErrorEnum::eNone); + + CompareUnitConfig(parsedUnitConfig, unitConfig); +} + +TEST_F(JSONProviderTest, UnitConfigRoundTrip) +{ + UnitConfig originalConfig; + originalConfig.mVersion = "3.0.0"; + originalConfig.mFormatVersion = "7"; + + NodeConfig node; + node.mNodeID = "test-node"; + node.mNodeType = "testType"; + node.mVersion = "2.0.0"; + node.mPriority = 5; + node.mLabels.PushBack("label1"); + node.mLabels.PushBack("label2"); + originalConfig.mNodes.PushBack(node); + + auto json = std::make_unique>(); + UnitConfig parsedConfig; + + ASSERT_EQ(mProvider.UnitConfigToJSON(originalConfig, *json), ErrorEnum::eNone); + ASSERT_EQ(mProvider.UnitConfigFromJSON(*json, parsedConfig), ErrorEnum::eNone); + + CompareUnitConfig(parsedConfig, originalConfig); +} + +} // namespace aos::cm::unitconfig diff --git a/src/sm/runner/tests/CMakeLists.txt b/src/cm/utils/CMakeLists.txt similarity index 81% rename from src/sm/runner/tests/CMakeLists.txt rename to src/cm/utils/CMakeLists.txt index 5c0e7090e..e68b11106 100644 --- a/src/sm/runner/tests/CMakeLists.txt +++ b/src/cm/utils/CMakeLists.txt @@ -1,41 +1,38 @@ # -# Copyright (C) 2024 EPAM Systems, Inc. +# Copyright (C) 2025 EPAM Systems, Inc. # # SPDX-License-Identifier: Apache-2.0 # - -set(TARGET_NAME runner_test) - # ###################################################################################################################### -# Sources +# Target name # ###################################################################################################################### -set(SOURCES runner.cpp) +set(TARGET_NAME utils) # ###################################################################################################################### -# Includes +# Sources # ###################################################################################################################### -set(INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}) +set(SOURCES uidgidvalidator.cpp) # ###################################################################################################################### # Libraries # ###################################################################################################################### -set(LIBRARIES aos::sm::runner aos::common::tests::utils GTest::gmock_main) +set(LIBRARIES aos::core::common::tools) # ###################################################################################################################### # Target # ###################################################################################################################### -add_test( +add_module( TARGET_NAME ${TARGET_NAME} LOG_MODULE + STACK_USAGE + ${AOS_STACK_USAGE} SOURCES ${SOURCES} - INCLUDES - ${INCLUDES} LIBRARIES ${LIBRARIES} ) diff --git a/src/cm/utils/uidgidvalidator.cpp b/src/cm/utils/uidgidvalidator.cpp new file mode 100644 index 000000000..1bb2672be --- /dev/null +++ b/src/cm/utils/uidgidvalidator.cpp @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2025 EPAM Systems, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include "uidgidvalidator.hpp" + +namespace aos::cm::utils { + +/*********************************************************************************************************************** + * Public + **********************************************************************************************************************/ + +bool IsUIDValid(size_t uid) +{ + auto passwd = getpwuid(uid); + if (passwd != nullptr) { + return false; + } + + return true; +} + +bool IsGIDValid(size_t gid) +{ + auto group = getgrgid(gid); + if (group != nullptr) { + return false; + } + + return true; +} + +} // namespace aos::cm::utils diff --git a/src/cm/utils/uidgidvalidator.hpp b/src/cm/utils/uidgidvalidator.hpp new file mode 100644 index 000000000..e74088513 --- /dev/null +++ b/src/cm/utils/uidgidvalidator.hpp @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2025 EPAM Systems, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef AOS_CM_UTILS_UIDGIDVALIDATOR_HPP_ +#define AOS_CM_UTILS_UIDGIDVALIDATOR_HPP_ + +#include + +namespace aos::cm::utils { + +/** + * Checks if UID is valid. + * + * @param uid user identifier. + * @return bool. + */ +bool IsUIDValid(size_t uid); + +/** + * Checks if GID is valid. + * + * @param gid group identifier. + * @return bool. + */ +bool IsGIDValid(size_t gid); + +} // namespace aos::cm::utils + +#endif diff --git a/src/common/config/config.cpp b/src/common/config/config.cpp index 6dd3556f4..2289b7921 100644 --- a/src/common/config/config.cpp +++ b/src/common/config/config.cpp @@ -28,64 +28,44 @@ constexpr auto cMinAlertPriorityLevel = 0; * Public functions **********************************************************************************************************************/ -Error ParseMonitoringConfig(const common::utils::CaseInsensitiveObjectWrapper& object, monitoring::Config& config) +void ParseMonitoringConfig(const common::utils::CaseInsensitiveObjectWrapper& object, monitoring::Config& config) { - try { - const auto pollPeriod = object.GetValue("pollPeriod", cDefaultMonitoringPollPeriod); - const auto averageWindow = object.GetValue("averageWindow", cDefaultMonitoringAverageWindow); + const auto pollPeriod = object.GetValue("pollPeriod", cDefaultMonitoringPollPeriod); + const auto averageWindow = object.GetValue("averageWindow", cDefaultMonitoringAverageWindow); - Error err = ErrorEnum::eNone; + Error err = ErrorEnum::eNone; - Tie(config.mPollPeriod, err) = common::utils::ParseDuration(pollPeriod); - if (err != ErrorEnum::eNone) { - return AOS_ERROR_WRAP(err); - } + Tie(config.mPollPeriod, err) = common::utils::ParseDuration(pollPeriod); + AOS_ERROR_CHECK_AND_THROW(err, "error parsing pollPeriod tag"); - Tie(config.mAverageWindow, err) = common::utils::ParseDuration(averageWindow); - - return AOS_ERROR_WRAP(err); - } catch (const std::exception& e) { - return common::utils::ToAosError(e); - } + Tie(config.mAverageWindow, err) = common::utils::ParseDuration(averageWindow); + AOS_ERROR_CHECK_AND_THROW(err, "error parsing averageWindow tag"); } -Error ParseMigrationConfig(const common::utils::CaseInsensitiveObjectWrapper& object, +void ParseMigrationConfig(const common::utils::CaseInsensitiveObjectWrapper& object, const std::string& defaultMigrationPath, const std::string& defaultMergedMigrationPath, Migration& config) { - try { - config.mMigrationPath = object.GetOptionalValue("migrationPath").value_or(defaultMigrationPath); - config.mMergedMigrationPath - = object.GetOptionalValue("mergedMigrationPath").value_or(defaultMergedMigrationPath); - } catch (const std::exception& e) { - return common::utils::ToAosError(e); - } - - return ErrorEnum::eNone; + config.mMigrationPath = object.GetOptionalValue("migrationPath").value_or(defaultMigrationPath); + config.mMergedMigrationPath + = object.GetOptionalValue("mergedMigrationPath").value_or(defaultMergedMigrationPath); } -Error ParseJournalAlertsConfig(const common::utils::CaseInsensitiveObjectWrapper& object, JournalAlerts& config) +void ParseJournalAlertsConfig(const common::utils::CaseInsensitiveObjectWrapper& object, JournalAlerts& config) { - try { - config.mFilter = common::utils::GetArrayValue(object, "filter"); - - config.mServiceAlertPriority - = object.GetOptionalValue("serviceAlertPriority").value_or(cDefaultServiceAlertPriority); - if (config.mServiceAlertPriority > cMaxAlertPriorityLevel - || config.mServiceAlertPriority < cMinAlertPriorityLevel) { - config.mServiceAlertPriority = cDefaultServiceAlertPriority; - } - - config.mSystemAlertPriority - = object.GetOptionalValue("systemAlertPriority").value_or(cDefaultSystemAlertPriority); - if (config.mSystemAlertPriority > cMaxAlertPriorityLevel - || config.mSystemAlertPriority < cMinAlertPriorityLevel) { - config.mSystemAlertPriority = cDefaultSystemAlertPriority; - } - } catch (const std::exception& e) { - return common::utils::ToAosError(e); + config.mFilter = common::utils::GetArrayValue(object, "filter"); + + config.mServiceAlertPriority + = object.GetOptionalValue("serviceAlertPriority").value_or(cDefaultServiceAlertPriority); + if (config.mServiceAlertPriority > cMaxAlertPriorityLevel + || config.mServiceAlertPriority < cMinAlertPriorityLevel) { + config.mServiceAlertPriority = cDefaultServiceAlertPriority; } - return ErrorEnum::eNone; + config.mSystemAlertPriority + = object.GetOptionalValue("systemAlertPriority").value_or(cDefaultSystemAlertPriority); + if (config.mSystemAlertPriority > cMaxAlertPriorityLevel || config.mSystemAlertPriority < cMinAlertPriorityLevel) { + config.mSystemAlertPriority = cDefaultSystemAlertPriority; + } } } // namespace aos::common::config diff --git a/src/common/config/config.hpp b/src/common/config/config.hpp index 3a5b38594..6a9bd9d10 100644 --- a/src/common/config/config.hpp +++ b/src/common/config/config.hpp @@ -47,9 +47,8 @@ struct Migration { * * @param object JSON object. * @param[out] config monitoring configuration. - * @return Error. */ -Error ParseMonitoringConfig(const common::utils::CaseInsensitiveObjectWrapper& object, monitoring::Config& config); +void ParseMonitoringConfig(const common::utils::CaseInsensitiveObjectWrapper& object, monitoring::Config& config); /* * Parses migration configuration. @@ -58,9 +57,8 @@ Error ParseMonitoringConfig(const common::utils::CaseInsensitiveObjectWrapper& o * @param defaultMigrationPath default migration path. * @param defaultMergedMigrationPath default merged migration path. * @param[out] config migration configuration. - * @return Error. */ -Error ParseMigrationConfig(const common::utils::CaseInsensitiveObjectWrapper& object, +void ParseMigrationConfig(const common::utils::CaseInsensitiveObjectWrapper& object, const std::string& defaultMigrationPath, const std::string& defaultMergedMigrationPath, Migration& config); /* @@ -68,9 +66,8 @@ Error ParseMigrationConfig(const common::utils::CaseInsensitiveObjectWrapper& ob * * @param object JSON object. * @param[out] config journal alerts configuration. - * @return Error. */ -Error ParseJournalAlertsConfig(const common::utils::CaseInsensitiveObjectWrapper& object, JournalAlerts& config); +void ParseJournalAlertsConfig(const common::utils::CaseInsensitiveObjectWrapper& object, JournalAlerts& config); } // namespace aos::common::config diff --git a/src/common/config/tests/config.cpp b/src/common/config/tests/config.cpp index 37a120196..3dbf9b625 100644 --- a/src/common/config/tests/config.cpp +++ b/src/common/config/tests/config.cpp @@ -96,9 +96,8 @@ TEST_F(CommonConfigTest, ParseMonitoringConfig) aos::common::utils::CaseInsensitiveObjectWrapper wrapper(object); aos::monitoring::Config config; - auto err = aos::common::config::ParseMonitoringConfig(wrapper.GetObject("monitoring"), config); - ASSERT_EQ(err, aos::ErrorEnum::eNone); + EXPECT_NO_THROW(aos::common::config::ParseMonitoringConfig(wrapper.GetObject("monitoring"), config)); EXPECT_EQ(config.mPollPeriod, aos::Time::cMinutes); EXPECT_EQ(config.mAverageWindow, aos::Time::cMinutes * 5); @@ -119,10 +118,9 @@ TEST_F(CommonConfigTest, ParseMigrationConfig) aos::common::utils::CaseInsensitiveObjectWrapper wrapper(object); aos::common::config::Migration config; - auto err = aos::common::config::ParseMigrationConfig( - wrapper.GetObject("migration"), "/default/migration/path", "/default/merged/path", config); - ASSERT_EQ(err, aos::ErrorEnum::eNone); + EXPECT_NO_THROW(aos::common::config::ParseMigrationConfig( + wrapper.GetObject("migration"), "/default/migration/path", "/default/merged/path", config)); EXPECT_EQ(config.mMigrationPath, "/custom/migration/path"); EXPECT_EQ(config.mMergedMigrationPath, "/custom/merged/path"); @@ -143,9 +141,8 @@ TEST_F(CommonConfigTest, ParseJournalAlertsConfig) aos::common::utils::CaseInsensitiveObjectWrapper wrapper(object); aos::common::config::JournalAlerts config; - auto err = aos::common::config::ParseJournalAlertsConfig(wrapper.GetObject("journalAlerts"), config); - ASSERT_EQ(err, aos::ErrorEnum::eNone); + EXPECT_NO_THROW(aos::common::config::ParseJournalAlertsConfig(wrapper.GetObject("journalAlerts"), config)); std::vector expectedFilter = {"test1", "test2", "test3"}; EXPECT_EQ(config.mFilter, expectedFilter); diff --git a/src/common/downloader/downloader.cpp b/src/common/downloader/downloader.cpp index c8e4d5e8d..0358e14d5 100644 --- a/src/common/downloader/downloader.cpp +++ b/src/common/downloader/downloader.cpp @@ -8,9 +8,9 @@ #include #include +#include #include -#include #include #include "downloader.hpp" @@ -54,7 +54,7 @@ Error Downloader::Download(const String& digest, const String& url, const String auto it = mCancelFlags.find(digest.CStr()); if (it != mCancelFlags.end()) { - return Error(ErrorEnum::eAlreadyExist, "Download already in progress"); + return Error(ErrorEnum::eAlreadyExist, "download already in progress"); } mCancelFlags[context.mDigest].store(false); @@ -84,20 +84,20 @@ Error Downloader::DownloadImage(const String& url, const String& path, ProgressC std::unique_ptr curl(curl_easy_init(), curl_easy_cleanup); if (!curl) { - return Error(ErrorEnum::eFailed, "Failed to init curl"); + return Error(ErrorEnum::eFailed, "failed to init curl"); } auto fileCloser = [](FILE* fp) { if (fp) { if (auto res = fclose(fp); res != 0) { - LOG_ERR() << "Failed to close file: res=" << res; + LOG_ERR() << "failed to close file: res=" << res; } } }; std::unique_ptr fp(fopen(path.CStr(), "ab"), fileCloser); if (!fp) { - return Error(ErrorEnum::eFailed, "Failed to open file"); + return Error(ErrorEnum::eFailed, "failed to open file"); } fseek(fp.get(), 0, SEEK_END); @@ -155,7 +155,7 @@ Error Downloader::CopyFile(const Poco::URI& uri, const String& outfilename) } if (!std::filesystem::exists(path)) { - return Error(ErrorEnum::eFailed, "File not found"); + return Error(ErrorEnum::eFailed, "file not found"); } try { @@ -177,18 +177,18 @@ Error Downloader::RetryDownload(const String& url, const String& path, ProgressC for (int retryCount = 0; (retryCount < cMaxRetryCount) && (!mShutdown); ++retryCount) { if (context->mCancelFlag && context->mCancelFlag->load()) { - return Error(ErrorEnum::eRuntime, "Download cancelled"); + return Error(ErrorEnum::eRuntime, "download cancelled"); } - LOG_DBG() << "Downloading: url=" << url << ", retry=" << retryCount; + LOG_DBG() << "Downloading" << Log::Field("url", url) << Log::Field("retry", retryCount); if (err = DownloadImage(url, path, context); err.IsNone()) { - LOG_DBG() << "Download success: url=" << url; + LOG_DBG() << "Download success" << Log::Field("url", url); return ErrorEnum::eNone; } - LOG_ERR() << "Failed to download: err=" << err.Message() << ", retry=" << retryCount; + LOG_ERR() << "Failed to download" << Log::Field("retry", retryCount) << Log::Field(AOS_ERROR_WRAP(err)); { std::unique_lock lock {mMutex}; @@ -281,12 +281,12 @@ Error Downloader::Cancel(const String& digest) if (auto it = mCancelFlags.find(digest.CStr()); it != mCancelFlags.end()) { it->second.store(true); - LOG_DBG() << "Cancel requested for download: digest=" << digest; + LOG_DBG() << "Cancel requested for download:" << Log::Field("digest", digest); return ErrorEnum::eNone; } - return Error(ErrorEnum::eNotFound, "Download not found"); + return Error(ErrorEnum::eNotFound, "download not found"); } } // namespace aos::common::downloader diff --git a/src/common/fileserver/CMakeLists.txt b/src/common/fileserver/CMakeLists.txt index 1a76f0f74..78956c55a 100644 --- a/src/common/fileserver/CMakeLists.txt +++ b/src/common/fileserver/CMakeLists.txt @@ -20,7 +20,7 @@ set(SOURCES fileserver.cpp) # Libraries # ###################################################################################################################### -set(LIBRARIES aos::common::utils Poco::Foundation Poco::Net Poco::NetSSL) +set(LIBRARIES aos::common::utils aos::core::cm::fileserver Poco::Foundation Poco::Net Poco::NetSSL) # ###################################################################################################################### # Target diff --git a/src/common/fileserver/fileserver.cpp b/src/common/fileserver/fileserver.cpp index 150bfe8c7..2c6b85fc3 100644 --- a/src/common/fileserver/fileserver.cpp +++ b/src/common/fileserver/fileserver.cpp @@ -16,7 +16,8 @@ #include #include -#include +#include + #include #include "fileserver.hpp" @@ -78,18 +79,14 @@ Error Fileserver::Init(const std::string& serverURL, const std::string& rootDir) return ErrorEnum::eNone; } -RetWithError Fileserver::TranslateURL(bool isLocal, const std::string& inURL) +Error Fileserver::TranslateFilePathURL(const String& filePath, String& outURL) { if (mHost.empty() || mPort == 0) { - return {{}, Error(ErrorEnum::eWrongState, "server is not started")}; - } - - if (isLocal) { - return inURL; + return Error(ErrorEnum::eWrongState, "server is not started"); } try { - Poco::URI uri(inURL); + Poco::URI uri(filePath.CStr()); std::filesystem::path path = uri.getPath(); auto filename = path.filename(); @@ -99,9 +96,11 @@ RetWithError Fileserver::TranslateURL(bool isLocal, const std::stri uri.setPort(mPort); uri.setPath(filename.string()); - return uri.toString(); + outURL = uri.toString().c_str(); + + return ErrorEnum::eNone; } catch (const std::exception& e) { - return {{}, common::utils::ToAosError(e)}; + return common::utils::ToAosError(e); } } diff --git a/src/common/fileserver/fileserver.hpp b/src/common/fileserver/fileserver.hpp index 13317321e..fc3d8d311 100644 --- a/src/common/fileserver/fileserver.hpp +++ b/src/common/fileserver/fileserver.hpp @@ -17,6 +17,7 @@ #include #include +#include #include namespace aos::common::fileserver { @@ -24,7 +25,7 @@ namespace aos::common::fileserver { /** * Fileserver. */ -class Fileserver { +class Fileserver : public cm::fileserver::FileServerItf { public: /** * Default constructor. @@ -41,13 +42,13 @@ class Fileserver { Error Init(const std::string& serverURL, const std::string& rootDir); /** - * Translates URL. + * Translates file path URL. * - * @param isLocal is local. - * @param inURL input URL. - * @return translated URL. + * @param filePath input file path. + * @param[out] outURL translated URL. + * @return Error. */ - RetWithError TranslateURL(bool isLocal, const std::string& inURL); + Error TranslateFilePathURL(const String& filePath, String& outURL) override; /** * File request handler factory. diff --git a/src/common/fileserver/tests/fileserver.cpp b/src/common/fileserver/tests/fileserver.cpp index 79c8d9485..3f1cbdb3a 100644 --- a/src/common/fileserver/tests/fileserver.cpp +++ b/src/common/fileserver/tests/fileserver.cpp @@ -16,6 +16,7 @@ #include #include +#include #include @@ -54,17 +55,13 @@ class CommonFileserverTest : public ::testing::Test { * Tests **********************************************************************************************************************/ -TEST_F(CommonFileserverTest, TranslateURL) +TEST_F(CommonFileserverTest, TranslateFilePathURL) { - auto [url, err] = mFileserver.TranslateURL(false, "file://download/test_file.dat"); + StaticString<256> url; + auto err = mFileserver.TranslateFilePathURL("file://download/test_file.dat", url); EXPECT_EQ(err, ErrorEnum::eNone); EXPECT_EQ(url, "http://localhost:8000/test_file.dat"); - - Tie(url, err) = mFileserver.TranslateURL(true, "download/test_file.dat"); - EXPECT_EQ(err, ErrorEnum::eNone); - - EXPECT_EQ(url, "download/test_file.dat"); } TEST_F(CommonFileserverTest, DownloadFileSuccess) diff --git a/src/common/iamclient/certificateservice.cpp b/src/common/iamclient/certificateservice.cpp index 9a04adb79..96a172b12 100644 --- a/src/common/iamclient/certificateservice.cpp +++ b/src/common/iamclient/certificateservice.cpp @@ -6,7 +6,8 @@ #include -#include +#include + #include #include diff --git a/src/common/iamclient/nodesservice.cpp b/src/common/iamclient/nodesservice.cpp index a7bb85443..c23a58132 100644 --- a/src/common/iamclient/nodesservice.cpp +++ b/src/common/iamclient/nodesservice.cpp @@ -7,7 +7,8 @@ #include #include -#include +#include + #include #include diff --git a/src/common/iamclient/permservice.cpp b/src/common/iamclient/permservice.cpp index bbd67586c..b09d95d30 100644 --- a/src/common/iamclient/permservice.cpp +++ b/src/common/iamclient/permservice.cpp @@ -5,7 +5,8 @@ */ #include -#include +#include + #include #include diff --git a/src/common/iamclient/provisioningservice.cpp b/src/common/iamclient/provisioningservice.cpp index 5d2553145..01e465007 100644 --- a/src/common/iamclient/provisioningservice.cpp +++ b/src/common/iamclient/provisioningservice.cpp @@ -6,7 +6,8 @@ #include -#include +#include + #include #include "provisioningservice.hpp" diff --git a/src/common/iamclient/publiccertservice.cpp b/src/common/iamclient/publiccertservice.cpp index 1c91bb939..0732c0286 100644 --- a/src/common/iamclient/publiccertservice.cpp +++ b/src/common/iamclient/publiccertservice.cpp @@ -6,7 +6,8 @@ #include -#include +#include + #include #include @@ -30,11 +31,11 @@ PublicCertService::~PublicCertService() Error PublicCertService::Init( const std::string& iamPublicServerURL, TLSCredentialsItf& tlsCredentials, bool insecureConnection) { - LOG_INF() << "Init public cert service" << Log::Field("iamPublicServerURL", iamPublicServerURL.c_str()) - << Log::Field("insecureConnection", insecureConnection); - std::lock_guard lock {mMutex}; + LOG_DBG() << "Init public cert service" << Log::Field("iamPublicServerURL", iamPublicServerURL.c_str()) + << Log::Field("insecureConnection", insecureConnection); + mTLSCredentials = &tlsCredentials; mIAMPublicServerURL = iamPublicServerURL; mInsecureConnection = insecureConnection; @@ -108,6 +109,8 @@ Error PublicCertService::UnsubscribeListener(aos::iamclient::CertListenerItf& ce { std::lock_guard lock {mMutex}; + LOG_INF() << "Unsubscribe from certificate changed"; + for (auto it = mSubscriptions.begin(); it != mSubscriptions.end();) { auto& manager = it->second; @@ -127,6 +130,8 @@ Error PublicCertService::GetCert( { std::lock_guard lock {mMutex}; + LOG_INF() << "Get certificate" << Log::Field("certType", certType); + auto ctx = std::make_unique(); ctx->set_deadline(std::chrono::system_clock::now() + cServiceTimeout); diff --git a/src/common/iamclient/publiccurrentnodeservice.cpp b/src/common/iamclient/publiccurrentnodeservice.cpp index d225a2c37..8e2e999b3 100644 --- a/src/common/iamclient/publiccurrentnodeservice.cpp +++ b/src/common/iamclient/publiccurrentnodeservice.cpp @@ -6,7 +6,8 @@ #include -#include +#include + #include #include @@ -28,7 +29,7 @@ PublicCurrentNodeService::~PublicCurrentNodeService() Error PublicCurrentNodeService::Init( const std::string& iamPublicServerURL, TLSCredentialsItf& tlsCredentials, bool insecureConnection) { - LOG_INF() << "Init public current node service" << Log::Field("iamPublicServerURL", iamPublicServerURL.c_str()) + LOG_DBG() << "Init public current node service" << Log::Field("iamPublicServerURL", iamPublicServerURL.c_str()) << Log::Field("insecureConnection", insecureConnection); std::lock_guard lock {mMutex}; diff --git a/src/common/iamclient/publicidentityservice.cpp b/src/common/iamclient/publicidentityservice.cpp index 1dc48319f..4f80888d0 100644 --- a/src/common/iamclient/publicidentityservice.cpp +++ b/src/common/iamclient/publicidentityservice.cpp @@ -6,7 +6,8 @@ #include -#include +#include + #include #include "publicidentityservice.hpp" @@ -27,7 +28,7 @@ PublicIdentityService::~PublicIdentityService() Error PublicIdentityService::Init( const std::string& iamPublicServerURL, TLSCredentialsItf& tlsCredentials, bool insecureConnection) { - LOG_INF() << "Init public identity service" << Log::Field("iamPublicServerURL", iamPublicServerURL.c_str()) + LOG_DBG() << "Init public identity service" << Log::Field("iamPublicServerURL", iamPublicServerURL.c_str()) << Log::Field("insecureConnection", insecureConnection); std::lock_guard lock {mMutex}; diff --git a/src/common/iamclient/publicnodeservice.cpp b/src/common/iamclient/publicnodeservice.cpp index bba81ffd2..c004fdd89 100644 --- a/src/common/iamclient/publicnodeservice.cpp +++ b/src/common/iamclient/publicnodeservice.cpp @@ -6,7 +6,8 @@ #include -#include +#include + #include #include @@ -28,7 +29,7 @@ PublicNodesService::~PublicNodesService() Error PublicNodesService::Init( const std::string& iamPublicServerURL, TLSCredentialsItf& tlsCredentials, bool insecureConnection) { - LOG_INF() << "Init public nodes service" << Log::Field("iamPublicServerURL", iamPublicServerURL.c_str()) + LOG_DBG() << "Init public nodes service" << Log::Field("iamPublicServerURL", iamPublicServerURL.c_str()) << Log::Field("insecureConnection", insecureConnection); std::lock_guard lock {mMutex}; diff --git a/src/common/iamclient/publicpermservice.cpp b/src/common/iamclient/publicpermservice.cpp index f2491f0ea..6c58557a1 100644 --- a/src/common/iamclient/publicpermservice.cpp +++ b/src/common/iamclient/publicpermservice.cpp @@ -8,7 +8,8 @@ #include -#include +#include + #include #include diff --git a/src/common/iamclient/tlscredentials.cpp b/src/common/iamclient/tlscredentials.cpp index f56d26be9..679b53a93 100644 --- a/src/common/iamclient/tlscredentials.cpp +++ b/src/common/iamclient/tlscredentials.cpp @@ -4,7 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include +#include #include "tlscredentials.hpp" diff --git a/src/common/jsonprovider/jsonprovider.cpp b/src/common/jsonprovider/jsonprovider.cpp index 2d80be334..3187a53f3 100644 --- a/src/common/jsonprovider/jsonprovider.cpp +++ b/src/common/jsonprovider/jsonprovider.cpp @@ -210,44 +210,34 @@ void LabelsFromJSON(const utils::CaseInsensitiveObjectWrapper& object, Array(Poco::JSON_PRESERVE_KEY_ORDER); - - object->set("version", nodeConfig.mVersion.CStr()); - object->set("nodeType", nodeConfig.mNodeType.CStr()); - object->set("nodeId", nodeConfig.mNodeID.CStr()); + auto object = Poco::makeShared(Poco::JSON_PRESERVE_KEY_ORDER); - if (nodeConfig.mAlertRules.HasValue()) { - object->set("alertRules", AlertRulesToJSON(*nodeConfig.mAlertRules)); - } + object->set("version", nodeConfig.mVersion.CStr()); + object->set("nodeType", nodeConfig.mNodeType.CStr()); + object->set("nodeId", nodeConfig.mNodeID.CStr()); - if (nodeConfig.mResourceRatios.HasValue()) { - object->set("resourceRatios", ResourceRatiosToJSON(*nodeConfig.mResourceRatios)); - } - - object->set("labels", utils::ToJsonArray(nodeConfig.mLabels, utils::ToStdString)); - object->set("priority", nodeConfig.mPriority); + if (nodeConfig.mAlertRules.HasValue()) { + object->set("alertRules", AlertRulesToJSON(*nodeConfig.mAlertRules)); + } - json = utils::Stringify(object).c_str(); - } catch (const std::exception& e) { - return AOS_ERROR_WRAP(utils::ToAosError(e)); + if (nodeConfig.mResourceRatios.HasValue()) { + object->set("resourceRatios", ResourceRatiosToJSON(*nodeConfig.mResourceRatios)); } - return ErrorEnum::eNone; + object->set("labels", utils::ToJsonArray(nodeConfig.mLabels, utils::ToStdString)); + object->set("priority", nodeConfig.mPriority); + + return object; } -Error JSONProvider::NodeConfigFromJSON(const String& json, NodeConfig& nodeConfig) const +Error NodeConfigFromJSONObject(const utils::CaseInsensitiveObjectWrapper& object, NodeConfig& nodeConfig) { try { - Poco::JSON::Parser parser; - auto result = parser.parse(json.CStr()); - utils::CaseInsensitiveObjectWrapper object(result.extract()); - auto err = nodeConfig.mVersion.Assign(object.GetValue("version").c_str()); AOS_ERROR_CHECK_AND_THROW(err, "parsed version length exceeds application limit"); @@ -275,4 +265,32 @@ Error JSONProvider::NodeConfigFromJSON(const String& json, NodeConfig& nodeConfi return ErrorEnum::eNone; } +/*********************************************************************************************************************** + * JSONProvider + **********************************************************************************************************************/ + +Error JSONProvider::NodeConfigToJSON(const NodeConfig& nodeConfig, String& json) const +{ + try { + json = utils::Stringify(NodeConfigToJSONObject(nodeConfig)).c_str(); + } catch (const std::exception& e) { + return AOS_ERROR_WRAP(utils::ToAosError(e)); + } + + return ErrorEnum::eNone; +} + +Error JSONProvider::NodeConfigFromJSON(const String& json, NodeConfig& nodeConfig) const +{ + try { + Poco::JSON::Parser parser; + auto result = parser.parse(json.CStr()); + utils::CaseInsensitiveObjectWrapper object(result.extract()); + + return NodeConfigFromJSONObject(object, nodeConfig); + } catch (const std::exception& e) { + return AOS_ERROR_WRAP(utils::ToAosError(e)); + } +} + } // namespace aos::common::jsonprovider diff --git a/src/common/jsonprovider/jsonprovider.hpp b/src/common/jsonprovider/jsonprovider.hpp index 513292494..a6aa054cb 100644 --- a/src/common/jsonprovider/jsonprovider.hpp +++ b/src/common/jsonprovider/jsonprovider.hpp @@ -7,10 +7,31 @@ #ifndef AOS_COMMON_JSONPROVIDER_JSONPROVIDER_HPP_ #define AOS_COMMON_JSONPROVIDER_JSONPROVIDER_HPP_ +#include + #include +#include + namespace aos::common::jsonprovider { +/** + * Converts NodeConfig object to JSON object. + * + * @param nodeConfig node config object. + * @return Poco::JSON::Object::Ptr. + */ +Poco::JSON::Object::Ptr NodeConfigToJSONObject(const NodeConfig& nodeConfig); + +/** + * Creates NodeConfig object from JSON object. + * + * @param object JSON object wrapper. + * @param[out] nodeConfig node config object. + * @return Error. + */ +Error NodeConfigFromJSONObject(const utils::CaseInsensitiveObjectWrapper& object, NodeConfig& nodeConfig); + /** * JSON provider. */ diff --git a/src/common/logger/logmodule.hpp b/src/common/logger/logmodule.hpp deleted file mode 100644 index 1e59459b7..000000000 --- a/src/common/logger/logmodule.hpp +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (C) 2024 EPAM Systems, Inc. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef AOS_COMMON_LOGGER_LOGMODULE_HPP_ -#define AOS_COMMON_LOGGER_LOGMODULE_HPP_ - -#include - -#include - -#ifndef LOG_MODULE -#define LOG_MODULE "default" -#endif - -#define LOG_DBG() LOG_MODULE_DBG(LOG_MODULE) -#define LOG_INF() LOG_MODULE_INF(LOG_MODULE) -#define LOG_WRN() LOG_MODULE_WRN(LOG_MODULE) -#define LOG_ERR() LOG_MODULE_ERR(LOG_MODULE) - -#endif diff --git a/src/common/logging/archiver.cpp b/src/common/logging/archiver.cpp index c525c4092..56e9f94f0 100644 --- a/src/common/logging/archiver.cpp +++ b/src/common/logging/archiver.cpp @@ -6,7 +6,8 @@ #include -#include +#include + #include #include "archiver.hpp" @@ -40,7 +41,7 @@ Error Archiver::AddLog(const std::string& message) return ErrorEnum::eNone; } -Error Archiver::SendLog(const String& correlationID) +Error Archiver::SendLog(const String& correlationId) { mCompressionStream->close(); @@ -56,7 +57,7 @@ Error Archiver::SendLog(const String& correlationID) auto emptyLog = std::make_unique(); - emptyLog->mCorrelationID = correlationID; + emptyLog->mCorrelationID = correlationId; emptyLog->mPartsCount = part; emptyLog->mPart = part; emptyLog->mStatus = LogStatusEnum::eEmpty; @@ -74,7 +75,7 @@ Error Archiver::SendLog(const String& correlationID) auto logPart = std::make_unique(); - logPart->mCorrelationID = correlationID; + logPart->mCorrelationID = correlationId; logPart->mPartsCount = mLogStreams.size(); logPart->mPart = part; logPart->mStatus = LogStatusEnum::eOK; diff --git a/src/common/logging/archiver.hpp b/src/common/logging/archiver.hpp index 3e517ef2b..7131342d1 100644 --- a/src/common/logging/archiver.hpp +++ b/src/common/logging/archiver.hpp @@ -44,10 +44,10 @@ class Archiver { /** * Sends accumulated log parts to the listener. * - * @param correlationID correlation ID. + * @param correlationId correlation ID. * @return Error. */ - Error SendLog(const String& correlationID); + Error SendLog(const String& correlationId); private: void CreateCompressionStream(); diff --git a/src/common/network/interfacemanager.cpp b/src/common/network/interfacemanager.cpp index a92c95525..08b27caf5 100644 --- a/src/common/network/interfacemanager.cpp +++ b/src/common/network/interfacemanager.cpp @@ -21,7 +21,7 @@ #include #include -#include +#include #include "interfacemanager.hpp" @@ -532,7 +532,7 @@ RetWithError InterfaceManager::GetMasterInterfaceIndex() const { LOG_DBG() << "Get master interface index"; - StaticArray routes; + std::vector routes; if (auto err = GetRouteList(routes); !err.IsNone()) { return {-1, err}; diff --git a/src/common/network/namespacemanager.cpp b/src/common/network/namespacemanager.cpp index ed9e41833..a7db0e45b 100644 --- a/src/common/network/namespacemanager.cpp +++ b/src/common/network/namespacemanager.cpp @@ -11,10 +11,9 @@ #include #include +#include #include -#include - #include "namespacemanager.hpp" namespace aos::common::network { diff --git a/src/common/network/utils.cpp b/src/common/network/utils.cpp index 67fde2c97..8bc8ecdc3 100644 --- a/src/common/network/utils.cpp +++ b/src/common/network/utils.cpp @@ -68,7 +68,7 @@ bool NetworkContainsIP(const std::string& networkCIDR, const std::string& ipAddr return result; } -Error GetRouteList(Array& routes) +Error GetRouteList(std::vector& routes) { auto [sock, err] = CreateNetlinkSocket(); if (!err.IsNone()) { @@ -112,9 +112,7 @@ Error GetRouteList(Array& routes) } } - if (err = routes.PushBack(info); !err.IsNone()) { - return AOS_ERROR_WRAP(err); - } + routes.push_back(info); } return ErrorEnum::eNone; @@ -145,7 +143,7 @@ RetWithError ParseAddress(const std::string& cidr) return addr; } -RetWithError CheckRouteOverlaps(const std::string& toCheck, const Array& routes) +RetWithError CheckRouteOverlaps(const std::string& toCheck, const std::vector& routes) { try { for (const auto& route : routes) { diff --git a/src/common/network/utils.hpp b/src/common/network/utils.hpp index f4f92adbf..28e45ee2f 100644 --- a/src/common/network/utils.hpp +++ b/src/common/network/utils.hpp @@ -26,14 +26,9 @@ namespace aos::common::network { struct RouteInfo { std::optional mDestination; std::optional mGateway; - int mLinkIndex; + int mLinkIndex {}; }; -/** - * Max route count. - */ -constexpr size_t cMaxRouteCount = 20; - using NetlinkSocketDeleter = std::function; using UniqueNetlinkSocket = std::unique_ptr; @@ -43,7 +38,7 @@ using UniqueNetlinkSocket = std::unique_ptr; * @param[out] routes routes. * @return Error. */ -Error GetRouteList(Array& routes); +Error GetRouteList(std::vector& routes); /** * Creates netlink socket. @@ -59,7 +54,7 @@ RetWithError CreateNetlinkSocket(); * @param routes routes to check against. * @return true if overlaps, false otherwise. */ -RetWithError CheckRouteOverlaps(const std::string& toCheck, const Array& routes); +RetWithError CheckRouteOverlaps(const std::string& toCheck, const std::vector& routes); /** * Parses address from CIDR. diff --git a/src/common/ocispec/imageconfig.cpp b/src/common/ocispec/imageconfig.cpp index f2a17e8b4..73b4e3b01 100644 --- a/src/common/ocispec/imageconfig.cpp +++ b/src/common/ocispec/imageconfig.cpp @@ -66,6 +66,32 @@ Poco::JSON::Object ConfigToJSON(const aos::oci::Config& config) return object; } +void RootfsFromJSON(const utils::CaseInsensitiveObjectWrapper& object, aos::oci::Rootfs& rootfs) +{ + const auto type = object.GetValue("type"); + rootfs.mType = type.c_str(); + + for (const auto& diffID : utils::GetArrayValue(object, "diff_ids")) { + auto err = rootfs.mDiffIDs.EmplaceBack(diffID.c_str()); + AOS_ERROR_CHECK_AND_THROW(err, "diff_ids parsing error"); + } +} + +Poco::JSON::Object RootfsToJSON(const aos::oci::Rootfs& rootfs) +{ + Poco::JSON::Object object {Poco::JSON_PRESERVE_KEY_ORDER}; + + if (!rootfs.mType.IsEmpty()) { + object.set("type", rootfs.mType.CStr()); + } + + if (!rootfs.mDiffIDs.IsEmpty()) { + object.set("diff_ids", utils::ToJsonArray(rootfs.mDiffIDs, utils::ToStdString)); + } + + return object; +} + } // namespace /*********************************************************************************************************************** @@ -87,10 +113,6 @@ Error OCISpec::LoadImageConfig(const String& path, aos::oci::ImageConfig& imageC Poco::JSON::Object::Ptr object = var.extract(); utils::CaseInsensitiveObjectWrapper wrapper(object); - if (wrapper.Has("config")) { - ConfigFromJSON(wrapper.GetObject("config"), imageConfig.mConfig); - } - imageConfig.mAuthor = wrapper.GetValue("author").c_str(); PlatformFromJSONObject(wrapper, imageConfig); @@ -99,6 +121,14 @@ Error OCISpec::LoadImageConfig(const String& path, aos::oci::ImageConfig& imageC Tie(imageConfig.mCreated, err) = utils::FromUTCString(created->c_str()); AOS_ERROR_CHECK_AND_THROW(err, "created time parsing error"); } + + if (wrapper.Has("config")) { + ConfigFromJSON(wrapper.GetObject("config"), imageConfig.mConfig); + } + + if (wrapper.Has("rootfs")) { + RootfsFromJSON(wrapper.GetObject("rootfs"), imageConfig.mRootfs); + } } catch (const std::exception& e) { return AOS_ERROR_WRAP(utils::ToAosError(e)); } @@ -128,6 +158,10 @@ Error OCISpec::SaveImageConfig(const String& path, const aos::oci::ImageConfig& object->set("config", configObject); } + if (auto rootfsObject = RootfsToJSON(imageConfig.mRootfs); rootfsObject.size() > 0) { + object->set("rootfs", rootfsObject); + } + auto err = utils::WriteJsonToFile(object, path.CStr()); AOS_ERROR_CHECK_AND_THROW(err, "failed to write json to file"); } catch (const std::exception& e) { diff --git a/src/common/ocispec/tests/ocispec.cpp b/src/common/ocispec/tests/ocispec.cpp index fd9a2fb69..5e80c942e 100644 --- a/src/common/ocispec/tests/ocispec.cpp +++ b/src/common/ocispec/tests/ocispec.cpp @@ -75,6 +75,10 @@ constexpr auto cImageConfig = R"( { "architecture": "x86_64", "author": "gtest", + "created": "2024-12-31T23:59:59Z", + "os": "Linux", + "osVersion": "6.0.8", + "variant": "6", "config": { "cmd": [ "test-cmd", @@ -96,10 +100,12 @@ constexpr auto cImageConfig = R"( ], "workingDir": "/test-working-dir" }, - "created": "2024-12-31T23:59:59Z", - "os": "Linux", - "osVersion": "6.0.8", - "variant": "6" + "rootfs": { + "type": "layers", + "diff_ids": [ + "sha256:129abeb509f55870ec19f24eba0caecccee3f0e055c467e1df8513bdcddc746f" + ] + } } )"; const auto cServiceConfigPath = fs::JoinPath(cTestBaseDir, "service_config.json"); @@ -236,7 +242,7 @@ std::unique_ptr CreateRuntimeConfig() { auto res = std::make_unique(); - aos::oci::CreateExampleRuntimeSpec(*res); + aos::oci::CreateExampleRuntimeConfig(*res); aos::oci::Linux lnx; lnx.mResources.EmplaceValue(CreateLinuxResources()); diff --git a/src/common/pbconvert/common.cpp b/src/common/pbconvert/common.cpp index efc1ea7cc..e9317c13e 100644 --- a/src/common/pbconvert/common.cpp +++ b/src/common/pbconvert/common.cpp @@ -104,7 +104,22 @@ google::protobuf::Timestamp TimestampToPB(const aos::Time& time) return result; } -void ConvertOSInfoToProto(const OSInfo& src, iamanager::v6::OSInfo& dst) +void ConvertToAos(const ::common::v2::InstanceFilter& src, InstanceFilter& dst) +{ + if (!src.item_id().empty()) { + dst.mItemID.SetValue(src.item_id().c_str()); + } + + if (!src.subject_id().empty()) { + dst.mSubjectID.SetValue(src.subject_id().c_str()); + } + + if (src.instance() >= 0) { + dst.mInstance.SetValue(static_cast(src.instance())); + } +} + +void ConvertToProto(const OSInfo& src, ::common::v2::OSInfo& dst) { dst.set_os(src.mOS.CStr()); @@ -117,18 +132,58 @@ void ConvertOSInfoToProto(const OSInfo& src, iamanager::v6::OSInfo& dst) } } +Error ConvertToAos(const ::common::v2::OSInfo& src, OSInfo& dst) +{ + if (auto err = dst.mOS.Assign(src.os().c_str()); !err.IsNone()) { + return AOS_ERROR_WRAP(err); + } + + if (!src.version().empty()) { + dst.mVersion.SetValue(src.version().c_str()); + } + + for (const auto& feature : src.features()) { + if (auto err = dst.mFeatures.PushBack(feature.c_str()); !err.IsNone()) { + return AOS_ERROR_WRAP(err); + } + } + + return ErrorEnum::eNone; +} + +void ConvertToProto(const ArchInfo& src, ::common::v2::ArchInfo& dst) +{ + dst.set_architecture(src.mArchitecture.CStr()); + + if (src.mVariant.HasValue()) { + dst.set_variant(src.mVariant->CStr()); + } +} + +Error ConvertToAos(const ::common::v2::ArchInfo& src, ArchInfo& dst) +{ + if (auto err = dst.mArchitecture.Assign(src.architecture().c_str()); !err.IsNone()) { + return AOS_ERROR_WRAP(err); + } + + if (!src.variant().empty()) { + dst.mVariant.SetValue(src.variant().c_str()); + } + + return ErrorEnum::eNone; +} + Error ConvertToAos(const google::protobuf::RepeatedPtrField& src, CPUInfoArray& dst) { for (const auto& srcCPU : src) { CPUInfo dstCPU; - dstCPU.mModelName = srcCPU.model_name().c_str(); - dstCPU.mNumCores = srcCPU.num_cores(); - dstCPU.mNumThreads = srcCPU.num_threads(); - dstCPU.mArchInfo.mArchitecture = srcCPU.arch_info().architecture().c_str(); + dstCPU.mModelName = srcCPU.model_name().c_str(); + dstCPU.mNumCores = srcCPU.num_cores(); + dstCPU.mNumThreads = srcCPU.num_threads(); - if (!srcCPU.arch_info().variant().empty()) { - dstCPU.mArchInfo.mVariant.SetValue(srcCPU.arch_info().variant().c_str()); + if (auto err = ConvertToAos(srcCPU.arch_info(), dstCPU.mArchInfo); !err.IsNone()) { + return AOS_ERROR_WRAP(err); } if (srcCPU.max_dmips() > 0) { diff --git a/src/common/pbconvert/common.hpp b/src/common/pbconvert/common.hpp index 7a331ac3e..fc4c1357a 100644 --- a/src/common/pbconvert/common.hpp +++ b/src/common/pbconvert/common.hpp @@ -68,6 +68,14 @@ InstanceIdent ConvertToAos(const ::common::v2::InstanceIdent& val); */ Optional