Skip to content

Commit

Permalink
CouchDBKeyValueStore ctor to ask for url
Browse files Browse the repository at this point in the history
FAB-2355
Current constructor asks for a client instance, it should instead
simply ask for the url and optionally the name of the database.

Change-Id: Idfddd1c5f5ca5598ee47cb4bd931adb2e4c1e258
Signed-off-by: Jim Zhang <[email protected]>
  • Loading branch information
jimthematrix committed Feb 19, 2017
1 parent f6a374c commit a8554c1
Show file tree
Hide file tree
Showing 15 changed files with 556 additions and 331 deletions.
46 changes: 18 additions & 28 deletions fabric-client/lib/impl/CouchDBKeyValueStore.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
var api = require('../api.js');
var fs = require('fs-extra');
var path = require('path');
var util = require('util');
var utils = require('../utils');
var nano = require('nano');

Expand All @@ -35,72 +36,61 @@ var CouchDBKeyValueStore = class extends api.KeyValueStore {
/**
* constructor
*
* @description <b>options</b> contains a path property which represents a CouchDB client instance.
* The following code snippet shows how to create a nano minimalistic client for CouchDB. For more
* information see <a href='https://github.com/dscape/nano'>github dscape / nano</a>.
* <pre><code>var nano = require('nano');
* var couchDBClient = nano(couchdb_IP_Address + ':' + couchdb_Port);</code></pre>
*
* <br>The following code snippet shows how to create a Cloudant CouchDB client.
* Username and password map to the IBM Bluemix service credentials VCAP_SERVICES environment variables username and password.
* To obtain an instance of Cloudant, see the IBM Bluemix Catalog --> Services --> Data & Analytics at
* <a href='https://console.ng.bluemix.net/catalog/services/cloudant-nosql-db'>Cloudant NoSQL DB</a>.
* <pre><code>var Cloudant = require('cloudant');
* var cloudantClient = Cloudant({account: username, password: password});</code></pre>
* <br>
*
* @param {Object} options Contains two properties:
* <li>path - The CouchDB database client instance.
* @param {Object} options Contains the properties:
* <li>url - The CouchDB instance url.
* <li>name - Optional. Identifies the name of the database if different from the default of 'member_db'.
*/
constructor(options) {
logger.debug('constructor, options: ' + options);

if (!options || !options.path) {
throw new Error('Must provide the CouchDB database client instance to store membership data.');
if (!options || !options.url) {
throw new Error('Must provide the CouchDB database url to store membership data.');
}

// Create the keyValStore instance
super();

var self = this;
// path is the database client instance
this._path = options.path;
// url is the database instance url
this._url = options.url;
// Name of the database, optional
if (!options.name) {
this._name = 'member_db';
} else {
this._name = options.name;
}

logger.debug('options.path - ' + options.path);
logger.debug('options.url - ' + options.url);
logger.debug('options.name - ' + options.name);

return new Promise(function(resolve, reject) {
// Initialize the CouchDB database client
var dbClient = self._path;
var dbClient = nano(self._url);
// Check if the database already exists. If not, create it.
dbClient.db.get(self._name, function(err, body) {
// Check for error
if (err) {
// Database doesn't exist
if (err.error == 'not_found') {
logger.info('No member_db found, creating member_db');
logger.info(util.format('No %s found, creating %s', self._name, self._name));

dbClient.db.create(self._name, function(err, body) {
if (err) {
return reject(new Error(util.format('Failed to create %s database due to error: %s', self._name, err.stack ? err.stack : err)));
}

dbClient.db.create(self._name, function() {
logger.info('Created member_db database');
logger.info(util.format('Created %s database', self._name));
// Specify it as the database to use
self._database = dbClient.use(self._name);
resolve(self);
});
} else {
// Other error
logger.error('ERROR: ' + err);
reject(new Error('Error creating member_db database to store membership data.'));
return reject(new Error(util.format('Error creating %s database to store membership data: %s', self._name, err.stack ? err.stack : err)));
}
} else {
// Database exists
logger.info('member_db already exists');
logger.info(util.format('%s already exists', self._name));
// Specify it as the database to use
self._database = dbClient.use(self._name);
resolve(self);
Expand Down
39 changes: 26 additions & 13 deletions fabric-client/lib/impl/CryptoSuite_ECDSA_AES.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,27 +49,41 @@ var CryptoSuite_ECDSA_AES = class extends api.CryptoSuite {
* constructor
*
* @param {number} keySize Key size for the ECDSA algorithm, can only be 256 or 384
* @param {string} kvsPath A path to a directory used by the built-in key store to save private keys
* @param {string} KVSImplClass Optional. The built-in key store saves private keys. The key store may be backed by different
* {@link KeyValueStore} implementations. If specified, the value of the argument must point to a module implementing the
* KeyValueStore interface.
* @param {object} opts Implementation-specific options object for the {@link KeyValueStore} class to instantiate an instance
*/
constructor(keySize, kvsPath) {
constructor(keySize, KVSImplClass, opts) {
if (keySize !== 256 && keySize !== 384) {
throw new Error('Illegal key size: ' + keySize + ' - this crypto suite only supports key sizes 256 or 384');
}

super();

if (typeof kvsPath === 'undefined' || kvsPath === null) {
this._storePath = null;
var superClass;

if (typeof KVSImplClass !== 'function') {
superClass = require(utils.getConfigSetting('key-value-store'));
} else {
if (typeof kvsPath !== 'string') {
throw new Error('The "kvsPath" parameter for this constructor, if specified, must be a string specifying a file system path');
}
superClass = KVSImplClass;
}

this._storePath = kvsPath;
if (KVSImplClass && typeof opts === 'undefined') {
// the function is called with only one argument for the 'opts'
opts = KVSImplClass;
} else if (typeof KVSImplClass === 'undefined' && typeof opts === 'undefined') {
opts = {
path: CryptoSuite_ECDSA_AES.getDefaultKeyStorePath()
};
}

this._keySize = keySize;
this._store = null;
this._storeConfig = {
superClass: superClass,
opts: opts
};
this._initialize();
}

Expand Down Expand Up @@ -226,16 +240,15 @@ var CryptoSuite_ECDSA_AES = class extends api.CryptoSuite {
var self = this;
return new Promise((resolve, reject) => {
if (self._store === null) {
var storePath = self._storePath ? self._storePath : CryptoSuite_ECDSA_AES.getDefaultKeyStorePath();
logger.info('This class requires a CryptoKeyStore to save keys, using the store at %s', self._storePath);
logger.info(util.format('This class requires a CryptoKeyStore to save keys, using the store: %j', self._storeConfig));

CKS({
path: storePath
})
CKS(self._storeConfig.superClass, self._storeConfig.opts)
.then((ks) => {
logger.debug('_getKeyStore returning ks');
self._store = ks;
return resolve(self._store);
}).catch((err) => {
reject(err);
});
} else {
logger.debug('_getKeyStore resolving store');
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"intercept-stdout": "^0.1.2",
"jsrsasign": "6.2.2",
"log4js": "^0.6.38",
"mock-couch": "https://github.com/jimthematrix/mock-couch.git",
"nano": "^6.2.0",
"require-dir": "^0.3.0",
"rewire": "^2.5.2",
Expand Down
2 changes: 1 addition & 1 deletion test/fixtures/couchdb.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"couchdb-ip-addr" : "http://localhost",
"couchdb-port" : "5984",
"key-value-store" : "./impl/CouchDBKeyValueStore.js"
"key-value-store" : "fabric-client/lib/impl/CouchDBKeyValueStore.js"
}
12 changes: 8 additions & 4 deletions test/integration/couchdb-fabricca-tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,14 @@ var couchdbUtil = require('./couchdb-util.js');

// Use the CouchDB specific config file
hfc.addConfigFile('test/fixtures/couchdb.json');
var dbClient = couchdbUtil.getCouchDBClient();

var keyValueStore = hfc.getConfigSetting('key-value-store');
console.log('Key Value Store = ' + keyValueStore);

var couchdbIPAddr = hfc.getConfigSetting('couchdb-ip-addr', 'notfound');
var couchdbPort = hfc.getConfigSetting('couchdb-port', 'notfound');
var keyValStorePath = couchdbIPAddr + ':' + couchdbPort;

// This test first checks to see if a user has already been enrolled. If so,
// the test terminates. If the user is not yet enrolled, the test uses the
// FabricCAClientImpl to enroll a user, and saves the enrollment materials into the
Expand All @@ -49,11 +53,11 @@ test('Use FabricCAServices with a CouchDB KeyValueStore', function(t) {
var dbname = 'member_db';

var member;
couchdbUtil.destroy(dbname, dbClient)
couchdbUtil.destroy(dbname, keyValStorePath)
.then( function(status) {
t.comment('Cleanup of existing ' + dbname + ' returned '+status);
t.comment('Initilize the CouchDB KeyValueStore');
utils.newKeyValueStore({name: dbname, path: dbClient})
utils.newKeyValueStore({name: dbname, url: keyValStorePath})
.then(
function(kvs) {
t.comment('Setting client keyValueStore to: ' +kvs);
Expand Down Expand Up @@ -88,7 +92,7 @@ test('Use FabricCAServices with a CouchDB KeyValueStore', function(t) {
});
},
function(err) {
t.fail('Failed to initilize the Fabric CA service: ' + err);
t.fail('Failed to initilize the Fabric CA service: ' + err.stack ? err.stack : err);
t.end();
}
)
Expand Down
16 changes: 3 additions & 13 deletions test/integration/couchdb-util.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,26 +25,16 @@ module.exports.getCloudantClient = function(configFile) {
return Cloudant({account: username, password: password});
};

module.exports.getCouchDBClient = function(configFile) {
var couchdbIPAddr = hfc.getConfigSetting('couchdb-ip-addr', 'notfound');
var couchdbPort = hfc.getConfigSetting('couchdb-port', 'notfound');

// Record the CouchDB KeyValueStorePath set by couchdb.json
var keyValStorePath = couchdbIPAddr + ':' + couchdbPort;
console.log('CouchDBClient IP address:port = ' + keyValStorePath);
return nano(keyValStorePath);
};

module.exports.destroy = function(name, path) {
this._path = path;
module.exports.destroy = function(name, url) {
this._url = url;
this._name = name;
// Name of the database, optional
if (!name) {
this._name = 'member_db';
}
var self = this;
return new Promise(function(resolve, reject) {
var dbClient = self._path;
var dbClient = nano(self._url);
dbClient.db.destroy(self._name, function(err, body) {
if (err) {
resolve(false);
Expand Down
Loading

0 comments on commit a8554c1

Please sign in to comment.