Skip to content

Commit

Permalink
Merge pull request #4406 from BigFunger/install-plugin
Browse files Browse the repository at this point in the history
Install plugin
  • Loading branch information
spalger committed Jul 15, 2015
2 parents c8e16fa + 49d1e5a commit 9d69b97
Show file tree
Hide file tree
Showing 29 changed files with 1,986 additions and 58 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ target
*.log
esvm
.htpasswd
src/server/bin/plugins
4 changes: 3 additions & 1 deletion Gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@ module.exports = function (grunt) {
'Gruntfile.js',
'<%= root %>/tasks/**/*.js',
'<%= src %>/kibana/*.js',
'<%= src %>/server/**/*.js',
'<%= src %>/server/bin/*.js',
'<%= src %>/server/{config,lib,plugins}/**/*.js',
'<%= src %>/server/bin/{plugin,startup}/**/*.js',
'<%= src %>/kibana/{components,directives,factories,filters,plugins,registry,services,utils}/**/*.js',
'<%= unitTestDir %>/**/*.js',
'!<%= unitTestDir %>/specs/vislib/fixture/**/*'
Expand Down
9 changes: 5 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
"scripts": {
"test": "grunt test",
"start": "node ./src/server/bin/kibana.js",
"postinstall": "bower install && grunt licenses --check-validity",
"precommit": "grunt lintStagedFiles"
},
"repository": {
Expand All @@ -48,6 +47,7 @@
"cookie-parser": "^1.3.3",
"debug": "^2.1.1",
"elasticsearch": "^5.0.0",
"expiry-js": "^0.1.7",
"express": "^4.10.6",
"glob": "^4.3.2",
"good": "^5.1.2",
Expand All @@ -57,12 +57,13 @@
"hapi": "^8.6.1",
"joi": "^6.4.3",
"js-yaml": "^3.2.5",
"lodash": "^3.9.3",
"json-stringify-safe": "^5.0.1",
"lodash": "^3.9.3",
"moment": "^2.10.3",
"numeral": "^1.5.3",
"request": "^2.40.0",
"requirefrom": "^0.2.0",
"rimraf": "^2.4.0",
"semver": "^4.3.6",
"serve-favicon": "^2.2.0",
"through": "^2.3.6"
Expand Down Expand Up @@ -94,14 +95,14 @@
"husky": "^0.8.1",
"istanbul": "^0.3.15",
"jade": "^1.8.2",
"license-checker": "^3.1.0",
"libesvm": "^1.0.1",
"license-checker": "^3.1.0",
"load-grunt-config": "^0.7.0",
"marked": "^0.3.3",
"marked-text-renderer": "^0.1.0",
"mkdirp": "^0.5.0",
"mocha": "^2.2.5",
"nock": "^1.6.0",
"nock": "^2.7.0",
"npm": "^2.11.0",
"opn": "^1.0.0",
"path-browserify": "0.0.0",
Expand Down
4 changes: 1 addition & 3 deletions src/server/bin/kibana.bat
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,4 @@ TITLE Kibana Server @@version

:finally

ENDLOCAL


ENDLOCAL
60 changes: 10 additions & 50 deletions src/server/bin/kibana.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
#!/usr/bin/env node

var _ = require('lodash');
var Kibana = require('../');
var program = require('commander');
require('../lib/commanderExtensions')(program);
var path = require('path');
var writePidFile = require('../lib/write_pid_file');
var loadSettingsFromYAML = require('../lib/load_settings_from_yaml');
var settings = { 'logging.console.json': true };
var startupOptions = require('./startup/startupOptions');
var startup = require('./startup/startup');
var pluginProgram = require('./plugin/plugin');

var env = (process.env.NODE_ENV) ? process.env.NODE_ENV : 'development';
var packagePath = path.resolve(__dirname, '..', '..', '..', 'package.json');
Expand All @@ -17,51 +16,12 @@ var package = require(packagePath);

program.description('Kibana is an open source (Apache Licensed), browser based analytics and search dashboard for Elasticsearch.');
program.version(package.version);
program.option('-e, --elasticsearch <uri>', 'Elasticsearch instance');
program.option('-c, --config <path>', 'Path to the config file');
program.option('-p, --port <port>', 'The port to bind to', parseInt);
program.option('-q, --quiet', 'Turns off logging');
program.option('-H, --host <host>', 'The host to bind to');
program.option('-l, --log-file <path>', 'The file to log to');
program.option('--plugins <path>', 'Path to scan for plugins');
program.parse(process.argv);


if (program.plugins) {
settings['kibana.externalPluginsFolder'] = program.plugins;
}

if (program.elasticsearch) {
settings['elasticsearch.url'] = program.elasticsearch;
}

if (program.port) {
settings['kibana.server.port'] = program.port;
}

if (program.host) {
settings['kibana.server.host'] = program.host;
}

if (program.quiet) {
settings['logging.quiet'] = program.quiet;
}

if (program.logFile) {
settings['logging.file'] = program.logFile;
}

var configPath = program.config || process.env.CONFIG_PATH;
if (configPath) {
settings = _.defaults(settings, loadSettingsFromYAML(configPath));
}

startupOptions(program);
pluginProgram(program);

program.parse(process.argv);

// Start the Kibana server with the settings fromt he CLI and YAML file
var kibana = new Kibana(settings);
kibana.listen()
.then(writePidFile)
.catch(function (err) {
process.exit(1);
});
if (!program.isCommandSpecified()) {
startup(program);
}
36 changes: 36 additions & 0 deletions src/server/bin/plugin/npmInstall.js
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);
});
};
53 changes: 53 additions & 0 deletions src/server/bin/plugin/plugin.js
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);
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);
};
40 changes: 40 additions & 0 deletions src/server/bin/plugin/pluginCleaner.js
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
};
};
94 changes: 94 additions & 0 deletions src/server/bin/plugin/pluginDownloader.js
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
};
};
Loading

0 comments on commit 9d69b97

Please sign in to comment.