aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBulat Gayazov <brgayazov@yandex-team.ru>2023-08-24 14:07:47 +0300
committerbrgayazov <bulat@ydb.tech>2023-08-24 14:47:31 +0300
commit509a971515bc6421a4a824fda0a8cb19c683d85f (patch)
treef38e11f2d86f8ccde4f297190636df21aaa38d28
parent0d5dd26da4012de80c0af860d7b244ca2be85cd3 (diff)
downloadydb-509a971515bc6421a4a824fda0a8cb19c683d85f.tar.gz
Added command ydb config info which print current connection parameters
Added command ydb config info which print current connection parameters Pull Request resolved: #285
-rw-r--r--ydb/public/lib/ydb_cli/commands/ydb_profile.cpp94
-rw-r--r--ydb/public/lib/ydb_cli/commands/ydb_profile.h12
-rw-r--r--ydb/public/lib/ydb_cli/commands/ydb_root_common.cpp584
-rw-r--r--ydb/public/lib/ydb_cli/commands/ydb_root_common.h11
-rw-r--r--ydb/public/lib/ydb_cli/common/command.h8
5 files changed, 542 insertions, 167 deletions
diff --git a/ydb/public/lib/ydb_cli/commands/ydb_profile.cpp b/ydb/public/lib/ydb_cli/commands/ydb_profile.cpp
index 0644465d27..2ca086c606 100644
--- a/ydb/public/lib/ydb_cli/commands/ydb_profile.cpp
+++ b/ydb/public/lib/ydb_cli/commands/ydb_profile.cpp
@@ -27,6 +27,7 @@ TCommandConfig::TCommandConfig()
: TClientCommandTree("config", {}, "Manage YDB CLI configuration")
{
AddCommand(std::make_unique<TCommandProfile>());
+ AddCommand(std::make_unique<TCommandConnectionInfo>());
}
void TCommandConfig::Config(TConfig& config) {
@@ -196,6 +197,16 @@ namespace {
}
}
+ TString TryBlurValue(const TString& authMethod, const TString& value) {
+ if (!IsStdoutInteractive() || authMethod == "sa-key-file" || authMethod == "token-file" || authMethod == "yc-token-file") {
+ return value;
+ }
+ if (authMethod == "password") {
+ return ReplaceWithAsterisks(value);
+ }
+ return BlurSecret(value);
+ }
+
void PrintProfileContent(std::shared_ptr<IProfile> profile) {
if (profile->Has("endpoint")) {
Cout << " endpoint: " << profile->GetValue("endpoint").as<TString>() << Endl;
@@ -209,14 +220,8 @@ namespace {
Cout << " " << authMethod;
if (authMethod == "ydb-token" ||authMethod == "iam-token"
|| authMethod == "yc-token" || authMethod == "sa-key-file"
- || authMethod == "token-file" || authMethod == "yc-token-file")
- {
- TString authData = authValue["data"].as<TString>();
- if (authMethod == "sa-key-file" || authMethod == "token-file" || authMethod == "yc-token-file") {
- Cout << ": " << authData;
- } else {
- Cout << ": " << BlurSecret(authData);
- }
+ || authMethod == "token-file" || authMethod == "yc-token-file") {
+ Cout << ": " << TryBlurValue(authMethod, authValue["data"].as<TString>());
} else if (authMethod == "static-credentials") {
auto authData = authValue["data"];
if (authData) {
@@ -224,7 +229,7 @@ namespace {
Cout << Endl << " user: " << authData["user"].as<TString>();
}
if (authData["password"]) {
- Cout << Endl << " password: " << ReplaceWithAsterisks(authData["password"].as<TString>());
+ Cout << Endl << " password: " << TryBlurValue("password", authData["password"].as<TString>());
}
if (authData["password-file"]) {
Cout << Endl << " password file: " << authData["password-file"].as<TString>();
@@ -242,6 +247,77 @@ namespace {
}
}
+TCommandConnectionInfo::TCommandConnectionInfo()
+ : TClientCommand("info", {}, "List current connection parameters")
+{}
+
+void TCommandConnectionInfo::Config(TConfig& config) {
+ TClientCommand::Config(config);
+
+ config.NeedToConnect = false;
+ config.SetFreeArgsNum(0);
+}
+
+int TCommandConnectionInfo::Run(TConfig& config) {
+ if (config.IsVerbose()) {
+ PrintVerboseInfo(config);
+ } else {
+ PrintInfo(config);
+ }
+ return EXIT_SUCCESS;
+}
+
+void TCommandConnectionInfo::PrintInfo(TConfig& config) {
+ if (config.Address) {
+ Cout << "endpoint: " << config.Address << Endl;
+ }
+ if (config.Database) {
+ Cout << "database: " << config.Database << Endl;
+ }
+ if (config.SecurityToken) {
+ Cout << "token: " << TryBlurValue("token", config.SecurityToken) << Endl;
+ }
+ if (config.UseIamAuth) {
+ if (config.YCToken) {
+ Cout << "yc-token: " << TryBlurValue("yc-token", config.YCToken) << Endl;
+ }
+ if (config.SaKeyFile) {
+ Cout << "sa-key-file: " << config.SaKeyFile << Endl;
+ }
+ if (config.UseMetadataCredentials) {
+ Cout << "use-metadata-credentials" << Endl;
+ }
+ if (config.IamEndpoint) {
+ Cout << "iam-endpoint: " << config.IamEndpoint << Endl;
+ }
+ }
+ if (config.UseStaticCredentials) {
+ if (config.StaticCredentials.User) {
+ Cout << "user: " << config.StaticCredentials.User << Endl;
+ }
+ if (config.StaticCredentials.Password) {
+ Cout << "password: " << TryBlurValue("password", config.StaticCredentials.Password) << Endl;
+ }
+ }
+ if (config.CaCertsFile) {
+ Cout << "ca-file: " << config.CaCertsFile << Endl;
+ }
+}
+
+void TCommandConnectionInfo::PrintVerboseInfo(TConfig& config) {
+ Cout << Endl;
+ PrintInfo(config);
+ Cout << "current auth method: " << (config.ChosenAuthMethod ? config.ChosenAuthMethod : "no-auth") << Endl;
+ for (const auto& [name, params] : config.ConnectionParams) {
+ size_t cnt = 1;
+ Cout << Endl << "\"" << name << "\" sources:" << Endl;
+ for (const auto& [value, source] : params) {
+ Cout << " " << cnt << ". Value: " << TryBlurValue(name, value) << ". Got from: " << source << Endl;
+ ++cnt;
+ }
+ }
+}
+
TCommandInit::TCommandInit()
: TCommandProfileCommon("init", {}, "YDB CLI initialization")
{}
diff --git a/ydb/public/lib/ydb_cli/commands/ydb_profile.h b/ydb/public/lib/ydb_cli/commands/ydb_profile.h
index 5272fc5985..a7333dd3b0 100644
--- a/ydb/public/lib/ydb_cli/commands/ydb_profile.h
+++ b/ydb/public/lib/ydb_cli/commands/ydb_profile.h
@@ -12,6 +12,18 @@ public:
virtual void Config(TConfig& config) override;
};
+class TCommandConnectionInfo : public TClientCommand {
+public:
+ TCommandConnectionInfo();
+
+ virtual void Config(TConfig& config) override;
+ virtual int Run(TConfig& config) override;
+
+private:
+ static void PrintInfo(TConfig& config);
+ static void PrintVerboseInfo(TConfig& config);
+};
+
class TCommandProfile : public TClientCommandTree {
public:
TCommandProfile();
diff --git a/ydb/public/lib/ydb_cli/commands/ydb_root_common.cpp b/ydb/public/lib/ydb_cli/commands/ydb_root_common.cpp
index 5baa84ced0..eae8a8a355 100644
--- a/ydb/public/lib/ydb_cli/commands/ydb_root_common.cpp
+++ b/ydb/public/lib/ydb_cli/commands/ydb_root_common.cpp
@@ -19,6 +19,7 @@
#include <util/folder/path.h>
#include <util/folder/dirut.h>
#include <util/string/strip.h>
+#include <util/string/builder.h>
#include <util/system/env.h>
namespace NYdb {
@@ -254,59 +255,145 @@ void TClientCommandRootCommon::Parse(TConfig& config) {
config.VerbosityLevel = std::min(static_cast<TConfig::EVerbosityLevel>(VerbosityLevel), TConfig::EVerbosityLevel::DEBUG);
}
+namespace {
+ inline void PrintSettingFromProfile(const TString& setting, std::shared_ptr<IProfile> profile, bool explicitOption) {
+ Cout << "Using " << setting << " due to configuration in" << (explicitOption ? "" : " active") << " profile \""
+ << profile->GetName() << "\"" << (explicitOption ? " from explicit --profile option" : "") << Endl;
+ }
+
+ inline TString GetProfileSource(std::shared_ptr<IProfile> profile, bool explicitOption) {
+ Y_VERIFY(profile, "No profile to get source");
+ if (explicitOption) {
+ return TStringBuilder() << "profile \"" << profile->GetName() << "\" from explicit --profile option";
+ }
+ return TStringBuilder() << "active profile \"" << profile->GetName() << "\"";
+ }
+}
+
+bool TClientCommandRootCommon::TryGetParamFromProfile(const TString& name, std::shared_ptr<IProfile> profile, bool explicitOption,
+ std::function<bool(const TString&, const TString&, bool)> callback) {
+ if (profile && profile->Has(name)) {
+ return callback(profile->GetValue(name).as<TString>(), GetProfileSource(profile, explicitOption), explicitOption);
+ }
+ return false;
+}
+
void TClientCommandRootCommon::ParseCaCerts(TConfig& config) {
- if (CaCertsFile.empty()) {
- auto profile = Profile;
- if (!profile) {
- profile = ProfileManager->GetActiveProfile();
+ auto getCaFile = [this, &config] (const TString& param, const TString& sourceText, bool explicitOption) {
+ if (!IsCaCertsFileSet && (explicitOption || !Profile)) {
+ config.CaCertsFile = param;
+ IsCaCertsFileSet = true;
+ GetCaCerts(config);
}
- if (profile && profile->Has("ca-file")) {
- CaCertsFile = profile->GetValue("ca-file").as<TString>();
+ if (!IsVerbose()) {
+ return true;
}
+ config.ConnectionParams["ca-file"].push_back({param, sourceText});
+ return false;
+ };
+ // Priority 1. Explicit --ca-file option
+ if (CaCertsFile && getCaFile(CaCertsFile, "explicit --ca-file option", true)) {
+ return;
+ }
+ // Priority 2. Explicit --profile option
+ if (TryGetParamFromProfile("ca-file", Profile, true, getCaFile)) {
+ return;
+ }
+ // Priority 3. Active profile (if --profile option is not specified)
+ if (TryGetParamFromProfile("ca-file", ProfileManager->GetActiveProfile(), false, getCaFile)) {
+ return;
}
- if (!config.EnableSsl && !CaCertsFile.empty()) {
+}
+
+void TClientCommandRootCommon::GetCaCerts(TConfig& config) {
+ if (!config.EnableSsl && !config.CaCertsFile.empty()) {
throw TMisuseException()
<< "\"ca-file\" option provided for a non-ssl connection. Use grpcs:// prefix for host to connect using SSL.";
}
- if (!CaCertsFile.empty()) {
- config.CaCerts = ReadFromFile(CaCertsFile, "CA certificates");
+ if (!config.CaCertsFile.empty()) {
+ config.CaCerts = ReadFromFile(config.CaCertsFile, "CA certificates");
}
}
void TClientCommandRootCommon::ParseAddress(TConfig& config) {
- TString hostname;
- TString port = "2135";
-
- if (Address.empty()) {
- auto profile = Profile;
- if (!profile) {
- profile = ProfileManager->GetActiveProfile();
- }
- if (profile && profile->Has("endpoint")) {
- Address = profile->GetValue("endpoint").as<TString>();
- }
+ auto getAddress = [this, &config] (const TString& param, const TString& sourceText, bool explicitOption) {
+ TString address;
+ if (!IsAddressSet && (explicitOption || !Profile)) {
+ config.Address = param;
+ IsAddressSet = true;
+ GetAddressFromString(config);
+ address = config.Address;
+ }
+ if (!IsVerbose()) {
+ return true;
+ }
+ if (!address) {
+ address = param;
+ GetAddressFromString(config, &address);
+ }
+ config.ConnectionParams["endpoint"].push_back({address, sourceText});
+ return false;
+ };
+ // Priority 1. Explicit --endpoint option
+ if (Address && getAddress(Address, "explicit --endpoint option", true)) {
+ return;
}
+ // Priority 2. Explicit --profile option
+ if (TryGetParamFromProfile("endpoint", Profile, true, getAddress)) {
+ return;
+ }
+ // Priority 3. Active profile (if --profile option is not specified)
+ if (TryGetParamFromProfile("endpoint", ProfileManager->GetActiveProfile(), false, getAddress)) {
+ return;
+ }
+}
+void TClientCommandRootCommon::GetAddressFromString(TConfig& config, TString* result) {
+ TString port = "2135";
+ Address = result ? *result : config.Address;
if (!Address.empty()) {
- config.EnableSsl = Settings.EnableSsl.GetRef();
+ if (!result) {
+ config.EnableSsl = Settings.EnableSsl.GetRef();
+ }
TString message;
- if (!ParseProtocol(config, message)) {
+ if ((result && !ParseProtocolNoConfig(message)) || (!result && !ParseProtocol(config, message))) {
MisuseErrors.push_back(message);
}
auto colon_pos = Address.find(":");
if (colon_pos == TString::npos) {
- config.Address = Address + ":" + port;
+ if (result) {
+ *result = Address + ":" + port;
+ } else {
+ config.Address = Address + ":" + port;
+ }
} else {
if (colon_pos == Address.rfind(":")) {
- config.Address = Address;
+ if (result) {
+ *result = Address;
+ } else {
+ config.Address = Address;
+ }
} else {
MisuseErrors.push_back("Wrong format for option 'endpoint': more than one colon found.");
- return;
}
}
}
}
+bool TClientCommandRootCommon::ParseProtocolNoConfig(TString& message) {
+ auto separator_pos = Address.find("://");
+ if (separator_pos != TString::npos) {
+ TString protocol = Address.substr(0, separator_pos);
+ protocol.to_lower();
+ if (protocol != "grpcs" && protocol != "grpc") {
+ message = TStringBuilder() << "Unknown protocol \"" << protocol << "\".";
+ return false;
+ }
+ Address = Address.substr(separator_pos + 3);
+ }
+ return true;
+}
+
void TClientCommandRootCommon::ParseProfile() {
if (ProfileName) {
if (ProfileManager->HasProfile(ProfileName)) {
@@ -320,37 +407,64 @@ void TClientCommandRootCommon::ParseProfile() {
}
void TClientCommandRootCommon::ParseDatabase(TConfig& config) {
- if (Database.empty()) {
- auto profile = Profile;
- if (!profile) {
- profile = ProfileManager->GetActiveProfile();
+ auto getDatabase = [this, &config] (const TString& param, const TString& sourceText, bool explicitOption) {
+ if (!IsDatabaseSet && (explicitOption || !Profile)) {
+ config.Database = param;
+ IsDatabaseSet = true;
}
- if (profile && profile->Has("database")) {
- Database = profile->GetValue("database").as<TString>();
+ if (!IsVerbose()) {
+ return true;
}
+ config.ConnectionParams["database"].push_back({param, sourceText});
+ return false;
+ };
+ // Priority 1. Explicit --database option
+ if (Database && getDatabase(Database, "explicit --database option", true)) {
+ return;
+ }
+ // Priority 2. Explicit --profile option
+ if (TryGetParamFromProfile("database", Profile, true, getDatabase)) {
+ return;
+ }
+ // Priority 3. Active profile (if --profile option is not specified)
+ if (TryGetParamFromProfile("database", ProfileManager->GetActiveProfile(), false, getDatabase)) {
+ return;
}
-
- config.Database = Database;
}
void TClientCommandRootCommon::ParseIamEndpoint(TConfig& config) {
- if (IamEndpoint.empty()) {
- auto profile = Profile;
- if (!profile) {
- profile = ProfileManager->GetActiveProfile();
+ auto getIamEndpoint = [this, &config] (const TString& param, const TString& sourceText, bool explicitOption) {
+ if (!IsIamEndpointSet && (explicitOption || !Profile)) {
+ config.IamEndpoint = param;
+ IsIamEndpointSet = true;
}
- if (profile && profile->Has("iam-endpoint")) {
- IamEndpoint = profile->GetValue("iam-endpoint").as<TString>();
+ if (!IsVerbose()) {
+ return true;
}
+ config.ConnectionParams["iam-endpoint"].push_back({param, sourceText});
+ return false;
+ };
+ // Priority 1. Explicit --iam-endpoint option
+ if (IamEndpoint && getIamEndpoint(IamEndpoint, "explicit --iam-endpoint option", true)) {
+ return;
}
- if (!IamEndpoint.empty()) {
- config.IamEndpoint = IamEndpoint;
+ // Priority 2. Explicit --profile option
+ if (TryGetParamFromProfile("iam-endpoint", Profile, true, getIamEndpoint)) {
+ return;
+ }
+ // Priority 3. Active profile (if --profile option is not specified)
+ if (TryGetParamFromProfile("iam-endpoint", ProfileManager->GetActiveProfile(), false, getIamEndpoint)) {
+ return;
+ }
+ // Priority 4. Default value
+ if (IsVerbose()) {
+ config.ConnectionParams["iam-endpoint"].push_back({config.IamEndpoint, "default value"});
}
}
void TClientCommandRootCommon::Validate(TConfig& config) {
TClientCommandRootBase::Validate(config);
- if (!config.NeedToConnect) {
+ if (!config.NeedToConnect && !IsVerbose()) {
return;
}
@@ -362,20 +476,25 @@ void TClientCommandRootCommon::Validate(TConfig& config) {
}
errors << *it;
}
-
- throw TMisuseException() << errors;
+ if (!config.NeedToConnect) {
+ Cerr << "Connection parameters parsing errors:" << Endl << errors << Endl;
+ } else {
+ throw TMisuseException() << errors;
+ }
+ }
+ if (!config.NeedToConnect) {
+ return;
}
- if (Address.empty()) {
- throw TMisuseException()
- << "Missing required option 'endpoint'.";
+ if (config.Address.empty()) {
+ throw TMisuseException() << "Missing required option 'endpoint'.";
}
- if (Database.empty()) {
+ if (config.Database.empty()) {
throw TMisuseException()
<< "Missing required option 'database'.";
- } else if (!Database.StartsWith('/')) {
- throw TMisuseException() << "Path to a database \"" << Database
+ } else if (!config.Database.StartsWith('/')) {
+ throw TMisuseException() << "Path to a database \"" << config.Database
<< "\" is incorrect. It must be absolute and thus must begin with '/'.";
}
}
@@ -398,13 +517,6 @@ int TClientCommandRootCommon::Run(TConfig& config) {
return EXIT_SUCCESS;
}
-namespace {
- inline void PrintSettingFromProfile(const TString& setting, std::shared_ptr<IProfile> profile, bool explicitOption) {
- Cout << "Using " << setting << " due to configuration in" << (explicitOption ? "" : " active") << " profile \""
- << profile->GetName() << "\"" << (explicitOption ? " from explicit --profile option" : "") << Endl;
- }
-}
-
bool TClientCommandRootCommon::GetCredentialsFromProfile(std::shared_ptr<IProfile> profile, TConfig& config, bool explicitOption) {
if (!profile || !profile->Has("authentication")) {
return false;
@@ -417,15 +529,29 @@ bool TClientCommandRootCommon::GetCredentialsFromProfile(std::shared_ptr<IProfil
TString authMethod = authValue["method"].as<TString>();
if (authMethod == "use-metadata-credentials") {
+ if (!IsAuthSet && (explicitOption || !Profile)) {
+ if (IsVerbose()) {
+ PrintSettingFromProfile("metadata service", profile, explicitOption);
+ }
+ config.UseMetadataCredentials = true;
+ config.ChosenAuthMethod = "use-metadata-credentials";
+ IsAuthSet = true;
+ }
if (IsVerbose()) {
- PrintSettingFromProfile("metadata service", profile, explicitOption);
+ config.ConnectionParams["use-metadata-credentials"].push_back({"true", GetProfileSource(profile, explicitOption)});
}
- config.UseMetadataCredentials = true;
return true;
}
if (authMethod == "anonymous-auth") {
+ if (!IsAuthSet && (explicitOption || !Profile)) {
+ if (IsVerbose()) {
+ PrintSettingFromProfile("anonymous authentication", profile, explicitOption);
+ }
+ config.ChosenAuthMethod = "anonymous-auth";
+ IsAuthSet = true;
+ }
if (IsVerbose()) {
- PrintSettingFromProfile("anonymous authentication", profile, explicitOption);
+ config.ConnectionParams["anonymous-auth"].push_back({"true", GetProfileSource(profile, explicitOption)});
}
return true;
}
@@ -453,14 +579,18 @@ bool TClientCommandRootCommon::GetCredentialsFromProfile(std::shared_ptr<IProfil
auto authData = authValue["data"];
if (authMethod == "iam-token") {
- if (IsVerbose()) {
- PrintSettingFromProfile("iam token", profile, explicitOption);
+ if (!IsAuthSet && (explicitOption || !Profile)) {
+ if (IsVerbose()) {
+ PrintSettingFromProfile("iam token", profile, explicitOption);
+ }
+ config.SecurityToken = authData.as<TString>();
+ config.ChosenAuthMethod = "token";
+ IsAuthSet = true;
}
- config.SecurityToken = authData.as<TString>();
- } else if (authMethod == "token-file") {
if (IsVerbose()) {
- PrintSettingFromProfile("token file", profile, explicitOption);
+ config.ConnectionParams["token"].push_back({authData.as<TString>(), GetProfileSource(profile, explicitOption)});
}
+ } else if (authMethod == "token-file") {
TString filename = authData.as<TString>();
TString fileContent;
if (!ReadFromFileIfExists(filename, "token", fileContent, true)) {
@@ -471,16 +601,30 @@ bool TClientCommandRootCommon::GetCredentialsFromProfile(std::shared_ptr<IProfil
MisuseErrors.push_back(TStringBuilder() << "Empty token file " << filename << " provided");
return false;
}
- config.SecurityToken = fileContent;
- } else if (authMethod == "yc-token") {
+ if (!IsAuthSet && (explicitOption || !Profile)) {
+ if (IsVerbose()) {
+ PrintSettingFromProfile("token file", profile, explicitOption);
+ }
+ config.SecurityToken = fileContent;
+ config.ChosenAuthMethod = "token";
+ IsAuthSet = true;
+ }
if (IsVerbose()) {
- PrintSettingFromProfile("Yandex.Cloud Passport token (yc-token)", profile, explicitOption);
+ config.ConnectionParams["token"].push_back({fileContent, GetProfileSource(profile, explicitOption)});
+ }
+ } else if (authMethod == "yc-token") {
+ if (!IsAuthSet && (explicitOption || !Profile)) {
+ if (IsVerbose()) {
+ PrintSettingFromProfile("Yandex.Cloud Passport token (yc-token)", profile, explicitOption);
+ }
+ config.YCToken = authData.as<TString>();
+ config.ChosenAuthMethod = "yc-token";
+ IsAuthSet = true;
}
- config.YCToken = authData.as<TString>();
- } else if (authMethod == "yc-token-file") {
if (IsVerbose()) {
- PrintSettingFromProfile("Yandex.Cloud Passport token file (yc-token-file)", profile, explicitOption);
+ config.ConnectionParams["yc-token"].push_back({authData.as<TString>(), GetProfileSource(profile, explicitOption)});
}
+ } else if (authMethod == "yc-token-file") {
TString filename = authData.as<TString>();
TString fileContent;
if (!ReadFromFileIfExists(filename, "token", fileContent, true)) {
@@ -491,32 +635,66 @@ bool TClientCommandRootCommon::GetCredentialsFromProfile(std::shared_ptr<IProfil
MisuseErrors.push_back(TStringBuilder() << "Empty token file " << filename << " provided");
return false;
}
- config.YCToken = fileContent;
- } else if (authMethod == "sa-key-file") {
+ if (!IsAuthSet && (explicitOption || !Profile)) {
+ if (IsVerbose()) {
+ PrintSettingFromProfile("Yandex.Cloud Passport token file (yc-token-file)", profile, explicitOption);
+ }
+ config.YCToken = fileContent;
+ config.ChosenAuthMethod = "yc-token";
+ IsAuthSet = true;
+ }
if (IsVerbose()) {
- PrintSettingFromProfile("service account key file (sa-key-file)", profile, explicitOption);
+ config.ConnectionParams["yc-token"].push_back({fileContent, GetProfileSource(profile, explicitOption)});
}
+ } else if (authMethod == "sa-key-file") {
TString filePath = authData.as<TString>();
if (filePath.StartsWith("~")) {
filePath = HomeDir + filePath.substr(1);
}
- config.SaKeyFile = filePath;
+ if (!IsAuthSet && (explicitOption || !Profile)) {
+ if (IsVerbose()) {
+ PrintSettingFromProfile("service account key file (sa-key-file)", profile, explicitOption);
+ }
+ config.SaKeyFile = filePath;
+ config.ChosenAuthMethod = "sa-key-file";
+ IsAuthSet = true;
+ }
+ if (IsVerbose()) {
+ config.ConnectionParams["sa-key-file"].push_back({filePath, GetProfileSource(profile, explicitOption)});
+ }
} else if (authMethod == "ydb-token") {
+ if (!IsAuthSet && (explicitOption || !Profile)) {
+ if (IsVerbose()) {
+ PrintSettingFromProfile("OAuth token (ydb-token)", profile, explicitOption);
+ }
+ config.SecurityToken = authData.as<TString>();
+ config.ChosenAuthMethod = "token";
+ IsAuthSet = true;
+ }
if (IsVerbose()) {
- PrintSettingFromProfile("OAuth token (ydb-token)", profile, explicitOption);
+ config.ConnectionParams["token"].push_back({authData.as<TString>(), GetProfileSource(profile, explicitOption)});
}
- config.SecurityToken = authData.as<TString>();
} else if (authMethod == "static-credentials") {
- if (IsVerbose()) {
+ if (!IsAuthSet && (explicitOption || !Profile) && IsVerbose()) {
PrintSettingFromProfile("user name & password", profile, explicitOption);
}
if (authData["user"]) {
- config.StaticCredentials.User = authData["user"].as<TString>();
+ if (!IsAuthSet && (explicitOption || !Profile)) {
+ config.StaticCredentials.User = authData["user"].as<TString>();
+ }
+ if (IsVerbose()) {
+ config.ConnectionParams["user"].push_back({authData["user"].as<TString>(), GetProfileSource(profile, explicitOption)});
+ }
}
if (authData["password"]) {
- config.StaticCredentials.Password = authData["password"].as<TString>();
- if (!config.StaticCredentials.Password) {
- DoNotAskForPassword = true;
+ if (!IsAuthSet && (explicitOption || !Profile)) {
+ config.StaticCredentials.Password = authData["password"].as<TString>();
+ if (!config.StaticCredentials.Password) {
+ DoNotAskForPassword = true;
+ }
+ }
+ if (IsVerbose()) {
+ config.ConnectionParams["password"].push_back({authData["password"].as<TString>(), GetProfileSource(profile, explicitOption)});
}
}
if (authData["password-file"]) {
@@ -527,13 +705,18 @@ bool TClientCommandRootCommon::GetCredentialsFromProfile(std::shared_ptr<IProfil
DoNotAskForPassword = true;
return false;
}
- config.StaticCredentials.Password = fileContent;
- if (!config.StaticCredentials.Password) {
- DoNotAskForPassword = true;
+ if (!IsAuthSet && (explicitOption || !Profile)) {
+ config.StaticCredentials.Password = fileContent;
+ if (!config.StaticCredentials.Password) {
+ DoNotAskForPassword = true;
+ }
+ }
+ if (IsVerbose()) {
+ config.ConnectionParams["password"].push_back({fileContent, GetProfileSource(profile, explicitOption)});
}
-
}
-
+ config.ChosenAuthMethod = "static-credentials";
+ IsAuthSet = true;
} else {
return false;
}
@@ -541,15 +724,77 @@ bool TClientCommandRootCommon::GetCredentialsFromProfile(std::shared_ptr<IProfil
}
void TClientCommandRootCommon::ParseCredentials(TConfig& config) {
- size_t explicitAuthMethodCount = (size_t)(!TokenFile.empty()) + (size_t)(!YCTokenFile.empty())
+ size_t explicitAuthMethodCount = (size_t)(config.ParseResult->Has("iam-token-file")) + (size_t)(config.ParseResult->Has("token-file"))
+ + (size_t)(!YCTokenFile.empty())
+ (size_t)UseMetadataCredentials + (size_t)(!SaKeyFile.empty())
+ (size_t)(!UserName.empty() || !PasswordFile.empty() || DoNotAskForPassword);
switch (explicitAuthMethodCount) {
+ case 1:
+ // Priority 1. Exactly one explicit auth method. Using it.
+ if (config.ParseResult->Has("token-file")) {
+ config.SecurityToken = ReadFromFile(TokenFile, "token");
+ config.ChosenAuthMethod = "token";
+ if (IsVerbose()) {
+ Cout << "Using token from file provided with explicit option" << Endl;
+ config.ConnectionParams["token"].push_back({config.SecurityToken, "file provided with explicit --token-file option"});
+ }
+ } else if (config.ParseResult->Has("iam-token-file")) {
+ config.SecurityToken = ReadFromFile(TokenFile, "token");
+ config.ChosenAuthMethod = "token";
+ if (IsVerbose()) {
+ Cout << "Using IAM token from file provided with explicit option" << Endl;
+ config.ConnectionParams["token"].push_back({config.SecurityToken, "file provided with explicit --iam-token-file option"});
+ }
+ } else if (YCTokenFile) {
+ config.YCToken = ReadFromFile(YCTokenFile, "token");
+ config.ChosenAuthMethod = "yc-token";
+ if (IsVerbose()) {
+ Cout << "Using Yandex.Cloud Passport token from file provided with --yc-token-file option" << Endl;
+ config.ConnectionParams["yc-token"].push_back({config.YCToken, "file provided with explicit --yc-token-file option"});
+ }
+ } else if (UseMetadataCredentials) {
+ config.ChosenAuthMethod = "use-metadata-credentials";
+ config.UseMetadataCredentials = true;
+ if (IsVerbose()) {
+ Cout << "Using metadata service due to --use-metadata-credentials option" << Endl;
+ config.ConnectionParams["use-metadata-credentials"].push_back({"true", "explicit --use-metadata-credentials option"});
+ }
+ } else if (SaKeyFile) {
+ config.SaKeyFile = SaKeyFile;
+ config.ChosenAuthMethod = "sa-key-file";
+ if (IsVerbose()) {
+ Cout << "Using service account key file provided with --sa-key-file option" << Endl;
+ config.ConnectionParams["sa-key-file"].push_back({config.SaKeyFile, "explicit --sa-key-file option"});
+ }
+ } else if (UserName || PasswordFile) {
+ if (UserName) {
+ config.StaticCredentials.User = UserName;
+ if (IsVerbose()) {
+ Cout << "Using user name provided with --user option" << Endl;
+ config.ConnectionParams["user"].push_back({UserName, "explicit --user option"});
+ }
+ }
+ if (PasswordFile) {
+ config.StaticCredentials.Password = ReadFromFile(PasswordFile, "password", true);
+ if (!config.StaticCredentials.Password) {
+ DoNotAskForPassword = true;
+ }
+ if (IsVerbose()) {
+ Cout << "Using user password from file provided with --password-file option" << Endl;
+ config.ConnectionParams["password"].push_back({config.StaticCredentials.Password, "file provided with explicit --password-file option"});
+ }
+ }
+ config.ChosenAuthMethod = "static-credentials";
+ }
+ IsAuthSet = true;
+ if (!IsVerbose()) {
+ break;
+ }
case 0:
{
// Priority 2. No explicit auth methods. Checking configuration profile given via --profile option.
- if (GetCredentialsFromProfile(Profile, config, true)) {
+ if (GetCredentialsFromProfile(Profile, config, true) && !IsVerbose()) {
break;
}
@@ -557,128 +802,148 @@ void TClientCommandRootCommon::ParseCredentials(TConfig& config) {
if (config.UseIamAuth) {
TString envIamToken = GetEnv("IAM_TOKEN");
if (!envIamToken.empty()) {
- if (IsVerbose()) {
- Cout << "Using iam token from IAM_TOKEN env variable" << Endl;
+ if (!IsAuthSet) {
+ if (IsVerbose()) {
+ Cout << "Using iam token from IAM_TOKEN env variable" << Endl;
+ }
+ config.ChosenAuthMethod = "token";
+ config.SecurityToken = envIamToken;
+ IsAuthSet = true;
}
- config.SecurityToken = envIamToken;
- break;
+ if (!IsVerbose()) {
+ break;
+ }
+ config.ConnectionParams["token"].push_back({envIamToken, "IAM_TOKEN enviroment variable"});
}
TString envYcToken = GetEnv("YC_TOKEN");
if (!envYcToken.empty()) {
- if (IsVerbose()) {
- Cout << "Using Yandex.Cloud Passport token from YC_TOKEN env variable" << Endl;
+ if (!IsAuthSet) {
+ if (IsVerbose()) {
+ Cout << "Using Yandex.Cloud Passport token from YC_TOKEN env variable" << Endl;
+ }
+ config.ChosenAuthMethod = "yc-token";
+ config.YCToken = envYcToken;
+ IsAuthSet = true;
}
- config.YCToken = envYcToken;
- break;
+ if (!IsVerbose()) {
+ break;
+ }
+ config.ConnectionParams["yc-token"].push_back({envYcToken, "YC_TOKEN enviroment variable"});
}
if (GetEnv("USE_METADATA_CREDENTIALS") == "1") {
- if (IsVerbose()) {
- Cout << "Using metadata service due to USE_METADATA_CREDENTIALS=\"1\" env variable" << Endl;
+ if (!IsAuthSet) {
+ if (IsVerbose()) {
+ Cout << "Using metadata service due to USE_METADATA_CREDENTIALS=\"1\" env variable" << Endl;
+ }
+ config.ChosenAuthMethod = "use-metadata-credentials";
+ config.UseMetadataCredentials = true;
+ IsAuthSet = true;
}
- config.UseMetadataCredentials = true;
- break;
+ if (!IsVerbose()) {
+ break;
+ }
+ config.ConnectionParams["use-metadata-credentials"].push_back({"true", "USE_METADATA_CREDENTIALS enviroment variable"});
}
TString envSaKeyFile = GetEnv("SA_KEY_FILE");
if (!envSaKeyFile.empty()) {
- if (IsVerbose()) {
- Cout << "Using service account key file from SA_KEY_FILE env variable" << Endl;
+ if (!IsAuthSet) {
+ if (IsVerbose()) {
+ Cout << "Using service account key file from SA_KEY_FILE env variable" << Endl;
+ }
+ config.ChosenAuthMethod = "sa-key-file";
+ config.SaKeyFile = envSaKeyFile;
+ IsAuthSet = true;
}
- config.SaKeyFile = envSaKeyFile;
- break;
+ if (!IsVerbose()) {
+ break;
+ }
+ config.ConnectionParams["sa-key-file"].push_back({envSaKeyFile, "SA_KEY_FILE enviroment variable"});
}
}
if (config.UseOAuthToken) {
TString envYdbToken = GetEnv("YDB_TOKEN");
if (!envYdbToken.empty()) {
- if (IsVerbose()) {
- Cout << "Using OAuth token from YDB_TOKEN env variable" << Endl;
+ if (!IsAuthSet) {
+ if (IsVerbose()) {
+ Cout << "Using OAuth token from YDB_TOKEN env variable" << Endl;
+ }
+ config.ChosenAuthMethod = "token";
+ config.SecurityToken = envYdbToken;
+ IsAuthSet = true;
}
- config.SecurityToken = envYdbToken;
- break;
+ if (!IsVerbose()) {
+ break;
+ }
+ config.ConnectionParams["token"].push_back({envYdbToken, "YDB_TOKEN enviroment variable"});
}
}
if (config.UseStaticCredentials) {
TString userName = GetEnv("YDB_USER");
+ bool hasStaticCredentials = false;
if (!userName.empty()) {
+ if (!IsAuthSet) {
+ if (IsVerbose()) {
+ Cout << "Using user name from YDB_USER env variable" << Endl;
+ }
+ hasStaticCredentials = true;
+ config.StaticCredentials.User = userName;
+ }
if (IsVerbose()) {
- Cout << "Using user name from YDB_USER env variable" << Endl;
+ config.ConnectionParams["user"].push_back({userName, "YDB_USER enviroment variable"});
}
- config.StaticCredentials.User = userName;
}
TString password = GetEnv("YDB_PASSWORD");
if (!password.empty()) {
+ if (!IsAuthSet) {
+ if (IsVerbose()) {
+ Cout << "Using user password from YDB_PASSWORD env variable" << Endl;
+ }
+ hasStaticCredentials = true;
+ config.StaticCredentials.Password = password;
+ }
if (IsVerbose()) {
- Cout << "Using user password from YDB_PASSWORD env variable" << Endl;
+ config.ConnectionParams["password"].push_back({password, "YDB_PASSWORD enviroment variable"});
}
- config.StaticCredentials.Password = password;
}
- if (!userName.empty() || !password.empty()) {
+ if (hasStaticCredentials) {
+ config.ChosenAuthMethod = "static-credentials";
+ IsAuthSet = true;
+ }
+ if (!IsVerbose() && (!userName.empty() || !password.empty())) {
break;
}
}
// Priority 4. No auth methods from environment variables too. Checking active configuration profile.
// (if --profile option is not set)
- if (!Profile && GetCredentialsFromProfile(ProfileManager->GetActiveProfile(), config, false)) {
+ if (GetCredentialsFromProfile(ProfileManager->GetActiveProfile(), config, false) && !IsVerbose()) {
break;
}
if (Settings.UseDefaultTokenFile.GetRef()) {
// Priority 5. No auth methods from active configuration profile. Checking default token file.
TString tokenFile = defaultTokenFile;
- if (ReadFromFileIfExists(tokenFile, "default token", config.SecurityToken)) {
+ TString fileContent;
+ if (ReadFromFileIfExists(tokenFile, "default token", fileContent)) {
+ if (!IsAuthSet) {
+ if (!IsVerbose()) {
+ Cout << "Using auth token from default token file " << defaultTokenFile << Endl;
+ }
+ config.ChosenAuthMethod = "token";
+ config.SecurityToken = fileContent;
+ }
if (IsVerbose()) {
- Cout << "Using auth token from default token file " << defaultTokenFile << Endl;
+ config.ConnectionParams["token"].push_back({fileContent, "default token file"});
}
} else {
- if (IsVerbose()) {
+ if (!IsAuthSet && IsVerbose()) {
Cout << "No authentication methods were found. Going without authentication" << Endl;
}
}
}
break;
}
- case 1:
- // Priority 1. Exactly one explicit auth method. Using it.
- if (TokenFile) {
- if (IsVerbose()) {
- Cout << "Using token from file provided with explicit option" << Endl;
- }
- config.SecurityToken = ReadFromFile(TokenFile, "token");
- } else if (YCTokenFile) {
- if (IsVerbose()) {
- Cout << "Using Yandex.Cloud Passport token from file provided with --yc-token-file option" << Endl;
- }
- config.YCToken = ReadFromFile(YCTokenFile, "token");
- } else if (UseMetadataCredentials) {
- if (IsVerbose()) {
- Cout << "Using metadata service due to --use-metadata-credentials option" << Endl;
- }
- config.UseMetadataCredentials = true;
- } else if (SaKeyFile) {
- if (IsVerbose()) {
- Cout << "Using service account key file provided with --sa-key-file option" << Endl;
- }
- config.SaKeyFile = SaKeyFile;
- } else if (UserName || PasswordFile) {
- if (UserName) {
- if (IsVerbose()) {
- Cout << "Using user name provided with --user option" << Endl;
- }
- config.StaticCredentials.User = UserName;
- }
- if (PasswordFile) {
- if (IsVerbose()) {
- Cout << "Using user password from file provided with --password-file option" << Endl;
- }
- config.StaticCredentials.Password = ReadFromFile(PasswordFile, "password", true);
- if (!config.StaticCredentials.Password) {
- DoNotAskForPassword = true;
- }
- }
- }
- break;
default:
TStringBuilder str;
str << explicitAuthMethodCount << " methods were provided via options:";
@@ -704,6 +969,9 @@ void TClientCommandRootCommon::ParseCredentials(TConfig& config) {
if (!config.StaticCredentials.Password && !DoNotAskForPassword) {
Cerr << "Enter password for user " << config.StaticCredentials.User << ": ";
config.StaticCredentials.Password = InputPassword();
+ if (IsVerbose()) {
+ config.ConnectionParams["password"].push_back({config.StaticCredentials.Password, "standard input"});
+ }
}
} else {
if (config.StaticCredentials.Password) {
diff --git a/ydb/public/lib/ydb_cli/commands/ydb_root_common.h b/ydb/public/lib/ydb_cli/commands/ydb_root_common.h
index 4946e1ad00..ed08c53525 100644
--- a/ydb/public/lib/ydb_cli/commands/ydb_root_common.h
+++ b/ydb/public/lib/ydb_cli/commands/ydb_root_common.h
@@ -46,6 +46,11 @@ private:
void ParseDatabase(TConfig& config);
void ParseIamEndpoint(TConfig& config);
void ParseCaCerts(TConfig& config) override;
+ void GetAddressFromString(TConfig& config, TString* result = nullptr);
+ bool ParseProtocolNoConfig(TString& message);
+ void GetCaCerts(TConfig& config);
+ bool TryGetParamFromProfile(const TString& name, std::shared_ptr<IProfile> profile, bool explicitOption,
+ std::function<bool(const TString&, const TString&, bool)> callback);
TString Database;
@@ -70,6 +75,12 @@ private:
TString IamEndpoint;
const TClientSettings& Settings;
TVector<TString> MisuseErrors;
+
+ bool IsAddressSet = false;
+ bool IsDatabaseSet = false;
+ bool IsIamEndpointSet = false;
+ bool IsCaCertsFileSet = false;
+ bool IsAuthSet = false;
};
}
diff --git a/ydb/public/lib/ydb_cli/common/command.h b/ydb/public/lib/ydb_cli/common/command.h
index a9bd59e1b8..ed06e376c5 100644
--- a/ydb/public/lib/ydb_cli/common/command.h
+++ b/ydb/public/lib/ydb_cli/common/command.h
@@ -36,6 +36,11 @@ public:
NLastGetopt::TOpts* Options;
};
+ struct TConnectionParam {
+ TString Value;
+ TString Source;
+ };
+
public:
using TCredentialsGetter = std::function<std::shared_ptr<ICredentialsProviderFactory>(const TClientCommand::TConfig&)>;
@@ -89,6 +94,8 @@ public:
TString Address;
TString Database;
TString CaCerts;
+ TString CaCertsFile;
+ TMap<TString, TVector<TConnectionParam>> ConnectionParams;
bool EnableSsl = false;
bool IsNetworkIntensive = false;
@@ -109,6 +116,7 @@ public:
TString SaKeyFile;
TString IamEndpoint;
TString YScope;
+ TString ChosenAuthMethod;
TString ProfileFile;
bool UseOAuthToken = true;