Skip to content

Commit ec8eca8

Browse files
authored
Merge c7578fe into 1ab62a5
2 parents 1ab62a5 + c7578fe commit ec8eca8

File tree

6 files changed

+152
-20
lines changed

6 files changed

+152
-20
lines changed

ydb/library/backup/backup.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -808,7 +808,7 @@ Ydb::Table::DescribeExternalDataSourceResult DescribeExternalDataSource(TDriver
808808

809809
std::string ToString(std::string_view key, std::string_view value) {
810810
// indented to follow the default YQL formatting
811-
return std::format(R"( {} = "{}")", key, value);
811+
return std::format(R"( {} = '{}')", key, value);
812812
}
813813

814814
namespace NExternalDataSource {

ydb/public/lib/ydb_cli/dump/restore_impl.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <library/cpp/threading/future/core/future.h>
2121

2222
#include <util/generic/deque.h>
23+
#include <util/generic/guid.h>
2324
#include <util/generic/hash.h>
2425
#include <util/generic/hash_set.h>
2526
#include <util/generic/maybe.h>
@@ -1115,6 +1116,32 @@ TRestoreResult TRestoreClient::RestoreTopic(
11151116
return Result<TRestoreResult>(dbPath, std::move(result));
11161117
}
11171118

1119+
TRestoreResult TRestoreClient::CheckSecretExistence(const TString& secretName) {
1120+
LOG_D("Check existence of the secret " << secretName.Quote());
1121+
1122+
const auto tmpUser = CreateGuidAsString();
1123+
const auto create = std::format("CREATE OBJECT `{}:{}` (TYPE SECRET_ACCESS);", secretName.c_str(), tmpUser.c_str());
1124+
const auto drop = std::format("DROP OBJECT `{}:{}` (TYPE SECRET_ACCESS);", secretName.c_str(), tmpUser.c_str());
1125+
1126+
auto result = QueryClient.RetryQuerySync([&](NQuery::TSession session) {
1127+
return session.ExecuteQuery(create, NQuery::TTxControl::NoTx()).ExtractValueSync();
1128+
});
1129+
if (!result.IsSuccess()) {
1130+
return Result<TRestoreResult>(EStatus::PRECONDITION_FAILED, TStringBuilder()
1131+
<< "Secret " << secretName.Quote() << " does not exist or you do not have access permissions");
1132+
}
1133+
1134+
result = QueryClient.RetryQuerySync([&](NQuery::TSession session) {
1135+
return session.ExecuteQuery(drop, NQuery::TTxControl::NoTx()).ExtractValueSync();
1136+
});
1137+
if (!result.IsSuccess()) {
1138+
return Result<TRestoreResult>(EStatus::INTERNAL_ERROR, TStringBuilder()
1139+
<< "Failed to drop temporary secret access " << secretName << ":" << tmpUser);
1140+
}
1141+
1142+
return result;
1143+
}
1144+
11181145
TRestoreResult TRestoreClient::RestoreReplication(
11191146
const TFsPath& fsPath,
11201147
const TString& dbRestoreRoot,
@@ -1136,6 +1163,11 @@ TRestoreResult TRestoreClient::RestoreReplication(
11361163
}
11371164

11381165
auto query = ReadAsyncReplicationQuery(fsPath, Log.get());
1166+
if (const auto secretName = GetSecretName(query)) {
1167+
if (auto result = CheckSecretExistence(secretName); !result.IsSuccess()) {
1168+
return Result<TRestoreResult>(fsPath.GetPath(), std::move(result));
1169+
}
1170+
}
11391171

11401172
NYql::TIssues issues;
11411173
if (!RewriteObjectRefs(query, dbRestoreRoot, issues)) {
@@ -1267,6 +1299,11 @@ TRestoreResult TRestoreClient::RestoreExternalDataSource(
12671299
}
12681300

12691301
TString query = ReadExternalDataSourceQuery(fsPath, Log.get());
1302+
if (const auto secretName = GetSecretName(query)) {
1303+
if (auto result = CheckSecretExistence(secretName); !result.IsSuccess()) {
1304+
return Result<TRestoreResult>(fsPath.GetPath(), std::move(result));
1305+
}
1306+
}
12701307

12711308
NYql::TIssues issues;
12721309
if (!RewriteCreateQuery(query, "CREATE EXTERNAL DATA SOURCE IF NOT EXISTS `{}`", dbPath, issues)) {

ydb/public/lib/ydb_cli/dump/restore_impl.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,8 @@ class TRestoreClient {
219219
const TString& dbPath, const TRestoreSettings& settings, const NTable::TTableDescription& desc,
220220
ui32 dataFilesCount);
221221

222+
TRestoreResult CheckSecretExistence(const TString& secretName);
223+
222224
public:
223225
explicit TRestoreClient(const TDriver& driver, const std::shared_ptr<TLog>& log);
224226

ydb/public/lib/ydb_cli/dump/util/query_utils.cpp

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ struct TTableRefValidator {
190190
NYql::TIssues& Issues;
191191
};
192192

193-
TString GetOpt(TStringInput query, TStringBuf pattern) {
193+
TString GetToken(TStringInput query, TStringBuf pattern) {
194194
TString line;
195195
while (query.ReadLine(line)) {
196196
StripInPlace(line);
@@ -205,11 +205,26 @@ TString GetOpt(TStringInput query, TStringBuf pattern) {
205205
} // anonymous
206206

207207
TString GetBackupRoot(const TString& query) {
208-
return GetOpt(query, R"(-- backup root: ")");
208+
return GetToken(query, R"(-- backup root: ")");
209209
}
210210

211211
TString GetDatabase(const TString& query) {
212-
return GetOpt(query, R"(-- database: ")");
212+
return GetToken(query, R"(-- database: ")");
213+
}
214+
215+
TString GetSecretName(const TString& query) {
216+
TString secretName;
217+
if (auto pwd = GetToken(query, R"(PASSWORD_SECRET_NAME = ')")) {
218+
secretName = std::move(pwd);
219+
} else if (auto token = GetToken(query, R"(TOKEN_SECRET_NAME = ')")) {
220+
secretName = std::move(token);
221+
}
222+
223+
if (secretName.EndsWith("'")) {
224+
secretName.resize(secretName.size() - 1);
225+
}
226+
227+
return secretName;
213228
}
214229

215230
bool SqlToProtoAst(const TString& queryStr, TRule_sql_query& queryProto, NYql::TIssues& issues) {

ydb/public/lib/ydb_cli/dump/util/query_utils.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,5 +28,6 @@ bool RewriteCreateQuery(TString& query, std::string_view pattern, const std::str
2828

2929
TString GetBackupRoot(const TString& query);
3030
TString GetDatabase(const TString& query);
31+
TString GetSecretName(const TString& query);
3132

3233
} // NYdb::NDump

ydb/services/ydb/backup_ut/ydb_backup_ut.cpp

Lines changed: 93 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -979,6 +979,20 @@ void TestCoordinationNodeResourcesArePreserved(
979979
}
980980
}
981981

982+
void WaitReplicationInit(NReplication::TReplicationClient& client, const TString& path) {
983+
int retry = 0;
984+
do {
985+
auto result = client.DescribeReplication(path).ExtractValueSync();
986+
const auto& desc = result.GetReplicationDescription();
987+
if (desc.GetItems().empty()) {
988+
Sleep(TDuration::Seconds(1));
989+
} else {
990+
break;
991+
}
992+
} while (++retry < 10);
993+
UNIT_ASSERT(retry < 10);
994+
}
995+
982996
void TestReplicationSettingsArePreserved(
983997
const TString& endpoint,
984998
NQuery::TSession& session,
@@ -997,20 +1011,6 @@ void TestReplicationSettingsArePreserved(
9971011
);)", endpoint.c_str()), true
9981012
);
9991013

1000-
auto waitReplicationInit = [&client]() {
1001-
int retry = 0;
1002-
do {
1003-
auto result = client.DescribeReplication("/Root/replication").ExtractValueSync();
1004-
const auto& desc = result.GetReplicationDescription();
1005-
if (desc.GetItems().empty()) {
1006-
Sleep(TDuration::Seconds(1));
1007-
} else {
1008-
break;
1009-
}
1010-
} while (++retry < 10);
1011-
UNIT_ASSERT(retry < 10);
1012-
};
1013-
10141014
auto checkDescription = [&client, &endpoint]() {
10151015
auto result = client.DescribeReplication("/Root/replication").ExtractValueSync();
10161016
const auto& desc = result.GetReplicationDescription();
@@ -1026,12 +1026,12 @@ void TestReplicationSettingsArePreserved(
10261026
UNIT_ASSERT_VALUES_EQUAL(items.at(0).DstPath, "/Root/replica");
10271027
};
10281028

1029-
waitReplicationInit();
1029+
WaitReplicationInit(client, "/Root/replication");
10301030
checkDescription();
10311031
backup();
10321032
ExecuteQuery(session, "DROP ASYNC REPLICATION `/Root/replication` CASCADE;", true);
10331033
restore();
1034-
waitReplicationInit();
1034+
WaitReplicationInit(client, "/Root/replication");
10351035
checkDescription();
10361036
}
10371037

@@ -1545,6 +1545,44 @@ Y_UNIT_TEST_SUITE(BackupRestore) {
15451545
);
15461546
}
15471547

1548+
Y_UNIT_TEST(RestoreReplicationWithoutSecret) {
1549+
TKikimrWithGrpcAndRootSchema server;
1550+
1551+
const auto endpoint = Sprintf("localhost:%u", server.GetPort());
1552+
auto driver = TDriver(TDriverConfig().SetEndpoint(endpoint).SetAuthToken("root@builtin"));
1553+
1554+
NQuery::TQueryClient queryClient(driver);
1555+
auto session = queryClient.GetSession().ExtractValueSync().GetSession();
1556+
NReplication::TReplicationClient replicationClient(driver);
1557+
1558+
TTempDir tempDir;
1559+
const auto& pathToBackup = tempDir.Path();
1560+
1561+
ExecuteQuery(session, "CREATE OBJECT `secret` (TYPE SECRET) WITH (value = 'root@builtin');", true);
1562+
ExecuteQuery(session, "CREATE TABLE `/Root/table` (k Uint32, v Utf8, PRIMARY KEY (k));", true);
1563+
ExecuteQuery(session, Sprintf(R"(
1564+
CREATE ASYNC REPLICATION `/Root/replication` FOR
1565+
`/Root/table` AS `/Root/replica`
1566+
WITH (
1567+
CONNECTION_STRING = 'grpc://%s/?database=/Root',
1568+
TOKEN_SECRET_NAME = 'secret'
1569+
);)", endpoint.c_str()), true
1570+
);
1571+
WaitReplicationInit(replicationClient, "/Root/replication");
1572+
1573+
NDump::TClient backupClient(driver);
1574+
{
1575+
const auto result = backupClient.Dump("/Root", pathToBackup, NDump::TDumpSettings().Database("/Root"));
1576+
UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
1577+
}
1578+
ExecuteQuery(session, "DROP OBJECT `secret` (TYPE SECRET);", true);
1579+
ExecuteQuery(session, "DROP ASYNC REPLICATION `/Root/replication` CASCADE;", true);
1580+
{
1581+
const auto result = backupClient.Restore(pathToBackup, "/Root");
1582+
UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::PRECONDITION_FAILED, result.GetIssues().ToString());
1583+
}
1584+
}
1585+
15481586
void TestExternalDataSourceBackupRestore() {
15491587
TKikimrWithGrpcAndRootSchema server;
15501588
server.GetRuntime()->GetAppData().FeatureFlags.SetEnableExternalDataSources(true);
@@ -1567,6 +1605,45 @@ Y_UNIT_TEST_SUITE(BackupRestore) {
15671605
);
15681606
}
15691607

1608+
Y_UNIT_TEST(RestoreExternalDataSourceWithoutSecret) {
1609+
TKikimrWithGrpcAndRootSchema server;
1610+
server.GetRuntime()->GetAppData().FeatureFlags.SetEnableExternalDataSources(true);
1611+
1612+
auto driver = TDriver(TDriverConfig().SetEndpoint(Sprintf("localhost:%u", server.GetPort())));
1613+
TTableClient tableClient(driver);
1614+
auto tableSession = tableClient.CreateSession().ExtractValueSync().GetSession();
1615+
1616+
NQuery::TQueryClient queryClient(driver);
1617+
auto querySession = queryClient.GetSession().ExtractValueSync().GetSession();
1618+
1619+
TTempDir tempDir;
1620+
const auto& pathToBackup = tempDir.Path();
1621+
1622+
ExecuteQuery(querySession, "CREATE OBJECT `secret` (TYPE SECRET) WITH (value = 'secret');", true);
1623+
ExecuteQuery(querySession, R"(
1624+
CREATE EXTERNAL DATA SOURCE `/Root/externalDataSource` WITH (
1625+
SOURCE_TYPE = "PostgreSQL",
1626+
DATABASE_NAME = "db",
1627+
LOCATION = "192.168.1.1:8123",
1628+
AUTH_METHOD = "BASIC",
1629+
LOGIN = "user",
1630+
PASSWORD_SECRET_NAME = "secret"
1631+
);
1632+
)", true);
1633+
1634+
NDump::TClient backupClient(driver);
1635+
{
1636+
const auto result = backupClient.Dump("/Root", pathToBackup, NDump::TDumpSettings().Database("/Root"));
1637+
UNIT_ASSERT_C(result.IsSuccess(), result.GetIssues().ToString());
1638+
}
1639+
ExecuteQuery(querySession, "DROP OBJECT `secret` (TYPE SECRET);", true);
1640+
ExecuteQuery(querySession, "DROP EXTERNAL DATA SOURCE `/Root/externalDataSource`;", true);
1641+
{
1642+
const auto result = backupClient.Restore(pathToBackup, "/Root");
1643+
UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::PRECONDITION_FAILED, result.GetIssues().ToString());
1644+
}
1645+
}
1646+
15701647
void TestExternalTableBackupRestore() {
15711648
TKikimrWithGrpcAndRootSchema server;
15721649
server.GetRuntime()->GetAppData().FeatureFlags.SetEnableExternalDataSources(true);

0 commit comments

Comments
 (0)