Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(external-database): add ability to pass readonly user to the external database #1350

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Taskfile.helper.yml
Original file line number Diff line number Diff line change
Expand Up @@ -506,4 +506,4 @@ tasks:
cmd: |
kubectl exec -it {{.postgres_container_name}} \
-n {{.postgres_database_namespace}} \
-- /bin/bash /tmp/init.sh "{{.postgres_username}}" "{{.postgres_password}}"
-- /bin/bash /tmp/init.sh "{{.postgres_username}}" "{{.postgres_readonly_username}}" "{{.postgres_readonly_password}}"
19 changes: 15 additions & 4 deletions examples/external-database-test/Taskfile.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,30 @@ includes:
vars:
use_port_forwards: "true"
postgres_username: "postgres"
postgres_password: "XXXXXXXXX"
postgres_password: "XXXXXXXX"

postgres_readonly_username: "readonlyuser"
postgres_readonly_password: "XXXXXXXX"

postgres_mirror_node_database_name: "mirror_node"

postgres_name: "my-postgresql"
postgres_database_namespace: "database"
postgres_container_name: "{{.postgres_name}}-0"
postgres_host_fqdn: "{{.postgres_name}}.database.svc.cluster.local"
postgres_container_fdqn: "{{.postgres_container_name}}.database.svc.cluster.local"
postgres_mirror_node_database_name: "mirror_node"
postgres_database_namespace: "database"
env:
SOLO_NETWORK_SIZE: "1"
SOLO_DEPLOYMENT: "solo-e2e"
SOLO_NAMESPACE: "solo-e2e"
SOLO_CLUSTER_NAME: "solo-e2e"
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}}"
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}}
--external-database-read-username {{.postgres_readonly_username}}
--external-database-read-password {{.postgres_readonly_password}}
tasks:
default:
silent: true
Expand Down
12 changes: 10 additions & 2 deletions examples/external-database-test/scripts/init.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ set -e

export HEDERA_MIRROR_DATABASE_NAME="mirror_node"
HEDERA_MIRROR_OWNER="$1"
HEDERA_MIRROR_OWNER_PASSWORD="$2"
HEDERA_MIRROR_READ="$2"
HEDERA_MIRROR_READ_PASSWORD="$3"


export HEDERA_MIRROR_GRPC_DB_HOST="localhost"

Expand All @@ -26,7 +28,9 @@ psql -d "user=postgres connect_timeout=3" \
--set "dbName=${HEDERA_MIRROR_IMPORTER_DB_NAME}" \
--set "dbSchema=${HEDERA_MIRROR_IMPORTER_DB_SCHEMA}" \
--set "ownerUsername=${HEDERA_MIRROR_IMPORTER_DB_OWNER}" \
--set "tempSchema=${HEDERA_MIRROR_IMPORTER_DB_TEMPSCHEMA}" <<__SQL__
--set "tempSchema=${HEDERA_MIRROR_IMPORTER_DB_TEMPSCHEMA}" \
--set "readUsername=${HEDERA_MIRROR_READ}" \
--set "readPassword=${HEDERA_MIRROR_READ_PASSWORD}" <<__SQL__

-- Create database & owner
create database :dbName with owner :ownerUsername;
Expand Down Expand Up @@ -59,6 +63,10 @@ create schema if not exists :tempSchema authorization temporary_admin;
grant usage on schema :tempSchema to public;
revoke create on schema :tempSchema from public;

-- Create readonly user with password and grant privileges
create user :readUsername with password :'readPassword';
grant readonly to :readUsername;

-- Grant readonly privileges
grant connect on database :dbName to readonly;
grant select on all tables in schema :dbSchema, :tempSchema to readonly;
Expand Down
47 changes: 47 additions & 0 deletions src/commands/flags.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1567,6 +1567,8 @@
prompt: undefined,
};

//* ----------------- External Mirror Node PostgreSQL Database Related Flags ------------------ *//

static readonly externalDatabaseHost: CommandFlag = {
constName: 'externalDatabaseHost',
name: 'external-database-host',
Expand Down Expand Up @@ -1628,6 +1630,49 @@
},
};

static readonly externalDatabaseReadonlyUsername: CommandFlag = {
constName: 'externalDatabaseReadonlyUsername',
name: 'external-database-read-username',
definition: {
describe: `Use to provide the external database readonly user's username if the '--${Flags.useExternalDatabase.name}' is passed`,
defaultValue: '',
type: 'string',
},
prompt: async function promptGrpcWebTlsKeyPath(task: ListrTaskWrapper<any, any, any>, input: any) {
return await Flags.promptText(
task,
input,
Flags.externalDatabaseReadonlyUsername.definition.defaultValue,
'Enter username of the external database readonly user',
null,
Flags.externalDatabaseReadonlyUsername.name,
);
},

Check warning on line 1650 in src/commands/flags.ts

View check run for this annotation

Codecov / codecov/patch

src/commands/flags.ts#L1642-L1650

Added lines #L1642 - L1650 were not covered by tests
};

