Skip to content

Commit

Permalink
Runtime code for install and start (hyperledger-archives#1583)
Browse files Browse the repository at this point in the history
* Runtime code for install and start

Signed-off-by: Dave Kelsey <[email protected]>

* comment improvements, fix system tests when not real fabric

Signed-off-by: Dave Kelsey <[email protected]>

* up version to 0.10.0. Correct captilisation

Signed-off-by: Dave Kelsey <[email protected]>

* add install/start support to all connectors in prep for playground

Signed-off-by: Dave Kelsey <[email protected]>

* system tests can all try install/start

Signed-off-by: Dave Kelsey <[email protected]>

* resolve merge conflict

Signed-off-by: Dave Kelsey <[email protected]>

* missed tests for connection.js

Signed-off-by: Dave Kelsey <[email protected]>

* added more tests as coverage has started failing on CLI

Signed-off-by: Dave Kelsey <[email protected]>
  • Loading branch information
Dave Kelsey authored and Simon Stone committed Jul 18, 2017
1 parent 79689df commit 3193e1f
Show file tree
Hide file tree
Showing 29 changed files with 1,824 additions and 60 deletions.
2 changes: 2 additions & 0 deletions packages/composer-admin/api.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ class AdminConnection {
+ Promise getProfile(string)
+ Promise getAllProfiles()
+ Promise disconnect()
+ Promise install(BusinessNetworkIdentifier,Object)
+ Promise start(BusinessNetworkDefinition,Object)
+ Promise deploy(BusinessNetworkDefinition,Object)
+ Promise undeploy(string)
+ Promise update(BusinessNetworkDefinition)
Expand Down
3 changes: 3 additions & 0 deletions packages/composer-admin/changelog.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
#
# Note that the latest public API is documented using JSDocs and is available in api.txt.
#
Version 0.10.0 {3af411e8da53bb013ab9718ed5980c20} 2017-07-17
- added install and start method.

Version 0.9.1 {8b6c392e59b8ad38ea271315231ca0e5} 2017-06-30
- added getLogLevel & setLogLevel methods. added deployOptions to deploy method.

Expand Down
52 changes: 52 additions & 0 deletions packages/composer-admin/lib/adminconnection.js
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,58 @@ class AdminConnection {
});
}

/**
* Installs the Hyperledger Composer runtime to the Hyperledger Fabric in preparation
* for the business network to be started. The connection mustbe connected for this method to succeed.
* You must pass the name of the business network that is defined in your archive that this
* runtime will be started with.
* @example
* // Install the Hyperledger Composer runtime
* var adminConnection = new AdminConnection();
* var businessNetworkDefinition = BusinessNetworkDefinition.fromArchive(myArchive);
* return adminConnection.install(businessNetworkDefinition.getName())
* .then(function(){
* // Business network definition installed
* })
* .catch(function(error){
* // Add optional error handling here.
* });
* @param {BusinessNetworkIdentifier} businessNetworkIdentifier - The name of business network which will be used to start this runtime.
* @param {Object} installOptions connector specific install options
* @return {Promise} A promise that will be fufilled when the business network has been
* deployed.
*/
install(businessNetworkIdentifier, installOptions) {
Util.securityCheck(this.securityContext);
return this.connection.install(this.securityContext, businessNetworkIdentifier, installOptions);
}

/**
* Starts a business network within the runtime previously installed to the Hyperledger Fabric with
* the same name as the business network to be started. The connection must be connected for this
* method to succeed.
* @example
* // Start a Business Network Definition
* var adminConnection = new AdminConnection();
* var businessNetworkDefinition = BusinessNetworkDefinition.fromArchive(myArchive);
* return adminConnection.start(businessNetworkDefinition)
* .then(function(){
* // Business network definition is started
* })
* .catch(function(error){
* // Add optional error handling here.
* });
* @param {BusinessNetworkDefinition} businessNetworkDefinition - The business network to start
* @param {Object} startOptions connector specific start options
* @return {Promise} A promise that will be fufilled when the business network has been
* deployed.
*/
start(businessNetworkDefinition, startOptions) {
Util.securityCheck(this.securityContext);
return this.connection.start(this.securityContext, businessNetworkDefinition, startOptions);
}


