Skip to content

Commit

Permalink
Address elastic#194573
Browse files Browse the repository at this point in the history
  • Loading branch information
afharo committed Oct 1, 2024
1 parent efa4864 commit 8c27ebe
Show file tree
Hide file tree
Showing 14 changed files with 84 additions and 13 deletions.
3 changes: 1 addition & 2 deletions src/plugins/maps_ems/public/kibana_services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@

import { LicensingPluginStart } from '@kbn/licensing-plugin/public';
import { ILicense } from '@kbn/licensing-plugin/common/types';
import { firstValueFrom, take } from 'rxjs';
import type { MapConfig } from '../server/config';
import { LICENSE_CHECK_ID } from '../common';

Expand All @@ -33,7 +32,7 @@ export function getIsEnterprisePlus() {
}

export async function setLicensingPluginStart(licensingPlugin: LicensingPluginStart) {
const license = await firstValueFrom(licensingPlugin.license$.pipe(take(1)));
const license = await licensingPlugin.getLicense();
updateLicenseState(license);
licensingPlugin.license$.subscribe(updateLicenseState);
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
*/
import { useContext } from 'react';
import { useQuery } from '@tanstack/react-query';
import { firstValueFrom, take } from 'rxjs';
import { SetupContext } from '../../application/setup_context';
import { isSubscriptionAllowed } from '../../../common/utils/subscription';
import { useKibana } from './use_kibana';
Expand All @@ -17,7 +16,7 @@ export const useSubscriptionStatus = () => {
const { licensing } = useKibana().services;
const { isCloudEnabled } = useContext(SetupContext);
return useQuery([SUBSCRIPTION_QUERY_KEY], async () => {
const license = await firstValueFrom(licensing.license$.pipe(take(1)));
const license = await licensing.getLicense();
return isSubscriptionAllowed(isCloudEnabled, license);
});
};
3 changes: 1 addition & 2 deletions x-pack/plugins/cloud_defend/server/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import {
SavedObjectsClientContract,
} from '@kbn/core/server';
import type { PackagePolicy, NewPackagePolicy } from '@kbn/fleet-plugin/common';
import { firstValueFrom, take } from 'rxjs';
import {
CloudDefendPluginSetup,
CloudDefendPluginStart,
Expand Down Expand Up @@ -62,7 +61,7 @@ export class CloudDefendPlugin implements Plugin<CloudDefendPluginSetup, CloudDe
plugins.fleet.registerExternalCallback(
'packagePolicyCreate',
async (packagePolicy: NewPackagePolicy): Promise<NewPackagePolicy> => {
const license = await firstValueFrom(plugins.licensing.license$.pipe(take(1)));
const license = await plugins.licensing.getLicense();
if (isCloudDefendPackage(packagePolicy.package?.name)) {
if (!isSubscriptionAllowed(this.isCloudEnabled, license)) {
throw new Error(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
*/
import { useContext } from 'react';
import { useQuery } from '@tanstack/react-query';
import { firstValueFrom, take } from 'rxjs';
import { SetupContext } from '../../application/setup_context';
import { isSubscriptionAllowed } from '../../../common/utils/subscription';
import { useKibana } from './use_kibana';
Expand All @@ -18,7 +17,7 @@ export const useIsSubscriptionStatusValid = () => {
const { isCloudEnabled } = useContext(SetupContext);

return useQuery([SUBSCRIPTION_QUERY_KEY], async () => {
const license = await firstValueFrom(licensing.license$.pipe(take(1)));
const license = await licensing.getLicense();
return isSubscriptionAllowed(isCloudEnabled, license);
});
};
3 changes: 1 addition & 2 deletions x-pack/plugins/cloud_security_posture/server/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ import type {
CspBenchmarkRule,
CspSettings,
} from '@kbn/cloud-security-posture-common/schema/rules/latest';
import { firstValueFrom, take } from 'rxjs';
import { isCspPackage } from '../common/utils/helpers';
import { isSubscriptionAllowed } from '../common/utils/subscription';
import { cleanupCredentials } from '../common/utils/helpers';
Expand Down Expand Up @@ -116,7 +115,7 @@ export class CspPlugin
plugins.fleet.registerExternalCallback(
'packagePolicyCreate',
async (packagePolicy: NewPackagePolicy): Promise<NewPackagePolicy> => {
const license = await firstValueFrom(plugins.licensing.license$.pipe(take(1)));
const license = await plugins.licensing.getLicense();
if (isCspPackage(packagePolicy.package?.name)) {
if (!isSubscriptionAllowed(this.isCloudEnabled, license)) {
throw new Error(
Expand Down
1 change: 1 addition & 0 deletions x-pack/plugins/licensing/public/mocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const createStartMock = () => {
const license = licenseMock.createLicense();
const mock: jest.Mocked<LicensingPluginStart> = {
license$: new BehaviorSubject(license),
getLicense: jest.fn(),
refresh: jest.fn(),
featureUsage: featureUsageMock.createStart(),
};
Expand Down
30 changes: 30 additions & 0 deletions x-pack/plugins/licensing/public/plugin.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,36 @@ describe('licensing plugin', () => {
});
});

describe('#getLicense', () => {
it('awaits for the license and returns it', async () => {
const sessionStorage = coreMock.createStorage();
plugin = new LicensingPlugin(coreMock.createPluginInitializerContext(), sessionStorage);

const coreSetup = coreMock.createSetup();
const firstLicense = licenseMock.createLicense({
license: { uid: 'first', type: 'basic' },
});
coreSetup.http.get.mockResolvedValueOnce(firstLicense);

await plugin.setup(coreSetup);
const { license$, getLicense, refresh } = await plugin.start(coreStart);
const getLicensePromise = getLicense();

let fromObservable;
license$.subscribe((license) => (fromObservable = license));
await refresh(); // force the license fetch

const licenseResult = await getLicensePromise;
expect(licenseResult.uid).toBe('first');
expect(licenseResult).toBe(fromObservable);

const secondResult = await getLicense(); // retrieves the same license without refreshing
expect(secondResult.uid).toBe('first');
expect(secondResult).toBe(fromObservable);
expect(coreSetup.http.get).toHaveBeenCalledTimes(1);
});
});

describe('#license$', () => {
it('starts with license saved in sessionStorage if available', async () => {
const sessionStorage = coreMock.createStorage();
Expand Down
3 changes: 2 additions & 1 deletion x-pack/plugins/licensing/public/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* 2.0.
*/

import { Observable, Subject, Subscription } from 'rxjs';
import { firstValueFrom, Observable, Subject, Subscription, take } from 'rxjs';

import { CoreSetup, CoreStart, Plugin, PluginInitializerContext } from '@kbn/core/public';
import { ILicense } from '../common/types';
Expand Down Expand Up @@ -134,6 +134,7 @@ export class LicensingPlugin implements Plugin<LicensingPluginSetup, LicensingPl
}
return {
refresh: this.refresh,
getLicense: async () => await firstValueFrom(this.license$!.pipe(take(1))),
license$: this.license$,
featureUsage: this.featureUsage.start({ http: core.http }),
};
Expand Down
4 changes: 4 additions & 0 deletions x-pack/plugins/licensing/public/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ export interface LicensingPluginStart {
* Steam of licensing information {@link ILicense}.
*/
license$: Observable<ILicense>;
/**
* Retrieves the {@link ILicense | licensing information}
*/
getLicense(): Promise<ILicense>;
/**
* Triggers licensing information re-fetch.
*/
Expand Down
1 change: 1 addition & 0 deletions x-pack/plugins/licensing/server/mocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ const createStartMock = (): jest.Mocked<LicensingPluginStart> => {
const license = licenseMock.createLicense();
const mock = {
license$: new BehaviorSubject(license),
getLicense: jest.fn(),
refresh: jest.fn(),
createLicensePoller: jest.fn(),
featureUsage: featureUsageMock.createStart(),
Expand Down
32 changes: 32 additions & 0 deletions x-pack/plugins/licensing/server/plugin.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,38 @@ describe('licensing plugin', () => {
});
});

describe('#getLicense', () => {
it('awaits for the license and returns it', async () => {
plugin = new LicensingPlugin(
coreMock.createPluginInitializerContext({
// disable polling mechanism
api_polling_frequency: moment.duration(50000),
license_cache_duration: moment.duration(1000),
})
);
const esClient = createEsClient({
license: buildRawLicense(),
features: {},
});

const coreSetup = createCoreSetupWith(esClient);
plugin.setup(coreSetup);
const { license$, getLicense } = plugin.start();

expect(esClient.asInternalUser.xpack.info).toHaveBeenCalledTimes(0);

const firstLicense = await getLicense();
let fromObservable;
license$.subscribe((license) => (fromObservable = license));
expect(firstLicense).toStrictEqual(fromObservable);
expect(esClient.asInternalUser.xpack.info).toHaveBeenCalledTimes(1); // the initial resolution

const secondLicense = await getLicense();
expect(secondLicense).toStrictEqual(fromObservable);
expect(esClient.asInternalUser.xpack.info).toHaveBeenCalledTimes(1); // still only one call
});
});

describe('#refresh', () => {
it('forces refresh immediately', async () => {
plugin = new LicensingPlugin(
Expand Down
3 changes: 3 additions & 0 deletions x-pack/plugins/licensing/server/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import {
distinctUntilChanged,
ReplaySubject,
timer,
firstValueFrom,
take,
} from 'rxjs';
import moment from 'moment';
import type { MaybePromise } from '@kbn/utility-types';
Expand Down Expand Up @@ -159,6 +161,7 @@ export class LicensingPlugin implements Plugin<LicensingPluginSetup, LicensingPl
}
return {
refresh: this.refresh,
getLicense: async () => await firstValueFrom(this.license$!.pipe(take(1))),
license$: this.license$,
featureUsage: this.featureUsage.start(),
createLicensePoller: this.createLicensePoller.bind(this),
Expand Down
5 changes: 5 additions & 0 deletions x-pack/plugins/licensing/server/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,11 @@ export interface LicensingPluginStart {
*/
license$: Observable<ILicense>;

/**
* Retrieves the {@link ILicense | licensing information}
*/
getLicense(): Promise<ILicense>;

/**
* Triggers licensing information re-fetch.
*/
Expand Down
3 changes: 1 addition & 2 deletions x-pack/plugins/maps/public/licensed_features.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@

import { ILicense, LicenseType } from '@kbn/licensing-plugin/common/types';
import { LicensingPluginSetup, LicensingPluginStart } from '@kbn/licensing-plugin/public';
import { firstValueFrom, take } from 'rxjs';
import { APP_ID } from '../common/constants';

export enum LICENSED_FEATURES {
Expand Down Expand Up @@ -51,7 +50,7 @@ export const whenLicenseInitialized = async (): Promise<void> => {
};

export async function setLicensingPluginStart(licensingPlugin: LicensingPluginStart) {
const license = await firstValueFrom(licensingPlugin.license$.pipe(take(1)));
const license = await licensingPlugin.getLicense();
updateLicenseState(license);

licensingPluginStart = licensingPlugin;
Expand Down

0 comments on commit 8c27ebe

Please sign in to comment.