static readonly externalDatabaseReadonlyPassword: CommandFlag = {
constName: 'externalDatabaseReadonlyPassword',
name: 'external-database-read-password',
definition: {
describe: `Use to provide the external database readonly user's password if the '--${Flags.useExternalDatabase.name}' is passed`,
defaultValue: '',
type: 'string',
dataMask: constants.STANDARD_DATAMASK,
},
prompt: async function promptGrpcWebTlsKeyPath(task: ListrTaskWrapper<any, any, any>, input: any) {
return await Flags.promptText(
task,
input,
Flags.externalDatabaseReadonlyPassword.definition.defaultValue,
'Enter password of the external database readonly user',
null,
Flags.externalDatabaseReadonlyPassword.name,
);
},

Check warning on line 1671 in src/commands/flags.ts

View check run for this annotation

Codecov / codecov/patch

src/commands/flags.ts#L1663-L1671

Added lines #L1663 - L1671 were not covered by tests
};

//* ------------------------------------------------------------------------------------------- *//

static readonly grpcTlsKeyPath: CommandFlag = {
constName: 'grpcTlsKeyPath',
name: 'grpc-tls-key',
Expand Down Expand Up @@ -1918,6 +1963,8 @@
Flags.externalDatabaseHost,
Flags.externalDatabaseOwnerUsername,
Flags.externalDatabaseOwnerPassword,
Flags.externalDatabaseReadonlyUsername,
Flags.externalDatabaseReadonlyPassword,
];

/** Resets the definition.disablePrompt for all flags */
Expand Down
84 changes: 53 additions & 31 deletions src/commands/mirror_node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@
externalDatabaseHost: Optional<string>;
externalDatabaseOwnerUsername: Optional<string>;
externalDatabaseOwnerPassword: Optional<string>;
externalDatabaseReadonlyUsername: Optional<string>;
externalDatabaseReadonlyPassword: Optional<string>;
}

interface Context {
Expand Down Expand Up @@ -102,6 +104,8 @@
flags.externalDatabaseHost,
flags.externalDatabaseOwnerUsername,
flags.externalDatabaseOwnerPassword,
flags.externalDatabaseReadonlyUsername,
flags.externalDatabaseReadonlyPassword,
];
}

Expand Down Expand Up @@ -149,8 +153,10 @@
if (config.useExternalDatabase) {
const {
externalDatabaseHost: host,
externalDatabaseOwnerUsername: username,
externalDatabaseOwnerPassword: password,
externalDatabaseOwnerUsername: ownerUsername,
externalDatabaseOwnerPassword: ownerPassword,
externalDatabaseReadonlyUsername: readonlyUsername,
externalDatabaseReadonlyPassword: readonlyPassword,

Check warning on line 159 in src/commands/mirror_node.ts

View check run for this annotation

Codecov / codecov/patch

src/commands/mirror_node.ts#L156-L159

Added lines #L156 - L159 were not covered by tests
} = config;

valuesArg += helpers.populateHelmArgs({
Expand All @@ -163,21 +169,24 @@
'db.name': 'mirror_node',

// set the usernames
'db.owner.username': username,
'importer.db.username': username,
'grpc.db.username': username,
'restjava.db.username': username,
'web3.db.username': username,
// Fixes problem where importer's V1.0__Init.sql migration fails
// 'rest.db.username': username,
'db.owner.username': ownerUsername,
'importer.db.username': ownerUsername,

'grpc.db.username': readonlyUsername,
'restjava.db.username': readonlyUsername,
'web3.db.username': readonlyUsername,

// TODO: Fixes a problem where importer's V1.0__Init.sql migration fails
// 'rest.db.username': readonlyUsername,

Check warning on line 180 in src/commands/mirror_node.ts

View check run for this annotation

Codecov / codecov/patch

src/commands/mirror_node.ts#L172-L180

Added lines #L172 - L180 were not covered by tests

// set the passwords
'db.owner.password': password,
'importer.db.password': password,
'grpc.db.password': password,
'rest.db.password': password,
'restjava.db.password': password,
'web3.db.password': password,
'db.owner.password': ownerPassword,
'importer.db.password': ownerPassword,

'grpc.db.password': readonlyPassword,
'restjava.db.password': readonlyPassword,
'web3.db.password': readonlyPassword,
'rest.db.password': readonlyPassword,

Check warning on line 189 in src/commands/mirror_node.ts

View check run for this annotation

Codecov / codecov/patch

src/commands/mirror_node.ts#L183-L189

Added lines #L183 - L189 were not covered by tests
});
}

