diff --git a/ydb/core/grpc_services/rpc_export_base.h b/ydb/core/grpc_services/rpc_export_base.h index c85ca5b5e7db..0950aa815270 100644 --- a/ydb/core/grpc_services/rpc_export_base.h +++ b/ydb/core/grpc_services/rpc_export_base.h @@ -46,12 +46,16 @@ struct TExportConv { } if (exprt.HasStartTime()) { - *operation.mutable_start_time() = exprt.GetStartTime(); + *operation.mutable_create_time() = exprt.GetStartTime(); } if (exprt.HasEndTime()) { *operation.mutable_end_time() = exprt.GetEndTime(); } + if (exprt.HasUserSID()) { + operation.set_created_by(exprt.GetUserSID()); + } + using namespace Ydb::Export; switch (exprt.GetSettingsCase()) { case NKikimrExport::TExport::kExportToYtSettings: diff --git a/ydb/core/grpc_services/rpc_import_base.h b/ydb/core/grpc_services/rpc_import_base.h index 16d88e0bb3c9..be700af4f026 100644 --- a/ydb/core/grpc_services/rpc_import_base.h +++ b/ydb/core/grpc_services/rpc_import_base.h @@ -43,12 +43,16 @@ struct TImportConv { } if (import.HasStartTime()) { - *operation.mutable_start_time() = import.GetStartTime(); + *operation.mutable_create_time() = import.GetStartTime(); } if (import.HasEndTime()) { *operation.mutable_end_time() = import.GetEndTime(); } + if (import.HasUserSID()) { + operation.set_created_by(import.GetUserSID()); + } + using namespace Ydb::Import; switch (import.GetSettingsCase()) { case NKikimrImport::TImport::kImportFromS3Settings: diff --git a/ydb/core/protos/export.proto b/ydb/core/protos/export.proto index ce0ff3df8abe..e8d78e9350a8 100644 --- a/ydb/core/protos/export.proto +++ b/ydb/core/protos/export.proto @@ -20,6 +20,7 @@ message TExport { Ydb.Export.ExportToYtSettings ExportToYtSettings = 5; Ydb.Export.ExportToS3Settings ExportToS3Settings = 6; } + optional string UserSID = 10; } message TCreateExportRequest { diff --git a/ydb/core/protos/import.proto b/ydb/core/protos/import.proto index 612309270c4c..be4d36954d78 100644 --- a/ydb/core/protos/import.proto +++ b/ydb/core/protos/import.proto @@ -19,6 +19,7 @@ message TImport { oneof Settings { Ydb.Import.ImportFromS3Settings ImportFromS3Settings = 6; } + optional string UserSID = 9; } message TCreateImportRequest { diff --git a/ydb/core/tx/schemeshard/schemeshard_export.cpp b/ydb/core/tx/schemeshard/schemeshard_export.cpp index 1a201de7edf4..2e0aa11030e4 100644 --- a/ydb/core/tx/schemeshard/schemeshard_export.cpp +++ b/ydb/core/tx/schemeshard/schemeshard_export.cpp @@ -91,6 +91,10 @@ void TSchemeShard::FromXxportInfo(NKikimrExport::TExport& exprt, const TExportIn *exprt.MutableEndTime() = SecondsToProtoTimeStamp(exportInfo->EndTime.Seconds()); } + if (exportInfo->UserSID) { + exprt.SetUserSID(*exportInfo->UserSID); + } + switch (exportInfo->State) { case TExportInfo::EState::CreateExportDir: case TExportInfo::EState::CopyTables: diff --git a/ydb/core/tx/schemeshard/schemeshard_import.cpp b/ydb/core/tx/schemeshard/schemeshard_import.cpp index c43e8198cddf..222f785228ba 100644 --- a/ydb/core/tx/schemeshard/schemeshard_import.cpp +++ b/ydb/core/tx/schemeshard/schemeshard_import.cpp @@ -55,6 +55,10 @@ void TSchemeShard::FromXxportInfo(NKikimrImport::TImport& import, const TImportI *import.MutableEndTime() = SecondsToProtoTimeStamp(importInfo->EndTime.Seconds()); } + if (importInfo->UserSID) { + import.SetUserSID(*importInfo->UserSID); + } + switch (importInfo->State) { case TImportInfo::EState::Waiting: switch (GetMinState(importInfo)) { diff --git a/ydb/core/tx/schemeshard/ut_export/ut_export.cpp b/ydb/core/tx/schemeshard/ut_export/ut_export.cpp index aebe7014e51d..b33027c91af7 100644 --- a/ydb/core/tx/schemeshard/ut_export/ut_export.cpp +++ b/ydb/core/tx/schemeshard/ut_export/ut_export.cpp @@ -1817,5 +1817,42 @@ partitioning_settings { min_partitions_count: 10 )")); } + + Y_UNIT_TEST(UserSID) { + TTestBasicRuntime runtime; + TTestEnv env(runtime); + ui64 txId = 100; + + TestCreateTable(runtime, ++txId, "/MyRoot", R"( + Name: "Table" + Columns { Name: "key" Type: "Utf8" } + Columns { Name: "value" Type: "Utf8" } + KeyColumnNames: ["key"] + )"); + env.TestWaitNotification(runtime, txId); + + TPortManager portManager; + const ui16 port = portManager.GetPort(); + + TS3Mock s3Mock({}, TS3Mock::TSettings(port)); + UNIT_ASSERT(s3Mock.Start()); + const TString request = Sprintf(R"( + ExportToS3Settings { + endpoint: "localhost:%d" + scheme: HTTP + items { + source_path: "/MyRoot/Table" + destination_prefix: "" + } + } + )", port); + const TString userSID = "user@builtin"; + TestExport(runtime, ++txId, "/MyRoot", request, userSID); + + const auto desc = TestGetExport(runtime, txId, "/MyRoot"); + const auto& entry = desc.GetResponse().GetEntry(); + UNIT_ASSERT_VALUES_EQUAL(entry.GetProgress(), Ydb::Export::ExportProgress::PROGRESS_PREPARING); + UNIT_ASSERT_VALUES_EQUAL(entry.GetUserSID(), userSID); + } } diff --git a/ydb/core/tx/schemeshard/ut_restore/ut_restore.cpp b/ydb/core/tx/schemeshard/ut_restore/ut_restore.cpp index 96558e86d2bc..d9a43c4c4473 100644 --- a/ydb/core/tx/schemeshard/ut_restore/ut_restore.cpp +++ b/ydb/core/tx/schemeshard/ut_restore/ut_restore.cpp @@ -3429,6 +3429,48 @@ Y_UNIT_TEST_SUITE(TImportTests) { UNIT_ASSERT(entry.HasEndTime()); UNIT_ASSERT_LT(entry.GetStartTime().seconds(), entry.GetEndTime().seconds()); } + + Y_UNIT_TEST(UserSID) { + TTestBasicRuntime runtime; + TTestEnv env(runtime); + ui64 txId = 100; + + const auto data = GenerateTestData(R"( + columns { + name: "key" + type { optional_type { item { type_id: UTF8 } } } + } + columns { + name: "value" + type { optional_type { item { type_id: UTF8 } } } + } + primary_key: "key" + )", {{"a", 1}}); + + TPortManager portManager; + const ui16 port = portManager.GetPort(); + + TS3Mock s3Mock(ConvertTestData(data), TS3Mock::TSettings(port)); + UNIT_ASSERT(s3Mock.Start()); + + const TString request = Sprintf(R"( + ImportFromS3Settings { + endpoint: "localhost:%d" + scheme: HTTP + items { + source_prefix: "" + destination_path: "/MyRoot/Table" + } + } + )", port); + const TString userSID = "user@builtin"; + TestImport(runtime, ++txId, "/MyRoot", request, userSID); + + const auto desc = TestGetImport(runtime, txId, "/MyRoot"); + const auto& entry = desc.GetResponse().GetEntry(); + UNIT_ASSERT_VALUES_EQUAL(entry.GetProgress(), Ydb::Import::ImportProgress::PROGRESS_PREPARING); + UNIT_ASSERT_VALUES_EQUAL(entry.GetUserSID(), userSID); + } } Y_UNIT_TEST_SUITE(TImportWithRebootsTests) { diff --git a/ydb/public/api/protos/ydb_operation.proto b/ydb/public/api/protos/ydb_operation.proto index b7b5d70605d4..2118403ec85c 100644 --- a/ydb/public/api/protos/ydb_operation.proto +++ b/ydb/public/api/protos/ydb_operation.proto @@ -122,9 +122,12 @@ message Operation { // For operations in progress, it might indicate the current cost of the operation (if supported). CostInfo cost_info = 7; - // The time at which this operation was started (if supported). - google.protobuf.Timestamp start_time = 8; + // The time at which this operation was created (if supported). + google.protobuf.Timestamp create_time = 8; // The time at which this operation was completed, doesn't matter successful or not (if supported). google.protobuf.Timestamp end_time = 9; + + // User SID (Security ID) of the user who created this operation (if supported). + string created_by = 10; } diff --git a/ydb/public/lib/ydb_cli/common/print_operation.cpp b/ydb/public/lib/ydb_cli/common/print_operation.cpp index 53832e65b02c..34802c9d175f 100644 --- a/ydb/public/lib/ydb_cli/common/print_operation.cpp +++ b/ydb/public/lib/ydb_cli/common/print_operation.cpp @@ -37,8 +37,12 @@ namespace { } } - if (operation.StartTime() != TInstant::Zero()) { - freeText << "Start time: " << operation.StartTime().ToStringUpToSeconds() << Endl; + if (!operation.CreatedBy().Empty()) { + freeText << "Created by: " << operation.CreatedBy() << Endl; + } + + if (operation.CreateTime() != TInstant::Zero()) { + freeText << "Create time: " << operation.CreateTime().ToStringUpToSeconds() << Endl; } if (operation.EndTime() != TInstant::Zero()) { @@ -122,8 +126,12 @@ namespace { freeText << "TypeV3: " << (settings.UseTypeV3_ ? "true" : "false") << Endl; - if (operation.StartTime() != TInstant::Zero()) { - freeText << "Start time: " << operation.StartTime().ToStringUpToSeconds() << Endl; + if (!operation.CreatedBy().Empty()) { + freeText << "Created by: " << operation.CreatedBy() << Endl; + } + + if (operation.CreateTime() != TInstant::Zero()) { + freeText << "Create time: " << operation.CreateTime().ToStringUpToSeconds() << Endl; } if (operation.EndTime() != TInstant::Zero()) { @@ -184,8 +192,12 @@ namespace { freeText << "Number of retries: " << settings.NumberOfRetries_.GetRef() << Endl; } - if (operation.StartTime() != TInstant::Zero()) { - freeText << "Start time: " << operation.StartTime().ToStringUpToSeconds() << Endl; + if (!operation.CreatedBy().Empty()) { + freeText << "Created by: " << operation.CreatedBy() << Endl; + } + + if (operation.CreateTime() != TInstant::Zero()) { + freeText << "Create time: " << operation.CreateTime().ToStringUpToSeconds() << Endl; } if (operation.EndTime() != TInstant::Zero()) { diff --git a/ydb/public/sdk/cpp/client/ydb_types/operation/operation.cpp b/ydb/public/sdk/cpp/client/ydb_types/operation/operation.cpp index 1cdd09222b2b..51cb186d0ebb 100644 --- a/ydb/public/sdk/cpp/client/ydb_types/operation/operation.cpp +++ b/ydb/public/sdk/cpp/client/ydb_types/operation/operation.cpp @@ -17,8 +17,9 @@ class TOperation::TImpl { : Id_(operation.id(), true /* allowEmpty */) , Status_(std::move(status)) , Ready_(operation.ready()) - , StartTime_(ProtoTimestampToInstant(operation.start_time())) + , CreateTime_(ProtoTimestampToInstant(operation.create_time())) , EndTime_(ProtoTimestampToInstant(operation.end_time())) + , CreatedBy_(operation.created_by()) , Operation_(std::move(operation)) { } @@ -35,14 +36,18 @@ class TOperation::TImpl { return Status_; } - TInstant StartTime() const { - return StartTime_; + TInstant CreateTime() const { + return CreateTime_; } TInstant EndTime() const { return EndTime_; } + const TString& CreatedBy() const { + return CreatedBy_; + } + const Ydb::Operations::Operation& GetProto() const { return Operation_; } @@ -51,8 +56,9 @@ class TOperation::TImpl { const TOperationId Id_; const TStatus Status_; const bool Ready_; - const TInstant StartTime_; + const TInstant CreateTime_; const TInstant EndTime_; + const TString CreatedBy_; const Ydb::Operations::Operation Operation_; }; @@ -76,14 +82,18 @@ const TStatus& TOperation::Status() const { return Impl_->Status(); } -TInstant TOperation::StartTime() const { - return Impl_->StartTime(); +TInstant TOperation::CreateTime() const { + return Impl_->CreateTime(); } TInstant TOperation::EndTime() const { return Impl_->EndTime(); } +const TString& TOperation::CreatedBy() const { + return Impl_->CreatedBy(); +} + TString TOperation::ToString() const { TString result; TStringOutput out(result); diff --git a/ydb/public/sdk/cpp/client/ydb_types/operation/operation.h b/ydb/public/sdk/cpp/client/ydb_types/operation/operation.h index 651d84f89806..52f2070eeefe 100644 --- a/ydb/public/sdk/cpp/client/ydb_types/operation/operation.h +++ b/ydb/public/sdk/cpp/client/ydb_types/operation/operation.h @@ -32,8 +32,9 @@ class TOperation { const TOperationId& Id() const; bool Ready() const; const TStatus& Status() const; - TInstant StartTime() const; + TInstant CreateTime() const; TInstant EndTime() const; + const TString& CreatedBy() const; TString ToString() const; TString ToJsonString() const;