NP Licensing service info endpoint (#51188)

* add NP licensing service info endpoint

* call licensing/info and mark it as system to prevent session update

* add integration api test for licensing/info endpoint

* readonly for static data!
This commit is contained in:
Mikhail Shustov 2019-11-20 21:39:06 +01:00 committed by GitHub
parent e16e3e3f63
commit d61cef41bb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 110 additions and 17 deletions

View file

@ -38,6 +38,25 @@ describe('licensing plugin', () => {
expect(license.uid).toBe('fetched');
});
it('data re-fetch call marked as a system api', async () => {
const sessionStorage = coreMock.createStorage();
plugin = new LicensingPlugin(coreMock.createPluginInitializerContext(), sessionStorage);
const coreSetup = coreMock.createSetup();
const fetchedLicense = licenseMock.create();
coreSetup.http.get.mockResolvedValue(fetchedLicense);
const { refresh } = await plugin.setup(coreSetup);
refresh();
expect(coreSetup.http.get.mock.calls[0][1]).toMatchObject({
headers: {
'kbn-system-api': 'true',
},
});
});
});
describe('#license$', () => {
@ -238,7 +257,7 @@ describe('licensing plugin', () => {
},
},
request: {
url: 'http://10.10.10.10:5601/api/xpack/v1/info',
url: 'http://10.10.10.10:5601/api/licensing/info',
},
};
expect(coreSetup.http.get).toHaveBeenCalledTimes(0);

View file

@ -5,7 +5,7 @@
*/
import { Subject, Subscription, merge } from 'rxjs';
import { takeUntil, tap } from 'rxjs/operators';
import { takeUntil } from 'rxjs/operators';
import { CoreSetup, Plugin, PluginInitializerContext } from 'src/core/public';
@ -31,8 +31,9 @@ export class LicensingPlugin implements Plugin<LicensingPluginSetup> {
*/
private removeInterceptor?: () => void;
private licenseFetchSubscription?: Subscription;
private storageSubscription?: Subscription;
private infoEndpoint = '/api/xpack/v1/info';
private readonly infoEndpoint = '/api/licensing/info';
private prevSignature?: string;
constructor(
@ -76,18 +77,16 @@ export class LicensingPlugin implements Plugin<LicensingPluginSetup> {
);
this.licenseFetchSubscription = fetchSubscription;
const license$ = update$.pipe(
tap(license => {
if (license.error) {
this.prevSignature = undefined;
// Prevent reusing stale license if the fetch operation fails
this.removeSaved();
} else {
this.prevSignature = license.signature;
this.save(license);
}
})
);
this.storageSubscription = update$.subscribe(license => {
if (license.isAvailable) {
this.prevSignature = license.signature;
this.save(license);
} else {
this.prevSignature = undefined;
// Prevent reusing stale license if the fetch operation fails
this.removeSaved();
}
});
this.removeInterceptor = core.http.intercept({
response: async httpResponse => {
@ -107,7 +106,7 @@ export class LicensingPlugin implements Plugin<LicensingPluginSetup> {
refresh: () => {
manualRefresh$.next();
},
license$,
license$: update$,
};
}
@ -124,11 +123,20 @@ export class LicensingPlugin implements Plugin<LicensingPluginSetup> {
this.licenseFetchSubscription.unsubscribe();
this.licenseFetchSubscription = undefined;
}
if (this.storageSubscription !== undefined) {
this.storageSubscription.unsubscribe();
this.storageSubscription = undefined;
}
}
private fetchLicense = async (core: CoreSetup): Promise<ILicense> => {
try {
const response = await core.http.get(this.infoEndpoint);
const response = await core.http.get(this.infoEndpoint, {
headers: {
'kbn-system-api': 'true',
},
});
return new License({
license: response.license,
features: response.features,

View file

@ -24,6 +24,8 @@ import { License } from '../common/license';
import { createLicenseUpdate } from '../common/license_update';
import { ElasticsearchError, RawLicense, RawFeatures } from './types';
import { registerRoutes } from './routes';
import { LicenseConfigType } from './licensing_config';
import { createRouteHandlerContext } from './licensing_route_handler_context';
@ -92,6 +94,7 @@ export class LicensingPlugin implements Plugin<LicensingPluginSetup> {
const { refresh, license$ } = this.createLicensePoller(dataClient, config.pollingFrequency);
core.http.registerRouteHandlerContext('licensing', createRouteHandlerContext(license$));
registerRoutes(core.http.createRouter());
return {
refresh,

View file

@ -0,0 +1,11 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { IRouter } from 'src/core/server';
import { registerInfoRoute } from './info';
export function registerRoutes(router: IRouter) {
registerInfoRoute(router);
}

View file

@ -0,0 +1,14 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { IRouter } from 'src/core/server';
export function registerInfoRoute(router: IRouter) {
router.get({ path: '/api/licensing/info', validate: false }, (context, request, response) => {
return response.ok({
body: context.licensing.license,
});
});
}

View file

@ -27,5 +27,6 @@ export default function ({ loadTestFile }) {
loadTestFile(require.resolve('./siem'));
loadTestFile(require.resolve('./short_urls'));
loadTestFile(require.resolve('./lens'));
loadTestFile(require.resolve('./licensing'));
});
}

View file

@ -0,0 +1,13 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { FtrProviderContext } from '../../ftr_provider_context';
export default function licensingIntegrationTests({ loadTestFile }: FtrProviderContext) {
describe('Licensing', () => {
loadTestFile(require.resolve('./info'));
});
}

View file

@ -0,0 +1,24 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import expect from '@kbn/expect';
import { FtrProviderContext } from '../../ftr_provider_context';
export default function({ getService }: FtrProviderContext) {
const supertest = getService('supertest');
describe('Info', () => {
describe('GET /api/licensing/info', () => {
it('returns licensing information', async () => {
const response = await supertest.get('/api/licensing/info').expect(200);
expect(response.body).property('features');
expect(response.body).property('license');
expect(response.body).property('signature');
});
});
});
}