-
Notifications
You must be signed in to change notification settings - Fork 8.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
Check plugin version on startup #8283
Changes from 8 commits
f74eb9b
ae492ff
83d0821
922c04a
5da33ad
2802410
2f52be6
e920bca
049c029
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 |
---|---|---|
|
@@ -21,7 +21,7 @@ target | |
/esvm | ||
.htpasswd | ||
.eslintcache | ||
plugins | ||
/plugins/ | ||
data | ||
disabledPlugins | ||
webpackstats.json | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import { cleanVersion, versionSatisfies } from '../../utils/version'; | ||
import { get } from 'lodash'; | ||
|
||
function compatibleWithKibana(kbnServer, plugin) { | ||
//core plugins have a version of 'kibana' and are always compatible | ||
if (plugin.kibanaVersion === 'kibana') return true; | ||
|
||
const pluginKibanaVersion = cleanVersion(plugin.kibanaVersion); | ||
const kibanaVersion = cleanVersion(kbnServer.version); | ||
|
||
return versionSatisfies(pluginKibanaVersion, kibanaVersion); | ||
} | ||
|
||
export default async function (kbnServer, server, config) { | ||
//because a plugin pack can contain more than one actual plugin, (for example x-pack) | ||
//we make sure that the warning messages are unique | ||
const warningMessages = new Set(); | ||
const plugins = kbnServer.plugins; | ||
|
||
for (let plugin of plugins) { | ||
const version = plugin.kibanaVersion; | ||
const name = get(plugin, 'pkg.name'); | ||
|
||
if (!compatibleWithKibana(kbnServer, plugin)) { | ||
const message = `Plugin "${name}" was disabled because it expected Kibana version "${version}", and found "${kbnServer.version}".`; | ||
warningMessages.add(message); | ||
plugins.delete(plugin); | ||
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. Now that @Bargs has pointed it out, I took a deeper look and discovered that |
||
} | ||
} | ||
|
||
for (let message of warningMessages) { | ||
server.log(['warning'], message); | ||
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. Why not just log this in the loop above? 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. for multi-plugin packs, I'm checking the version of the pack as a whole, but there will be one plugin object for each plugin in the pack. I only want to show one message for the overall pack. |
||
} | ||
|
||
return; | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -59,6 +59,12 @@ module.exports = class Plugin { | |
this.uiExportsSpecs = opts.uiExports || {}; | ||
this.requiredIds = opts.require || []; | ||
this.version = opts.version || pkg.version; | ||
|
||
// Plugins must specify their version, and by default that version should match | ||
// the version of kibana down to the patch level. If these two versions need | ||
// to diverge, they can specify a kibana.version in the package to indicate the | ||
// version of kibana the plugin is intended to work with. | ||
this.kibanaVersion = opts.kibanaVersion || _.get(pkg, 'kibana.version', this.version); | ||
this.externalPreInit = opts.preInit || _.noop; | ||
this.externalInit = opts.init || _.noop; | ||
this.configPrefix = opts.configPrefix || this.id; | ||
|
@@ -89,17 +95,14 @@ module.exports = class Plugin { | |
}; | ||
} | ||
|
||
async readConfig() { | ||
async readConfigSchema() { | ||
let schema = await this.getConfigSchema(Joi); | ||
let { config } = this.kbnServer; | ||
config.extendSchema(this.configPrefix, schema || defaultConfigSchema); | ||
|
||
if (config.get([...toPath(this.configPrefix), 'enabled'])) { | ||
return true; | ||
} else { | ||
config.removeSchema(this.configPrefix); | ||
return false; | ||
} | ||
return schema || defaultConfigSchema; | ||
} | ||
|
||
get enabled() { | ||
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. Let's just use a function, getters for this type of stuff can be deceptive. |
||
const { config } = this.kbnServer; | ||
return config.get([...toPath(this.configPrefix), 'enabled']); | ||
} | ||
|
||
async preInit() { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,11 +2,23 @@ | |
import PluginApi from './plugin_api'; | ||
import { inspect } from 'util'; | ||
import { get, indexBy } from 'lodash'; | ||
import toPath from 'lodash/internal/toPath'; | ||
import Collection from '../../utils/collection'; | ||
|
||
let byIdCache = Symbol('byIdCache'); | ||
let pluginApis = Symbol('pluginApis'); | ||
|
||
async function addPluginConfig(pluginCollection, plugin) { | ||
const configSchema = await plugin.readConfigSchema(); | ||
let { config } = pluginCollection.kbnServer; | ||
config.extendSchema(plugin.configPrefix, configSchema); | ||
} | ||
|
||
function removePluginConfig(pluginCollection, plugin) { | ||
let { config } = pluginCollection.kbnServer; | ||
config.removeSchema(plugin.configPrefix); | ||
} | ||
|
||
module.exports = class Plugins extends Collection { | ||
|
||
constructor(kbnServer) { | ||
|
@@ -27,21 +39,26 @@ module.exports = class Plugins extends Collection { | |
// clear the byIdCache | ||
this[byIdCache] = null; | ||
|
||
for (let product of output) { | ||
|
||
if (product instanceof api.Plugin) { | ||
let plugin = product; | ||
this.add(plugin); | ||
|
||
let enabled = await plugin.readConfig(); | ||
if (!enabled) this.delete(plugin); | ||
continue; | ||
for (let plugin of output) { | ||
if (!plugin instanceof api.Plugin) { | ||
throw new TypeError('unexpected plugin export ' + inspect(plugin)); | ||
} | ||
|
||
throw new TypeError('unexpected plugin export ' + inspect(product)); | ||
await this.add(plugin); | ||
if (!plugin.enabled) this.delete(plugin); | ||
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. It's really unclear why these two lines are necessary, I think it would be clearer if we added and removed the configuration from the config schema right here. |
||
} | ||
} | ||
|
||
async add(plugin) { | ||
await addPluginConfig(this, plugin); | ||
super.add(plugin); | ||
} | ||
|
||
delete(plugin) { | ||
removePluginConfig(this, plugin); | ||
super.delete(plugin); | ||
} | ||
|
||
get byId() { | ||
return this[byIdCache] || (this[byIdCache] = indexBy([...this], 'id')); | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
{ | ||
"name": "plugin_async_foo", | ||
"version": "0.0.0" | ||
"version": "kibana" | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
{ | ||
"name": "plugin_bar", | ||
"version": "0.0.0" | ||
"version": "kibana" | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
{ | ||
"name": "plugin_foo", | ||
"version": "0.0.0" | ||
"version": "kibana" | ||
} |
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.
The indentation here is really hard for me to read. Would something like this be better?