From 6fd6b901921d717da850d021d74365ad030903e8 Mon Sep 17 00:00:00 2001
From: claire bontempo <68122737+hellobontempo@users.noreply.github.com>
Date: Thu, 12 Sep 2024 13:51:11 +0000
Subject: [PATCH] backport of commit 49b46ead82b1d6db93c18a9a5d60cd8cc3120364
---
changelog/28371.txt | 3 ++
ui/app/app.js | 1 +
.../components/enable-replication-form.js | 17 ++++---
.../addon/components/page/mode-index.hbs | 4 +-
.../addon/components/page/mode-index.js | 40 ++++++++++++++++
ui/lib/replication/addon/controllers/index.js | 20 ++++++++
ui/lib/replication/addon/engine.js | 1 +
.../replication/addon/routes/application.js | 46 +++++++++++++------
ui/lib/replication/addon/templates/index.hbs | 4 +-
.../components/page/mode-index-test.js | 42 +++++++++++++++++
10 files changed, 150 insertions(+), 28 deletions(-)
create mode 100644 changelog/28371.txt
create mode 100644 ui/lib/replication/addon/components/page/mode-index.js
diff --git a/changelog/28371.txt b/changelog/28371.txt
new file mode 100644
index 000000000000..c719c4be56c0
--- /dev/null
+++ b/changelog/28371.txt
@@ -0,0 +1,3 @@
+```release-note:bug
+ui: Fix UI improperly checking capabilities for enabling performance and dr replication
+```
diff --git a/ui/app/app.js b/ui/app/app.js
index e5484bf392e1..9409b0cd916f 100644
--- a/ui/app/app.js
+++ b/ui/app/app.js
@@ -27,6 +27,7 @@ export default class App extends Application {
dependencies: {
services: [
'auth',
+ 'capabilities',
'flash-messages',
'namespace',
'replication-mode',
diff --git a/ui/lib/replication/addon/components/enable-replication-form.js b/ui/lib/replication/addon/components/enable-replication-form.js
index f27f13709367..bd1145e0d417 100644
--- a/ui/lib/replication/addon/components/enable-replication-form.js
+++ b/ui/lib/replication/addon/components/enable-replication-form.js
@@ -19,16 +19,15 @@ import { waitFor } from '@ember/test-waiters';
* but otherwise it handles the rest of the form inputs. On success it will clear the form and call the onSuccess callback.
*
* @example
- * ```js
*
- * @param {string} replicationMode - should be one of "dr" or "performance"
- * @param {boolean} canEnablePrimary - if the capabilities allow the user to enable a primary cluster
- * @param {boolean} canEnableSecondary - if the capabilities allow the user to enable a secondary cluster
- * @param {boolean} performanceMode - should be "primary", "secondary", or "disabled". If enabled, form will show a warning when attempting to enable DR secondary
- * @param {Promise} onSuccess - (optional) callback called after successful replication enablement. Must be a promise.
- * @param {boolean} doTransition - (optional) if provided, passed to onSuccess callback to determine if a transition should be done
- * />
- * ```
+ *
+ * @param {string} replicationMode - should be one of "dr" or "performance"
+ * @param {boolean} canEnablePrimary - if the capabilities allow the user to enable a primary cluster, parent getter returns capabilities based on type (i.e. "dr" or "performance")
+ * @param {boolean} canEnableSecondary - if the capabilities allow the user to enable a secondary cluster, parent getter returns capabilities based on type (i.e. "dr" or "performance")
+ * @param {boolean} performanceMode - should be "primary", "secondary", or "disabled". If enabled, form will show a warning when attempting to enable DR secondary
+ * @param {Promise} onSuccess - (optional) callback called after successful replication enablement. Must be a promise.
+ * @param {boolean} doTransition - (optional) if provided, passed to onSuccess callback to determine if a transition should be done
+ *
*/
export default class EnableReplicationFormComponent extends Component {
@service version;
diff --git a/ui/lib/replication/addon/components/page/mode-index.hbs b/ui/lib/replication/addon/components/page/mode-index.hbs
index bc45bcc4c37f..d35e024b0f28 100644
--- a/ui/lib/replication/addon/components/page/mode-index.hbs
+++ b/ui/lib/replication/addon/components/page/mode-index.hbs
@@ -45,8 +45,8 @@
+ *
+ * @param {model} cluster - cluster route model
+ * @param {function} onEnableSuccess - callback after enabling is successful, handles transition if enabled from the top-level index route
+ * @param {boolean} replicationDisabled - whether or not replication is enabled
+ * @param {string} replicationMode - should be "dr" or "performance"
+ */
+export default class PageModeIndex extends Component {
+ canEnable = (type) => {
+ const { cluster, replicationMode } = this.args;
+ let perm;
+ if (replicationMode === 'dr') {
+ // returns canEnablePrimaryDr or canEnableSecondaryDr
+ perm = `canEnable${type}Dr`;
+ }
+ if (replicationMode === 'performance') {
+ // returns canEnablePrimaryPerformance or canEnableSecondaryPerformance
+ perm = `canEnable${type}Performance`;
+ }
+ // if there's a problem checking capabilities, default to true
+ // since the backend can gate as a fallback
+ return cluster[perm] ?? true;
+ };
+}
diff --git a/ui/lib/replication/addon/controllers/index.js b/ui/lib/replication/addon/controllers/index.js
index cab8fc4eb9ac..e5be14b7a7fc 100644
--- a/ui/lib/replication/addon/controllers/index.js
+++ b/ui/lib/replication/addon/controllers/index.js
@@ -8,4 +8,24 @@ import { tracked } from '@glimmer/tracking';
export default class ReplicationIndexController extends ReplicationModeBaseController {
@tracked modeSelection = 'dr';
+
+ getPerm(type) {
+ if (this.modeSelection === 'dr') {
+ // returns canEnablePrimaryDr or canEnableSecondaryDr
+ return `canEnable${type}Dr`;
+ }
+ if (this.modeSelection === 'performance') {
+ // returns canEnablePrimaryPerformance or canEnableSecondaryPerformance
+ return `canEnable${type}Performance`;
+ }
+ }
+
+ // if there's a problem checking capabilities, default to true
+ // since the backend will gate as a fallback
+ get canEnablePrimary() {
+ return this.model[this.getPerm('Primary')] ?? true;
+ }
+ get canEnableSecondary() {
+ return this.model[this.getPerm('Secondary')] ?? true;
+ }
}
diff --git a/ui/lib/replication/addon/engine.js b/ui/lib/replication/addon/engine.js
index f3ddb560ea47..b7757a16b6d4 100644
--- a/ui/lib/replication/addon/engine.js
+++ b/ui/lib/replication/addon/engine.js
@@ -16,6 +16,7 @@ const Eng = Engine.extend({
dependencies: {
services: [
'auth',
+ 'capabilities',
'flash-messages',
'namespace',
'replication-mode',
diff --git a/ui/lib/replication/addon/routes/application.js b/ui/lib/replication/addon/routes/application.js
index 72bdd69741fb..e54b870f9793 100644
--- a/ui/lib/replication/addon/routes/application.js
+++ b/ui/lib/replication/addon/routes/application.js
@@ -5,7 +5,6 @@
import { service } from '@ember/service';
import { setProperties } from '@ember/object';
-import { hash } from 'rsvp';
import Route from '@ember/routing/route';
import ClusterRoute from 'vault/mixins/cluster-route';
@@ -14,6 +13,23 @@ export default Route.extend(ClusterRoute, {
store: service(),
auth: service(),
router: service(),
+ capabilities: service(),
+
+ async fetchCapabilities() {
+ const enablePath = (type, cluster) => `sys/replication/${type}/${cluster}/enable`;
+ const perms = await this.capabilities.fetchMultiplePaths([
+ enablePath('dr', 'primary'),
+ enablePath('dr', 'primary'),
+ enablePath('performance', 'secondary'),
+ enablePath('performance', 'secondary'),
+ ]);
+ return {
+ canEnablePrimaryDr: perms[enablePath('dr', 'primary')].canUpdate,
+ canEnableSecondaryDr: perms[enablePath('dr', 'primary')].canUpdate,
+ canEnablePrimaryPerformance: perms[enablePath('performance', 'secondary')].canUpdate,
+ canEnableSecondaryPerformance: perms[enablePath('performance', 'secondary')].canUpdate,
+ };
+ },
beforeModel() {
if (this.auth.activeCluster.replicationRedacted) {
@@ -29,21 +45,21 @@ export default Route.extend(ClusterRoute, {
return this.auth.activeCluster;
},
- afterModel(model) {
- return hash({
- canEnablePrimary: this.store
- .findRecord('capabilities', 'sys/replication/primary/enable')
- .then((c) => c.canUpdate),
- canEnableSecondary: this.store
- .findRecord('capabilities', 'sys/replication/secondary/enable')
- .then((c) => c.canUpdate),
- }).then(({ canEnablePrimary, canEnableSecondary }) => {
- setProperties(model, {
- canEnablePrimary,
- canEnableSecondary,
- });
- return model;
+ async afterModel(model) {
+ const {
+ canEnablePrimaryDr,
+ canEnableSecondaryDr,
+ canEnablePrimaryPerformance,
+ canEnableSecondaryPerformance,
+ } = await this.fetchCapabilities();
+
+ setProperties(model, {
+ canEnablePrimaryDr,
+ canEnableSecondaryDr,
+ canEnablePrimaryPerformance,
+ canEnableSecondaryPerformance,
});
+ return model;
},
actions: {
refresh() {
diff --git a/ui/lib/replication/addon/templates/index.hbs b/ui/lib/replication/addon/templates/index.hbs
index 79aefcc04424..3ebf430f7f7b 100644
--- a/ui/lib/replication/addon/templates/index.hbs
+++ b/ui/lib/replication/addon/templates/index.hbs
@@ -91,8 +91,8 @@