Expand Down Expand Up @@ -206,6 +215,8 @@
flags.externalDatabaseHost,
flags.externalDatabaseOwnerUsername,
flags.externalDatabaseOwnerPassword,
flags.externalDatabaseReadonlyUsername,
flags.externalDatabaseReadonlyPassword,
]);

await self.configManager.executePrompt(task, MirrorNodeCommand.DEPLOY_FLAGS_LIST);
Expand Down Expand Up @@ -276,24 +287,35 @@
flags.externalDatabaseHost,
flags.externalDatabaseOwnerUsername,
flags.externalDatabaseOwnerPassword,
flags.externalDatabaseReadonlyUsername,
flags.externalDatabaseReadonlyPassword,

Check warning on line 291 in src/commands/mirror_node.ts

View check run for this annotation

Codecov / codecov/patch

src/commands/mirror_node.ts#L290-L291

Added lines #L290 - L291 were not covered by tests
]);
} else if (ctx.config.useExternalDatabase) {
if (
!ctx.config.externalDatabaseHost ||
} else if (

Check warning on line 293 in src/commands/mirror_node.ts

View check run for this annotation

Codecov / codecov/patch

src/commands/mirror_node.ts#L293

Added line #L293 was not covered by tests
ctx.config.useExternalDatabase &&
(!ctx.config.externalDatabaseHost ||

Check warning on line 295 in src/commands/mirror_node.ts

View check run for this annotation

Codecov / codecov/patch

src/commands/mirror_node.ts#L295

Added line #L295 was not covered by tests
!ctx.config.externalDatabaseOwnerUsername ||
!ctx.config.externalDatabaseOwnerPassword
) {
const missingFlags: CommandFlag[] = [];
if (!ctx.config.externalDatabaseHost) missingFlags.push(flags.externalDatabaseHost);
if (!ctx.config.externalDatabaseOwnerUsername) missingFlags.push(flags.externalDatabaseOwnerUsername);
if (!ctx.config.externalDatabaseOwnerPassword) missingFlags.push(flags.externalDatabaseOwnerPassword);
if (missingFlags.length) {
const errorMessage =
'There are missing values that need to be provided when' +
`${chalk.cyan(`--${flags.useExternalDatabase.name}`)} is provided: `;

throw new SoloError(`${errorMessage} ${missingFlags.map(flag => `--${flag.name}`).join(', ')}`);
}
!ctx.config.externalDatabaseOwnerPassword ||
!ctx.config.externalDatabaseReadonlyUsername ||
!ctx.config.externalDatabaseReadonlyPassword)

Check warning on line 299 in src/commands/mirror_node.ts

View check run for this annotation

Codecov / codecov/patch

src/commands/mirror_node.ts#L297-L299

Added lines #L297 - L299 were not covered by tests
) {
const missingFlags: CommandFlag[] = [];
if (!ctx.config.externalDatabaseHost) missingFlags.push(flags.externalDatabaseHost);
if (!ctx.config.externalDatabaseOwnerUsername) missingFlags.push(flags.externalDatabaseOwnerUsername);
if (!ctx.config.externalDatabaseOwnerPassword) missingFlags.push(flags.externalDatabaseOwnerPassword);

if (!ctx.config.externalDatabaseReadonlyUsername) {
missingFlags.push(flags.externalDatabaseReadonlyUsername);
}
if (!ctx.config.externalDatabaseReadonlyPassword) {
missingFlags.push(flags.externalDatabaseReadonlyPassword);
}

if (missingFlags.length) {
const errorMessage =
'There are missing values that need to be provided when' +
`${chalk.cyan(`--${flags.useExternalDatabase.name}`)} is provided: `;

throw new SoloError(`${errorMessage} ${missingFlags.map(flag => `--${flag.name}`).join(', ')}`);

Check warning on line 318 in src/commands/mirror_node.ts

View check run for this annotation

Codecov / codecov/patch

src/commands/mirror_node.ts#L301-L318

Added lines #L301 - L318 were not covered by tests
}
}

Expand Down
2 changes: 2 additions & 0 deletions test/e2e/commands/mirror_node.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@ e2eTestSuite(testName, argv, undefined, undefined, undefined, undefined, undefin
flags.externalDatabaseHost.constName,
flags.externalDatabaseOwnerUsername.constName,
flags.externalDatabaseOwnerPassword.constName,
flags.externalDatabaseReadonlyUsername.constName,
flags.externalDatabaseReadonlyPassword.constName,
]);
expect(explorerCommand.getUnusedConfigs(MirrorNodeCommand.DEPLOY_CONFIGS_NAME)).to.deep.equal([
flags.hederaExplorerTlsHostName.constName,
Expand Down
Loading