Skip to content

Commit

Permalink
UI: Replication page navigation fix (#26325)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
hashishaw committed Apr 10, 2024
1 parent e1be7ef commit b2e16c8
Show file tree
Hide file tree
Showing 6 changed files with 179 additions and 10 deletions.
3 changes: 3 additions & 0 deletions changelog/26325.txt
Original file line number Diff line number Diff line change
@@ -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
```
8 changes: 5 additions & 3 deletions ui/lib/replication/addon/components/replication-summary.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@
* SPDX-License-Identifier: BUSL-1.1
*/

import { inject as service } from '@ember/service';
import { alias } from '@ember/object/computed';
import { service } from '@ember/service';
import { computed } from '@ember/object';
import Component from '@ember/component';
import decodeConfigFromJWT from 'replication/utils/decode-config-from-jwt';
Expand All @@ -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;
Expand All @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,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>
Expand All @@ -345,28 +345,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>
Expand Down
2 changes: 2 additions & 0 deletions ui/mirage/handlers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import oidcConfig from './oidc-config';
import hcpLink from './hcp-link';
import kubernetes from './kubernetes';
import ldap from './ldap';
import replication from './replication';

export {
base,
Expand All @@ -29,4 +30,5 @@ export {
mfaConfig,
mfaLogin,
oidcConfig,
replication,
};
107 changes: 107 additions & 0 deletions ui/mirage/handlers/replication.js
Original file line number Diff line number Diff line change
@@ -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',
},
};
});
}
55 changes: 55 additions & 0 deletions ui/tests/acceptance/replication-nav-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/**
* 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 ENV from 'vault/config/environment';
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.before(function () {
ENV['ember-cli-mirage'].handler = 'replication';
});
hooks.after(function () {
ENV['ember-cli-mirage'].handler = null;
});

hooks.beforeEach(function () {
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');
});
});

0 comments on commit b2e16c8

Please sign in to comment.