Skip to content

Commit

Permalink
[FAB-2060] Transmit chaincodePath during deployment
Browse files Browse the repository at this point in the history
We need to transmit the chaincode path to the peer now that
the peer builds our dockerfile.  The path is used for GOLANG
chaincode to understand the package that must be compiled.

In addition, packageChaincode() now produces a tar.gz that
contains the 'src/<package name>' directory structure instead
of the flattened files as before.

Fixes FAB-2060

Change-Id: Iff55c481fe0caf1061d61d51ea57fcf9b73a8222
Signed-off-by: Greg Haskins <[email protected]>
Signed-off-by: Jim Zhang <[email protected]>
  • Loading branch information
ghaskins authored and jimthematrix committed Feb 7, 2017
1 parent 0fd7d2c commit dfbf9be
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 22 deletions.
56 changes: 38 additions & 18 deletions fabric-client/lib/Chain.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ var utils = require('./utils.js');
var urlParser = require('url');
var net = require('net');
var util = require('util');
var fs = require('fs');
var fs = require('fs-extra');
var os = require('os');
var path = require('path');
var Peer = require('./Peer.js');
var Orderer = require('./Orderer.js');
var settle = require('promise-settle');
Expand Down Expand Up @@ -891,7 +893,8 @@ var Chain = class {
let ccSpec = {
type: _ccProto.ChaincodeSpec.Type.GOLANG,
chaincodeID: {
name: request.chaincodeId
name: request.chaincodeId,
path: request.chaincodePath
},
input: {
args: args
Expand Down Expand Up @@ -1339,32 +1342,49 @@ function writeFile(path, contents) {
}

function packageChaincode(devmode, request) {
if (devmode) {
logger.debug('Skipping chaincode packaging due to devmode configuration');
return Promise.resolve(null);
} else if (!request.chaincodePath || request.chaincodePath === '') {
// Verify that chaincodePath is being passed
return Promise.reject(new Error('Missing chaincodePath parameter in Deployment proposal request'));
} else {
return new Promise(function(resolve, reject) {
if (devmode) {
logger.debug('Skipping chaincode packaging due to devmode configuration');
return resolve(null);
}

if (!request.chaincodePath || request.chaincodePath === '') {
// Verify that chaincodePath is being passed
return reject(new Error('Missing chaincodePath parameter in Deployment proposal request'));
}

var chaincodePath = request.chaincodePath;
var chaincodeId = request.chaincodeId;

// Determine the user's $GOPATH
let goPath = process.env['GOPATH'];

// Compose the path to the chaincode project directory
let projDir = goPath + '/src/' + chaincodePath;
let projDir = path.join(goPath, 'src', chaincodePath);

// Create the .tar.gz file of the chaincode package
// FIXME: this should use a mktmp to avoid collisions
let targzFilePath = '/tmp/deployment-package.tar.gz';

return utils.generateTarGz(projDir, targzFilePath)
.then(function() {
logger.debug('Chain.sendDeployment- Successfully generated chaincode deploy archive and name (%s)', chaincodeId);
return readFile(targzFilePath);
fs.mkdtemp(path.join(os.tmpdir(), path.sep), (err, folder) => {
if (err) return reject(new Error('Failed to create temp folder. ' + err));

// first copy all the target chaincode files from the source folder to
// <this_temp_folder>/src/<chaincodePath> folder so that the tar.gz
// archive can be created with the folder structure preserved
var dest = path.join(folder, 'src', chaincodePath);
fs.copy(projDir, dest, (err) => {
if (err) return reject(new Error('Failed to copy chaincode source to temp folder. ' + err));

let targzFilePath = path.join(folder, 'deployment-package.tar.gz');
return utils.generateTarGz(folder, targzFilePath)
.then(function() {
logger.debug('Chain.sendDeployment- Successfully generated chaincode deploy archive %s and name (%s)', targzFilePath, chaincodeId);
return readFile(targzFilePath)
.then((data) => {
return resolve(data);
});
});
});
}
});
});
}

//utility method to build a common chain header
Expand Down
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,22 @@
"bunyan": "^1.8.1",
"cloudant": "^1.7.0",
"elliptic": "^6.3.2",
"fabric-ca-client": "file:./fabric-ca-client",
"fabric-client": "file:./fabric-client",
"gulp": "^3.9.1",
"gulp-debug": "^3.0.0",
"gulp-eslint": "^3.0.1",
"gulp-istanbul": "^1.1.1",
"gulp-jsdoc3": "^0.3.0",
"gulp-tape": "0.0.9",
"gulp-watch": "^4.3.11",
"fabric-client": "file:./fabric-client",
"fabric-ca-client": "file:./fabric-ca-client",
"gunzip-maybe": "^1.3.1",
"intercept-stdout": "^0.1.2",
"jsrsasign": "6.2.2",
"log4js": "^0.6.38",
"nano": "^6.2.0",
"require-dir": "^0.3.0",
"rewire": "^2.5.2",
"tap-colorize": "^1.2.0",
"tape": "^4.5.1",
"tape-promise": "^1.1.0",
Expand Down
44 changes: 42 additions & 2 deletions test/unit/headless-tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,13 @@
var tape = require('tape');
var _test = require('tape-promise');
var test = _test(tape);
var rewire = require('rewire');

var path = require('path');
var util = require('util');
var testUtil = require('./util.js');
var hfc = require('fabric-client');
var fs = require('fs');
var fs = require('fs-extra');
var execSync = require('child_process').execSync;
var utils = require('fabric-client/lib/utils.js');
var cryptoSuiteReq = require('fabric-client/lib/impl/CryptoSuite_ECDSA_AES.js');
Expand Down Expand Up @@ -180,7 +181,6 @@ test('\n\n ** lib/Client.js **\n\n', function (t) {
.then(function(response){
if (response && response.getName() === 'someUser') {
t.pass('Client tests: successfully setUserContext with skipPersistence.');
debugger;//check out this return
return response;
}
else t.fail('Client tests: failed name check after setUserContext with skipPersistence.');
Expand Down Expand Up @@ -832,6 +832,46 @@ test('\n\n ** Chain addPeer() duplicate tests **\n\n', function (t) {
t.end();
});

// use rewire to load the module to get access to the private functions to test
var ChainModule = rewire('../../fabric-client/lib/Chain.js');
var tar = require('tar-fs');
var gunzip = require('gunzip-maybe');

test('\n\n** Chain packageChaincode tests **\n\n', function(t) {
var packageChaincode = ChainModule.__get__('packageChaincode');
t.equal(typeof packageChaincode, 'function', 'The rewired module should return the private function here');

packageChaincode(true, 'blah')
.then((data) => {
t.equal(data, null, 'Chain.packageChaincode() should return null for dev mode');
return packageChaincode(false, {});
}).then(() => {
t.fail('Chain.packageChaincode() should have rejected a call that does not have the valid request argument');
}).catch((err) => {
t.equal(err.message, 'Missing chaincodePath parameter in Deployment proposal request', 'Chain.packageChaincode() argument validation');

testUtil.setupChaincodeDeploy();

return packageChaincode(false, {
chaincodePath: testUtil.CHAINCODE_PATH,
chaincodeId: 'testChaincodeId'
});
}).then((data) => {
var tmpFile = '/tmp/test-deploy-copy.tar.gz';
var destDir = '/tmp/test-deploy-copy-tar-gz';
fs.writeFileSync(tmpFile, data);
fs.removeSync(destDir);
var pipe = fs.createReadStream(tmpFile).pipe(gunzip()).pipe(tar.extract(destDir));

pipe.on('close', function() {
var checkPath = path.join(destDir, 'src', 'github.com', 'example_cc');
t.equal(fs.existsSync(checkPath), true, 'The tar.gz file produced by Chain.packageChaincode() has the "src/github.com/example_cc" folder');
});
});

t.end();
});

test('\n\n ** Chain sendDeploymentProposal() tests **\n\n', function (t) {
var c = new Chain('does not matter', client);
var peer = new Peer('grpc://localhost:7051');
Expand Down

0 comments on commit dfbf9be

Please sign in to comment.