Skip to content

Commit

Permalink
Merge pull request #595 from aklenik/fabric-network-validation
Browse files Browse the repository at this point in the history
Add declarative validation for Fabric network config files
  • Loading branch information
aklenik committed Oct 2, 2019
2 parents ac069dc + dbc864b commit cdd1a0b
Show file tree
Hide file tree
Showing 10 changed files with 4,496 additions and 603 deletions.
107 changes: 95 additions & 12 deletions packages/caliper-core/lib/config/Config.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,65 @@ const nconf = require('nconf');

nconf.formats.yaml = require('nconf-yaml');

const keys = {
Bind: {
Sut: 'caliper-bind-sut',
Sdk: 'caliper-bind-sdk',
Args: 'caliper-bind-args',
Cwd: 'caliper-bind-cwd'
},
Workspace: 'caliper-workspace',
ProjectConfig: 'caliper-projectconfig',
UserConfig: 'caliper-userconfig',
MachineConfig: 'caliper-machineconfig',
BenchConfig: 'caliper-benchconfig',
NetworkConfig: 'caliper-networkconfig',
ZooAddress: 'caliper-zooaddress',
ZooConfig: 'caliper-zooconfig',
TxUpdateTime: 'caliper-txupdatetime',
Logging: 'caliper-logging',
Flow: {
Skip: {
Start : 'caliper-flow-skip-start',
Init: 'caliper-flow-skip-init',
Install: 'caliper-flow-skip-install',
Test: 'caliper-flow-skip-test',
End: 'caliper-flow-skip-end'
},
Only: {
Start: 'caliper-flow-only-start',
Init: 'caliper-flow-only-init',
Install: 'caliper-flow-only-install',
Test: 'caliper-flow-only-test',
End: 'caliper-flow-only-end'
}
},
Fabric: {
SleepAfter: {
CreateChannel: 'caliper-fabric-sleepafter-createchannel',
JoinChannel: 'caliper-fabric-sleepafter-joinchannel',
InstantiateChaincode: 'caliper-fabric-sleepafter-instantiatechaincode',
},
Verify: {
ProposalResponse: 'caliper-fabric-verify-proposalresponse',
ReadWriteSets: 'caliper-fabric-verify-readwritesets',
},
Timeout: {
ChaincodeInstantiate: 'caliper-fabric-timeout-chaincodeinstantiate',
ChaincodeInstantiateEvent: 'caliper-fabric-timeout-chaincodeinstantiateevent',
InvokeOrQuery: 'caliper-fabric-timeout-invokeorquery',
},
LoadBalancing: 'caliper-fabric-loadbalancing',
OverwriteGopath: 'caliper-fabric-overwritegopath',
LatencyThreshold: 'caliper-fabric-latencythreshold',
CountQueryAsLoad: 'caliper-fabric-countqueryasload',
SkipCreateChannelPrefix: 'caliper-fabric-skipcreatechannel-',
Gateway: 'caliper-fabric-usegateway',
GatewayLocalHost: 'caliper-fabric-gatewaylocalhost',
Discovery: 'caliper-fabric-discovery'
}
};

/**
* Normalizes the key of the given setting.
* @param {{key: string, value: any}} kvPair The setting as a key-value pair.
Expand All @@ -44,6 +103,25 @@ function getFileParsingOptions(filename) {
return { file: filename, logicalSeparator: '-', format: nconf.formats.yaml };
}

/**
* Creates an absolute path from the provided relative path if necessary.
* @param {String} relOrAbsPath The relative or absolute path to convert to an absolute path.
* Relative paths are considered relative to the Caliper root folder.
* @param {String} root_path root path to use
* @return {String} The resolved absolute path.
*/
function resolvePath(relOrAbsPath, root_path) {
if (!relOrAbsPath) {
throw new Error('Config.resolvePath: Parameter is undefined');
}

if (path.isAbsolute(relOrAbsPath)) {
return relOrAbsPath;
}

return path.join(root_path, relOrAbsPath);
}

