-
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
Install plugin #4406
Install plugin #4406
Changes from all commits
c0f114d
015d3ab
56d3eba
c0b36b2
a9b7296
ca224a4
4a021a2
c0a6572
cad5aa2
550c1c3
49e67dd
6a59781
7a37dcf
49d1e5a
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 |
---|---|---|
|
@@ -13,3 +13,4 @@ target | |
*.log | ||
esvm | ||
.htpasswd | ||
src/server/bin/plugins |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,6 +16,4 @@ TITLE Kibana Server @@version | |
|
||
:finally | ||
|
||
ENDLOCAL | ||
|
||
|
||
ENDLOCAL |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
var Promise = require('bluebird'); | ||
var fs = require('fs'); | ||
var path = require('path'); | ||
var exec = require('child_process').exec; | ||
|
||
module.exports = function (dest, logger) { | ||
return new Promise(function (resolve, reject) { | ||
//throw an exception if package.json does not exist | ||
try { | ||
var packageFile = path.join(dest, 'package.json'); | ||
fs.statSync(packageFile); | ||
} catch (e) { | ||
if (e.code !== 'ENOENT') | ||
throw e; | ||
|
||
return reject(new Error('Plugin does not contain package.json file')); | ||
} | ||
|
||
var cmd = '"' + path.resolve(path.dirname(process.execPath), 'npm').replace(/\\/g, '/') + '" install --production'; | ||
|
||
var child = exec(cmd, { cwd: dest }); | ||
child.on('error', function (err) { | ||
reject(err); | ||
}); | ||
child.on('exit', function (code, signal) { | ||
if (code === 0) { | ||
resolve(); | ||
} else { | ||
reject(new Error('npm install failed with code ' + code)); | ||
} | ||
}); | ||
|
||
logger.error(child.stderr); | ||
logger.log(child.stdout); | ||
}); | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
var settingParser = require('./settingParser'); | ||
var installer = require('./pluginInstaller'); | ||
var remover = require('./pluginRemover'); | ||
var pluginLogger = require('./pluginLogger'); | ||
|
||
module.exports = function (program) { | ||
function processCommand(command, options) { | ||
var settings; | ||
try { | ||
settings = settingParser(command).parse(); | ||
} catch (ex) { | ||
//The logger has not yet been initialized. | ||
console.error(ex.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. we need to respect the 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 should already be respecting the silent option. The stdout and stserr streams are passed to the logger. The logger then checks the silent option to determine whether the output should be piped. Any errors ignore the silent option. 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. Modified the --silent option so that it applies to both log and error messages per a conversation with @rashidkpc. 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. @BigFunger the logger isn't initialized until the next line. |
||
process.exit(64); | ||
} | ||
|
||
var logger = pluginLogger(settings); | ||
|
||
if (settings.action === 'install') { | ||
installer.install(settings, logger); | ||
} | ||
if (settings.action === 'remove') { | ||
remover.remove(settings, logger); | ||
} | ||
} | ||
|
||
var installDesc = | ||
'The plugin to install\n\n' + | ||
'\tCommon examples:\n' + | ||
'\t -i username/sample\n' + | ||
'\t attempts to download the latest version from the following urls:\n' + | ||
'\t https://download.elastic.co/username/sample/sample-latest.tar.gz\n' + | ||
'\t https://github.com/username/sample/archive/master.tar.gz\n\n' + | ||
'\t -i username/sample/v1.1.1\n' + | ||
'\t attempts to download version v1.1.1 from the following urls:\n' + | ||
'\t https://download.elastic.co/username/sample/sample-v1.1.1.tar.gz\n' + | ||
'\t https://github.com/username/sample/archive/v1.1.1.tar.gz\n\n' + | ||
'\t -i sample -u http://www.example.com/other_name.tar.gz\n' + | ||
'\t attempts to download from the specified url,\n' + | ||
'\t and installs the plugin found at that url as "sample"' + | ||
'\n'; | ||
|
||
program | ||
.command('plugin') | ||
.description('Maintain Plugins') | ||
.option('-i, --install <org>/<plugin>/<version>', installDesc) | ||
.option('-r, --remove <plugin>', 'The plugin to remove') | ||
.option('-q, --quiet', 'Disable all process messaging except errors') | ||
.option('-s, --silent', 'Disable all process messaging') | ||
.option('-u, --url <url>', 'Specify download url') | ||
.option('-t, --timeout <duration>', 'Length of time before failing; 0 for never fail', settingParser.parseMilliseconds) | ||
.action(processCommand); | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
var rimraf = require('rimraf'); | ||
var fs = require('fs'); | ||
var Promise = require('bluebird'); | ||
|
||
module.exports = function (settings, logger) { | ||
|
||
function cleanPrevious() { | ||
return new Promise(function (resolve, reject) { | ||
try { | ||
fs.statSync(settings.workingPath); | ||
|
||
logger.log('Found previous install attempt. Deleting...'); | ||
try { | ||
rimraf.sync(settings.workingPath); | ||
} catch (e) { | ||
return reject(e); | ||
} | ||
return resolve(); | ||
} catch (e) { | ||
if (e.code !== 'ENOENT') | ||
return reject(e); | ||
|
||
return resolve(); | ||
} | ||
}); | ||
} | ||
|
||
function cleanError() { | ||
//delete the working directory. | ||
//At this point we're bailing, so swallow any errors on delete. | ||
try { | ||
rimraf.sync(settings.workingPath); | ||
} catch (e) { } | ||
} | ||
|
||
return { | ||
cleanPrevious: cleanPrevious, | ||
cleanError: cleanError | ||
}; | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
var _ = require('lodash'); | ||
var zlib = require('zlib'); | ||
var Promise = require('bluebird'); | ||
var request = require('request'); | ||
var tar = require('tar'); | ||
var progressReporter = require('./progressReporter'); | ||
|
||
module.exports = function (settings, logger) { | ||
|
||
//Attempts to download each url in turn until one is successful | ||
function download() { | ||
var urls = settings.urls; | ||
|
||
function tryNext() { | ||
var sourceUrl = urls.shift(); | ||
if (!sourceUrl) { | ||
throw new Error('Not a valid url.'); | ||
} | ||
|
||
logger.log('attempting to download ' + sourceUrl); | ||
|
||
return Promise.try(function () { | ||
return downloadSingle(sourceUrl, settings.workingPath, settings.timeout, logger) | ||
.catch(function (err) { | ||
if (err.message === 'ENOTFOUND') { | ||
return tryNext(); | ||
} | ||
if (err.message === 'EEXTRACT') { | ||
throw (new Error('Error extracting the plugin archive')); | ||
} | ||
throw (err); | ||
}); | ||
}) | ||
.catch(function (err) { | ||
//Special case for when request.get throws an exception | ||
if (err.message.match(/invalid uri/i)) { | ||
return tryNext(); | ||
} | ||
throw (err); | ||
}); | ||
} | ||
|
||
return tryNext(); | ||
} | ||
|
||
//Attempts to download a single url | ||
function downloadSingle(source, dest, timeout) { | ||
var gunzip = zlib.createGunzip(); | ||
var tarExtract = tar.Extract({ path: dest, strip: 1 }); | ||
|
||
var requestOptions = { url: source }; | ||
if (timeout !== 0) { | ||
requestOptions.timeout = timeout; | ||
} | ||
|
||
return wrappedRequest(requestOptions) | ||
.then(function (req) { | ||
//debugger; | ||
var reporter = progressReporter(logger, req); | ||
|
||
req | ||
.on('response', reporter.handleResponse) | ||
.on('data', reporter.handleData) | ||
.on('error', _.partial(reporter.handleError, 'ENOTFOUND')) | ||
.pipe(gunzip) | ||
.on('error', _.partial(reporter.handleError, 'EEXTRACT')) | ||
.pipe(tarExtract) | ||
.on('error', _.partial(reporter.handleError, 'EEXTRACT')) | ||
.on('end', reporter.handleEnd); | ||
|
||
return reporter.promise; | ||
}); | ||
} | ||
|
||
function wrappedRequest(requestOptions) { | ||
//debugger; | ||
return Promise.try(function () { | ||
//debugger; | ||
return request.get(requestOptions); | ||
}) | ||
.catch(function (err) { | ||
if (err.message.match(/invalid uri/i)) { | ||
throw new Error('ENOTFOUND'); | ||
} | ||
throw err; | ||
}); | ||
} | ||
|
||
|
||
return { | ||
download: download, | ||
_downloadSingle: downloadSingle | ||
}; | ||
}; |
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 output of this command needs to be ignored when the
--silent
option is specified.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.
Modified the --silent option so that it applies to both log and error messages per a conversation with @rashidkpc.