From 50372d19f82796ac1d8ad0c61e520a33514f10e9 Mon Sep 17 00:00:00 2001 From: claire bontempo <68122737+hellobontempo@users.noreply.github.com> Date: Fri, 29 Oct 2021 09:58:56 -0700 Subject: [PATCH] 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 --- changelog/12945.txt | 3 + .../components/database-connection.hbs | 17 ++- .../components/transformation-edit.hbs | 2 +- ui/app/utils/database-helpers.js | 131 +++++++++++------- .../addon/components/confirmation-modal.js | 1 + .../secrets/backend/database/secret-test.js | 41 +++++- 6 files changed, 136 insertions(+), 59 deletions(-) create mode 100644 changelog/12945.txt diff --git a/changelog/12945.txt b/changelog/12945.txt new file mode 100644 index 000000000..128378716 --- /dev/null +++ b/changelog/12945.txt @@ -0,0 +1,3 @@ +```release-note:feature +**Postgres in the UI**: Postgres DB is now supported by the UI +``` \ No newline at end of file diff --git a/ui/app/templates/components/database-connection.hbs b/ui/app/templates/components/database-connection.hbs index 69b34a7c3..5a032c586 100644 --- a/ui/app/templates/components/database-connection.hbs +++ b/ui/app/templates/components/database-connection.hbs @@ -23,7 +23,7 @@ + + +

+ Deleting the connection means that any associated roles won't be able to generate credentials until the connection is reconfigured. +

+ +
diff --git a/ui/app/templates/components/transformation-edit.hbs b/ui/app/templates/components/transformation-edit.hbs index c8088cbb4..e0aa239ed 100644 --- a/ui/app/templates/components/transformation-edit.hbs +++ b/ui/app/templates/components/transformation-edit.hbs @@ -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"}} >

diff --git a/ui/app/utils/database-helpers.js b/ui/app/utils/database-helpers.js index 2702912fd..34df12c86 100644 --- a/ui/app/utils/database-helpers.js +++ b/ui/app/utils/database-helpers.js @@ -1,4 +1,24 @@ 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', displayName: 'MongoDB', @@ -35,26 +55,6 @@ export const AVAILABLE_PLUGIN_TYPES = [ { 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', displayName: 'MySQL (Aurora)', @@ -75,26 +75,6 @@ export const AVAILABLE_PLUGIN_TYPES = [ { 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', displayName: 'MySQL (Legacy)', @@ -116,23 +96,43 @@ export const AVAILABLE_PLUGIN_TYPES = [ ], }, { - value: 'elasticsearch-database-plugin', - displayName: 'Elasticsearch', + value: 'mysql-database-plugin', + displayName: 'MySQL/MariaDB', 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: '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' }, ], }, + { + 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 = { @@ -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', + ], }, }; diff --git a/ui/lib/core/addon/components/confirmation-modal.js b/ui/lib/core/addon/components/confirmation-modal.js index 7f193fffb..981dc6942 100644 --- a/ui/lib/core/addon/components/confirmation-modal.js +++ b/ui/lib/core/addon/components/confirmation-modal.js @@ -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 diff --git a/ui/tests/acceptance/secrets/backend/database/secret-test.js b/ui/tests/acceptance/secrets/backend/database/secret-test.js index 8ab2744ba..0cc0a456d 100644 --- a/ui/tests/acceptance/secrets/backend/database/secret-test.js +++ b/ui/tests/acceptance/secrets/backend/database/secret-test.js @@ -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}`); + }, + }, + // 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', @@ -256,7 +281,7 @@ 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; @@ -264,9 +289,9 @@ module('Acceptance | secrets/database/*', function(hooks) { 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( @@ -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( @@ -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')