/**
* The class encapsulating the hierarchy of runtime configurations.
* @type {Config}
Expand All @@ -70,27 +148,31 @@ class Config {
// normalize the argument names to be more robust
this._config.env({ parseValues: true, transform: normalizeSettingKey });

// TODO: resolve the paths according to the workspace, once it's set through the config API

// if "caliper-projectconfig" is set at this point, include that file
let projectConf = this.get('caliper-projectconfig', undefined);
let projectConf = this.get(keys.ProjectConfig, undefined);
if (projectConf && (typeof projectConf === 'string')) {
this._config.file('project', getFileParsingOptions(projectConf));
} else if (fs.existsSync('caliper.yaml')) {
// check whether caliper.yaml is present in the current working directory for convenience
this._config.file('project', getFileParsingOptions('caliper.yaml'));
let projectConfFile = resolvePath(projectConf, this.get(keys.Workspace, '.'));
this._config.file('project', getFileParsingOptions(projectConfFile));
} else {
// check whether caliper.yaml is present in the workspace directory for convenience
let projectConfFile = resolvePath('caliper.yaml', this.get(keys.Workspace, '.'));
if (fs.existsSync(projectConfFile)) {
this._config.file('project', getFileParsingOptions(projectConfFile));
}
}

// if "caliper-userconfig" is set at this point, include that file
let userConfig = this.get('caliper-userconfig', undefined);
let userConfig = this.get(keys.UserConfig, undefined);
if (userConfig && (typeof userConfig === 'string')) {
this._config.file('user', getFileParsingOptions(userConfig));
let userConfFile = resolvePath(userConfig, this.get(keys.Workspace, '.'));
this._config.file('user', getFileParsingOptions(userConfFile));
}

// if "caliper-machineconfig" is set at this point, include that file
let machineConfig = this.get('caliper-machineconfig', undefined);
if (machineConfig) {
this._config.file('machine', getFileParsingOptions(machineConfig));
let machineConfig = this.get(keys.MachineConfig, undefined);
if (machineConfig && (typeof machineConfig === 'string')) {
let machineConfFile = resolvePath(machineConfig, this.get(keys.Workspace, '.'));
this._config.file('machine', getFileParsingOptions(machineConfFile));
}

// as fallback, always include the default config packaged with Caliper
Expand Down Expand Up @@ -135,4 +217,5 @@ class Config {
}

module.exports = Config;
module.exports.keys = keys;

58 changes: 1 addition & 57 deletions packages/caliper-core/lib/config/config-util.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,62 +52,6 @@ function get(name, defaultValue) {
return _getConfigInstance().get(name, defaultValue);
}

const keys = {
Bind: {
Sut: 'caliper-bind-sut',
Sdk: 'caliper-bind-sdk',
Args: 'caliper-bind-args',
Cwd: 'caliper-bind-cwd'
},
Workspace: 'caliper-workspace',
BenchConfig: 'caliper-benchconfig',
NetworkConfig: 'caliper-networkconfig',
ZooAddress: 'caliper-zooaddress',
ZooConfig: 'caliper-zooconfig',
TxUpdateTime: 'caliper-txupdatetime',
Logging: 'caliper-logging',
Flow: {
Skip: {
Start : 'caliper-flow-skip-start',
Init: 'caliper-flow-skip-init',
Install: 'caliper-flow-skip-install',
Test: 'caliper-flow-skip-test',
End: 'caliper-flow-skip-end'
},
Only: {
Start: 'caliper-flow-only-start',
Init: 'caliper-flow-only-init',
Install: 'caliper-flow-only-install',
Test: 'caliper-flow-only-test',
End: 'caliper-flow-only-end'
}
},
Fabric: {
SleepAfter: {
CreateChannel: 'caliper-fabric-sleepafter-createchannel',
JoinChannel: 'caliper-fabric-sleepafter-joinchannel',
InstantiateChaincode: 'caliper-fabric-sleepafter-instantiatechaincode',
},
Verify: {
ProposalResponse: 'caliper-fabric-verify-proposalresponse',
ReadWriteSets: 'caliper-fabric-verify-readwritesets',
},
Timeout: {
ChaincodeInstantiate: 'caliper-fabric-timeout-chaincodeinstantiate',
ChaincodeInstantiateEvent: 'caliper-fabric-timeout-chaincodeinstantiateevent',
InvokeOrQuery: 'caliper-fabric-timeout-invokeorquery',
},
LoadBalancing: 'caliper-fabric-loadbalancing',
OverwriteGopath: 'caliper-fabric-overwritegopath',
LatencyThreshold: 'caliper-fabric-latencythreshold',
CountQueryAsLoad: 'caliper-fabric-countqueryasload',
SkipCreateChannelPrefix: 'caliper-fabric-skipcreatechannel-',
Gateway: 'caliper-fabric-usegateway',
GatewayLocalHost: 'caliper-fabric-gatewaylocalhost',
Discovery: 'caliper-fabric-discovery'
}
};

module.exports.get = get;
module.exports.set = set;
module.exports.keys = keys;
module.exports.keys = Config.keys;
6 changes: 6 additions & 0 deletions packages/caliper-core/lib/config/default.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@ caliper:
args:
# Workspace directory that contains all configuration information
workspace: './'
# The file path for the project-level configuration file. Can be relative to the workspace.
projectconfig:
# The file path for the user-level configuration file. Can be relative to the workspace.
userconfig:
# The file path for the user-level configuration file. Can be relative to the workspace.
machineconfig:
# Path to the benchmark workload file that describes the test client(s), test rounds and monitor
benchconfig:
# Path to the blockchain configuration file that contains information required to interact with the SUT
Expand Down
18 changes: 18 additions & 0 deletions packages/caliper-core/lib/utils/caliper-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,24 @@ class CaliperUtils {
}
}

/**
* Convert an object to YAML string.
* @param {object} obj The object to stringify.
* @return {string} The string YAML content.
*/
static stringifyYaml(obj) {
if (!obj) {
throw new Error('Util.stringifyYaml: object to stringify is undefined');
}

try{
return yaml.safeDump(obj);
}
catch(err) {
throw new Error(`Failed to stringify object: ${(err.message || err)}`);
}
}

/**
* Parse a YAML conform string into an object.
* @param {string} stringContent The YAML content.
Expand Down
Loading

0 comments on commit cdd1a0b

Please sign in to comment.