import * as path from 'path'; import * as util from 'util'; import moment from 'moment'; import * as _ from 'lodash'; import { Docker, Options as DockerOptions } from 'docker-cli-js'; import nodeify from 'nodeify-ts'; const promiseDelay = require('promise-delay'); //const JSONPath = require('jsonpath-plus'); import { JSONPath} from 'jsonpath-plus'; //const exec2 = child_process.exec; class WaitForContainerToFinishOptions { public internalUseOnly: { endTime: moment.Moment, startTime: moment.Moment }; public constructor( public timeoutInSeconds: number = 15 * 60, public checkIntervalInMilliSeconds: number = 1000, ) { this.internalUseOnly = { endTime: moment().add(timeoutInSeconds, 's'), startTime: moment(), }; } } const waitForContainerToFinish = function (containerid: string, machinename = 'localhost', options: WaitForContainerToFinishOptions = new WaitForContainerToFinishOptions()): Promise { containerid = containerid.substring(0, 12); if (!options) { options = new WaitForContainerToFinishOptions(); } const now = moment(); //console.log('now', now.format()); //const diff = now.valueOf() - options.internalUseOnly.startTime.valueOf(); //console.log('diff ms', diff); if (now.isBefore(options.internalUseOnly.endTime)) { return Promise.resolve().then(function () { return promiseDelay(options.checkIntervalInMilliSeconds); }).then(function () { const dockeroptions = new DockerOptions( /* machinename */ machinename === 'localhost' ? undefined : machinename, /* currentWorkingDirectory */ undefined, ); const docker = new Docker(dockeroptions); return docker.command('ps'); }).then(function (data) { //console.log('data.containerList', data.containerList); //'$.*[?(@.names="zookeeper")]' const result = JSONPath({ json: data.containerList, path: '$.*.container id' }); const stillRunning = _.includes(result, containerid); //console.log('result', result); //console.log('stillRunning', stillRunning); if (stillRunning) { return waitForContainerToFinish(containerid, machinename, options); } }); } return Promise.resolve().then(function () { const dockeroptions = new DockerOptions( /* machinename */ machinename === 'localhost' ? undefined : machinename, /* currentWorkingDirectory */ undefined, ); const docker = new Docker(dockeroptions); return docker.command('rm -f ' + containerid); }).then(function (data) { //console.log('data', data); throw new Error('ERROR timeout'); }); }; export class SolrZkcliResult { public constructor( public error = '', public ok = false, public returnedData = '', ) { } } const zkcliViaDocker = function (options: SolrZkcliOptions, cmdArray: Array, cmd: string = ''): Promise { const machinename = options.machineName; const dockeroptions = new DockerOptions( /* machinename */ machinename === 'localhost' ? undefined : machinename, /* currentWorkingDirectory */ undefined, ); const docker = new Docker(dockeroptions); let containerid: string; let error = ''; let returned_data = ''; return Promise.resolve().then(function () { const command = cmdArray.join(''); console.log('zkcliViaDocker command', command); return docker.command(command); }).then(function (data) { console.log('zkcliViaDocker data', data); containerid = data.containerId; //return Promise.delay(10000); return waitForContainerToFinish(containerid, options.machineName); }).then(function () { const command2 = 'logs ' + containerid; return docker.command(command2); }).then(function (data2) { console.log('zkcliViaDocker data2', data2); if (!data2) { error += 'docker logs failed !data2 '; } else { //if (data2.raw === '') { // data2.raw = '{}'; //} //const obj = JSON.parse(data2.raw); if (cmd === 'get') { returned_data = data2.raw; } else if (cmd === 'list' || cmd === 'mkroot') { returned_data = data2.raw; } else { //failed if logs returns data error += data2.raw; //const lines = obj.split(os.EOL); ////const foundException = false; //lines.forEach(function (line) { // if (_.startsWith(line, 'Exception')) { // //foundException = true; // error += line; // } //}); } } }).then(function () { //console.log('error 0', error); if (containerid) { return docker.command('rm -f ' + containerid); } }).then(function (data3) { //console.log('data3', data3); if (!data3 || !data3.raw) { error += 'docker rm -f failed !data3.raw '; } else { const id = data3.raw.trim(); if (id !== containerid) { throw new Error('failed to remove docker container ' + data3.raw); } } const result = new SolrZkcliResult(error, error.length === 0, returned_data); //console.log('error 1', error); //console.log('result', result); return result; }).catch(function (e) { //console.log('error 2', error); return new SolrZkcliResult(error + ' ' + e, false, returned_data); }); }; const clusterprop = function (options: SolrZkcliOptions) { const cmdArray = [ util.format(`run --net ${options.network} `), options.BaseCommand(), util.format(' -cmd clusterprop '), ]; if (options.clusterprop) { cmdArray.push(util.format(' -name %s', options.clusterprop.name)); cmdArray.push(util.format(' -val %s', options.clusterprop.val)); } return zkcliViaDocker(options, cmdArray); }; const makepath = function (options: SolrZkcliOptions) { const cmdArray = [ util.format(`run --net ${options.network} `), options.BaseCommand(), util.format(' -cmd %s', options.cmd), ]; return zkcliViaDocker(options, cmdArray); }; //Exception in thread "main" org.apache.solr.common.SolrException: solr.xml does not exist in ///opt/solr / server / solr / configsets cannot start Solr //const linkconfig = function (options) { // const console.log = require('console.log')('solr-zkcli:lib/index.js linkconfig'); // const cmdArray = [ // util.format('run-d quobjectio/solr:1.0.0 ./server/scripts/cloud-scripts/zkcli.sh -zkhost %s', options.zkhost), // ' -cmd linkconfig ', // util.format(' -collection %s ', options.collection), // util.format(' -confname %s ', options.confname) // ]; // return zkcliViaDocker(options, cmdArray); //}; const put = function (options: SolrZkcliOptions) { const cmdArray = [ util.format(`run --net ${options.network} `), options.BaseCommand(), util.format(' -cmd %s', options.cmd), ]; return zkcliViaDocker(options, cmdArray); }; const get = function (options: SolrZkcliOptions) { const cmdArray = [ util.format(`run --net ${options.network} `), options.BaseCommand(), util.format(' -cmd %s', options.cmd), ]; return zkcliViaDocker(options, cmdArray, 'get'); }; const list = function (options: SolrZkcliOptions) { const cmdArray = [ util.format(`run --net ${options.network} `), options.BaseCommand(), util.format(' -cmd %s', options.cmd), ]; return zkcliViaDocker(options, cmdArray, 'list'); }; const clear = function (options: SolrZkcliOptions) { const cmdArray = [ util.format(`run --net ${options.network} `), options.BaseCommand(), util.format(' -cmd %s', options.cmd), ]; return zkcliViaDocker(options, cmdArray); }; const getfile = function (options: SolrZkcliOptions) { const cmdParts = options.cmd.split(' '); const zkPath = cmdParts[1]; const filePath = cmdParts[2]; const filePathDirname = path.dirname(filePath); const fileName = path.basename(filePath); console.log('filePathDirname', filePathDirname); console.log('fileName', fileName); const cmdArray = [ util.format(`run --net ${options.network} -v %s:/const/opt `, filePathDirname), options.BaseCommand(), util.format(' -cmd getfile %s /const/opt/%s ', zkPath, fileName), ]; return zkcliViaDocker(options, cmdArray, 'getfile'); }; const putfile = function (options: SolrZkcliOptions) { const cmdParts = options.cmd.split(' '); const zkPath = cmdParts[1]; const filePath = cmdParts[2]; const filePathDirname = path.dirname(filePath); const fileName = path.basename(filePath); const cmdArray = [ util.format(`run --net ${options.network} -v %s:/opt/solr/server/solr/configsets `, filePathDirname), options.BaseCommand(), util.format(' -cmd putfile %s /opt/solr/server/solr/configsets/%s', zkPath, fileName), ]; return zkcliViaDocker(options, cmdArray); }; const bootstrap = function (options: SolrZkcliOptions) { const cmdArray = [ util.format(`run --net ${options.network} -v %s:/opt/solr/server/solr/configsets `, options.solrhome), options.BaseCommand(), ' -cmd bootstrap ', ' -solrhome /opt/solr/server/solr/configsets ', ]; return zkcliViaDocker(options, cmdArray); }; const upconfig = function (options: SolrZkcliOptions) { const cmdArray = [ util.format(`run --net ${options.network} -v %s:/opt/solr/server/solr/configsets `, options.confdir), options.BaseCommand(), util.format(' -cmd %s ', options.cmd), util.format(' -confname %s ', options.confname), ' -confdir /opt/solr/server/solr/configsets ', ]; return zkcliViaDocker(options, cmdArray); }; const downconfig = function (options: SolrZkcliOptions) { const cmdArray = [ util.format(`run --net ${options.network} -v %s:/const/opt `, options.confdir), options.BaseCommand(), util.format(' -cmd %s ', options.cmd), util.format(' -confname %s ', options.confname), ' -confdir /const/opt ', ]; return zkcliViaDocker(options, cmdArray); }; const mkroot = function (options: SolrZkcliOptions) { const cmdArray = [ util.format(`run --net ${options.network} `), options.BaseCommandSolr(), util.format(` mkroot /${options.confname} `), util.format(` -z ${options.zkhost} `), ]; return zkcliViaDocker(options, cmdArray, 'mkroot'); }; export function SolrZkCliCommand(options: SolrZkcliOptions, callback?: (err: string, data: string) => void) { const promise = Promise.resolve().then(function () { if (!options) { throw new Error('need options object'); } options.cmd = options.cmd.trim(); if (options.cmd === 'upconfig') { return upconfig(options); } if (options.cmd === 'downconfig') { return downconfig(options); } if (options.cmd === 'bootstrap') { return bootstrap(options); } if (options.cmd.startsWith('put ')) { return put(options); } if (options.cmd.startsWith('get ')) { return get(options); } if (options.cmd.startsWith('putfile ')) { return putfile(options); } if (options.cmd.startsWith('list')) { return list(options); } if (options.cmd.startsWith('clear')) { return clear(options); } if (options.cmd.startsWith('getfile ')) { return getfile(options); } //if (options.cmd === 'linkconfig') { // return bootstrap(options); //} if (options.cmd.startsWith('makepath ')) { return makepath(options); } if (options.cmd === 'clusterprop') { return clusterprop(options); } if (options.cmd === 'mkroot') { return mkroot(options); } throw new Error('options.cmd ' + options.cmd + ' not implemented'); }); return nodeify(promise, callback); } export class SolrZkcliOptions { public constructor( public cmd: string, public currentWorkingDirectory?: string, public zkhost?: string, public confname?: string, public confdir?: string, // tslint:disable-next-line: no-shadowed-variable public clusterprop?: { name: string, val: string }, public solrhome?: string, public solrDockerImage = 'solr:7.2.0', public machineName = 'localhost', public network = 'host', ) { } public BaseCommand(): string { return ` -d ${this.solrDockerImage} ./server/scripts/cloud-scripts/zkcli.sh -zkhost ${this.zkhost} `; } public BaseCommandSolr(): string { return ` -d ${this.solrDockerImage} ./bin/solr zk `; } }