Skip to content
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

Add declarative validation for Fabric network config files #595

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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