diff --git a/ydb/core/testlib/common_helper.cpp b/ydb/core/testlib/common_helper.cpp index 8e92ccd15c1b..0f329d951717 100644 --- a/ydb/core/testlib/common_helper.cpp +++ b/ydb/core/testlib/common_helper.cpp @@ -53,7 +53,7 @@ void THelper::WaitForSchemeOperation(TActorId sender, ui64 txId) { void THelper::StartScanRequest(const TString& request, const bool expectSuccess, TVector>* result) const { NYdb::NTable::TTableClient tClient(Server.GetDriver(), - NYdb::NTable::TClientSettings().UseQueryCache(false).AuthToken("root@builtin")); + NYdb::NTable::TClientSettings().UseQueryCache(false).AuthToken(AuthToken)); auto expectation = expectSuccess; bool resultReady = false; TVector> rows; @@ -109,7 +109,7 @@ void THelper::StartScanRequest(const TString& request, const bool expectSuccess, void THelper::StartDataRequest(const TString& request, const bool expectSuccess, TString* result) const { NYdb::NTable::TTableClient tClient(Server.GetDriver(), - NYdb::NTable::TClientSettings().UseQueryCache(false).AuthToken("root@builtin")); + NYdb::NTable::TClientSettings().UseQueryCache(false).AuthToken(AuthToken)); auto expectation = expectSuccess; bool resultReady = false; bool* rrPtr = &resultReady; @@ -144,7 +144,7 @@ void THelper::StartDataRequest(const TString& request, const bool expectSuccess, void THelper::StartSchemaRequestTableServiceImpl(const TString& request, const bool expectation, const bool waiting) const { NYdb::NTable::TTableClient tClient(Server.GetDriver(), - NYdb::NTable::TClientSettings().UseQueryCache(false).AuthToken("root@builtin")); + NYdb::NTable::TClientSettings().UseQueryCache(false).AuthToken(AuthToken)); std::shared_ptr rrPtr = std::make_shared(false); tClient.CreateSession().Subscribe([rrPtr, request, expectation](NThreading::TFuture f) { @@ -171,7 +171,7 @@ void THelper::StartSchemaRequestTableServiceImpl(const TString& request, const b void THelper::StartSchemaRequestQueryServiceImpl(const TString& request, const bool expectation, const bool waiting) const { NYdb::NQuery::TQueryClient qClient(Server.GetDriver(), - NYdb::NQuery::TClientSettings().AuthToken("root@builtin")); + NYdb::NQuery::TClientSettings().AuthToken(AuthToken)); std::shared_ptr rrPtr = std::make_shared(false); auto future = qClient.ExecuteQuery(request, NYdb::NQuery::TTxControl::NoTx()); diff --git a/ydb/core/testlib/common_helper.h b/ydb/core/testlib/common_helper.h index 76b3eaf67938..cf1c1d1351d8 100644 --- a/ydb/core/testlib/common_helper.h +++ b/ydb/core/testlib/common_helper.h @@ -54,6 +54,10 @@ class TLoggerInit { }; class THelper { +private: + inline static const TString DefaultAuthToken = "root@builtin"; + YDB_ACCESSOR(TString, AuthToken, DefaultAuthToken); + protected: void WaitForSchemeOperation(TActorId sender, ui64 txId); void PrintResultSet(const NYdb::TResultSet& resultSet, NYson::TYsonWriter& writer) const; @@ -73,6 +77,10 @@ class THelper { UseQueryService = use; } + void ResetAuthToken() { + AuthToken = DefaultAuthToken; + } + void DropTable(const TString& tablePath); void StartScanRequest(const TString& request, const bool expectSuccess, TVector>* result) const; diff --git a/ydb/mvp/meta/meta_cloud.h b/ydb/mvp/meta/meta_cloud.h index 5b68f8e1c02b..06b67ed1193a 100644 --- a/ydb/mvp/meta/meta_cloud.h +++ b/ydb/mvp/meta/meta_cloud.h @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/ydb/mvp/meta/meta_cluster.h b/ydb/mvp/meta/meta_cluster.h index 29d01a2932ea..f29a8445512e 100644 --- a/ydb/mvp/meta/meta_cluster.h +++ b/ydb/mvp/meta/meta_cluster.h @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/ydb/mvp/meta/meta_clusters.h b/ydb/mvp/meta/meta_clusters.h index c869daa9127a..7155d15dc4e1 100644 --- a/ydb/mvp/meta/meta_clusters.h +++ b/ydb/mvp/meta/meta_clusters.h @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include diff --git a/ydb/mvp/meta/meta_cp_databases.h b/ydb/mvp/meta/meta_cp_databases.h index d1a8a3941738..fe5c3e8c3028 100644 --- a/ydb/mvp/meta/meta_cp_databases.h +++ b/ydb/mvp/meta/meta_cp_databases.h @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/ydb/mvp/meta/meta_db_clusters.h b/ydb/mvp/meta/meta_db_clusters.h index 6ccf7e02fcd8..e9260694d259 100644 --- a/ydb/mvp/meta/meta_db_clusters.h +++ b/ydb/mvp/meta/meta_db_clusters.h @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/ydb/services/metadata/manager/abstract.h b/ydb/services/metadata/manager/abstract.h index 318aa66c8094..0696a90c06ee 100644 --- a/ydb/services/metadata/manager/abstract.h +++ b/ydb/services/metadata/manager/abstract.h @@ -4,16 +4,17 @@ #include #include + #include #include -#include +#include #include - +#include #include #include +#include #include -#include #include namespace NKikimr::NMetadata::NModifications { @@ -168,6 +169,11 @@ class IObjectOperationsManager: public IOperationsManager { const TInternalModificationContext& context, const TAlterOperationContext& alterContext) const { return DoPrepareObjectsBeforeModification(std::move(patchedObjects), controller, context, alterContext); } + + virtual std::vector GetPreconditions( + const std::vector& /*objects*/, const IOperationsManager::TInternalModificationContext& /*context*/) const { + return {}; + } }; class IObjectModificationCommand { diff --git a/ydb/services/metadata/manager/alter.h b/ydb/services/metadata/manager/alter.h index 481675db202d..326c9d8d32de 100644 --- a/ydb/services/metadata/manager/alter.h +++ b/ydb/services/metadata/manager/alter.h @@ -15,8 +15,8 @@ class TUpdateObjectActor: public TModificationActor { using TBase = TModificationActor; protected: virtual bool ProcessPreparedObjects(NInternal::TTableRecords&& records) const override { - TBase::Register(new TUpdateObjectsActor(std::move(records), TBase::UserToken, - TBase::InternalController, TBase::SessionId, TBase::TransactionId, TBase::Context.GetExternalData().GetUserToken())); + TBase::Register(new TUpdateObjectsActor(std::move(records), TBase::UserToken, TBase::InternalController, TBase::SessionId, + TBase::TransactionId, TBase::Context.GetExternalData().GetUserToken(), TBase::Preconditions)); return true; } @@ -33,9 +33,8 @@ class TUpsertObjectActor: public TModificationActor { using TBase = TModificationActor; protected: virtual bool ProcessPreparedObjects(NInternal::TTableRecords&& records) const override { - TBase::Register(new TUpsertObjectsActor(std::move(records), TBase::UserToken, - TBase::InternalController, TBase::SessionId, TBase::TransactionId, - TBase::Context.GetExternalData().GetUserToken())); + TBase::Register(new TUpsertObjectsActor(std::move(records), TBase::UserToken, TBase::InternalController, TBase::SessionId, + TBase::TransactionId, TBase::Context.GetExternalData().GetUserToken(), TBase::Preconditions)); return true; } @@ -53,9 +52,8 @@ class TCreateObjectActor: public TModificationActor { bool ExistingOk = false; protected: virtual bool ProcessPreparedObjects(NInternal::TTableRecords&& records) const override { - TBase::Register(new TInsertObjectsActor(std::move(records), TBase::UserToken, - TBase::InternalController, TBase::SessionId, TBase::TransactionId, - TBase::Context.GetExternalData().GetUserToken(), ExistingOk)); + TBase::Register(new TInsertObjectsActor(std::move(records), TBase::UserToken, TBase::InternalController, TBase::SessionId, + TBase::TransactionId, TBase::Context.GetExternalData().GetUserToken(), TBase::Preconditions, ExistingOk)); return true; } @@ -103,8 +101,8 @@ class TDeleteObjectActor: public TModificationActor { using TBase::TBase; virtual bool ProcessPreparedObjects(NInternal::TTableRecords&& records) const override { - TBase::Register(new TDeleteObjectsActor(std::move(records), TBase::UserToken, - TBase::InternalController, TBase::SessionId, TBase::TransactionId, TBase::Context.GetExternalData().GetUserToken())); + TBase::Register(new TDeleteObjectsActor(std::move(records), TBase::UserToken, TBase::InternalController, TBase::SessionId, + TBase::TransactionId, TBase::Context.GetExternalData().GetUserToken(), TBase::Preconditions)); return true; } diff --git a/ydb/services/metadata/manager/alter_impl.h b/ydb/services/metadata/manager/alter_impl.h index 127c6d530954..82a8dc19fc78 100644 --- a/ydb/services/metadata/manager/alter_impl.h +++ b/ydb/services/metadata/manager/alter_impl.h @@ -58,6 +58,7 @@ class TModificationActorImpl: public NActors::TActorBootstrapped::TPtr Manager; const IOperationsManager::TInternalModificationContext Context; std::vector Patches; + std::vector Preconditions; NInternal::TTableRecords RestoreObjectIds; const NACLib::TUserToken UserToken = NACLib::TSystemUsers::Metadata(); virtual bool PrepareRestoredObjects(std::vector& objects) const = 0; @@ -179,6 +180,7 @@ class TModificationActorImpl: public NActors::TActorBootstrapped::TPtr& ev) { + Preconditions = Manager->GetPreconditions(ev->Get()->GetObjects(), Context); NInternal::TTableRecords records; records.InitColumns(Manager->GetSchema().GetYDBColumns()); records.ReserveRows(ev->Get()->GetObjects().size()); diff --git a/ydb/services/metadata/manager/modification.h b/ydb/services/metadata/manager/modification.h index 382fd23f6f27..17dbd306a5f5 100644 --- a/ydb/services/metadata/manager/modification.h +++ b/ydb/services/metadata/manager/modification.h @@ -10,6 +10,32 @@ namespace NKikimr::NMetadata::NModifications { +class TModificationStage { +private: + YDB_ACCESSOR_DEF(Ydb::Table::ExecuteDataQueryRequest, Request); + +public: + using TPtr = std::shared_ptr; + + virtual TConclusionStatus HandleResult(const Ydb::Table::ExecuteQueryResult& /*result*/) const { + return TConclusionStatus::Success(); + } + + virtual TConclusionStatus HandleError(const NRequest::TEvRequestFailed& ev) const { + return TConclusionStatus::Fail(ev.GetErrorMessage()); + } + + void SetCommit() { + Request.mutable_tx_control()->set_commit_tx(true); + } + + TModificationStage(Ydb::Table::ExecuteDataQueryRequest request) + : Request(std::move(request)) { + } + + virtual ~TModificationStage() = default; +}; + template class TModifyObjectsActor: public NActors::TActorBootstrapped> { private: @@ -19,17 +45,44 @@ class TModifyObjectsActor: public NActors::TActorBootstrapped UserToken; + + void FillRequestSettings(Ydb::Table::ExecuteDataQueryRequest& request) { + request.set_session_id(SessionId); + request.mutable_tx_control()->set_tx_id(TransactionId); + } + + void AdvanceStage() { + AFL_VERIFY(!Stages.empty()); + Stages.pop_front(); + if (Stages.size()) { + TBase::Register( + new NRequest::TYDBCallbackRequest(Stages.front()->GetRequest(), SystemUserToken, TBase::SelfId())); + } else { + Controller->OnModificationFinished(); + TBase::PassAway(); + } + } + protected: - std::deque Requests; + std::deque Stages; NInternal::TTableRecords Objects; virtual Ydb::Table::ExecuteDataQueryRequest BuildModifyQuery() const = 0; virtual TString GetModifyType() const = 0; + virtual TModificationStage::TPtr DoBuildRequestDirect(Ydb::Table::ExecuteDataQueryRequest query) const { + return std::make_shared(std::move(query)); + } + + void BuildPreconditionStages(const std::vector& stages) { + for (auto&& stage : stages) { + FillRequestSettings(stage->MutableRequest()); + Stages.emplace_back(std::move(stage)); + } + } void BuildRequestDirect() { Ydb::Table::ExecuteDataQueryRequest request = BuildModifyQuery(); - request.set_session_id(SessionId); - request.mutable_tx_control()->set_tx_id(TransactionId); - Requests.emplace_back(std::move(request)); + FillRequestSettings(request); + Stages.emplace_back(DoBuildRequestDirect(request)); } void BuildRequestHistory() { @@ -42,31 +95,39 @@ class TModifyObjectsActor: public NActors::TActorBootstrappedGetStorageHistoryTablePath()); - request.set_session_id(SessionId); - request.mutable_tx_control()->set_tx_id(TransactionId); - Requests.emplace_back(std::move(request)); + FillRequestSettings(request); + Stages.emplace_back(std::make_shared(std::move(request))); } - void Handle(NRequest::TEvRequestResult::TPtr& /*ev*/) { - if (Requests.size()) { - TBase::Register(new NRequest::TYDBCallbackRequest( - Requests.front(), SystemUserToken, TBase::SelfId())); - Requests.pop_front(); - } else { - Controller->OnModificationFinished(); + void Handle(NRequest::TEvRequestResult::TPtr& ev) { + const auto& operation = ev->Get()->GetResult().operation(); + AFL_VERIFY(operation.ready()); + + Ydb::Table::ExecuteQueryResult result; + operation.result().UnpackTo(&result); + + if (auto status = Stages.front()->HandleResult(result); status.IsFail()) { + Controller->OnModificationProblem(status.GetErrorMessage()); TBase::PassAway(); + return; } + + AdvanceStage(); } - virtual void Handle(NRequest::TEvRequestFailed::TPtr& ev) { + void Handle(NRequest::TEvRequestFailed::TPtr& ev) { auto g = TBase::PassAwayGuard(); - Controller->OnModificationProblem("cannot execute yql request for " + GetModifyType() + - " objects: " + ev->Get()->GetErrorMessage()); + if (auto status = Stages.front()->HandleError(*ev->Get()); status.IsFail()) { + Controller->OnModificationProblem(status.GetErrorMessage()); + } else { + Controller->OnModificationFinished(); + } } public: - TModifyObjectsActor(NInternal::TTableRecords&& objects, const NACLib::TUserToken& systemUserToken, IModificationObjectsController::TPtr controller, const TString& sessionId, - const TString& transactionId, const std::optional& userToken) + TModifyObjectsActor(NInternal::TTableRecords&& objects, const NACLib::TUserToken& systemUserToken, + IModificationObjectsController::TPtr controller, const TString& sessionId, const TString& transactionId, + const std::optional& userToken, const std::vector& preconditions) : Controller(controller) , SessionId(sessionId) , TransactionId(transactionId) @@ -75,6 +136,7 @@ class TModifyObjectsActor: public NActors::TActorBootstrappedset_commit_tx(true); + Y_ABORT_UNLESS(Stages.size()); + Stages.back()->SetCommit(); - TBase::Register(new NRequest::TYDBCallbackRequest( - Requests.front(), SystemUserToken, TBase::SelfId())); - Requests.pop_front(); + TBase::Register(new NRequest::TYDBCallbackRequest(Stages.front()->GetRequest(), SystemUserToken, TBase::SelfId())); } }; @@ -148,6 +208,23 @@ class TDeleteObjectsActor: public TModifyObjectsActor { using TBase::TBase; }; +class TStageInsertObjects: public NModifications::TModificationStage { +private: + const bool ExistingOk; + +public: + TConclusionStatus HandleError(const NRequest::TEvRequestFailed& ev) const override { + if (ExistingOk && ev.GetStatus() == Ydb::StatusIds::PRECONDITION_FAILED) { + return TConclusionStatus::Success(); + } + return TConclusionStatus::Fail(ev.GetErrorMessage()); + } + + TStageInsertObjects(Ydb::Table::ExecuteDataQueryRequest request, const bool existingOk) + : TModificationStage(std::move(request)), ExistingOk(existingOk) { + } +}; + template class TInsertObjectsActor: public TModifyObjectsActor { private: @@ -161,19 +238,13 @@ class TInsertObjectsActor: public TModifyObjectsActor { return "insert"; } - void Handle(NRequest::TEvRequestFailed::TPtr& ev) override { - if (ev->Get()->GetStatus() == Ydb::StatusIds::PRECONDITION_FAILED && ExistingOk) { - NRequest::TDialogYQLRequest::TResponse resp; - this->Send(this->SelfId(), new NRequest::TEvRequestResult(std::move(resp))); - this->Requests.clear(); // Remove history request - return; - } - TBase::Handle(ev); + TModificationStage::TPtr DoBuildRequestDirect(Ydb::Table::ExecuteDataQueryRequest query) const override { + return std::make_shared(std::move(query), ExistingOk); } public: TInsertObjectsActor(NInternal::TTableRecords&& objects, const NACLib::TUserToken& systemUserToken, IModificationObjectsController::TPtr controller, const TString& sessionId, - const TString& transactionId, const std::optional& userToken, bool existingOk) - : TBase(std::move(objects), systemUserToken, std::move(controller), sessionId, transactionId, userToken) + const TString& transactionId, const std::optional& userToken, const std::vector& preconditions, bool existingOk) + : TBase(std::move(objects), systemUserToken, std::move(controller), sessionId, transactionId, userToken, preconditions) , ExistingOk(existingOk) { } diff --git a/ydb/services/metadata/secret/checker_secret.cpp b/ydb/services/metadata/secret/checker_secret.cpp index b9d54935ea5a..e612d291aa35 100644 --- a/ydb/services/metadata/secret/checker_secret.cpp +++ b/ydb/services/metadata/secret/checker_secret.cpp @@ -8,21 +8,31 @@ namespace NKikimr::NMetadata::NSecret { void TSecretPreparationActor::StartChecker() { Y_ABORT_UNLESS(Secrets); auto g = PassAwayGuard(); - for (auto&& i : Objects) { + THashMap secretNameToOwner; + for (auto&& object : Objects) { + if (Context.GetActivityType() == NModifications::IOperationsManager::EActivityType::Create || + Context.GetActivityType() == NModifications::IOperationsManager::EActivityType::Upsert) { + const auto* findSecret = secretNameToOwner.FindPtr(object.GetSecretId()); + if (findSecret && *findSecret != object.GetOwnerUserId()) { + Controller->OnPreparationProblem("cannot create multiple secrets with same id: " + object.GetSecretId()); + return; + } + } if (Context.GetActivityType() == NModifications::IOperationsManager::EActivityType::Alter) { - if (!Secrets->GetSecrets().contains(i)) { - Controller->OnPreparationProblem("secret " + i.GetSecretId() + " not found for alter"); + if (!Secrets->GetSecrets().contains(object)) { + Controller->OnPreparationProblem("secret " + object.GetSecretId() + " not found for alter"); return; } } for (auto&& sa : Secrets->GetAccess()) { if (Context.GetActivityType() == NModifications::IOperationsManager::EActivityType::Drop) { - if (sa.GetOwnerUserId() == i.GetOwnerUserId() && sa.GetSecretId() == i.GetSecretId()) { - Controller->OnPreparationProblem("secret " + i.GetSecretId() + " using in access for " + sa.GetAccessSID()); + if (sa.GetOwnerUserId() == object.GetOwnerUserId() && sa.GetSecretId() == object.GetSecretId()) { + Controller->OnPreparationProblem("secret " + object.GetSecretId() + " using in access for " + sa.GetAccessSID()); return; } } } + secretNameToOwner.emplace(object.GetSecretId(), object.GetOwnerUserId()); } Controller->OnPreparationFinished(std::move(Objects)); } diff --git a/ydb/services/metadata/secret/initializer.cpp b/ydb/services/metadata/secret/initializer.cpp index 045f83898de3..4be1f480128d 100644 --- a/ydb/services/metadata/secret/initializer.cpp +++ b/ydb/services/metadata/secret/initializer.cpp @@ -33,6 +33,19 @@ void TSecretInitializer::DoPrepare(NInitializer::IInitializerInput::TPtr control } result.emplace_back(NInitializer::TACLModifierConstructor::GetNoAccessModifier(TSecret::GetBehaviour()->GetStorageTablePath(), "acl")); result.emplace_back(NInitializer::TACLModifierConstructor::GetNoAccessModifier(TSecret::GetBehaviour()->GetStorageHistoryTablePath(), "acl_history")); + { + Ydb::Table::AlterTableRequest request; + request.set_session_id(""); + request.set_path(TSecret::GetBehaviour()->GetStorageTablePath()); + { + auto& index = *request.add_add_indexes(); + index.set_name("index_by_secret_id"); + index.add_index_columns(TSecret::TDecoder::SecretId); + index.add_index_columns(TSecret::TDecoder::OwnerUserId); + index.mutable_global_index(); + } + result.emplace_back(new NInitializer::TGenericTableModifier(request, "add_index_by_secret_id")); + } controller->OnPreparationFinished(result); } diff --git a/ydb/services/metadata/secret/manager.cpp b/ydb/services/metadata/secret/manager.cpp index 882c282064f4..5d08d2e2c52e 100644 --- a/ydb/services/metadata/secret/manager.cpp +++ b/ydb/services/metadata/secret/manager.cpp @@ -1,10 +1,62 @@ #include "checker_access.h" #include "checker_secret.h" #include "manager.h" + #include +#include + namespace NKikimr::NMetadata::NSecret { +class TCheckSecretNameUnique: public NModifications::TModificationStage { +private: + THashMap SecretNameToOwner; + + static Ydb::Table::ExecuteDataQueryRequest BuildRequest(std::vector secrets) { + std::vector secretNameLiterals; + for (const auto& id : secrets) { + secretNameLiterals.push_back(TStringBuilder() << '"' << id.GetSecretId() << '"'); + } + + Ydb::Table::ExecuteDataQueryRequest request; + TStringBuilder sb; + sb << "SELECT " + TSecret::TDecoder::SecretId + ", " + TSecret::TDecoder::OwnerUserId + ", " + TSecret::TDecoder::Value << Endl; + sb << "FROM `" + TSecret::GetBehaviour()->GetStorageTablePath() + "`" << Endl; + sb << "VIEW index_by_secret_id" << Endl; + sb << "WHERE " + TSecret::TDecoder::SecretId + " IN (" + JoinStrings(secretNameLiterals.begin(), secretNameLiterals.end(), ", ") + ")" + << Endl; + AFL_DEBUG(NKikimrServices::METADATA_SECRET)("event", "build_precondition")("sql", sb); + request.mutable_query()->set_yql_text(sb); + return request; + } + +public: + TConclusionStatus HandleResult(const Ydb::Table::ExecuteQueryResult& result) const override { + AFL_VERIFY(result.result_sets_size() == 1)("size", result.result_sets_size()); + const auto& resultSet = result.result_sets(0); + TSecret::TDecoder decoder(resultSet); + + for (const auto& row : resultSet.rows()) { + TSecret secret; + AFL_VERIFY(secret.DeserializeFromRecord(decoder, row)); + auto findOwner = SecretNameToOwner.FindPtr(secret.GetSecretId()); + AFL_VERIFY(findOwner); + if (*findOwner != secret.GetOwnerUserId()) { + return TConclusionStatus::Fail("Secret already exists: " + secret.GetSecretId()); + } + } + + return TConclusionStatus::Success(); + } + + TCheckSecretNameUnique(std::vector secrets) + : TModificationStage(BuildRequest(secrets)) { + for (const auto& id : secrets) { + AFL_VERIFY(SecretNameToOwner.emplace(id.GetSecretId(), id.GetOwnerUserId()).second); + } + } +}; + void TAccessManager::DoPrepareObjectsBeforeModification(std::vector&& patchedObjects, NModifications::IAlterPreparationController::TPtr controller, const TInternalModificationContext& context, const NMetadata::NModifications::TAlterOperationContext& /*alterContext*/) const { if (context.GetActivityType() == IOperationsManager::EActivityType::Alter) { @@ -100,4 +152,16 @@ void TSecretManager::DoPrepareObjectsBeforeModification(std::vector&& p TActivationContext::Register(new TSecretPreparationActor(std::move(patchedObjects), controller, context)); } +std::vector TSecretManager::GetPreconditions( + const std::vector& objects, const IOperationsManager::TInternalModificationContext& context) const { + if (context.GetActivityType() == NModifications::IOperationsManager::EActivityType::Create || + context.GetActivityType() == NModifications::IOperationsManager::EActivityType::Upsert) { + std::vector secretIds; + for (const auto& secret : objects) { + secretIds.emplace_back(TSecretId(secret.GetOwnerUserId(), secret.GetSecretId())); + } + return { std::make_shared(std::move(secretIds)) }; + } + return {}; +} } diff --git a/ydb/services/metadata/secret/manager.h b/ydb/services/metadata/secret/manager.h index df231cdb65f0..a415f6c331e8 100644 --- a/ydb/services/metadata/secret/manager.h +++ b/ydb/services/metadata/secret/manager.h @@ -14,6 +14,9 @@ class TSecretManager: public NModifications::TGenericOperationsManager virtual NModifications::TOperationParsingResult DoBuildPatchFromSettings( const NYql::TObjectSettingsImpl& settings, TInternalModificationContext& context) const override; + + virtual std::vector GetPreconditions( + const std::vector& objects, const IOperationsManager::TInternalModificationContext& context) const override; }; class TAccessManager: public NModifications::TGenericOperationsManager { diff --git a/ydb/services/metadata/secret/snapshot.cpp b/ydb/services/metadata/secret/snapshot.cpp index 2a1a38121fb5..b43faa810024 100644 --- a/ydb/services/metadata/secret/snapshot.cpp +++ b/ydb/services/metadata/secret/snapshot.cpp @@ -2,10 +2,18 @@ namespace NKikimr::NMetadata::NSecret { +void TSnapshot::BuildIndex() { + IndexByName.clear(); + for (const auto& [id, secret] : Secrets) { + IndexByName[id.GetSecretId()].emplace_back(id); + } +} + bool TSnapshot::DoDeserializeFromResultSet(const Ydb::Table::ExecuteQueryResult& rawDataResult) { Y_ABORT_UNLESS(rawDataResult.result_sets().size() == 2); ParseSnapshotObjects(rawDataResult.result_sets()[0], [this](TSecret&& s) {Secrets.emplace(s, s); }); ParseSnapshotObjects(rawDataResult.result_sets()[1], [this](TAccess&& s) {Access.emplace_back(std::move(s)); }); + BuildIndex(); return true; } diff --git a/ydb/services/metadata/secret/snapshot.h b/ydb/services/metadata/secret/snapshot.h index 6b1f97871d61..c216aa73dee2 100644 --- a/ydb/services/metadata/secret/snapshot.h +++ b/ydb/services/metadata/secret/snapshot.h @@ -11,8 +11,12 @@ class TSnapshot: public NFetcher::ISnapshot { private: using TBase = NFetcher::ISnapshot; using TSecrets = std::map; + using TIdsByName = THashMap>; YDB_READONLY_DEF(TSecrets, Secrets); YDB_READONLY_DEF(std::vector, Access); + YDB_READONLY_DEF(TIdsByName, IndexByName); +private: + void BuildIndex(); protected: virtual bool DoDeserializeFromResultSet(const Ydb::Table::ExecuteQueryResult& rawData) override; virtual TString DoSerializeToString() const override; diff --git a/ydb/services/metadata/secret/ut/ut_secret.cpp b/ydb/services/metadata/secret/ut/ut_secret.cpp index b7b215659432..16da9e76d149 100644 --- a/ydb/services/metadata/secret/ut/ut_secret.cpp +++ b/ydb/services/metadata/secret/ut/ut_secret.cpp @@ -197,7 +197,7 @@ Y_UNIT_TEST_SUITE(Secret) { { TString resultData; lHelper.StartDataRequest("SELECT COUNT(*) FROM `/Root/.metadata/initialization/migrations`", true, &resultData); - UNIT_ASSERT_EQUAL_C(resultData, "[6u]", resultData); + UNIT_ASSERT_EQUAL_C(resultData, "[7u]", resultData); } emulator->SetExpectedSecretsCount(2).SetExpectedAccessCount(0).CheckFound(); @@ -214,7 +214,7 @@ Y_UNIT_TEST_SUITE(Secret) { { TString resultData; lHelper.StartDataRequest("SELECT COUNT(*) FROM `/Root/.metadata/initialization/migrations`", true, &resultData); - UNIT_ASSERT_EQUAL_C(resultData, "[10u]", resultData); + UNIT_ASSERT_EQUAL_C(resultData, "[11u]", resultData); } emulator->SetExpectedSecretsCount(2).SetExpectedAccessCount(1).CheckFound(); @@ -296,10 +296,17 @@ Y_UNIT_TEST_SUITE(Secret) { lHelper.StartSchemaRequest("CREATE OBJECT IF NOT EXISTS `secret1:test@test1` (TYPE SECRET_ACCESS)"); lHelper.StartSchemaRequest("DROP OBJECT `secret1` (TYPE SECRET)", false); lHelper.StartDataRequest("SELECT * FROM `/Root/.metadata/secrets/values`", false); + + lHelper.SetAuthToken("test@test1"); + lHelper.StartSchemaRequest("CREATE OBJECT secret1 (TYPE SECRET) WITH value = `100`", false); + lHelper.StartSchemaRequest("UPSERT OBJECT secret1 (TYPE SECRET) WITH value = `100`", false); + lHelper.StartSchemaRequest("CREATE OBJECT secret2 (TYPE SECRET) WITH value = `100`"); + lHelper.ResetAuthToken(); + { TString resultData; lHelper.StartDataRequest("SELECT COUNT(*) FROM `/Root/.metadata/initialization/migrations`", true, &resultData); - UNIT_ASSERT_EQUAL_C(resultData, "[10u]", resultData); + UNIT_ASSERT_EQUAL_C(resultData, "[11u]", resultData); } } }