Skip to content

Commit 18b7a7c

Browse files
author
Andrey Kravchenko
committed
Add sub-section to configure username and password for sync_replica with the ability to read its from a file or from an environment variable
Also fix use :@ characters in username and password
1 parent 933ac7b commit 18b7a7c

File tree

3 files changed

+122
-28
lines changed

3 files changed

+122
-28
lines changed

src/jrd/replication/Config.cpp

Lines changed: 99 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
#include "../common/isc_f_proto.h"
2727
#include "../common/status.h"
2828
#include "../common/StatusArg.h"
29+
#include "../common/utils_proto.h"
30+
#include "../common/os/os_utils.h"
2931
#include "../jrd/constants.h"
3032

3133
#include "Utils.h"
@@ -50,6 +52,8 @@ using namespace Replication;
5052
namespace
5153
{
5254
const char* REPLICATION_CFGFILE = "replication.conf";
55+
constexpr const char* KEY_ENV = "env";
56+
constexpr const char* KEY_FILE = "file";
5357

5458
const ULONG DEFAULT_BUFFER_SIZE = 1024 * 1024; // 1 MB
5559
const ULONG DEFAULT_SEGMENT_SIZE = 16 * 1024 * 1024; // 16 MB
@@ -216,7 +220,69 @@ Config* Config::get(const PathName& lookupName)
216220

217221
if (key == "sync_replica")
218222
{
219-
config->syncReplicas.add(value);
223+
SyncReplica syncReplica(config->getPool());
224+
if (el.sub)
225+
{
226+
syncReplica.database = value;
227+
for (const auto& sub_el : el.sub->getParameters())
228+
{
229+
string sub_key(sub_el.name.c_str());
230+
string sub_value(sub_el.value);
231+
232+
if (sub_value.isEmpty())
233+
continue;
234+
235+
auto pos = sub_key.rfind('_');
236+
if (pos != string::npos)
237+
{
238+
const string key_source = sub_key.substr(pos + 1);
239+
sub_key = sub_key.substr(0, pos);
240+
241+
if (key_source.equals(KEY_ENV))
242+
{
243+
fb_utils::readenv(sub_value.c_str(), sub_value);
244+
if (sub_value.isEmpty())
245+
configError("missing environment variable", value, sub_value);
246+
}
247+
else if (key_source.equals(KEY_FILE))
248+
{
249+
const PathName sub_filename =
250+
fb_utils::getPrefix(IConfigManager::DIR_CONF, sub_value.c_str());
251+
252+
AutoPtr<FILE> file(os_utils::fopen(sub_filename.c_str(), "rt"));
253+
if (!file)
254+
configError("missing file", value, sub_filename.c_str());
255+
256+
// skip first empty lines
257+
sub_value = "";
258+
do
259+
{
260+
if (feof(file))
261+
break;
262+
263+
if (!sub_value.LoadFromFile(file))
264+
break;
265+
266+
sub_value.alltrim(" \t\r");
267+
} while (sub_value.isEmpty());
268+
269+
if (sub_value.isEmpty())
270+
configError("empty file", value, sub_filename.c_str());
271+
}
272+
}
273+
274+
if (sub_key == "username")
275+
syncReplica.username = sub_value.c_str();
276+
else if (sub_key == "password")
277+
syncReplica.password = sub_value.c_str();
278+
else
279+
configError("unknown parameter", value, sub_key);
280+
}
281+
}
282+
else
283+
splitConnectionString(value, syncReplica.database, syncReplica.username, syncReplica.password);
284+
285+
config->syncReplicas.add(syncReplica);
220286
}
221287
else if (key == "buffer_size")
222288
{
@@ -427,3 +493,35 @@ void Config::enumerate(ReplicaList& replicas)
427493
logReplicaStatus(dbName, &localStatus);
428494
}
429495
}
496+
497+
// This routine is used for split input connection string to parts
498+
// input => [<username>[:<password>]@]<database>
499+
//
500+
// Examples:
501+
// server2:/my/replica/database.fdb
502+
// john:smith@server2:/my/replica/database.fdb
503+
504+
void Config::splitConnectionString(const string& input, string& database, string& username, string& password)
505+
{
506+
database = input;
507+
508+
auto pos = database.rfind('@');
509+
if (pos != string::npos)
510+
{
511+
//john:smith
512+
const string temp = database.substr(0, pos);
513+
//server2:/my/replica/database.fdb
514+
database = database.substr(pos + 1);
515+
516+
pos = temp.find(':');
517+
if (pos != string::npos)
518+
{
519+
username = temp.substr(0, pos);
520+
password = temp.substr(pos + 1);
521+
}
522+
else
523+
{
524+
username = temp;
525+
}
526+
}
527+
}

