x-pack/platform/plugins/shared/licensing/README.md
The licensing plugin retrieves license data from Elasticsearch at regular configurable intervals.
license$: Observable<ILicense> Provides a steam of license data ILicense. Plugin emits new value whenever it detects changes in license info. If the plugin cannot retrieve a license from Elasticsearch, it will emit an empty license object.getLicense(): Promise<ILicense> returns the latest license data retrieved or waits for it to be resolved.refresh: () => Promise<ILicense> triggers the licensing information re-fetch.The licensing plugin retrieves license data from licensing Kibana plugin and does not communicate with Elasticsearch directly.
license$: Observable<ILicense> Provides a steam of license data ILicense. Plugin emits new value whenever it detects changes in license info. If the plugin cannot retrieve a license from Kibana, it will emit an empty license object.getLicense(): Promise<ILicense> returns the latest license data retrieved or waits for it to be resolved.refresh: () => Promise<ILicense> triggers the licensing information re-fetch.The new platform licensing plugin became stateless now. It means that instead of storing all your data from checkLicense within the plugin, you should react on license data change on both the client and server sides.
// my_plugin/server/plugin.ts
function checkLicense(xpackLicenseInfo: XPackInfo){
if (!xpackLicenseInfo || !xpackLicenseInfo.isAvailable()) {
return {
isAvailable: false,
showLinks: true,
}
}
if (!xpackLicenseInfo.feature('id').isEnabled()) {
return {
isAvailable: false,
showLinks: false,
}
}
const hasRequiredLicense = xPackInfo.license.isOneOf([
'gold',
'platinum',
'trial',
]);
return {
isAvailable: hasRequiredLicense,
showLinks: hasRequiredLicense,
}
}
xpackMainPlugin.info.feature(pluginId).registerLicenseCheckResultsGenerator(checkLicense);
// my_plugin/client/plugin.ts
chrome.navLinks.update('myPlugin', {
hidden: !xpackInfo.get('features.myPlugin.showLinks', false)
});
// kibana.json
"requiredPlugins": ["licensing"],
// my_plugin/server/plugin.ts
import { LicensingPluginSetup } from '../licensing/server'
interface SetupDeps {
licensing: LicensingPluginSetup;
}
class MyPlugin {
setup(core: CoreSetup, deps: SetupDeps) {
deps.licensing.license$.subscribe(license => {
const { state, message } = license.check('myPlugin', 'gold')
const hasRequiredLicense = state === 'valid';
if (hasRequiredLicense && license.getFeature('id').isAvailable) {
// enable some server side logic
} else {
log(message);
// disable some server side logic
}
})
}
}
// my_plugin/public/plugin.ts
import { LicensingPluginSetup } from '../licensing/public'
class MyPlugin {
setup(core: CoreSetup, deps: SetupDeps) {
const appUpdater$ = new BehaviorSubject<AppUpdater>(() => {});
core.application.register({
id: 'myApp',
updater$: appUpdater$,
});
deps.licensing.license$.subscribe(license => {
const { state, message } = license.check('myPlugin', 'gold')
const hasRequiredLicense = state === 'valid';
const showLinks = hasRequiredLicense && license.getFeature('id').isAvailable;
appUpdater$.next(() => {
status: showLinks ? AppStatus.accessible : AppStatus.inaccessible,
});
})
}
}
LP: The plugin allows consumers to calculate state on license change event and store this
The signature calculation is based on this state + license content
NP: We decided that license service doesn't keep plugins state https://github.com/elastic/kibana/pull/49345#issuecomment-553451472. Plugins have to react on license change and calculate license state on every license change. If another plugin needs that information, it should be exposed via a plugin contract.
This change makes NP & LP licensing service not compatible. We have to keep both until all plugins migrate to the new platform service. The legacy plugin consumes license data from the LP plugin.
LP: The licensing plugin didn’t emit a license in case of network errors. NP: Emits the license even if the request failed.
LP: Allows specifying cluster source to perform polling.
NP: The plugin always uses a data client. Provides createLicensePoller on the server-side to create a license poller with custom ES cluster.
LP: Passed on the page via inlined xpackInitialInfo
NP: Should be fetched
LP: xpack.xpack_main.xpack_api_polling_frequency_millis
NP: xpack.licensing.api_polling_frequency
Support for deprecated xpack.xpack_main.xpack_api_polling_frequency_millis is removed in v8.0.0. See https://github.com/elastic/kibana/issues/103915 for more details.
NP: mode field is provided, but deprecated.
LP: License and signature were stored under different keys in session storage
NP: License and signature were stored under one key xpack.licensing
isOneOf removed, use check or hasAtLeast instead
/api/xpack/v1/info API endpoint is going to be removed. switch to /api/licensing/info instead
getUnavailableReason doesn't return Error object anymore, but string