-
Notifications
You must be signed in to change notification settings - Fork 4.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Secrets Sync] enable access to Sync clients page for HVD clusters #26713
Changes from all commits
4246593
af3e6dd
173ea7f
91abd18
9993cd6
9c95c05
9d375f9
396b122
bdbfc30
a9488bf
64d5338
69c65c5
1571799
f1e855d
1fecf96
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
{{! | ||
Copyright (c) HashiCorp, Inc. | ||
SPDX-License-Identifier: BUSL-1.1 | ||
~}} | ||
|
||
<nav class="tabs has-bottom-margin-s" aria-label="navigation for managing client counts"> | ||
<ul> | ||
<li> | ||
<LinkTo @route="vault.cluster.clients.counts.overview" data-test-tab="overview"> | ||
Overview | ||
</LinkTo> | ||
</li> | ||
<li> | ||
<LinkTo @route="vault.cluster.clients.counts.token" data-test-tab="token"> | ||
Entity/Non-entity clients | ||
</LinkTo> | ||
</li> | ||
{{#if @showSecretsSync}} | ||
<li> | ||
<LinkTo @route="vault.cluster.clients.counts.sync" data-test-tab="sync"> | ||
Secrets sync clients | ||
</LinkTo> | ||
</li> | ||
{{/if}} | ||
<li> | ||
<LinkTo @route="vault.cluster.clients.counts.acme" data-test-tab="acme"> | ||
ACME clients | ||
</LinkTo> | ||
</li> | ||
</ul> | ||
</nav> |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,6 +12,7 @@ import { filterVersionHistory, formatDateObject } from 'core/utils/client-count- | |
import timestamp from 'core/utils/timestamp'; | ||
|
||
import type AdapterError from '@ember-data/adapter'; | ||
import type FlagsService from 'vault/services/flags'; | ||
import type StoreService from 'vault/services/store'; | ||
import type VersionService from 'vault/services/version'; | ||
import type ClientsActivityModel from 'vault/models/clients/activity'; | ||
|
@@ -30,6 +31,7 @@ interface Args { | |
} | ||
|
||
export default class ClientsCountsPageComponent extends Component<Args> { | ||
@service declare readonly flags: FlagsService; | ||
@service declare readonly version: VersionService; | ||
@service declare readonly store: StoreService; | ||
|
||
|
@@ -162,6 +164,22 @@ export default class ClientsCountsPageComponent extends Component<Args> { | |
return activity?.total; | ||
} | ||
|
||
get showSecretsSync(): boolean { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. since this value is only needed on one component, we don't need to compute this in the route to add to the model. better off calculating it closer to where we actually use the value, where we already have enough context to compute it. in other words, by calculating the value here we can simply pass it straight into the |
||
const { activity } = this.args; | ||
// if there is any sync client data, show it | ||
if (activity && activity?.total?.secret_syncs > 0) return true; | ||
|
||
// otherwise, show the tab based on the cluster type and license | ||
if (this.version.isCommunity) return false; | ||
|
||
const isHvd = this.flags.isHvdManaged; | ||
const onLicense = this.version.hasSecretsSync; | ||
|
||
// we can't tell if HVD clusters have the feature or not, so we show it by default | ||
// if the cluster is not HVD, show the tab if the feature is on the license | ||
return isHvd || onLicense; | ||
} | ||
|
||
@action | ||
onDateChange(dateObject: { dateType: string; monthIdx: number; year: number }) { | ||
const { dateType, monthIdx, year } = dateObject; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,17 +5,16 @@ | |
|
||
import Route from '@ember/routing/route'; | ||
import { service } from '@ember/service'; | ||
import { DEBUG } from '@glimmer/env'; | ||
import timestamp from 'core/utils/timestamp'; | ||
import { getUnixTime } from 'date-fns'; | ||
|
||
import type FlagsService from 'vault/services/flags'; | ||
import type StoreService from 'vault/services/store'; | ||
import type VersionService from 'vault/services/version'; | ||
|
||
import type { ModelFrom } from 'vault/vault/route'; | ||
import type ClientsRoute from '../clients'; | ||
import type ClientsConfigModel from 'vault/models/clients/config'; | ||
import type ClientsActivityModel from 'vault/models/clients/activity'; | ||
import type ClientsConfigModel from 'vault/models/clients/config'; | ||
import type ClientsCountsController from 'vault/controllers/vault/cluster/clients/counts'; | ||
export interface ClientsCountsRouteParams { | ||
start_time?: string | number | undefined; | ||
|
@@ -24,14 +23,8 @@ export interface ClientsCountsRouteParams { | |
mountPath?: string | undefined; | ||
} | ||
|
||
interface ActivationFlagsResponse { | ||
data: { | ||
activated: Array<string>; | ||
unactivated: Array<string>; | ||
}; | ||
} | ||
|
||
export default class ClientsCountsRoute extends Route { | ||
@service declare readonly flags: FlagsService; | ||
@service declare readonly store: StoreService; | ||
@service declare readonly version: VersionService; | ||
|
||
|
@@ -42,6 +35,10 @@ export default class ClientsCountsRoute extends Route { | |
mountPath: { refreshModel: false, replace: true }, | ||
}; | ||
|
||
beforeModel() { | ||
return this.flags.fetchActivatedFlags(); | ||
} | ||
|
||
async getActivity(start_time: number | null, end_time: number) { | ||
let activity, activityError; | ||
// if there is no start_time we want the user to manually choose a date | ||
|
@@ -59,30 +56,6 @@ export default class ClientsCountsRoute extends Route { | |
return { activity, activityError }; | ||
} | ||
|
||
async getActivatedFeatures() { | ||
try { | ||
const resp: ActivationFlagsResponse = await this.store | ||
.adapterFor('application') | ||
.ajax('/v1/sys/activation-flags', 'GET', { unauthenticated: true, namespace: null }); | ||
return resp.data?.activated; | ||
} catch (error) { | ||
if (DEBUG) console.error(error); // eslint-disable-line no-console | ||
return []; | ||
} | ||
} | ||
|
||
async isSecretsSyncActivated(activity: ClientsActivityModel | undefined) { | ||
// if there are secrets, the feature is activated | ||
if (activity && activity.total?.secret_syncs > 0) return true; | ||
|
||
// if feature is not in license, it's definitely not activated | ||
if (!this.version.hasSecretsSync) return false; | ||
|
||
// otherwise check explicitly if the feature has been activated | ||
const activatedFeatures = await this.getActivatedFeatures(); | ||
return activatedFeatures.includes('secrets-sync'); | ||
} | ||
|
||
async model(params: ClientsCountsRouteParams) { | ||
const { config, versionHistory } = this.modelFor('vault.cluster.clients') as ModelFrom<ClientsRoute>; | ||
// only enterprise versions will have a relevant billing start date, if null users must select initial start time | ||
|
@@ -95,14 +68,11 @@ export default class ClientsCountsRoute extends Route { | |
const endTimestamp = Number(params.end_time) || getUnixTime(timestamp.now()); | ||
const { activity, activityError } = await this.getActivity(startTimestamp, endTimestamp); | ||
|
||
const isSecretsSyncActivated = await this.isSecretsSyncActivated(activity); | ||
|
||
return { | ||
activity, | ||
activityError, | ||
config, | ||
endTimestamp, | ||
isSecretsSyncActivated, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Great idea moving this to the |
||
startTimestamp, | ||
versionHistory, | ||
}; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this file & its associated test were getting a bit hairy, so moved it into a separate component 🧹