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

UI/ Add PostgreSQL DB #12945

Merged
merged 13 commits into from Oct 29, 2021
3 changes: 3 additions & 0 deletions changelog/12945.txt
@@ -0,0 +1,3 @@
```release-note:feature
**Postgres in the UI**: Postgres DB is now supported by the UI
```
17 changes: 16 additions & 1 deletion ui/app/templates/components/database-connection.hbs
Expand Up @@ -23,7 +23,7 @@
<button
type="button"
class="toolbar-link"
{{on 'click' this.delete}}
onclick={{action (mut isDeleteModalActive) true}}
data-test-database-connection-delete
>
Delete connection
Expand Down Expand Up @@ -367,3 +367,18 @@
</button>
</footer>
</Modal>

<ConfirmationModal
@title="Delete connection?"
@onClose={{action (mut isDeleteModalActive) false}}
@isActive={{isDeleteModalActive}}
@confirmText={{@model.name}}
@toConfirmMsg="deleting the connection"
@onConfirm={{action "delete"}}
@testSelector="delete"
>
<p>
Deleting the connection means that any associated roles won't be able to generate credentials until the connection is reconfigured.
</p>
<MessageError @model={{model}} @errorMessage={{error}} />
</ConfirmationModal>
2 changes: 1 addition & 1 deletion ui/app/templates/components/transformation-edit.hbs
Expand Up @@ -91,7 +91,7 @@
@onClose={{action (mut isDeleteModalActive) false}}
@isActive={{isDeleteModalActive}}
@confirmText={{model.name}}
@toConfirmMsg="Type {{model.name}} to confirm deleting the transformation."
@toConfirmMsg="deleting the transformation."
@onConfirm={{action "delete"}}
>
<p class="has-bottom-margin-m">
Expand Down
71 changes: 48 additions & 23 deletions ui/app/utils/database-helpers.js
@@ -1,4 +1,24 @@
export const AVAILABLE_PLUGIN_TYPES = [
{
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved elasticsearch to the top because alphabetized plugin list

value: 'elasticsearch-database-plugin',
displayName: 'Elasticsearch',
fields: [
{ attr: 'plugin_name' },
{ attr: 'name' },
{ attr: 'verify_connection' },
{ attr: 'password_policy' },
{ attr: 'url', group: 'pluginConfig' },
{ attr: 'username', group: 'pluginConfig', show: false },
{ attr: 'password', group: 'pluginConfig', show: false },
{ attr: 'ca_cert', group: 'pluginConfig' },
{ attr: 'ca_path', group: 'pluginConfig' },
{ attr: 'client_cert', group: 'pluginConfig' },
{ attr: 'client_key', group: 'pluginConfig' },
{ attr: 'tls_server_name', group: 'pluginConfig' },
{ attr: 'insecure', group: 'pluginConfig' },
{ attr: 'username_template', group: 'pluginConfig' },
],
},
{
value: 'mongodb-database-plugin',
displayName: 'MongoDB',
Expand Down Expand Up @@ -36,8 +56,8 @@ export const AVAILABLE_PLUGIN_TYPES = [
],
},
{
value: 'mysql-database-plugin',
displayName: 'MySQL/MariaDB',
value: 'mysql-aurora-database-plugin',
displayName: 'MySQL (Aurora)',
fields: [
{ attr: 'plugin_name' },
{ attr: 'name' },
Expand All @@ -56,8 +76,8 @@ export const AVAILABLE_PLUGIN_TYPES = [
],
},
{
value: 'mysql-aurora-database-plugin',
displayName: 'MySQL (Aurora)',
value: 'mysql-legacy-database-plugin',
displayName: 'MySQL (Legacy)',
fields: [
{ attr: 'plugin_name' },
{ attr: 'name' },
Expand All @@ -76,8 +96,8 @@ export const AVAILABLE_PLUGIN_TYPES = [
],
},
{
value: 'mysql-rds-database-plugin',
displayName: 'MySQL (RDS)',
value: 'mysql-database-plugin',
displayName: 'MySQL/MariaDB',
fields: [
{ attr: 'plugin_name' },
{ attr: 'name' },
Expand All @@ -96,8 +116,8 @@ export const AVAILABLE_PLUGIN_TYPES = [
],
},
{
value: 'mysql-legacy-database-plugin',
displayName: 'MySQL (Legacy)',
value: 'mysql-rds-database-plugin',
displayName: 'MySQL (RDS)',
fields: [
{ attr: 'plugin_name' },
{ attr: 'name' },
Expand All @@ -116,28 +136,26 @@ export const AVAILABLE_PLUGIN_TYPES = [
],
},
{
value: 'elasticsearch-database-plugin',
displayName: 'Elasticsearch',
value: 'oracle-database-plugin',
displayName: 'Oracle',
fields: [
{ attr: 'plugin_name' },
{ attr: 'name' },
{ attr: 'verify_connection' },
{ attr: 'password_policy' },
{ attr: 'url', group: 'pluginConfig' },
{ attr: 'connection_url', group: 'pluginConfig' },
{ attr: 'username', group: 'pluginConfig', show: false },
{ attr: 'password', group: 'pluginConfig', show: false },
{ attr: 'ca_cert', group: 'pluginConfig' },
{ attr: 'ca_path', group: 'pluginConfig' },
{ attr: 'client_cert', group: 'pluginConfig' },
{ attr: 'client_key', group: 'pluginConfig' },
{ attr: 'tls_server_name', group: 'pluginConfig' },
{ attr: 'insecure', group: 'pluginConfig' },
{ attr: 'max_open_connections', group: 'pluginConfig' },
{ attr: 'max_idle_connections', group: 'pluginConfig' },
{ attr: 'max_connection_lifetime', group: 'pluginConfig' },
{ attr: 'username_template', group: 'pluginConfig' },
{ attr: 'root_rotation_statements', group: 'statements' },
],
},
{
value: 'oracle-database-plugin',
displayName: 'Oracle',
value: 'postgresql-database-plugin',
displayName: 'PostgreSQL',
fields: [
{ attr: 'plugin_name' },
{ attr: 'name' },
Expand All @@ -163,25 +181,32 @@ export const ROLE_FIELDS = {
export const STATEMENT_FIELDS = {
static: {
default: ['rotation_statements'],
'elasticsearch-database-plugin': [],
'mongodb-database-plugin': [],
'mssql-database-plugin': [],
'mysql-database-plugin': [],
'mysql-aurora-database-plugin': [],
'mysql-rds-database-plugin': [],
'mysql-legacy-database-plugin': [],
'elasticsearch-database-plugin': [],
'mysql-rds-database-plugin': [],
'oracle-database-plugin': [],
'postgresql-database-plugin': [],
},
dynamic: {
default: ['creation_statements', 'revocation_statements', 'rollback_statements', 'renew_statements'],
'elasticsearch-database-plugin': ['creation_statement'],
'mongodb-database-plugin': ['creation_statement', 'revocation_statement'],
'mssql-database-plugin': ['creation_statements', 'revocation_statements'],
'mysql-database-plugin': ['creation_statements', 'revocation_statements'],
'mysql-aurora-database-plugin': ['creation_statements', 'revocation_statements'],
'mysql-rds-database-plugin': ['creation_statements', 'revocation_statements'],
'mysql-legacy-database-plugin': ['creation_statements', 'revocation_statements'],
'elasticsearch-database-plugin': ['creation_statement'],
'mysql-rds-database-plugin': ['creation_statements', 'revocation_statements'],
'oracle-database-plugin': ['creation_statements', 'revocation_statements'],
'postgresql-database-plugin': [
'creation_statements',
'revocation_statements',
'rollback_statements',
'renew_statements',
],
},
};

Expand Down
1 change: 1 addition & 0 deletions ui/lib/core/addon/components/confirmation-modal.js
Expand Up @@ -9,6 +9,7 @@
* @title="Do Dangerous Thing?"
* @isActive={{isModalActive}}
* @onClose={{action (mut isModalActive) false}}
* @onConfirmMsg="deleting this thing to delete."
* />
* ```
* @param {function} onConfirm - onConfirm is the action that happens when user clicks onConfirm after filling in the confirmation block
Expand Down
41 changes: 37 additions & 4 deletions ui/tests/acceptance/secrets/backend/database/secret-test.js
Expand Up @@ -185,6 +185,31 @@ const connectionTests = [
.exists(`Root rotation statements exists for ${name}`);
},
},
{
name: 'postgresql-connection',
plugin: 'postgresql-database-plugin',
url: `postgresql://{{username}}:{{password}}@localhost:5432/postgres?sslmode=disable`,
requiredFields: async (assert, name) => {
assert.dom('[data-test-input="username"]').exists(`Username field exists for ${name}`);
assert.dom('[data-test-input="password"]').exists(`Password field exists for ${name}`);
assert
.dom('[data-test-input="max_open_connections"]')
.exists(`Max open connections exists for ${name}`);
assert
.dom('[data-test-input="max_idle_connections"]')
.exists(`Max idle connections exists for ${name}`);
assert
.dom('[data-test-input="max_connection_lifetime"]')
.exists(`Max connection lifetime exists for ${name}`);
assert
.dom('[data-test-input="root_rotation_statements"]')
.exists(`Root rotation statements exists for ${name}`);
assert
.dom('[data-test-toggle-input="show-username_template"]')
.exists(`Username template toggle exists for ${name}`);
},
},
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tests fail when Oracle isn't the last database - since actually connecting Oracle is skipped after checking that the fields exist, the test doesn't redirect to the connection list page and start the connecting a database process over. (And the test checks for an empty state when no DB is selected)

// keep oracle as last DB because it is skipped in some tests (line 285) the UI doesn't return to empty state after
{
name: 'oracle-connection',
plugin: 'oracle-database-plugin',
Expand Down Expand Up @@ -256,17 +281,17 @@ module('Acceptance | secrets/database/*', function(hooks) {
} else {
await connectionPage.connectionUrl(testCase.url);
}
// skip adding oracle db connection since plugin doesn't exists
// skip adding oracle db connection since plugin doesn't exist
if (testCase.plugin === 'oracle-database-plugin') {
testCase.requiredFields(assert, testCase.name);
continue;
}
testCase.requiredFields(assert, testCase.name);
await connectionPage.toggleVerify();
await connectionPage.save();
await connectionPage.enable();
await settled();
assert
.dom('[data-test-modal-title]')
.dom('.modal.is-active .title')
.hasText('Rotate your root credentials?', 'Modal appears asking to rotate root credentials');
await connectionPage.enable();
assert.ok(
Expand Down Expand Up @@ -335,8 +360,9 @@ module('Acceptance | secrets/database/*', function(hooks) {
// uncheck verify for the save step to work
await connectionPage.toggleVerify();
await connectionPage.save();
await settled();
assert
.dom('[data-test-modal-title]')
.dom('.modal.is-active .title')
.hasText('Rotate your root credentials?', 'Modal appears asking to ');
await connectionPage.enable();
assert.equal(
Expand All @@ -356,6 +382,13 @@ module('Acceptance | secrets/database/*', function(hooks) {
}
});
await connectionPage.delete();
assert
.dom('.modal.is-active .title')
.hasText('Delete connection?', 'Modal appears asking to confirm delete action');
await fillIn('[data-test-confirmation-modal-input="delete"]', connectionDetails.id);
await click('[data-test-confirm-button]');
await settled();

assert.equal(currentURL(), `/vault/secrets/${backend}/list`, 'Redirects to connection list page');
assert
.dom('[data-test-empty-state-title')
Expand Down