Skip to content

Commit

Permalink
Load configs once, then forward them as needed
Browse files Browse the repository at this point in the history
Signed-off-by: Attila Klenik <[email protected]>
  • Loading branch information
aklenik committed Nov 6, 2019
1 parent ff5625c commit c9e4317
Show file tree
Hide file tree
Showing 18 changed files with 237 additions and 241 deletions.
6 changes: 0 additions & 6 deletions packages/caliper-cli/caliper.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,7 @@
'use strict';

process.env.SUPPRESS_NO_CONFIG_WARNING = true;
const cmdUtil = require('./lib/utils/cmdutils');
const yargs = require('yargs');
const chalk = require('chalk');
const version = 'v' + require('./package.json').version;

let results = yargs
Expand All @@ -35,11 +33,7 @@ let results = yargs
.argv;

results.thePromise.then( () => {
if (!results.quiet) {
cmdUtil.log(chalk.green('\nCommand succeeded\n'));
}
process.exit(0);
}).catch((error) => {
cmdUtil.log(error.stack+chalk.red('\nCommand failed\n'));
process.exit(1);
});
66 changes: 42 additions & 24 deletions packages/caliper-cli/lib/benchmark/lib/runBenchmark.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@
'use strict';

const {CaliperEngine, CaliperUtils, ConfigUtil} = require('@hyperledger/caliper-core');
const chalk = require('chalk');
const cmdUtil = require('../../utils/cmdutils');
const logger = CaliperUtils.getLogger('CLI');
const path = require('path');
const fs = require('fs');
/**
Expand All @@ -30,47 +29,66 @@ class RunBenchmark {
* @param {string} argv argument list from caliper benchmark command
*/
static async handler(argv) {
let workspace = ConfigUtil.get(ConfigUtil.keys.Workspace, './');
let benchConfigFile = ConfigUtil.get(ConfigUtil.keys.BenchConfig, undefined);
let blockchainConfigFile = ConfigUtil.get(ConfigUtil.keys.NetworkConfig, undefined);
let workspacePath = ConfigUtil.get(ConfigUtil.keys.Workspace);
let benchmarkConfigPath = ConfigUtil.get(ConfigUtil.keys.BenchConfig);
let networkConfigPath = ConfigUtil.get(ConfigUtil.keys.NetworkConfig);

// Workspace is expected to be the root location of working folders
workspace = path.resolve(workspace);
benchConfigFile = path.isAbsolute(benchConfigFile) ? benchConfigFile : path.join(workspace, benchConfigFile);
blockchainConfigFile = path.isAbsolute(blockchainConfigFile) ? blockchainConfigFile : path.join(workspace, blockchainConfigFile);
workspacePath = path.resolve(workspacePath);
benchmarkConfigPath = CaliperUtils.resolvePath(benchmarkConfigPath, workspacePath);
networkConfigPath = CaliperUtils.resolvePath(networkConfigPath, workspacePath);

if(!benchConfigFile || !fs.existsSync(benchConfigFile)) {
throw new Error(`Benchmark configuration file "${benchConfigFile || 'UNSET'}" does not exist`);
if(!benchmarkConfigPath || !fs.existsSync(benchmarkConfigPath)) {
let msg = `Benchmark configuration file "${benchmarkConfigPath || 'UNSET'}" does not exist`;
logger.error(msg);
throw new Error(msg);
}

if(!blockchainConfigFile || !fs.existsSync(blockchainConfigFile)) {
throw new Error(`Network configuration file "${blockchainConfigFile || 'UNSET'}" does not exist`);
if(!networkConfigPath || !fs.existsSync(networkConfigPath)) {
let msg = `Network configuration file "${networkConfigPath || 'UNSET'}" does not exist`;
logger.error(msg);
throw new Error(msg);
}

let benchmarkConfig = CaliperUtils.parseYaml(benchmarkConfigPath);
let networkConfig = CaliperUtils.parseYaml(networkConfigPath);

let blockchainType = '';
let networkObject = CaliperUtils.parseYaml(blockchainConfigFile);
if (networkObject.hasOwnProperty('caliper') && networkObject.caliper.hasOwnProperty('blockchain')) {
blockchainType = networkObject.caliper.blockchain;
if (networkConfig.caliper && networkConfig.caliper.blockchain) {
blockchainType = networkConfig.caliper.blockchain;
} else {
throw new Error('The configuration file [' + blockchainConfigFile + '] is missing its "caliper.blockchain" attribute');
let msg = `Network configuration file "${networkConfigPath}" is missing its "caliper.blockchain" attribute`;
logger.error(msg);
throw new Error(msg);
}

let knownError = false;

try {
cmdUtil.log(chalk.blue.bold('Benchmark for target Blockchain type ' + blockchainType + ' about to start'));
const {AdminClient, ClientFactory} = require('@hyperledger/caliper-' + blockchainType);
const adminClient = new AdminClient(blockchainConfigFile, workspace);
const clientFactory = new ClientFactory(blockchainConfigFile, workspace);
logger.info(`Set workspace path: ${workspacePath}`);
logger.info(`Set benchmark configuration path: ${benchmarkConfigPath}`);
logger.info(`Set network configuration path: ${networkConfigPath}`);
logger.info(`Detected SUT type: ${blockchainType}`);

const engine = new CaliperEngine(benchConfigFile, blockchainConfigFile, adminClient, clientFactory, workspace);
const {AdminClient, ClientFactory} = require(`@hyperledger/caliper-${blockchainType}`);
const blockchainAdapter = new AdminClient(networkConfigPath, workspacePath);
const workerFactory = new ClientFactory(networkConfigPath, workspacePath);

const engine = new CaliperEngine(benchmarkConfig, networkConfig, blockchainAdapter, workerFactory);
const response = await engine.run();

if (response === 0) {
cmdUtil.log(chalk.blue.bold('Benchmark run successful'));
logger.info('Benchmark successfully finished');
} else {
cmdUtil.log(chalk.red.bold(`Benchmark failure with code ${response}`));
throw new Error(`Benchmark failure with code ${response}`);
knownError = true;
let msg = `Benchmark failed with error code ${response}`;
logger.error(msg);
throw new Error(msg);
}
} catch (err) {
if (!knownError) {
logger.error(`Unexpected error during benchmark execution: ${err.stack || err}`);
}
throw err;
}
}
Expand Down
3 changes: 1 addition & 2 deletions packages/caliper-cli/lib/bind/bind.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
'use strict';

const { CaliperUtils, ConfigUtil } = require('@hyperledger/caliper-core');
const chalk = require('chalk');
const cmdUtil = require('../utils/cmdutils');
const path = require('path');

Expand Down Expand Up @@ -107,7 +106,7 @@ class Bind {
settings = {};
}

cmdUtil.log(chalk.blue.bold(`Binding for ${sut}@${sdk}. This might take some time...`));
logger.info(`Binding for ${sut}@${sdk}. This might take some time...`);
try {
// combine, then convert the arguments to an array
let npmArgs;
Expand Down
12 changes: 0 additions & 12 deletions packages/caliper-cli/lib/utils/cmdutils.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,6 @@ const { spawn }= require('child_process');
*/
class CmdUtil {


/** Simple log method to output to the console
* Used to put a single console.log() here, so eslinting is easier.
* And if this needs to written to a file at some point it is also eaiser
*/
static log(){
Array.from(arguments).forEach((s)=>{
// eslint-disable-next-line no-console
console.log(s);
});
}

/**
* Invokes a given command in a spawned child process and attaches all standard IO.
* @param {string} cmd The command to be run.
Expand Down
1 change: 0 additions & 1 deletion packages/caliper-cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
"@hyperledger/caliper-sawtooth": "0.2.0",
"@hyperledger/caliper-ethereum": "0.2.0",
"@hyperledger/caliper-fisco-bcos": "0.2.0",
"chalk": "1.1.3",
"yargs": "10.0.3"
},
"devDependencies": {
Expand Down
4 changes: 2 additions & 2 deletions packages/caliper-core/lib/common/utils/caliper-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ class CaliperUtils {
* @param {String} root_path root path to use
* @return {String} The resolved absolute path.
*/
static resolvePath(relOrAbsPath, root_path) {
static resolvePath(relOrAbsPath, root_path = undefined) {
if (!relOrAbsPath) {
throw new Error('Util.resolvePath: Parameter is undefined');
}
Expand All @@ -73,7 +73,7 @@ class CaliperUtils {
return relOrAbsPath;
}

return path.resolve(root_path, relOrAbsPath);
return path.resolve(root_path || Config.get(Config.keys.Workspace), relOrAbsPath);
}

/**
Expand Down
68 changes: 38 additions & 30 deletions packages/caliper-core/lib/master/caliper-engine.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

const Blockchain = require('../common/core/blockchain');
const CaliperUtils = require('../common/utils/caliper-utils');
const ConfigUtils = require('../common/config/config-util');
const RoundOrchestrator = require('./test-runners/round-orchestrator');
const BenchValidator = require('../common/utils/benchmark-validator');

Expand All @@ -26,32 +27,30 @@ const logger = CaliperUtils.getLogger('caliper-engine');
*/
class CaliperEngine {
/**
*
* @param {String} absConfigFile fully qualified path of the test configuration file
* @param {String} absNetworkFile fully qualified path of the blockchain configuration file
* @param {AdminClient} admin a constructed Caliper Admin Client
* @param {ClientFactory} clientFactory a Caliper Client Factory
* @param {String} workspace fully qualified path to the root location of network files
* Initializes the CaliperEngine instance.
* @param {object} benchmarkConfig The benchmark configuration object.
* @param {object} networkConfig The network configuration object.
* @param {AdminClient} blockchainAdapter The blockchain adapter instance.
* @param {ClientFactory} workerFactory The worker process factory.
*/
constructor(absConfigFile, absNetworkFile, admin, clientFactory, workspace) {
this.absConfigFile = absConfigFile;
this.absNetworkFile = absNetworkFile;
this.admin = admin;
this.clientFactory = clientFactory;
this.workspace = workspace;
constructor(benchmarkConfig, networkConfig, blockchainAdapter, workerFactory) {
this.benchmarkConfig = benchmarkConfig;
this.networkConfig = networkConfig;
this.blockchainAdapter = blockchainAdapter;
this.workerFactory = workerFactory;
this.workspace = ConfigUtils.get(ConfigUtils.keys.workspace);
this.returnCode = -1;
}

/**
* Executes the given start/end command with proper checking and error handling.
* @param {object} networkConfig The network configuration object. //TODO: move this to instance var
* @param {string} commandName Either "start" or "end". Used in the error messages.
* @param {number} errorStatusStart The last taken error status code. Execution errors will use the next 3 status code.
* @private
*/
async _executeCommand(networkConfig, commandName, errorStatusStart) {
if (networkConfig.caliper && networkConfig.caliper.command && networkConfig.caliper.command[commandName]) {
let command = networkConfig.caliper.command[commandName];
async _executeCommand(commandName, errorStatusStart) {
if (this.networkConfig.caliper && this.networkConfig.caliper.command && this.networkConfig.caliper.command[commandName]) {
let command = this.networkConfig.caliper.command[commandName];
if (typeof command !== 'string') {
let msg = `Network configuration attribute "caliper.command.${commandName}" is not a string`;
logger.error(msg, command);
Expand All @@ -64,13 +63,17 @@ class CaliperEngine {
this.returnCode = errorStatusStart + 2;
throw new Error(msg);
} else {
let startTime = Date.now();
try {
await CaliperUtils.execAsync(`cd ${this.workspace}; ${command}`);
} catch (err) {
let msg = `An error occurred while executing the ${commandName} command: ${err.message}`;
logger.error(msg);
this.returnCode = errorStatusStart + 3;
throw new Error(msg);
} finally {
let endTime = Date.now();
logger.info(`Executed ${commandName} command in ${(endTime - startTime)/1000.0} seconds`);
}
}
} else {
Expand All @@ -85,60 +88,65 @@ class CaliperEngine {
async run() {
// Retrieve flow conditioning options
const flowOpts = CaliperUtils.getFlowOptions();
let configObject = CaliperUtils.parseYaml(this.absConfigFile);
let networkObject = CaliperUtils.parseYaml(this.absNetworkFile);

// Validate configObject (benchmark configuration file)
BenchValidator.validateObject(configObject);
BenchValidator.validateObject(this.benchmarkConfig);

logger.info('####### Caliper Test #######');
const adminClient = new Blockchain(this.admin);
logger.info('Starting benchmark flow');
const blockchainWrapper = new Blockchain(this.blockchainAdapter);

try {
// Conditional running of 'start' commands
if (!flowOpts.performStart) {
logger.info('Skipping start commands due to benchmark flow conditioning');
} else {
await this._executeCommand(networkObject, 'start', 0);
await this._executeCommand('start', 0);
}

// Conditional network initialization
if (!flowOpts.performInit) {
logger.info('Skipping initialization phase due to benchmark flow conditioning');
} else {
let initStartTime = Date.now();
try {
await adminClient.init();
await blockchainWrapper.init();
} catch (err) {
let msg = `Error while performing "init" step: ${err.message}`;
logger.error(msg);
this.returnCode = 4;
throw new Error(msg);
} finally {
let initEndTime = Date.now();
logger.info(`Executed "init" step in ${(initEndTime - initStartTime)/1000.0} seconds`);
}
}

// Conditional smart contract installation
if (!flowOpts.performInstall) {
logger.info('Skipping install smart contract phase due to benchmark flow conditioning');
} else {
let installStartTime = Date.now();
try {
await adminClient.installSmartContract();
await blockchainWrapper.installSmartContract();
} catch (err) {
let msg = `Error while performing "install" step: ${err.message}`;
logger.error(msg);
this.returnCode = 5;
throw new Error(msg);
} finally {
let installEndTime = Date.now();
logger.info(`Executed "install" step in ${(installEndTime - installStartTime)/1000.0} seconds`);
}
}

// Conditional test phase
if (!flowOpts.performTest) {
logger.info('Skipping benchmark test phase due to benchmark flow conditioning');
} else {
let numberSet = configObject.tests && configObject.tests.clients && configObject.tests.clients.number;
let numberOfClients = numberSet ? configObject.tests.clients.number : 1;
let clientArgs = await adminClient.prepareClients(numberOfClients);
let numberSet = this.benchmarkConfig.tests && this.benchmarkConfig.tests.clients && this.benchmarkConfig.tests.clients.number;
let numberOfClients = numberSet ? this.benchmarkConfig.tests.clients.number : 1;
let workerArguments = await blockchainWrapper.prepareClients(numberOfClients);

const roundOrchestrator = new RoundOrchestrator(clientArgs, this.absConfigFile, this.absNetworkFile, this.clientFactory, this.workspace);
const roundOrchestrator = new RoundOrchestrator(this.benchmarkConfig, this.networkConfig, this.workerFactory, workerArguments);
await roundOrchestrator.run();
}
} catch (err) {
Expand All @@ -155,7 +163,7 @@ class CaliperEngine {
logger.info('Skipping end command due to benchmark flow conditioning');
} else {
try {
await this._executeCommand(networkObject, 'end', 6);
await this._executeCommand('end', 6);
} catch (err) {
// the error was already handled/logged, so ignore it
}
Expand Down
Loading

0 comments on commit c9e4317

Please sign in to comment.