Skip to content

Commit d9626ac

Browse files
authored
feat(external-database): add ability to pass readonly user to the external database (#1350)
Signed-off-by: instamenta <[email protected]>
1 parent 77b769f commit d9626ac

File tree

6 files changed

+128
-38
lines changed

6 files changed

+128
-38
lines changed

Taskfile.helper.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -506,4 +506,4 @@ tasks:
506506
cmd: |
507507
kubectl exec -it {{.postgres_container_name}} \
508508
-n {{.postgres_database_namespace}} \
509-
-- /bin/bash /tmp/init.sh "{{.postgres_username}}" "{{.postgres_password}}"
509+
-- /bin/bash /tmp/init.sh "{{.postgres_username}}" "{{.postgres_readonly_username}}" "{{.postgres_readonly_password}}"

examples/external-database-test/Taskfile.yml

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,30 @@ includes:
66
vars:
77
use_port_forwards: "true"
88
postgres_username: "postgres"
9-
postgres_password: "XXXXXXXXX"
9+
postgres_password: "XXXXXXXX"
10+
11+
postgres_readonly_username: "readonlyuser"
12+
postgres_readonly_password: "XXXXXXXX"
13+
14+
postgres_mirror_node_database_name: "mirror_node"
15+
1016
postgres_name: "my-postgresql"
17+
postgres_database_namespace: "database"
1118
postgres_container_name: "{{.postgres_name}}-0"
1219
postgres_host_fqdn: "{{.postgres_name}}.database.svc.cluster.local"
1320
postgres_container_fdqn: "{{.postgres_container_name}}.database.svc.cluster.local"
14-
postgres_mirror_node_database_name: "mirror_node"
15-
postgres_database_namespace: "database"
1621
env:
1722
SOLO_NETWORK_SIZE: "1"
1823
SOLO_DEPLOYMENT: "solo-e2e"
1924
SOLO_NAMESPACE: "solo-e2e"
2025
SOLO_CLUSTER_NAME: "solo-e2e"
21-
MIRROR_NODE_DEPLOY_EXTRA_FLAGS: "--use-external-database --external-database-host {{.postgres_host_fqdn}} --external-database-owner-username {{.postgres_username}} --external-database-owner-password {{.postgres_password}}"
26+
MIRROR_NODE_DEPLOY_EXTRA_FLAGS: |
27+
--use-external-database
28+
--external-database-host {{.postgres_host_fqdn}}
29+
--external-database-owner-username {{.postgres_username}}
30+
--external-database-owner-password {{.postgres_password}}
31+
--external-database-read-username {{.postgres_readonly_username}}
32+
--external-database-read-password {{.postgres_readonly_password}}
2233
tasks:
2334
default:
2435
silent: true

examples/external-database-test/scripts/init.sh

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ set -e
33

44
export HEDERA_MIRROR_DATABASE_NAME="mirror_node"
55
HEDERA_MIRROR_OWNER="$1"
6-
HEDERA_MIRROR_OWNER_PASSWORD="$2"
6+
HEDERA_MIRROR_READ="$2"
7+
HEDERA_MIRROR_READ_PASSWORD="$3"
8+
79

810
export HEDERA_MIRROR_GRPC_DB_HOST="localhost"
911

@@ -26,7 +28,9 @@ psql -d "user=postgres connect_timeout=3" \
2628
--set "dbName=${HEDERA_MIRROR_IMPORTER_DB_NAME}" \
2729
--set "dbSchema=${HEDERA_MIRROR_IMPORTER_DB_SCHEMA}" \
2830
--set "ownerUsername=${HEDERA_MIRROR_IMPORTER_DB_OWNER}" \
29-
--set "tempSchema=${HEDERA_MIRROR_IMPORTER_DB_TEMPSCHEMA}" <<__SQL__
31+
--set "tempSchema=${HEDERA_MIRROR_IMPORTER_DB_TEMPSCHEMA}" \
32+
--set "readUsername=${HEDERA_MIRROR_READ}" \
33+
--set "readPassword=${HEDERA_MIRROR_READ_PASSWORD}" <<__SQL__
3034
3135
-- Create database & owner
3236
create database :dbName with owner :ownerUsername;
@@ -59,6 +63,10 @@ create schema if not exists :tempSchema authorization temporary_admin;
5963
grant usage on schema :tempSchema to public;
6064
revoke create on schema :tempSchema from public;
6165
66+
-- Create readonly user with password and grant privileges
67+
create user :readUsername with password :'readPassword';
68+
grant readonly to :readUsername;
69+
6270
-- Grant readonly privileges
6371
grant connect on database :dbName to readonly;
6472
grant select on all tables in schema :dbSchema, :tempSchema to readonly;

src/commands/flags.ts

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1567,6 +1567,8 @@ export class Flags {
15671567
prompt: undefined,
15681568
};
15691569

1570+
//* ----------------- External Mirror Node PostgreSQL Database Related Flags ------------------ *//
1571+
15701572
static readonly externalDatabaseHost: CommandFlag = {
15711573
constName: 'externalDatabaseHost',
15721574
name: 'external-database-host',
@@ -1628,6 +1630,49 @@ export class Flags {
16281630
},
16291631
};
16301632

1633+
static readonly externalDatabaseReadonlyUsername: CommandFlag = {
1634+
constName: 'externalDatabaseReadonlyUsername',
1635+
name: 'external-database-read-username',
1636+
definition: {
1637+
describe: `Use to provide the external database readonly user's username if the '--${Flags.useExternalDatabase.name}' is passed`,
1638+
defaultValue: '',
1639+
type: 'string',
1640+
},
1641+
prompt: async function promptGrpcWebTlsKeyPath(task: ListrTaskWrapper<any, any, any>, input: any) {
1642+
return await Flags.promptText(
1643+
task,
1644+
input,
1645+
Flags.externalDatabaseReadonlyUsername.definition.defaultValue,
1646+
'Enter username of the external database readonly user',
1647+
null,
1648+
Flags.externalDatabaseReadonlyUsername.name,
1649+
);
1650+
},
1651+
};
1652+
1653+
static readonly externalDatabaseReadonlyPassword: CommandFlag = {
1654+
constName: 'externalDatabaseReadonlyPassword',
1655+
name: 'external-database-read-password',
1656+
definition: {
1657+
describe: `Use to provide the external database readonly user's password if the '--${Flags.useExternalDatabase.name}' is passed`,
1658+
defaultValue: '',
1659+
type: 'string',
1660+
dataMask: constants.STANDARD_DATAMASK,
1661+
},
1662+
prompt: async function promptGrpcWebTlsKeyPath(task: ListrTaskWrapper<any, any, any>, input: any) {
1663+
return await Flags.promptText(
1664+
task,
1665+
input,
1666+
Flags.externalDatabaseReadonlyPassword.definition.defaultValue,
1667+
'Enter password of the external database readonly user',
1668+
null,
1669+
Flags.externalDatabaseReadonlyPassword.name,
1670+
);
1671+
},
1672+
};
1673+
1674+
//* ------------------------------------------------------------------------------------------- *//
1675+
16311676
static readonly grpcTlsKeyPath: CommandFlag = {
16321677
constName: 'grpcTlsKeyPath',
16331678
name: 'grpc-tls-key',
@@ -1918,6 +1963,8 @@ export class Flags {
19181963
Flags.externalDatabaseHost,
19191964
Flags.externalDatabaseOwnerUsername,
19201965
Flags.externalDatabaseOwnerPassword,
1966+
Flags.externalDatabaseReadonlyUsername,
1967+
Flags.externalDatabaseReadonlyPassword,
19211968
];
19221969

19231970
/** Resets the definition.disablePrompt for all flags */

src/commands/mirror_node.ts

Lines changed: 53 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ interface MirrorNodeDeployConfigClass {
5454
externalDatabaseHost: Optional<string>;
5555
externalDatabaseOwnerUsername: Optional<string>;
5656
externalDatabaseOwnerPassword: Optional<string>;
57+
externalDatabaseReadonlyUsername: Optional<string>;
58+
externalDatabaseReadonlyPassword: Optional<string>;
5759
}
5860

5961
interface Context {
@@ -102,6 +104,8 @@ export class MirrorNodeCommand extends BaseCommand {
102104
flags.externalDatabaseHost,
103105
flags.externalDatabaseOwnerUsername,
104106
flags.externalDatabaseOwnerPassword,
107+
flags.externalDatabaseReadonlyUsername,
108+
flags.externalDatabaseReadonlyPassword,
105109
];
106110
}
107111

@@ -149,8 +153,10 @@ export class MirrorNodeCommand extends BaseCommand {
149153
if (config.useExternalDatabase) {
150154
const {
151155
externalDatabaseHost: host,
152-
externalDatabaseOwnerUsername: username,
153-
externalDatabaseOwnerPassword: password,
156+
externalDatabaseOwnerUsername: ownerUsername,
157+
externalDatabaseOwnerPassword: ownerPassword,
158+
externalDatabaseReadonlyUsername: readonlyUsername,
159+
externalDatabaseReadonlyPassword: readonlyPassword,
154160
} = config;
155161

156162
valuesArg += helpers.populateHelmArgs({
@@ -163,21 +169,24 @@ export class MirrorNodeCommand extends BaseCommand {
163169
'db.name': 'mirror_node',
164170

165171
// set the usernames
166-
'db.owner.username': username,
167-
'importer.db.username': username,
168-
'grpc.db.username': username,
169-
'restjava.db.username': username,
170-
'web3.db.username': username,
171-
// Fixes problem where importer's V1.0__Init.sql migration fails
172-
// 'rest.db.username': username,
172+
'db.owner.username': ownerUsername,
173+
'importer.db.username': ownerUsername,
174+
175+
'grpc.db.username': readonlyUsername,
176+
'restjava.db.username': readonlyUsername,
177+
'web3.db.username': readonlyUsername,
178+
179+
// TODO: Fixes a problem where importer's V1.0__Init.sql migration fails
180+
// 'rest.db.username': readonlyUsername,
173181

174182
// set the passwords
175-
'db.owner.password': password,
176-
'importer.db.password': password,
177-
'grpc.db.password': password,
178-
'rest.db.password': password,
179-
'restjava.db.password': password,
180-
'web3.db.password': password,
183+
'db.owner.password': ownerPassword,
184+
'importer.db.password': ownerPassword,
185+
186+
'grpc.db.password': readonlyPassword,
187+
'restjava.db.password': readonlyPassword,
188+
'web3.db.password': readonlyPassword,
189+
'rest.db.password': readonlyPassword,
181190
});
182191
}
183192

@@ -206,6 +215,8 @@ export class MirrorNodeCommand extends BaseCommand {
206215
flags.externalDatabaseHost,
207216
flags.externalDatabaseOwnerUsername,
208217
flags.externalDatabaseOwnerPassword,
218+
flags.externalDatabaseReadonlyUsername,
219+
flags.externalDatabaseReadonlyPassword,
209220
]);
210221

211222
await self.configManager.executePrompt(task, MirrorNodeCommand.DEPLOY_FLAGS_LIST);
@@ -276,24 +287,35 @@ export class MirrorNodeCommand extends BaseCommand {
276287
flags.externalDatabaseHost,
277288
flags.externalDatabaseOwnerUsername,
278289
flags.externalDatabaseOwnerPassword,
290+
flags.externalDatabaseReadonlyUsername,
291+
flags.externalDatabaseReadonlyPassword,
279292
]);
280-
} else if (ctx.config.useExternalDatabase) {
281-
if (
282-
!ctx.config.externalDatabaseHost ||
293+
} else if (
294+
ctx.config.useExternalDatabase &&
295+
(!ctx.config.externalDatabaseHost ||
283296
!ctx.config.externalDatabaseOwnerUsername ||
284-
!ctx.config.externalDatabaseOwnerPassword
285-
) {
286-
const missingFlags: CommandFlag[] = [];
287-
if (!ctx.config.externalDatabaseHost) missingFlags.push(flags.externalDatabaseHost);
288-
if (!ctx.config.externalDatabaseOwnerUsername) missingFlags.push(flags.externalDatabaseOwnerUsername);
289-
if (!ctx.config.externalDatabaseOwnerPassword) missingFlags.push(flags.externalDatabaseOwnerPassword);
290-
if (missingFlags.length) {
291-
const errorMessage =
292-
'There are missing values that need to be provided when' +
293-
`${chalk.cyan(`--${flags.useExternalDatabase.name}`)} is provided: `;
294-
295-
throw new SoloError(`${errorMessage} ${missingFlags.map(flag => `--${flag.name}`).join(', ')}`);
296-
}
297+
!ctx.config.externalDatabaseOwnerPassword ||
298+
!ctx.config.externalDatabaseReadonlyUsername ||
299+
!ctx.config.externalDatabaseReadonlyPassword)
300+
) {
301+
const missingFlags: CommandFlag[] = [];
302+
if (!ctx.config.externalDatabaseHost) missingFlags.push(flags.externalDatabaseHost);
303+
if (!ctx.config.externalDatabaseOwnerUsername) missingFlags.push(flags.externalDatabaseOwnerUsername);
304+
if (!ctx.config.externalDatabaseOwnerPassword) missingFlags.push(flags.externalDatabaseOwnerPassword);
305+
306+
if (!ctx.config.externalDatabaseReadonlyUsername) {
307+
missingFlags.push(flags.externalDatabaseReadonlyUsername);
308+
}
309+
if (!ctx.config.externalDatabaseReadonlyPassword) {
310+
missingFlags.push(flags.externalDatabaseReadonlyPassword);
311+
}
312+
313+
if (missingFlags.length) {
314+
const errorMessage =
315+
'There are missing values that need to be provided when' +
316+
`${chalk.cyan(`--${flags.useExternalDatabase.name}`)} is provided: `;
317+
318+
throw new SoloError(`${errorMessage} ${missingFlags.map(flag => `--${flag.name}`).join(', ')}`);
297319
}
298320
}
299321

test/e2e/commands/mirror_node.test.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,8 @@ e2eTestSuite(testName, argv, undefined, undefined, undefined, undefined, undefin
9898
flags.externalDatabaseHost.constName,
9999
flags.externalDatabaseOwnerUsername.constName,
100100
flags.externalDatabaseOwnerPassword.constName,
101+
flags.externalDatabaseReadonlyUsername.constName,
102+
flags.externalDatabaseReadonlyPassword.constName,
101103
]);
102104
expect(explorerCommand.getUnusedConfigs(MirrorNodeCommand.DEPLOY_CONFIGS_NAME)).to.deep.equal([
103105
flags.hederaExplorerTlsHostName.constName,

0 commit comments

Comments
 (0)