/**
* Deploys a new BusinessNetworkDefinition to the Hyperledger Fabric. The connection must
* be connected for this method to succeed.
Expand Down
67 changes: 67 additions & 0 deletions packages/composer-admin/test/adminconnection.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ describe('AdminConnection', () => {
mockConnection.disconnect.resolves();
mockConnection.login.resolves(mockSecurityContext);
mockConnection.deploy.resolves();
mockConnection.install.resolves();
mockConnection.start.resolves();
mockConnection.ping.resolves();
mockConnection.queryChainCode.resolves();
mockConnection.invokeChainCode.resolves();
Expand Down Expand Up @@ -200,6 +202,59 @@ describe('AdminConnection', () => {
});
});

describe('#install', () => {

it('should be able to install a business network definition', () => {
adminConnection.connection = mockConnection;
adminConnection.securityContext = mockSecurityContext;
let businessNetworkDefinition = new BusinessNetworkDefinition('[email protected]');
return adminConnection.install(businessNetworkDefinition)
.then(() => {
sinon.assert.calledOnce(mockConnection.install);
sinon.assert.calledWith(mockConnection.install, mockSecurityContext, businessNetworkDefinition);
});
});

it('should be able to install a business network definition with install options', () => {
adminConnection.connection = mockConnection;
adminConnection.securityContext = mockSecurityContext;
let businessNetworkDefinition = new BusinessNetworkDefinition('[email protected]');
return adminConnection.install(businessNetworkDefinition, {opt: 1})
.then(() => {
sinon.assert.calledOnce(mockConnection.install);
sinon.assert.calledWith(mockConnection.install, mockSecurityContext, businessNetworkDefinition, {opt: 1});
});
});

});

describe('#start', () => {

it('should be able to start a business network definition', () => {
adminConnection.connection = mockConnection;
adminConnection.securityContext = mockSecurityContext;
let businessNetworkDefinition = new BusinessNetworkDefinition('[email protected]');
return adminConnection.start(businessNetworkDefinition)
.then(() => {
sinon.assert.calledOnce(mockConnection.start);
sinon.assert.calledWith(mockConnection.start, mockSecurityContext, businessNetworkDefinition);
});
});

it('should be able to start a business network definition with start options', () => {
adminConnection.connection = mockConnection;
adminConnection.securityContext = mockSecurityContext;
let businessNetworkDefinition = new BusinessNetworkDefinition('[email protected]');
return adminConnection.start(businessNetworkDefinition, {opt: 1})
.then(() => {
sinon.assert.calledOnce(mockConnection.start);
sinon.assert.calledWith(mockConnection.start, mockSecurityContext, businessNetworkDefinition, {opt: 1});
});
});

});


describe('#deploy', () => {

it('should be able to deploy a business network definition', () => {
Expand All @@ -212,6 +267,18 @@ describe('AdminConnection', () => {
sinon.assert.calledWith(mockConnection.deploy, mockSecurityContext, businessNetworkDefinition);
});
});

it('should be able to deploy a business network definition with deployOptions', () => {
adminConnection.connection = mockConnection;
adminConnection.securityContext = mockSecurityContext;
let businessNetworkDefinition = new BusinessNetworkDefinition('[email protected]');
return adminConnection.deploy(businessNetworkDefinition, {opt: 1})
.then(() => {
sinon.assert.calledOnce(mockConnection.deploy);
sinon.assert.calledWith(mockConnection.deploy, mockSecurityContext, businessNetworkDefinition, {opt: 1});
});
});

});

describe('#undeploy', () => {
Expand Down
124 changes: 124 additions & 0 deletions packages/composer-cli/lib/cmds/network/lib/start.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

'use strict';

const Admin = require('composer-admin');
const BusinessNetworkDefinition = Admin.BusinessNetworkDefinition;
const cmdUtil = require('../../utils/cmdutils');
const fs = require('fs');

const ora = require('ora');
const chalk = require('chalk');
const LogLevel = require('../../network/lib/loglevel');


/**
* <p>
* Composer deploy command
* </p>
* <p><a href="diagrams/Deploy.svg"><img src="diagrams/deploy.svg" style="width:100%;"/></a></p>
* @private
*/
class Start {

/**
* Command process for deploy command
* @param {string} argv argument list from composer command
* @param {boolean} updateOption true if the network is to be updated
* @return {Promise} promise when command complete
*/
static handler(argv, updateOption) {

let updateBusinessNetwork = (updateOption === true)
? true
: false;
let businessNetworkDefinition;

let adminConnection;
let businessNetworkName;
let spinner;
let loglevel;

if (argv.loglevel) {
// validate log level as yargs cannot at this time
// https://github.com/yargs/yargs/issues/849
loglevel = argv.loglevel.toUpperCase();
if (!LogLevel.validLogLevel(loglevel)) {
return Promise.reject(new Error('loglevel unspecified or not one of (INFO|WARNING|ERROR|DEBUG)'));
}
}

return (() => {
console.log(chalk.blue.bold('Starting business network from archive: ')+argv.archiveFile);
let archiveFileContents = null;
// Read archive file contents
archiveFileContents = Start.getArchiveFileContents(argv.archiveFile);
return BusinessNetworkDefinition.fromArchive(archiveFileContents);
})()
.then ((result) => {
businessNetworkDefinition = result;
businessNetworkName = businessNetworkDefinition.getIdentifier();
console.log(chalk.blue.bold('Business network definition:'));
console.log(chalk.blue('\tIdentifier: ')+businessNetworkName);
console.log(chalk.blue('\tDescription: ')+businessNetworkDefinition.getDescription());
console.log();
adminConnection = cmdUtil.createAdminConnection();
return adminConnection.connect(argv.connectionProfileName, argv.startId, argv.startSecret, updateBusinessNetwork ? businessNetworkDefinition.getName() : null);
})
.then((result) => {
if (updateBusinessNetwork === false) {
spinner = ora('Starting business network definition. This may take a minute...').start();
let startOptions = cmdUtil.parseOptions(argv);
if (loglevel) {
startOptions.logLevel = loglevel;
}
return adminConnection.start(businessNetworkDefinition, startOptions);
} else {
spinner = ora('Updating business network definition. This may take a few seconds...').start();
return adminConnection.update(businessNetworkDefinition);
}
}).then((result) => {
spinner.succeed();
console.log();

return result;
}).catch((error) => {

if (spinner) {
spinner.fail();
}

console.log();

throw error;
});
}

/**
* Get contents from archive file
* @param {string} archiveFile connection profile name
* @return {String} archiveFileContents archive file contents
*/
static getArchiveFileContents(archiveFile) {
let archiveFileContents;
if (fs.existsSync(archiveFile)) {
archiveFileContents = fs.readFileSync(archiveFile);
} else {
throw new Error('Archive file '+archiveFile+' does not exist.');
}
return archiveFileContents;
}
}
module.exports = Start;
42 changes: 42 additions & 0 deletions packages/composer-cli/lib/cmds/network/startCommand.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

