mirror of
https://github.com/optim-enterprises-bv/vault.git
synced 2025-10-29 09:42:25 +00:00
UI: Replication page navigation fix (#26325)
* Add replication mirage handler * Add test with skipped failed assertion * Use component-calculated attrsForCurrentMode instead of cluster.replicationAttrs which wasn't triggering component updates * assert previously-skipped assertion * Add changelog
This commit is contained in:
3
changelog/26325.txt
Normal file
3
changelog/26325.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
```release-note:bug
|
||||
ui: fixed a bug where the replication pages did not update display when navigating between DR and performance
|
||||
```
|
||||
@@ -4,7 +4,6 @@
|
||||
*/
|
||||
|
||||
import { service } from '@ember/service';
|
||||
import { alias } from '@ember/object/computed';
|
||||
import { computed } from '@ember/object';
|
||||
import Component from '@ember/component';
|
||||
import decodeConfigFromJWT from 'replication/utils/decode-config-from-jwt';
|
||||
@@ -27,6 +26,7 @@ export default Component.extend(ReplicationActions, DEFAULTS, {
|
||||
replicationMode: 'dr',
|
||||
mode: 'primary',
|
||||
version: service(),
|
||||
rm: service('replication-mode'),
|
||||
didReceiveAttrs() {
|
||||
this._super(...arguments);
|
||||
const initialReplicationMode = this.initialReplicationMode;
|
||||
@@ -38,7 +38,9 @@ export default Component.extend(ReplicationActions, DEFAULTS, {
|
||||
initialReplicationMode: null,
|
||||
cluster: null,
|
||||
|
||||
replicationAttrs: alias('cluster.replicationAttrs'),
|
||||
attrsForCurrentMode: computed('cluster', 'rm.mode', function () {
|
||||
return this.cluster[this.rm.mode];
|
||||
}),
|
||||
|
||||
tokenIncludesAPIAddr: computed('token', function () {
|
||||
const config = decodeConfigFromJWT(this.token);
|
||||
|
||||
@@ -334,7 +334,7 @@
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{else}}
|
||||
{{#if (eq this.replicationAttrs.mode "initializing")}}
|
||||
{{#if (eq this.attrsForCurrentMode.mode "initializing")}}
|
||||
The cluster is initializing replication. This may take some time.
|
||||
{{else}}
|
||||
<p>{{this.cluster.replicationModeStatus.cluster_id}}</p>
|
||||
@@ -343,28 +343,28 @@
|
||||
<Page.dashboard
|
||||
@data={{this.cluster}}
|
||||
@componentToRender={{if
|
||||
(eq this.replicationAttrs.mode "secondary")
|
||||
(eq this.attrsForCurrentMode.mode "secondary")
|
||||
"replication-secondary-card"
|
||||
"replication-primary-card"
|
||||
}}
|
||||
as |Dashboard|
|
||||
>
|
||||
{{#if (eq this.replicationAttrs.mode "secondary")}}
|
||||
{{#if (eq this.attrsForCurrentMode.mode "secondary")}}
|
||||
<Dashboard.card @title="Status" />
|
||||
<Dashboard.card @title="Primary cluster" />
|
||||
{{else}}
|
||||
<Dashboard.card
|
||||
@title="State"
|
||||
@description="The cluster’s current operating state."
|
||||
@glyph={{get (cluster-states this.replicationAttrs.state) "glyph"}}
|
||||
@metric={{this.replicationAttrs.state}}
|
||||
@glyph={{get (cluster-states this.attrsForCurrentMode.state) "glyph"}}
|
||||
@metric={{this.attrsForCurrentMode.state}}
|
||||
/>
|
||||
<Dashboard.card
|
||||
@title="Last WAL entry"
|
||||
@description="Index of last Write Ahead Logs entry written on local storage. Updates every ten seconds."
|
||||
@metric={{format-number this.replicationAttrs.lastWAL}}
|
||||
@metric={{format-number this.attrsForCurrentMode.lastWAL}}
|
||||
/>
|
||||
<Dashboard.secondaryCard @cluster={{this.cluster}} @replicationAttrs={{this.replicationAttrs}} />
|
||||
<Dashboard.secondaryCard @cluster={{this.cluster}} @replicationAttrs={{this.attrsForCurrentMode}} />
|
||||
{{/if}}
|
||||
</Page.dashboard>
|
||||
</ReplicationPage>
|
||||
|
||||
@@ -19,6 +19,7 @@ import mfaLogin from './mfa-login';
|
||||
import oidcConfig from './oidc-config';
|
||||
import reducedDisclosure from './reduced-disclosure';
|
||||
import sync from './sync';
|
||||
import replication from './replication';
|
||||
|
||||
export {
|
||||
base,
|
||||
@@ -35,4 +36,5 @@ export {
|
||||
reducedDisclosure,
|
||||
customMessages,
|
||||
sync,
|
||||
replication,
|
||||
};
|
||||
|
||||
107
ui/mirage/handlers/replication.js
Normal file
107
ui/mirage/handlers/replication.js
Normal file
@@ -0,0 +1,107 @@
|
||||
/**
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
export default function (server) {
|
||||
server.get('sys/replication/status', function () {
|
||||
return {
|
||||
data: {
|
||||
dr: {
|
||||
cluster_id: 'dr-cluster-id',
|
||||
corrupted_merkle_tree: false,
|
||||
known_secondaries: ['foobar'],
|
||||
last_corruption_check_epoch: '-62135596800',
|
||||
last_dr_wal: 98,
|
||||
last_reindex_epoch: '0',
|
||||
last_wal: 98,
|
||||
merkle_root: 'ad721f32ed6789a1e5824841f358a517340a4585',
|
||||
mode: 'primary',
|
||||
primary_cluster_addr: 'dr-foobar',
|
||||
secondaries: [
|
||||
{
|
||||
api_address: 'http://127.0.0.1:8202',
|
||||
cluster_address: 'https://127.0.0.1:8203',
|
||||
connection_status: 'disconnected',
|
||||
last_heartbeat: '2024-04-09T09:04:22-05:00',
|
||||
node_id: 'foobar',
|
||||
},
|
||||
],
|
||||
ssct_generation_counter: 0,
|
||||
state: 'running',
|
||||
},
|
||||
performance: {
|
||||
cluster_id: 'perf-cluster-id',
|
||||
corrupted_merkle_tree: false,
|
||||
known_secondaries: [],
|
||||
last_corruption_check_epoch: '-62135596800',
|
||||
last_performance_wal: 98,
|
||||
last_reindex_epoch: '0',
|
||||
last_wal: 98,
|
||||
merkle_root: '618c9136bb443aa584f5d6b90755d42888c9c54a',
|
||||
mode: 'primary',
|
||||
primary_cluster_addr: 'perf-foobar',
|
||||
secondaries: [],
|
||||
ssct_generation_counter: 0,
|
||||
state: 'running',
|
||||
},
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
server.get('sys/replication/performance/status', function () {
|
||||
return {
|
||||
data: {
|
||||
cluster_id: 'perf-cluster-id',
|
||||
corrupted_merkle_tree: false,
|
||||
known_secondaries: ['foobar'],
|
||||
last_corruption_check_epoch: '-62135596800',
|
||||
last_dr_wal: 98,
|
||||
last_reindex_epoch: '0',
|
||||
last_wal: 98,
|
||||
merkle_root: 'ad721f32ed6789a1e5824841f358a517340a4585',
|
||||
mode: 'primary',
|
||||
primary_cluster_addr: 'perf-foobar',
|
||||
secondaries: [
|
||||
{
|
||||
api_address: 'http://127.0.0.1:8202',
|
||||
cluster_address: 'https://127.0.0.1:8203',
|
||||
connection_status: 'disconnected',
|
||||
last_heartbeat: '2024-04-09T09:04:22-05:00',
|
||||
node_id: 'foobar',
|
||||
},
|
||||
],
|
||||
ssct_generation_counter: 0,
|
||||
state: 'running',
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
server.get('sys/replication/dr/status', function () {
|
||||
return {
|
||||
data: {
|
||||
cluster_id: 'dr-cluster-id',
|
||||
corrupted_merkle_tree: false,
|
||||
known_secondaries: ['foobar'],
|
||||
last_corruption_check_epoch: '-62135596800',
|
||||
last_dr_wal: 98,
|
||||
last_reindex_epoch: '0',
|
||||
last_wal: 98,
|
||||
merkle_root: 'ad721f32ed6789a1e5824841f358a517340a4585',
|
||||
mode: 'primary',
|
||||
primary_cluster_addr: 'dr-foobar',
|
||||
secondaries: [
|
||||
{
|
||||
api_address: 'http://127.0.0.1:8202',
|
||||
cluster_address: 'https://127.0.0.1:8203',
|
||||
connection_status: 'disconnected',
|
||||
last_heartbeat: '2024-04-09T09:04:22-05:00',
|
||||
node_id: 'foobar',
|
||||
},
|
||||
],
|
||||
ssct_generation_counter: 0,
|
||||
state: 'running',
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
49
ui/tests/acceptance/replication-nav-test.js
Normal file
49
ui/tests/acceptance/replication-nav-test.js
Normal file
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: BUSL-1.1
|
||||
*/
|
||||
|
||||
import { module, test } from 'qunit';
|
||||
import { setupApplicationTest } from 'ember-qunit';
|
||||
import { setupMirage } from 'ember-cli-mirage/test-support';
|
||||
import authPage from 'vault/tests/pages/auth';
|
||||
import replicationHandlers from 'vault/mirage/handlers/replication';
|
||||
import { click } from '@ember/test-helpers';
|
||||
|
||||
const SELECTORS = {
|
||||
navReplication: '[data-test-sidebar-nav-link="Replication"]',
|
||||
navPerformance: '[data-test-sidebar-nav-link="Performance"]',
|
||||
navDR: '[data-test-sidebar-nav-link="Disaster Recovery"]',
|
||||
title: '[data-test-replication-title]',
|
||||
primaryCluster: '[data-test-value-div="primary_cluster_addr"]',
|
||||
replicationSet: '[data-test-row-value="Replication set"]',
|
||||
knownSecondariesTitle: '.known-secondaries-card h3',
|
||||
};
|
||||
module('Acceptance | Enterprise | replication navigation', function (hooks) {
|
||||
setupApplicationTest(hooks);
|
||||
setupMirage(hooks);
|
||||
|
||||
hooks.beforeEach(function () {
|
||||
replicationHandlers(this.server);
|
||||
return authPage.login();
|
||||
});
|
||||
|
||||
test('navigate between replication types updates page', async function (assert) {
|
||||
await click(SELECTORS.navReplication);
|
||||
assert.dom(SELECTORS.title).hasText('Disaster Recovery & Performance primary');
|
||||
await click(SELECTORS.navPerformance);
|
||||
|
||||
// Ensure data is expected for performance
|
||||
assert.dom(SELECTORS.title).hasText('Performance primary');
|
||||
assert.dom(SELECTORS.primaryCluster).hasText('perf-foobar');
|
||||
assert.dom(SELECTORS.replicationSet).hasText('perf-cluster-id');
|
||||
assert.dom(SELECTORS.knownSecondariesTitle).hasText('0 Known secondaries');
|
||||
|
||||
// Nav to DR and see updated data
|
||||
await click(SELECTORS.navDR);
|
||||
assert.dom(SELECTORS.title).hasText('Disaster Recovery primary');
|
||||
assert.dom(SELECTORS.primaryCluster).hasText('dr-foobar');
|
||||
assert.dom(SELECTORS.replicationSet).hasText('dr-cluster-id');
|
||||
assert.dom(SELECTORS.knownSecondariesTitle).hasText('1 Known secondaries');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user