diff --git a/ydb/core/blobstorage/base/blobstorage_console_events.h b/ydb/core/blobstorage/base/blobstorage_console_events.h index fea8a4dd1eef..eb6798f35d68 100644 --- a/ydb/core/blobstorage/base/blobstorage_console_events.h +++ b/ydb/core/blobstorage/base/blobstorage_console_events.h @@ -77,14 +77,9 @@ namespace NKikimr { NKikimrBlobStorage::TEvControllerReplaceConfigRequest, EvControllerReplaceConfigRequest> { TEvControllerReplaceConfigRequest() = default; - TEvControllerReplaceConfigRequest( - std::optional clusterYaml, - std::optional storageYaml, - std::optional switchDedicatedStorageSection, - bool dedicatedConfigMode, - bool allowUnknownFields, - bool bypassMetadataChecks) { - + TEvControllerReplaceConfigRequest(std::optional clusterYaml, std::optional storageYaml, + std::optional switchDedicatedStorageSection, bool dedicatedConfigMode, bool allowUnknownFields, + bool bypassMetadataChecks, bool enableConfigV2, bool disableConfigV2) { if (clusterYaml) { Record.SetClusterYaml(*clusterYaml); } @@ -97,6 +92,11 @@ namespace NKikimr { Record.SetDedicatedConfigMode(dedicatedConfigMode); Record.SetAllowUnknownFields(allowUnknownFields); Record.SetBypassMetadataChecks(bypassMetadataChecks); + if (enableConfigV2) { + Record.SetSwitchEnableConfigV2(true); + } else if (disableConfigV2) { + Record.SetSwitchEnableConfigV2(false); + } } TString ToString() const override { diff --git a/ydb/core/blobstorage/nodewarden/distconf_console.cpp b/ydb/core/blobstorage/nodewarden/distconf_console.cpp index a02ab98404da..c05867db04ad 100644 --- a/ydb/core/blobstorage/nodewarden/distconf_console.cpp +++ b/ydb/core/blobstorage/nodewarden/distconf_console.cpp @@ -213,7 +213,7 @@ namespace NKikimr::NStorage { if (!fetched) { // fill in 'to-be-fetched' version of config with version incremented by one try { auto metadata = NYamlConfig::GetMainMetadata(yaml); - metadata.Cluster = metadata.Cluster.value_or("unknown"); // TODO: fix this + metadata.Cluster = metadata.Cluster.value_or(AppData()->ClusterName); metadata.Version = metadata.Version.value_or(0) + 1; temp = NYamlConfig::ReplaceMetadata(yaml, metadata); } catch (const std::exception& ex) { diff --git a/ydb/core/blobstorage/nodewarden/distconf_invoke_storage_config.cpp b/ydb/core/blobstorage/nodewarden/distconf_invoke_storage_config.cpp index eea8ca22190f..8d3ce407cd36 100644 --- a/ydb/core/blobstorage/nodewarden/distconf_invoke_storage_config.cpp +++ b/ydb/core/blobstorage/nodewarden/distconf_invoke_storage_config.cpp @@ -13,20 +13,17 @@ namespace NKikimr::NStorage { void TInvokeRequestHandlerActor::FetchStorageConfig(bool manual, bool fetchMain, bool fetchStorage) { if (!Self->StorageConfig) { FinishWithError(TResult::ERROR, "no agreed StorageConfig"); - } else if (!Self->MainConfigFetchYaml) { + } else if (!Self->MainConfigYaml) { FinishWithError(TResult::ERROR, "no stored YAML for storage config"); } else { auto ev = PrepareResult(TResult::OK, std::nullopt); auto *record = &ev->Record; auto *res = record->MutableFetchStorageConfig(); if (fetchMain) { - res->SetYAML(Self->MainConfigFetchYaml); + res->SetYAML(Self->MainConfigYaml); } if (fetchStorage && Self->StorageConfigYaml) { - auto metadata = NYamlConfig::GetStorageMetadata(*Self->StorageConfigYaml); - metadata.Cluster = metadata.Cluster.value_or("unknown"); // TODO: fix this - metadata.Version = metadata.Version.value_or(0) + 1; - res->SetStorageYAML(NYamlConfig::ReplaceMetadata(*Self->StorageConfigYaml, metadata)); + res->SetStorageYAML(*Self->StorageConfigYaml); } if (manual) { @@ -48,6 +45,22 @@ namespace NKikimr::NStorage { NewYaml = request.HasYAML() ? std::make_optional(request.GetYAML()) : std::nullopt; NewStorageYaml = request.HasStorageYAML() ? std::make_optional(request.GetStorageYAML()) : std::nullopt; + // check if we are really changing something? + if (NewYaml == Self->MainConfigYaml) { + NewYaml.reset(); + } + if (NewStorageYaml == Self->StorageConfigYaml) { + NewStorageYaml.reset(); + } + if (!NewYaml && !NewStorageYaml) { + if (request.HasSwitchDedicatedStorageSection()) { + return FinishWithError(TResult::ERROR, "switching dedicated storage section mode without providing any new config"); + } else { + // finish this request prematurely: no configs are actually changed + return Finish(Sender, SelfId(), PrepareResult(TResult::OK, std::nullopt).release(), 0, Cookie); + } + } + // start deriving a config from current one TString state; NKikimrBlobStorage::TStorageConfig config(*Self->StorageConfig); @@ -67,6 +80,10 @@ namespace NKikimr::NStorage { throw yexception() << "missing or invalid kind provided"; } version = metadata["version"].GetUIntegerRobust(); + if (metadata.Has("cluster") && metadata["cluster"] != AppData()->ClusterName) { + throw yexception() << "cluster name mismatch: provided# " << metadata["cluster"] + << " expected# " << AppData()->ClusterName; + } state = TStringBuilder() << "validating " << expectedKind << " config section"; if (!json.Has("config") || !json["config"].IsMap()) { diff --git a/ydb/core/cms/console/console_configs_manager.cpp b/ydb/core/cms/console/console_configs_manager.cpp index 625bf1277348..80bbe991408c 100644 --- a/ydb/core/cms/console/console_configs_manager.cpp +++ b/ydb/core/cms/console/console_configs_manager.cpp @@ -56,7 +56,7 @@ void TConfigsManager::ReplaceMainConfigMetadata(const TString &config, bool forc try { if (!force) { auto metadata = NYamlConfig::GetMainMetadata(config); - opCtx.Cluster = metadata.Cluster.value_or(TString("unknown")); + opCtx.Cluster = metadata.Cluster.value_or(ClusterName); opCtx.Version = metadata.Version.value_or(0); } else { opCtx.Cluster = ClusterName; diff --git a/ydb/core/grpc_services/rpc_config.cpp b/ydb/core/grpc_services/rpc_config.cpp index 6ff65e193f74..914356f3a745 100644 --- a/ydb/core/grpc_services/rpc_config.cpp +++ b/ydb/core/grpc_services/rpc_config.cpp @@ -232,7 +232,9 @@ class TReplaceStorageConfigRequest : public TBSConfigRequestGrpcallow_unknown_fields() || request->bypass_checks(), - request->bypass_checks()); + request->bypass_checks(), + false /* TODO: implement */, + false /* TODO: implement */); } private: diff --git a/ydb/core/grpc_services/rpc_config_base.h b/ydb/core/grpc_services/rpc_config_base.h index f65cfeed6ccb..39b5d526de3f 100644 --- a/ydb/core/grpc_services/rpc_config_base.h +++ b/ydb/core/grpc_services/rpc_config_base.h @@ -284,6 +284,14 @@ class TBSConfigRequestGrpc : public TRpcOperationRequestActor) { TResultRecord result; const auto& record = ev->Get()->Record; + if (record.HasErrorReason()) { + const auto status = record.GetDisabledConfigV2() + ? Ydb::StatusIds::UNSUPPORTED + : Ydb::StatusIds::INTERNAL_ERROR; + self->Reply(status, TStringBuilder() << "failed to fetch config: " << record.GetErrorReason(), + NKikimrIssues::TIssuesIds::DEFAULT_ERROR, self->ActorContext()); + return; + } if (record.HasClusterYaml()) { auto conf = ev->Get()->Record.GetClusterYaml(); auto metadata = NYamlConfig::GetMainMetadata(conf); @@ -327,7 +335,10 @@ class TBSConfigRequestGrpc : public TRpcOperationRequestActorReplyWithResult(Ydb::StatusIds::SUCCESS, result, self->ActorContext()); } else { - self->Reply(Ydb::StatusIds::INTERNAL_ERROR, TStringBuilder() << "failed to replace configuration: " + const auto status = record.GetDisabledConfigV2() + ? Ydb::StatusIds::UNSUPPORTED + : Ydb::StatusIds::INTERNAL_ERROR; + self->Reply(status, TStringBuilder() << "failed to replace configuration: " << NKikimrBlobStorage::TEvControllerReplaceConfigResponse::EStatus_Name(record.GetStatus()) << ": " << record.GetErrorReason(), NKikimrIssues::TIssuesIds::DEFAULT_ERROR, self->ActorContext()); } diff --git a/ydb/core/mind/bscontroller/bsc.cpp b/ydb/core/mind/bscontroller/bsc.cpp index 812b2f69eca4..1b61b1a0d7a8 100644 --- a/ydb/core/mind/bscontroller/bsc.cpp +++ b/ydb/core/mind/bscontroller/bsc.cpp @@ -442,7 +442,7 @@ void TBlobStorageController::Handle(TEvBlobStorage::TEvControllerDistconfRequest // commit it Execute(CreateTxCommitConfig(std::move(yamlConfig), std::make_optional(std::move(storageYaml)), std::nullopt, - expectedStorageYamlConfigVersion, std::exchange(h, {}))); + expectedStorageYamlConfigVersion, std::exchange(h, {}), std::nullopt)); break; } diff --git a/ydb/core/mind/bscontroller/commit_config.cpp b/ydb/core/mind/bscontroller/commit_config.cpp index 6eae3ac61e90..fca8960d51a5 100644 --- a/ydb/core/mind/bscontroller/commit_config.cpp +++ b/ydb/core/mind/bscontroller/commit_config.cpp @@ -15,6 +15,7 @@ namespace NKikimr::NBsController { std::optional StorageConfig; std::optional ExpectedStorageYamlConfigVersion; std::unique_ptr Handle; + std::optional SwitchEnableConfigV2; ui64 GenerationOnStart = 0; TString FingerprintOnStart; @@ -23,13 +24,15 @@ namespace NKikimr::NBsController { TTxCommitConfig(TBlobStorageController *controller, std::optional&& yamlConfig, std::optional>&& storageYamlConfig, std::optional&& storageConfig, - std::optional expectedStorageYamlConfigVersion, std::unique_ptr handle) + std::optional expectedStorageYamlConfigVersion, std::unique_ptr handle, + std::optional switchEnableConfigV2) : TTransactionBase(controller) , YamlConfig(std::move(yamlConfig)) , StorageYamlConfig(std::move(storageYamlConfig)) , StorageConfig(std::move(storageConfig)) , ExpectedStorageYamlConfigVersion(expectedStorageYamlConfigVersion) , Handle(std::move(handle)) + , SwitchEnableConfigV2(switchEnableConfigV2) {} TTxType GetTxType() const override { return NBlobStorageController::TXTYPE_COMMIT_CONFIG; } @@ -53,6 +56,9 @@ namespace NKikimr::NBsController { if (ExpectedStorageYamlConfigVersion) { row.Update(*ExpectedStorageYamlConfigVersion); } + if (SwitchEnableConfigV2) { + row.Update(*SwitchEnableConfigV2); + } return true; } @@ -104,6 +110,9 @@ namespace NKikimr::NBsController { if (update && Self->StorageYamlConfig) { update->SetStorageConfigVersion(NYamlConfig::GetStorageMetadata(*Self->StorageYamlConfig).Version.value_or(0)); } + if (SwitchEnableConfigV2) { + Self->EnableConfigV2 = *SwitchEnableConfigV2; + } if (Handle) { TActivationContext::Send(Handle.release()); @@ -126,9 +135,10 @@ namespace NKikimr::NBsController { ITransaction* TBlobStorageController::CreateTxCommitConfig(std::optional&& yamlConfig, std::optional>&& storageYamlConfig, std::optional&& storageConfig, - std::optional expectedStorageYamlConfigVersion, std::unique_ptr handle) { + std::optional expectedStorageYamlConfigVersion, std::unique_ptr handle, + std::optional switchEnableConfigV2) { return new TTxCommitConfig(this, std::move(yamlConfig), std::move(storageYamlConfig), std::move(storageConfig), - expectedStorageYamlConfigVersion, std::move(handle)); + expectedStorageYamlConfigVersion, std::move(handle), switchEnableConfigV2); } } // namespace NKikimr::NBsController diff --git a/ydb/core/mind/bscontroller/console_interaction.cpp b/ydb/core/mind/bscontroller/console_interaction.cpp index 84c2399d5003..a506e0cfac81 100644 --- a/ydb/core/mind/bscontroller/console_interaction.cpp +++ b/ydb/core/mind/bscontroller/console_interaction.cpp @@ -75,6 +75,10 @@ namespace NKikimr::NBsController { auto& record = ev->Get()->Record; STLOG(PRI_DEBUG, BS_CONTROLLER, BSC19, "Console proposed config response", (Response, record)); + if (!Self.EnableConfigV2 && !PendingReplaceRequest) { + return; + } + auto overwriteConfig = [&] { TString yamlReturnedByFetch = record.GetYAML(); if (!yamlReturnedByFetch) { @@ -101,7 +105,7 @@ namespace NKikimr::NBsController { TYamlConfig yamlConfig(std::move(yaml), version, std::move(yamlReturnedByFetch)); Self.Execute(Self.CreateTxCommitConfig(std::move(yamlConfig), std::nullopt, - std::move(storageConfig), std::nullopt, nullptr)); + std::move(storageConfig), std::nullopt, nullptr, std::nullopt)); CommitInProgress = true; } } catch (const std::exception& ex) { @@ -146,14 +150,17 @@ namespace NKikimr::NBsController { break; case NKikimrBlobStorage::TEvControllerProposeConfigResponse::ReverseCommit: - if (!Self.YamlConfig && !Self.StorageYamlConfig) { + if (PendingReplaceRequest) { + ExpectedYamlConfigVersion.emplace(record.GetConsoleConfigVersion()); + Handle(PendingReplaceRequest); + PendingReplaceRequest.Reset(); + } else if (!Self.YamlConfig && !Self.StorageYamlConfig) { overwriteConfig(); } else { STLOG(PRI_CRIT, BS_CONTROLLER, BSC29, "ReverseCommit status received when BSC has YamlConfig/StorageYamlConfig", (YamlConfig, Self.YamlConfig), (StorageYamlConfig, Self.StorageYamlConfig), (Record, record)); Y_DEBUG_ABORT(); } - break; default: @@ -217,10 +224,15 @@ namespace NKikimr::NBsController { auto& record = ev->Get()->Record; - if (!Working || CommitInProgress || ClientId) { + const bool reasonOngoingCommit = CommitInProgress || (ClientId && ClientId != ev->Sender); + if (reasonOngoingCommit || (!Self.EnableConfigV2 && !record.GetSwitchEnableConfigV2())) { // reply to newly came query const TActorId temp = std::exchange(ClientId, ev->Sender); - IssueGRpcResponse(NKikimrBlobStorage::TEvControllerReplaceConfigResponse::OngoingCommit, "ongoing commit"); + if (reasonOngoingCommit) { + IssueGRpcResponse(NKikimrBlobStorage::TEvControllerReplaceConfigResponse::OngoingCommit, "ongoing commit"); + } else { + IssueGRpcResponse(NKikimrBlobStorage::TEvControllerReplaceConfigResponse::InvalidRequest, "configuration v2 is disabled", true); + } ClientId = temp; return; } @@ -233,6 +245,34 @@ namespace NKikimr::NBsController { "configuration is locked by distconf"); } + SwitchEnableConfigV2 = record.HasSwitchEnableConfigV2() + ? std::make_optional(record.GetSwitchEnableConfigV2()) + : std::nullopt; + + if (!Self.EnableConfigV2 && record.HasSwitchDedicatedStorageSection()) { + return IssueGRpcResponse(NKikimrBlobStorage::TEvControllerReplaceConfigResponse::InvalidRequest, + "can't enable configuration v2 and switch dedicated storage section mode at the same time"); + } + + if (Self.EnableConfigV2 && SwitchEnableConfigV2 && !*SwitchEnableConfigV2 && Self.StorageYamlConfig) { + return IssueGRpcResponse(NKikimrBlobStorage::TEvControllerReplaceConfigResponse::InvalidRequest, + "can't revert to configuration v1 with dedicated storage section enabled"); + } + + if (!Self.EnableConfigV2 && !PendingReplaceRequest) { + Y_ABORT_UNLESS(SwitchEnableConfigV2); + Y_ABORT_UNLESS(*SwitchEnableConfigV2); + if (!ConsolePipe) { + return IssueGRpcResponse(NKikimrBlobStorage::TEvControllerReplaceConfigResponse::SessionClosed, + "connection to Console tablet terminated"); + } + + // just ask console for the latest config + NTabletPipe::SendData(Self.SelfId(), ConsolePipe, new TEvBlobStorage::TEvControllerProposeConfigRequest); + PendingReplaceRequest = std::move(ev); + return; + } + PendingStorageYamlConfig.reset(); if (Self.StorageYamlConfig.has_value()) { // separate configuration @@ -282,17 +322,29 @@ namespace NKikimr::NBsController { if (record.HasClusterYaml()) { PendingYamlConfig.emplace(record.GetClusterYaml()); + // don't need to reset them explicitly // every time we get new request we just replace them AllowUnknownFields = record.GetAllowUnknownFields(); + + if (Self.YamlConfig && PendingYamlConfig == std::get<0>(*Self.YamlConfig)) { + PendingYamlConfig.reset(); // no cluster yaml config changed + } } else { PendingYamlConfig.reset(); } + if (PendingStorageYamlConfig == Self.StorageYamlConfig) { + PendingStorageYamlConfig.reset(); // no storage yaml config changed + } + + if (!PendingYamlConfig && !PendingStorageYamlConfig) { + // nothing changes -- finish request now + return IssueGRpcResponse(NKikimrBlobStorage::TEvControllerReplaceConfigResponse::Success); + } + if (PendingYamlConfig) { - const ui64 expected = Self.YamlConfig - ? GetVersion(*Self.YamlConfig) + 1 - : 0; + const ui64 expected = ExpectedYamlConfigVersion.value_or(Self.YamlConfig ? GetVersion(*Self.YamlConfig) + 1 : 0); if (!NYamlConfig::IsMainConfig(*PendingYamlConfig)) { return IssueGRpcResponse(NKikimrBlobStorage::TEvControllerReplaceConfigResponse::InvalidRequest, @@ -301,6 +353,10 @@ namespace NKikimr::NBsController { return IssueGRpcResponse(NKikimrBlobStorage::TEvControllerReplaceConfigResponse::InvalidRequest, TStringBuilder() << "cluster YAML config version mismatch got# " << meta.Version << " expected# " << expected); + } else if (meta.Cluster != AppData()->ClusterName) { + return IssueGRpcResponse(NKikimrBlobStorage::TEvControllerReplaceConfigResponse::InvalidRequest, + TStringBuilder() << "cluster YAML config cluster name mismatch got# " << meta.Cluster + << " expected# " << AppData()->ClusterName); } } @@ -314,7 +370,11 @@ namespace NKikimr::NBsController { return IssueGRpcResponse(NKikimrBlobStorage::TEvControllerReplaceConfigResponse::InvalidRequest, TStringBuilder() << "storage YAML config version mismatch got# " << meta.Version << " expected# " << expected); - } + } else if (meta.Cluster != AppData()->ClusterName) { + return IssueGRpcResponse(NKikimrBlobStorage::TEvControllerReplaceConfigResponse::InvalidRequest, + TStringBuilder() << "storage YAML config cluster name mismatch got# " << meta.Cluster + << " expected# " << AppData()->ClusterName); + } } if (record.GetSkipConsoleValidation() || !record.HasClusterYaml()) { @@ -342,21 +402,23 @@ namespace NKikimr::NBsController { void TBlobStorageController::TConsoleInteraction::Handle(TEvBlobStorage::TEvControllerFetchConfigRequest::TPtr &ev) { const auto& record = ev->Get()->Record; auto response = std::make_unique(); - if (!Self.ConfigLock.empty() || Self.SelfManagementEnabled) { + if (!Self.EnableConfigV2) { + response->Record.SetErrorReason("configuration v2 is disabled"); + response->Record.SetDisabledConfigV2(true); + } else if (!Self.ConfigLock.empty() || Self.SelfManagementEnabled) { response->Record.SetErrorReason("configuration is locked by distconf"); } else if (Self.StorageYamlConfig) { if (record.GetDedicatedStorageSection()) { - // TODO(alexvru): increment generation response->Record.SetStorageYaml(*Self.StorageYamlConfig); } if (record.GetDedicatedClusterSection() && Self.YamlConfig) { const auto& [yaml, configVersion, yamlReturnedByFetch] = *Self.YamlConfig; - response->Record.SetClusterYaml(yamlReturnedByFetch); + response->Record.SetClusterYaml(yaml); } } else { if (!record.GetDedicatedClusterSection() && !record.GetDedicatedStorageSection() && Self.YamlConfig) { const auto& [yaml, configVersion, yamlReturnedByFetch] = *Self.YamlConfig; - response->Record.SetClusterYaml(yamlReturnedByFetch); + response->Record.SetClusterYaml(yaml); } } auto h = std::make_unique(ev->Sender, Self.SelfId(), response.release(), 0, ev->Cookie); @@ -455,7 +517,7 @@ namespace NKikimr::NBsController { } Self.Execute(Self.CreateTxCommitConfig(std::move(yamlConfig), std::exchange(PendingStorageYamlConfig, {}), - std::move(storageConfig), expectedStorageYamlConfigVersion, nullptr)); + std::move(storageConfig), expectedStorageYamlConfigVersion, nullptr, SwitchEnableConfigV2)); CommitInProgress = true; PendingYamlConfig.reset(); } catch (const TExError& error) { @@ -498,13 +560,20 @@ namespace NKikimr::NBsController { } void TBlobStorageController::TConsoleInteraction::IssueGRpcResponse( - NKikimrBlobStorage::TEvControllerReplaceConfigResponse::EStatus status, std::optional errorReason) { + NKikimrBlobStorage::TEvControllerReplaceConfigResponse::EStatus status, std::optional errorReason, + bool disabledConfigV2) { Y_ABORT_UNLESS(ClientId); - Self.Send(ClientId, new TEvBlobStorage::TEvControllerReplaceConfigResponse(status, std::move(errorReason))); + auto resp = std::make_unique(status, std::move(errorReason)); + if (disabledConfigV2) { + resp->Record.SetDisabledConfigV2(true); + } + Self.Send(ClientId, resp.release()); ClientId = {}; ++ExpectedValidationTimeoutCookie; // spoil validation cookie as incoming GRPC request has expired PendingYamlConfig.reset(); PendingStorageYamlConfig.reset(); + ExpectedYamlConfigVersion.reset(); + PendingReplaceRequest.Reset(); } } diff --git a/ydb/core/mind/bscontroller/console_interaction.h b/ydb/core/mind/bscontroller/console_interaction.h index 5b4d6adbf0a2..03a02425756b 100644 --- a/ydb/core/mind/bscontroller/console_interaction.h +++ b/ydb/core/mind/bscontroller/console_interaction.h @@ -47,18 +47,20 @@ namespace NKikimr::NBsController { bool NeedRetrySession = false; bool Working = false; bool CommitInProgress = false; + std::optional SwitchEnableConfigV2; + TEvBlobStorage::TEvControllerReplaceConfigRequest::TPtr PendingReplaceRequest; std::optional PendingYamlConfig; bool AllowUnknownFields = false; - std::optional> PendingStorageYamlConfig; + std::optional ExpectedYamlConfigVersion; void MakeCommitToConsole(TString& config, ui32 configVersion); void MakeGetBlock(); void MakeRetrySession(); void IssueGRpcResponse(NKikimrBlobStorage::TEvControllerReplaceConfigResponse::EStatus status, - std::optional errorReason = std::nullopt); + std::optional errorReason = std::nullopt, bool disabledConfigV2 = false); }; } diff --git a/ydb/core/mind/bscontroller/impl.h b/ydb/core/mind/bscontroller/impl.h index 567002a16443..a117728323fc 100644 --- a/ydb/core/mind/bscontroller/impl.h +++ b/ydb/core/mind/bscontroller/impl.h @@ -1562,6 +1562,7 @@ class TBlobStorageController : public TActor, public TTa bool AllowMultipleRealmsOccupation = true; bool StorageConfigObtained = false; bool Loaded = false; + bool EnableConfigV2 = false; std::shared_ptr EnableSelfHealWithDegraded; struct TLifetimeToken {}; @@ -1980,7 +1981,8 @@ class TBlobStorageController : public TActor, public TTa std::optional>&& storageYamlConfig, std::optional&& storageConfig, std::optional expectedStorageYamlConfigVersion, - std::unique_ptr handle); + std::unique_ptr handle, + std::optional switchEnableConfigV2); struct TVDiskAvailabilityTiming { TVSlotId VSlotId; diff --git a/ydb/core/mind/bscontroller/load_everything.cpp b/ydb/core/mind/bscontroller/load_everything.cpp index 803c1e7dc3f6..962e94b86dc3 100644 --- a/ydb/core/mind/bscontroller/load_everything.cpp +++ b/ydb/core/mind/bscontroller/load_everything.cpp @@ -109,6 +109,7 @@ class TBlobStorageController::TTxLoadEverything : public TTransactionBase()) { Self->ShredState.OnLoad(state.GetValue()); } + Self->EnableConfigV2 = state.GetValue(); } } @@ -472,14 +473,6 @@ class TBlobStorageController::TTxLoadEverything : public TTransactionBase().Key(key).Delete(); - } - for (const auto& key : vdiskMetricsToDelete) { - db.Table().Key(key).Delete(); - } - // apply storage pool stats std::unordered_map allocatedSizeMap; for (const auto& [vslotId, slot] : Self->VSlots) { @@ -523,6 +516,14 @@ class TBlobStorageController::TTxLoadEverything : public TTransactionBaseCalculateGroupStatus(); } + // primitive garbage collection for obsolete metrics + for (const auto& key : pdiskMetricsToDelete) { + db.Table().Key(key).Delete(); + } + for (const auto& key : vdiskMetricsToDelete) { + db.Table().Key(key).Delete(); + } + return true; } diff --git a/ydb/core/mind/bscontroller/migrate.cpp b/ydb/core/mind/bscontroller/migrate.cpp index 9c3fc52e7b29..8dc26b40c308 100644 --- a/ydb/core/mind/bscontroller/migrate.cpp +++ b/ydb/core/mind/bscontroller/migrate.cpp @@ -171,6 +171,14 @@ class TBlobStorageController::TTxMigrate : public TTransactionBase().Key(true).Update(true); + return true; + } + }; + TDeque> Queue; public: @@ -232,6 +240,10 @@ class TBlobStorageController::TTxMigrate : public TTransactionBase {}; struct StorageYamlConfig : Column<27, NScheme::NTypeIds::String> {}; struct ExpectedStorageYamlConfigVersion : Column<28, NScheme::NTypeIds::Uint64> {}; + struct EnableConfigV2 : Column<29, NScheme::NTypeIds::Bool> { static constexpr Type Default = false; }; using TKey = TableKey; using TColumns = TableColumns; + ExpectedStorageYamlConfigVersion, EnableConfigV2>; }; struct VSlot : Table<5> { diff --git a/ydb/core/protos/blobstorage.proto b/ydb/core/protos/blobstorage.proto index d5dc6759ef17..dcecae12f0cb 100644 --- a/ydb/core/protos/blobstorage.proto +++ b/ydb/core/protos/blobstorage.proto @@ -1448,6 +1448,7 @@ message TEvControllerReplaceConfigRequest { optional bool SkipConsoleValidation = 5; optional bool SwitchDedicatedStorageSection = 6; optional bool DedicatedConfigMode = 7; + optional bool SwitchEnableConfigV2 = 10; // if set, overrides EnableConfigV2 field in BSC // console flags optional bool AllowUnknownFields = 8; optional bool BypassMetadataChecks = 9; @@ -1466,6 +1467,7 @@ message TEvControllerReplaceConfigResponse { } optional EStatus Status = 1; optional string ErrorReason = 2; + optional bool DisabledConfigV2 = 3; // set along with InvalidRequest when Configuration V2 is disabled and BSC can't process this query } message TEvControllerValidateConfigRequest { @@ -1510,6 +1512,7 @@ message TEvControllerFetchConfigResponse { optional string ClusterYaml = 1; optional string StorageYaml = 2; optional string ErrorReason = 3; + optional bool DisabledConfigV2 = 4; } message TEvControllerDistconfRequest { diff --git a/ydb/public/lib/ydb_cli/commands/ydb_dynamic_config.cpp b/ydb/public/lib/ydb_cli/commands/ydb_dynamic_config.cpp index 3d9226a1431c..1e9ae43c8e28 100644 --- a/ydb/public/lib/ydb_cli/commands/ydb_dynamic_config.cpp +++ b/ydb/public/lib/ydb_cli/commands/ydb_dynamic_config.cpp @@ -110,7 +110,7 @@ int TCommandConfigFetch::Run(TConfig& config) { auto result = client.FetchAllConfigs(settings).GetValueSync(); // if the new Config API is not supported, fallback to the old DynamicConfig API - if (result.GetStatus() == EStatus::CLIENT_CALL_UNIMPLEMENTED) { + if (result.GetStatus() == EStatus::CLIENT_CALL_UNIMPLEMENTED || result.GetStatus() == EStatus::UNSUPPORTED) { auto client = NYdb::NDynamicConfig::TDynamicConfigClient(*driver); auto result = client.GetConfig().GetValueSync(); NStatusHelpers::ThrowOnErrorOrPrintIssues(result); @@ -212,7 +212,7 @@ void TCommandConfigReplace::Parse(TConfig& config) { ythrow yexception() << "Must specify non-empty -f (--filename)"; } - const auto configStr = Filename == "-" ? Cin.ReadAll() : TFileInput(Filename).ReadAll(); + const auto configStr = Filename == "-" ? Cin.ReadAll() : TFileInput(Filename).ReadAll(); DynamicConfig = configStr; @@ -244,7 +244,7 @@ int TCommandConfigReplace::Run(TConfig& config) { auto status = client.ReplaceConfig(DynamicConfig, settings).GetValueSync(); - if (status.GetStatus() == EStatus::CLIENT_CALL_UNIMPLEMENTED) { + if (status.GetStatus() == EStatus::CLIENT_CALL_UNIMPLEMENTED || status.GetStatus() == EStatus::UNSUPPORTED) { Cerr << "Warning: Fallback to DynamicConfig API" << Endl; auto client = NYdb::NDynamicConfig::TDynamicConfigClient(*driver); diff --git a/ydb/services/config/bsconfig_ut.cpp b/ydb/services/config/bsconfig_ut.cpp index 10f42e4d390b..372cb44980ad 100644 --- a/ydb/services/config/bsconfig_ut.cpp +++ b/ydb/services/config/bsconfig_ut.cpp @@ -297,13 +297,12 @@ selector_config: [] port: 12001 host_config_id: 2 )"; - TString yamlConfigExpected = SubstGlobalCopy(yamlConfig, "version: 0", "version: 1"); ReplaceConfig(server.GetChannel(), yamlConfig, std::nullopt, std::nullopt, false); std::optional yamlConfigFetched, storageYamlConfigFetched; FetchConfig(server.GetChannel(), false, false, yamlConfigFetched, storageYamlConfigFetched); UNIT_ASSERT(yamlConfigFetched); UNIT_ASSERT(!storageYamlConfigFetched); - UNIT_ASSERT_VALUES_EQUAL(yamlConfigExpected, *yamlConfigFetched); + UNIT_ASSERT_VALUES_EQUAL(yamlConfig, *yamlConfigFetched); } Y_UNIT_TEST(FetchConfig) { diff --git a/ydb/tests/functional/config/test_config_with_metadata.py b/ydb/tests/functional/config/test_config_with_metadata.py index 0a0f7f975e29..13cad5ffdf05 100644 --- a/ydb/tests/functional/config/test_config_with_metadata.py +++ b/ydb/tests/functional/config/test_config_with_metadata.py @@ -193,7 +193,6 @@ def test_config_stored_in_config_store(self): for node in self.cluster.nodes.values(): node_config = node.read_node_config() - node_config['metadata']['version'] = get_config_version(yaml.dump(node_config)) + 1 assert_that( yaml.dump(yaml.safe_load(fetched_config), sort_keys=True) == yaml.dump(yaml.safe_load(yaml.dump(node_config)), sort_keys=True) diff --git a/ydb/tests/functional/scheme_tests/canondata/tablet_scheme_tests.TestTabletSchemes.test_tablet_schemes_flat_bs_controller_/flat_bs_controller.schema b/ydb/tests/functional/scheme_tests/canondata/tablet_scheme_tests.TestTabletSchemes.test_tablet_schemes_flat_bs_controller_/flat_bs_controller.schema index e023551d51fd..1284d9021db3 100644 --- a/ydb/tests/functional/scheme_tests/canondata/tablet_scheme_tests.TestTabletSchemes.test_tablet_schemes_flat_bs_controller_/flat_bs_controller.schema +++ b/ydb/tests/functional/scheme_tests/canondata/tablet_scheme_tests.TestTabletSchemes.test_tablet_schemes_flat_bs_controller_/flat_bs_controller.schema @@ -6,6 +6,11 @@ 1 ], "ColumnsAdded": [ + { + "ColumnId": 29, + "ColumnName": "EnableConfigV2", + "ColumnType": "Bool" + }, { "ColumnId": 1, "ColumnName": "FixedKey", @@ -141,6 +146,7 @@ "ColumnFamilies": { "0": { "Columns": [ + 29, 1, 2, 4,