UI/ Add PostgreSQL DB (#12945)

* alphabetize DB plugin types

* adds changelog

* add postgres to database plugins

* add statement fields

* adds tests for postgres db

* add delete confirm modal to db connection

* fixes text for confirmation modal - transform

* editing tests for delete modal

* fixes tests, oracle must be last DB tested

* adds test for modal and updates old modal tests
This commit is contained in:
claire bontempo 2021-10-29 09:58:56 -07:00 committed by GitHub
parent 2d5a1f7ed4
commit 50372d19f8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 136 additions and 59 deletions

3
changelog/12945.txt Normal file
View File

@ -0,0 +1,3 @@
```release-note:feature
**Postgres in the UI**: Postgres DB is now supported by the UI
```

View File

@ -23,7 +23,7 @@
<button <button
type="button" type="button"
class="toolbar-link" class="toolbar-link"
{{on 'click' this.delete}} onclick={{action (mut isDeleteModalActive) true}}
data-test-database-connection-delete data-test-database-connection-delete
> >
Delete connection Delete connection
@ -367,3 +367,18 @@
</button> </button>
</footer> </footer>
</Modal> </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>

View File

@ -91,7 +91,7 @@
@onClose={{action (mut isDeleteModalActive) false}} @onClose={{action (mut isDeleteModalActive) false}}
@isActive={{isDeleteModalActive}} @isActive={{isDeleteModalActive}}
@confirmText={{model.name}} @confirmText={{model.name}}
@toConfirmMsg="Type {{model.name}} to confirm deleting the transformation." @toConfirmMsg="deleting the transformation."
@onConfirm={{action "delete"}} @onConfirm={{action "delete"}}
> >
<p class="has-bottom-margin-m"> <p class="has-bottom-margin-m">

View File

@ -1,4 +1,24 @@
export const AVAILABLE_PLUGIN_TYPES = [ export const AVAILABLE_PLUGIN_TYPES = [
{
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', value: 'mongodb-database-plugin',
displayName: 'MongoDB', displayName: 'MongoDB',
@ -35,26 +55,6 @@ export const AVAILABLE_PLUGIN_TYPES = [
{ attr: 'root_rotation_statements', group: 'statements' }, { attr: 'root_rotation_statements', group: 'statements' },
], ],
}, },
{
value: 'mysql-database-plugin',
displayName: 'MySQL/MariaDB',
fields: [
{ attr: 'plugin_name' },
{ attr: 'name' },
{ attr: 'verify_connection' },
{ attr: 'password_policy' },
{ attr: 'connection_url', group: 'pluginConfig' },
{ attr: 'username', group: 'pluginConfig', show: false },
{ attr: 'password', group: 'pluginConfig', show: false },
{ attr: 'max_open_connections', group: 'pluginConfig' },
{ attr: 'max_idle_connections', group: 'pluginConfig' },
{ attr: 'max_connection_lifetime', group: 'pluginConfig' },
{ attr: 'username_template', group: 'pluginConfig' },
{ attr: 'tls', group: 'pluginConfig', subgroup: 'TLS options' },
{ attr: 'tls_ca', group: 'pluginConfig', subgroup: 'TLS options' },
{ attr: 'root_rotation_statements', group: 'statements' },
],
},
{ {
value: 'mysql-aurora-database-plugin', value: 'mysql-aurora-database-plugin',
displayName: 'MySQL (Aurora)', displayName: 'MySQL (Aurora)',
@ -75,26 +75,6 @@ export const AVAILABLE_PLUGIN_TYPES = [
{ attr: 'root_rotation_statements', group: 'statements' }, { attr: 'root_rotation_statements', group: 'statements' },
], ],
}, },
{
value: 'mysql-rds-database-plugin',
displayName: 'MySQL (RDS)',
fields: [
{ attr: 'plugin_name' },
{ attr: 'name' },
{ attr: 'verify_connection' },
{ attr: 'password_policy' },
{ attr: 'connection_url', group: 'pluginConfig' },
{ attr: 'username', group: 'pluginConfig', show: false },
{ attr: 'password', group: 'pluginConfig', show: false },
{ attr: 'max_open_connections', group: 'pluginConfig' },
{ attr: 'max_idle_connections', group: 'pluginConfig' },
{ attr: 'max_connection_lifetime', group: 'pluginConfig' },
{ attr: 'username_template', group: 'pluginConfig' },
{ attr: 'tls', group: 'pluginConfig', subgroup: 'TLS options' },
{ attr: 'tls_ca', group: 'pluginConfig', subgroup: 'TLS options' },
{ attr: 'root_rotation_statements', group: 'statements' },
],
},
{ {
value: 'mysql-legacy-database-plugin', value: 'mysql-legacy-database-plugin',
displayName: 'MySQL (Legacy)', displayName: 'MySQL (Legacy)',
@ -116,23 +96,43 @@ export const AVAILABLE_PLUGIN_TYPES = [
], ],
}, },
{ {
value: 'elasticsearch-database-plugin', value: 'mysql-database-plugin',
displayName: 'Elasticsearch', displayName: 'MySQL/MariaDB',
fields: [ fields: [
{ attr: 'plugin_name' }, { attr: 'plugin_name' },
{ attr: 'name' }, { attr: 'name' },
{ attr: 'verify_connection' }, { attr: 'verify_connection' },
{ attr: 'password_policy' }, { attr: 'password_policy' },
{ attr: 'url', group: 'pluginConfig' }, { attr: 'connection_url', group: 'pluginConfig' },
{ attr: 'username', group: 'pluginConfig', show: false }, { attr: 'username', group: 'pluginConfig', show: false },
{ attr: 'password', group: 'pluginConfig', show: false }, { attr: 'password', group: 'pluginConfig', show: false },
{ attr: 'ca_cert', group: 'pluginConfig' }, { attr: 'max_open_connections', group: 'pluginConfig' },
{ attr: 'ca_path', group: 'pluginConfig' }, { attr: 'max_idle_connections', group: 'pluginConfig' },
{ attr: 'client_cert', group: 'pluginConfig' }, { attr: 'max_connection_lifetime', group: 'pluginConfig' },
{ attr: 'client_key', group: 'pluginConfig' },
{ attr: 'tls_server_name', group: 'pluginConfig' },
{ attr: 'insecure', group: 'pluginConfig' },
{ attr: 'username_template', group: 'pluginConfig' }, { attr: 'username_template', group: 'pluginConfig' },
{ attr: 'tls', group: 'pluginConfig', subgroup: 'TLS options' },
{ attr: 'tls_ca', group: 'pluginConfig', subgroup: 'TLS options' },
{ attr: 'root_rotation_statements', group: 'statements' },
],
},
{
value: 'mysql-rds-database-plugin',
displayName: 'MySQL (RDS)',
fields: [
{ attr: 'plugin_name' },
{ attr: 'name' },
{ attr: 'verify_connection' },
{ attr: 'password_policy' },
{ attr: 'connection_url', group: 'pluginConfig' },
{ attr: 'username', group: 'pluginConfig', show: false },
{ attr: 'password', group: 'pluginConfig', show: false },
{ attr: 'max_open_connections', group: 'pluginConfig' },
{ attr: 'max_idle_connections', group: 'pluginConfig' },
{ attr: 'max_connection_lifetime', group: 'pluginConfig' },
{ attr: 'username_template', group: 'pluginConfig' },
{ attr: 'tls', group: 'pluginConfig', subgroup: 'TLS options' },
{ attr: 'tls_ca', group: 'pluginConfig', subgroup: 'TLS options' },
{ attr: 'root_rotation_statements', group: 'statements' },
], ],
}, },
{ {
@ -153,6 +153,24 @@ export const AVAILABLE_PLUGIN_TYPES = [
{ attr: 'root_rotation_statements', group: 'statements' }, { attr: 'root_rotation_statements', group: 'statements' },
], ],
}, },
{
value: 'postgresql-database-plugin',
displayName: 'PostgreSQL',
fields: [
{ attr: 'plugin_name' },
{ attr: 'name' },
{ attr: 'verify_connection' },
{ attr: 'password_policy' },
{ attr: 'connection_url', group: 'pluginConfig' },
{ attr: 'username', group: 'pluginConfig', show: false },
{ attr: 'password', group: 'pluginConfig', show: false },
{ 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' },
],
},
]; ];
export const ROLE_FIELDS = { export const ROLE_FIELDS = {
@ -163,25 +181,32 @@ export const ROLE_FIELDS = {
export const STATEMENT_FIELDS = { export const STATEMENT_FIELDS = {
static: { static: {
default: ['rotation_statements'], default: ['rotation_statements'],
'elasticsearch-database-plugin': [],
'mongodb-database-plugin': [], 'mongodb-database-plugin': [],
'mssql-database-plugin': [], 'mssql-database-plugin': [],
'mysql-database-plugin': [], 'mysql-database-plugin': [],
'mysql-aurora-database-plugin': [], 'mysql-aurora-database-plugin': [],
'mysql-rds-database-plugin': [],
'mysql-legacy-database-plugin': [], 'mysql-legacy-database-plugin': [],
'elasticsearch-database-plugin': [], 'mysql-rds-database-plugin': [],
'oracle-database-plugin': [], 'oracle-database-plugin': [],
'postgresql-database-plugin': [],
}, },
dynamic: { dynamic: {
default: ['creation_statements', 'revocation_statements', 'rollback_statements', 'renew_statements'], default: ['creation_statements', 'revocation_statements', 'rollback_statements', 'renew_statements'],
'elasticsearch-database-plugin': ['creation_statement'],
'mongodb-database-plugin': ['creation_statement', 'revocation_statement'], 'mongodb-database-plugin': ['creation_statement', 'revocation_statement'],
'mssql-database-plugin': ['creation_statements', 'revocation_statements'], 'mssql-database-plugin': ['creation_statements', 'revocation_statements'],
'mysql-database-plugin': ['creation_statements', 'revocation_statements'], 'mysql-database-plugin': ['creation_statements', 'revocation_statements'],
'mysql-aurora-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'], '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'], 'oracle-database-plugin': ['creation_statements', 'revocation_statements'],
'postgresql-database-plugin': [
'creation_statements',
'revocation_statements',
'rollback_statements',
'renew_statements',
],
}, },
}; };

View File

@ -9,6 +9,7 @@
* @title="Do Dangerous Thing?" * @title="Do Dangerous Thing?"
* @isActive={{isModalActive}} * @isActive={{isModalActive}}
* @onClose={{action (mut isModalActive) false}} * @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 * @param {function} onConfirm - onConfirm is the action that happens when user clicks onConfirm after filling in the confirmation block

View File

@ -185,6 +185,31 @@ const connectionTests = [
.exists(`Root rotation statements exists for ${name}`); .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}`);
},
},
// 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', name: 'oracle-connection',
plugin: 'oracle-database-plugin', plugin: 'oracle-database-plugin',
@ -256,7 +281,7 @@ module('Acceptance | secrets/database/*', function(hooks) {
} else { } else {
await connectionPage.connectionUrl(testCase.url); 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') { if (testCase.plugin === 'oracle-database-plugin') {
testCase.requiredFields(assert, testCase.name); testCase.requiredFields(assert, testCase.name);
continue; continue;
@ -264,9 +289,9 @@ module('Acceptance | secrets/database/*', function(hooks) {
testCase.requiredFields(assert, testCase.name); testCase.requiredFields(assert, testCase.name);
await connectionPage.toggleVerify(); await connectionPage.toggleVerify();
await connectionPage.save(); await connectionPage.save();
await connectionPage.enable(); await settled();
assert assert
.dom('[data-test-modal-title]') .dom('.modal.is-active .title')
.hasText('Rotate your root credentials?', 'Modal appears asking to rotate root credentials'); .hasText('Rotate your root credentials?', 'Modal appears asking to rotate root credentials');
await connectionPage.enable(); await connectionPage.enable();
assert.ok( assert.ok(
@ -335,8 +360,9 @@ module('Acceptance | secrets/database/*', function(hooks) {
// uncheck verify for the save step to work // uncheck verify for the save step to work
await connectionPage.toggleVerify(); await connectionPage.toggleVerify();
await connectionPage.save(); await connectionPage.save();
await settled();
assert assert
.dom('[data-test-modal-title]') .dom('.modal.is-active .title')
.hasText('Rotate your root credentials?', 'Modal appears asking to '); .hasText('Rotate your root credentials?', 'Modal appears asking to ');
await connectionPage.enable(); await connectionPage.enable();
assert.equal( assert.equal(
@ -356,6 +382,13 @@ module('Acceptance | secrets/database/*', function(hooks) {
} }
}); });
await connectionPage.delete(); 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.equal(currentURL(), `/vault/secrets/${backend}/list`, 'Redirects to connection list page');
assert assert
.dom('[data-test-empty-state-title') .dom('[data-test-empty-state-title')