'use strict';

const Start = require ('./lib/start.js');

module.exports.command = 'start [options]';
module.exports.describe = 'Starts a business network';
module.exports.builder = {
archiveFile: {alias: 'a', required: true, describe: 'The business network archive file name', type: 'string' },
connectionProfileName: {alias: 'p', optional: true, describe: 'The connection profile name', type: 'string' },
loglevel: { alias: 'l', required: false, describe: 'The initial loglevel to set (INFO|WARNING|ERROR|DEBUG)', type: 'string' },
option: { alias: 'o', required: false, describe: 'Options that are specific specific to connection. Multiple options are specified by repeating this option', type: 'string' },
optionsFile: { alias: 'O', required: false, describe: 'A file containing options that are specific to connection', type: 'string' },
startId: { alias: 'i', required: true, describe: 'The id of the user permitted to start a network', type: 'string' },
startSecret: { alias: 's', required: false, describe: 'The secret of the user permitted to start a network, if required', type: 'string' }
};

module.exports.handler = (argv) => {
argv.thePromise = Start.handler(argv)
.then(() => {
return;
})
.catch((error) => {
throw error;

});

return argv.thePromise;
};
25 changes: 25 additions & 0 deletions packages/composer-cli/lib/cmds/runtime.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

'use strict';

exports.command = 'runtime <subcommand>';
exports.desc = 'Composer runtime command';
exports.builder = function (yargs) {
// apply commands in subdirectories
return yargs.commandDir('runtime');
};
exports.handler = function (argv) {

};
Loading

0 comments on commit 3193e1f

Please sign in to comment.