src/jrd/replication/Config.h

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,21 @@
3333

3434
namespace Replication
3535
{
36+
struct SyncReplica
37+
{
38+
SyncReplica(MemoryPool& p)
39+
: database(p), username(p), password(p)
40+
{}
41+
42+
SyncReplica(MemoryPool& p, const SyncReplica& other)
43+
: database(p, other.database), username(p, other.username), password(p, other.password)
44+
{}
45+
46+
Firebird::string database;
47+
Firebird::string username;
48+
Firebird::string password;
49+
};
50+
3651
struct Config : public Firebird::GlobalStorage
3752
{
3853
typedef Firebird::HalfStaticArray<Config*, 4> ReplicaList;
@@ -42,6 +57,8 @@ namespace Replication
4257

4358
static Config* get(const Firebird::PathName& dbName);
4459
static void enumerate(ReplicaList& replicas);
60+
static void splitConnectionString(const Firebird::string& input, Firebird::string& database,
61+
Firebird::string& username, Firebird::string& password);
4562

4663
Firebird::PathName dbName;
4764
ULONG bufferSize;
@@ -55,7 +72,7 @@ namespace Replication
5572
Firebird::PathName archiveDirectory;
5673
Firebird::string archiveCommand;
5774
ULONG archiveTimeout;
58-
Firebird::ObjectsArray<Firebird::string> syncReplicas;
75+
Firebird::ObjectsArray<SyncReplica> syncReplicas;
5976
Firebird::PathName sourceDirectory;
6077
std::optional<Firebird::Guid> sourceGuid;
6178
bool verboseLogging;

src/jrd/replication/Manager.cpp

Lines changed: 5 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -128,39 +128,18 @@ Manager::Manager(const string& dbId,
128128

129129
for (const auto& iter : m_config->syncReplicas)
130130
{
131-
string database = iter;
132-
string login, password;
133-
134-
auto pos = database.find('@');
135-
if (pos != string::npos)
136-
{
137-
const string temp = database.substr(0, pos);
138-
database = database.substr(pos + 1);
139-
140-
pos = temp.find(':');
141-
if (pos != string::npos)
142-
{
143-
login = temp.substr(0, pos);
144-
password = temp.substr(pos + 1);
145-
}
146-
else
147-
{
148-
login = temp;
149-
}
150-
}
151-
152131
ClumpletWriter dpb(ClumpletReader::dpbList, MAX_DPB_SIZE);
153132
dpb.insertByte(isc_dpb_no_db_triggers, 1);
154133

155-
if (login.hasData())
134+
if (iter.username.hasData())
156135
{
157-
dpb.insertString(isc_dpb_user_name, login);
136+
dpb.insertString(isc_dpb_user_name, iter.username);
158137

159-
if (password.hasData())
160-
dpb.insertString(isc_dpb_password, password);
138+
if (iter.password.hasData())
139+
dpb.insertString(isc_dpb_password, iter.password);
161140
}
162141

163-
const auto attachment = provider->attachDatabase(&localStatus, database.c_str(),
142+
const auto attachment = provider->attachDatabase(&localStatus, iter.database.c_str(),
164143
dpb.getBufferLength(), dpb.getBuffer());
165144
if (localStatus->getState() & IStatus::STATE_ERRORS)
166145
{

0 commit comments

Comments
 (0)