├── .gitignore ├── README.md ├── add-org ├── app.js ├── app │ ├── add-org.js │ └── upgrade-chaincode.js └── artifacts │ ├── crypto-new-org-template.yaml │ └── new_org.sh ├── modify-org ├── app │ └── network-config-template.json ├── artifacts │ ├── channel │ │ ├── configtx-template.yaml │ │ └── cryptogen-template.yaml │ ├── docker-compose-template.yaml │ └── set_config.sh └── config-template.json └── multi-machine-deploy ├── deploy ├── artifacts │ ├── base.yaml │ ├── crypto-template.yaml │ ├── docker-compose-template.yaml │ └── fabric-ca-server-template.yaml ├── deploy.sh └── pkg │ └── list.txt └── new-org ├── add_org.sh ├── modify-network.js └── network-config-template.json /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .idea 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Hyperledger Fabric自动化部署工具集 2 | 3 | 本项目包含一系列对fabric区块链进行动态调整组织和自动化部署的工具,旨在简化fabric网络在部署或变更时繁杂的配置和操作流程,提高生产环境下的运维效率。 4 | 5 | 项目的实现过程和踩坑细节可参考[博客](http://zhayujie.com/category/fabric/)。以下文档以[balance-transfer](https://github.com/hyperledger/fabric-samples/tree/release-1.0/balance-transfer)项目为例介绍如何在实际项目中集成这些工具。 6 | 7 | ## 功能一:修改组织和通道名称 8 | 代码位于`modify-org`目录中,将该目录下所有文件根据相对路径放入实际项目中。执行set_config.sh脚本可完成组织和通道名称的修改: 9 | ``` 10 | ./set_config.sh 11 | ``` 12 | + orgName: 组织名称 13 | + channelName: 通道名称 14 | 15 | 具体参见:[详细文档](http://zhayujie.com/fabric/modify-orgname.html) 16 | 17 | ## 功能二:动态增加或删除组织 18 | 代码位于`add-org`目录中 19 | + 首先需要把app.js、add-org.js等二次开发的代码整合到实际项目中:add-org.js放置于app/目录下,并在app.js中添加addNewOrg接口; 20 | + 将new_org.sh和crypto-new-org-template.yaml文件放入项目的artifacts目录下; 21 | + 编译生成configtxlator工具,与new_org.sh脚本置于同一目录下。 22 | 23 | 完成准备工作后即可实现以下功能: 24 | 25 | 1.动态增加组织 26 | ``` 27 | ./new_org.sh --add --number 28 | ``` 29 | + domain: 新增组织的域名,域名的第一部分为组织名 30 | + num: 新增组织中初始节点数量 31 | 32 | 2.删除已有组织 33 | ``` 34 | ./new_org.sh --del 35 | ``` 36 | + orgName: 组织名称 37 | 38 | 具体参见:[详细文档](http://zhayujie.com/fabric/add-org.html) 39 | 40 | ## 功能三:多机部署新组织并加入网络 41 | 代码位于`multi-machine-deploy`目录中。在此之前,应用程序需参考上一节实现使用SDK增加组织的接口。 42 | ### 第一步 43 | 将deploy/目录放置于待加入的机器上,并在目录下执行以下命令。将自动安装所需镜像及依赖,新组织默认为1CA, 2peer, 2couchdb的架构: 44 | ``` 45 | sudo ./deploy.sh --domain --order 46 | ``` 47 | + domain: 新加组织的域名 48 | + orderIp: orderer节点所在机器的ip 49 | ``` 50 | 例: sudo ./deploy.sh --domain org3.example.com --order 192.168.1.51 51 | ``` 52 | 53 | ### 第二步 54 | 首先将new-org/目录放置于应用程序的根目录下(如balance-transfer/new-org),然后把上一步在deploy/artifacts下生成的新组织的证书目录 (如org3.example.com) 复制一份到new-org目录中,并在new-org目录下执行脚本: 55 | ``` 56 | sudo ./add_org.sh --org --ip 57 | ``` 58 | + orgName: 组织名称 59 | + ip: 新组织所在机器的ip 60 | ``` 61 | 例: sudo ./add_org.sh --org org3 --ip 192.168.1.52 62 | ``` 63 | 具体参见:[详细文档](http://zhayujie.com/fabric/multi-host.html) 64 | -------------------------------------------------------------------------------- /add-org/app.js: -------------------------------------------------------------------------------- 1 | var newOrg = require('./app/add-org.js'); 2 | var upgrade = require('./app/upgrade-chaincode.js'); 3 | 4 | // Add Org 5 | // need: configtxlator listen in 7059 6 | app.post('/channels/:channelName/addNewOrg', function(req, res) { 7 | logger.info('<<<<<<<<<<<<<<<<< A D D O R G >>>>>>>>>>>>>>>>>'); 8 | var channelName = req.params.channelName; 9 | var domain = req.body.domain; 10 | var fcn = req.body.fcn; 11 | logger.debug('channelName : ' + channelName); 12 | 13 | if (!channelName) { 14 | res.json(getErrorMessage('\'channelName\'')); 15 | return; 16 | } 17 | if (!domain) { 18 | res.json(getErrorMessage('\'domain\'')); 19 | return; 20 | } 21 | if (!fcn || (fcn != 'add' && fcn != 'delete')) { 22 | res.json(getErrorMessage('\'fcn\'')); 23 | return; 24 | } 25 | 26 | newOrg.addNewOrg(domain, channelName, fcn) 27 | .then(function(message) { 28 | res.status(200).send(message); 29 | }, function(err) { 30 | res.status(500).send(message); 31 | }); 32 | }); 33 | 34 | // Upgrade chaincode on all peers 35 | app.post('/channels/:channelName/chaincodes/upgrade', function(req, res) { 36 | logger.debug('==================== Upgrade CHAINCODE =================='); 37 | var chaincodeName = req.body.chaincodeName; 38 | var chaincodeVersion = req.body.chaincodeVersion; 39 | var channelName = req.params.channelName; 40 | var peers = req.body.peers; 41 | var fcn = req.body.fcn; 42 | logger.debug('channelName : ' + channelName); 43 | logger.debug('chaincodeName : ' + chaincodeName); 44 | logger.debug('chaincodeVersion : ' + chaincodeVersion); 45 | if (!chaincodeName) { 46 | res.json(getErrorMessage('\'chaincodeName\'')); 47 | return; 48 | } 49 | if (!chaincodeVersion) { 50 | res.json(getErrorMessage('\'chaincodeVersion\'')); 51 | return; 52 | } 53 | if (!channelName) { 54 | res.json(getErrorMessage('\'channelName\'')); 55 | return; 56 | } 57 | upgrade.upgradeChaincode(peers, channelName, chaincodeName, chaincodeVersion, fcn, req.username, req.orgname) 58 | .then(function(message) { 59 | res.send(message); 60 | }); 61 | }); 62 | -------------------------------------------------------------------------------- /add-org/app/add-org.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var log4js = require('log4js'); 3 | var logger = log4js.getLogger('new-org'); 4 | var fs = require('fs-extra'); 5 | //var superagent = require('superagent'); 6 | var agent = require('superagent-promise')(require('superagent'), Promise); 7 | var requester = require('request'); 8 | 9 | require('../config.js'); 10 | var helper = require('./multi-machine-deploy/app/helper.js'); 11 | 12 | var addNewOrg = async function(domain, channel_name, fcn) { 13 | var orgs = ORGS; 14 | var cur_orgs = []; 15 | var orgname = domain.split('.')[0] 16 | for (var key in orgs) { 17 | if (orgname == key && fcn == 'add') { 18 | return null; 19 | } 20 | if (key != 'orderer') 21 | cur_orgs.push(key) 22 | } 23 | var cur_org = cur_orgs[0]; 24 | var cur_MSP = cur_org + 'MSP'; 25 | var new_MSP = orgname + 'MSP'; 26 | 27 | var client = getClientForOrg(cur_org); 28 | var channel = getChannelForOrg(cur_org); 29 | var admins = path.join(__dirname, '../artifacts/channel/crypto-config/peerOrganizations/' +domain +'/msp/admincerts/' + 'Admin@' + domain + '-cert.pem') 30 | var root_certs = path.join(__dirname, '../artifacts/channel/crypto-config/peerOrganizations/' +domain +'/msp/cacerts/' + 'ca.' + domain + '-cert.pem') 31 | var tls_root_certs = path.join(__dirname, '../artifacts/channel/crypto-config/peerOrganizations/' +domain +'/msp/tlscacerts/' +'tlsca.' + domain + '-cert.pem') 32 | 33 | console.log(cur_org) 34 | try { 35 | 36 | await getOrgAdmin(cur_org); 37 | // get the latest config block of the channel: map 38 | var config_envelope = await channel.getChannelConfig() 39 | 40 | // original "config" object: protobuf 41 | var original_config_proto = config_envelope.config.toBuffer(); 42 | 43 | // use tool : configtxlator : pb->json 44 | var response = await agent.post('http://127.0.0.1:7059/protolator/decode/common.Config', 45 | original_config_proto).buffer(); 46 | 47 | // original config: json 48 | var original_config_json = response.text.toString() 49 | 50 | var updated_config_json = original_config_json; 51 | // Json string -> Json object 52 | var updated_config = JSON.parse(updated_config_json); 53 | 54 | // modify the config -- add new org 55 | 56 | if (fcn == 'add') { 57 | // deep copy 58 | var new_config = JSON.stringify(updated_config.channel_group.groups.Application.groups[cur_MSP]); 59 | new_config = JSON.parse(new_config); 60 | new_config.policies.Admins.policy.value.identities[0].principal.msp_identifier = new_MSP; 61 | new_config.policies.Readers.policy.value.identities[0].principal.msp_identifier = new_MSP; 62 | new_config.policies.Writers.policy.value.identities[0].principal.msp_identifier = new_MSP; 63 | new_config.values.MSP.value.config.name = new_MSP; 64 | 65 | var f1 = fs.readFileSync(admins) 66 | var f2 = fs.readFileSync(root_certs) 67 | var f3 = fs.readFileSync(tls_root_certs) 68 | 69 | f1 = new Buffer(f1).toString('base64') 70 | f2 = new Buffer(f2).toString('base64') 71 | f3 = new Buffer(f3).toString('base64') 72 | 73 | new_config.values.MSP.value.config.admins[0] = f1; 74 | new_config.values.MSP.value.config.root_certs[0] = f2; 75 | new_config.values.MSP.value.config.tls_root_certs[0] = f3; 76 | 77 | updated_config.channel_group.groups.Application.groups[new_MSP] = new_config; 78 | } 79 | else if (fcn == 'delete'){ 80 | var del_org = domain + 'MSP' 81 | var res = delete updated_config.channel_group.groups.Application.groups[del_org] 82 | } 83 | //console.log(JSON.stringify(updated_config)) 84 | updated_config_json = JSON.stringify(updated_config); 85 | 86 | // configtxlator: json -> pb 87 | response = await agent.post('http://127.0.0.1:7059/protolator/encode/common.Config', 88 | updated_config_json.toString()).buffer(); 89 | 90 | var updated_config_proto = response.body; 91 | 92 | var formData = { 93 | channel: channel_name, 94 | original: { 95 | value: original_config_proto, 96 | options: { 97 | filename: 'original.proto', 98 | contentType: 'application/octet-stream' 99 | } 100 | }, 101 | updated: { 102 | value: updated_config_proto, 103 | options: { 104 | filename: 'updated.proto', 105 | contentType: 'application/octet-stream' 106 | } 107 | } 108 | }; 109 | 110 | // configtxlator: computer 111 | // need request v1.9.8 (2.87.0 err) 112 | response = await new Promise((resolve, reject) => { 113 | requester.post({ 114 | url: 'http://127.0.0.1:7059/configtxlator/compute/update-from-configs', 115 | // if dont have 'encoding' and 'headers', it will: error authorizing update 116 | encoding: null, 117 | headers: { 118 | accept: '/', 119 | expect: '100-continue' 120 | }, 121 | formData: formData 122 | }, (err, res, body) => { 123 | if (err) { 124 | logger.error('Failed to get the updated configuration ::' + err); 125 | reject(err); 126 | } else { 127 | const proto = Buffer.from(body, 'binary'); 128 | resolve(proto); 129 | } 130 | }); 131 | }); 132 | 133 | logger.debug('Successfully had configtxlator compute the updated config object') 134 | var config_proto = response; 135 | 136 | var signatures = [] 137 | //client._userContext = null; 138 | 139 | for (let org of cur_orgs) { 140 | // assign the admin userobj to client 141 | client = getClientForOrg(org) 142 | var r = await getOrgAdmin(org) 143 | //console.log(r) 144 | //console.log(client) 145 | 146 | let signature = client.signChannelConfig(config_proto); 147 | signatures.push(signature) 148 | } 149 | logger.debug('Successfully signed config update by orgs') 150 | 151 | let tx_id = client.newTransactionID(); 152 | var request = { 153 | config: config_proto, 154 | signatures: signatures, 155 | name: channel_name, 156 | orderer: channel.getOrderers()[0], 157 | txId: tx_id 158 | }; 159 | var result = await client.updateChannel(request); 160 | if(result.status && result.status === 'SUCCESS') { 161 | logger.debug('Successfully updated the channel.'); 162 | } else { 163 | 164 | logger.error('Failed to update the channel.'); 165 | } 166 | } 167 | catch(err) { 168 | logger.error('Failed to update the channel: ' + err.stack ? err.stack : err); 169 | } 170 | return result; 171 | 172 | }; 173 | 174 | // 采用http接口方式调用时注释此行 175 | // addNewOrg("org3.example.com", "mychannel", "add") 176 | -------------------------------------------------------------------------------- /add-org/app/upgrade-chaincode.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var path = require('path'); 3 | var fs = require('fs'); 4 | var util = require('util'); 5 | var hfc = require('fabric-client'); 6 | var Peer = require('fabric-client/lib/Peer.js'); 7 | var EventHub = require('fabric-client/lib/EventHub.js'); 8 | var helper = require('./multi-machine-deploy/app/helper.js'); 9 | var logger = helper.getLogger('upgrade-chaincode'); 10 | var ORGS = hfc.getConfigSetting('network-config'); 11 | 12 | 13 | var upgradeChaincode = function(peerNames, channelName, chaincodeName, chaincodeVersion, functionName, username, org) { 14 | logger.debug('\n============ upgradeChaincode chaincode on organization ' + org + 15 | ' ============\n'); 16 | 17 | var channel = helper.getChannelForOrg(org); 18 | var client = helper.getClientForOrg(org); 19 | var targets = (peerNames) ? helper.newPeers(peerNames, org) : undefined; 20 | 21 | return helper.getOrgAdmin(org).then((user) => { 22 | // read the config block from the orderer for the channel 23 | // and initialize the verify MSPs based on the participating 24 | // organizations 25 | return channel.initialize(); 26 | }, (err) => { 27 | logger.error('Failed to enroll user \'' + username + '\'. ' + err); 28 | throw new Error('Failed to enroll user \'' + username + '\'. ' + err); 29 | }).then((success) => { 30 | tx_id = client.newTransactionID(); 31 | // send proposal to endorser 32 | var request = { 33 | "chaincodeId": chaincodeName, 34 | "chaincodeVersion": chaincodeVersion, 35 | "args": [''], 36 | "txId": tx_id, 37 | "endorsement-policy": getEndorsementpolicy() 38 | }; 39 | console.log(JSON.stringify(request['endorsement-policy'])) 40 | 41 | if (functionName) 42 | request.fcn = functionName; 43 | 44 | if (targets) 45 | request.targets = targets; 46 | 47 | return channel.sendUpgradeProposal(request); 48 | }, (err) => { 49 | logger.error('Failed to initialize the channel'); 50 | throw new Error('Failed to initialize the channel'); 51 | }).then((results) => { 52 | var proposalResponses = results[0]; 53 | var proposal = results[1]; 54 | var all_good = true; 55 | for (var i in proposalResponses) { 56 | let one_good = false; 57 | if (proposalResponses && proposalResponses[i].response && 58 | proposalResponses[i].response.status === 200) { 59 | one_good = true; 60 | logger.info('upgrade proposal was good'); 61 | } else { 62 | logger.error('upgrade proposal was bad'); 63 | } 64 | all_good = all_good & one_good; 65 | } 66 | if (all_good) { 67 | logger.info(util.format( 68 | 'Successfully sent Proposal and received ProposalResponse: Status - %s, message - "%s", metadata - "%s", endorsement signature: %s', 69 | proposalResponses[0].response.status, proposalResponses[0].response.message, 70 | proposalResponses[0].response.payload, proposalResponses[0].endorsement 71 | .signature)); 72 | var request = { 73 | proposalResponses: proposalResponses, 74 | proposal: proposal 75 | }; 76 | // set the transaction listener and set a timeout of 30sec 77 | // if the transaction did not get committed within the timeout period, 78 | // fail the test 79 | var deployId = tx_id.getTransactionID(); 80 | 81 | eh = client.newEventHub(); 82 | let data = fs.readFileSync(path.join(__dirname, ORGS[org].peers['peer1'][ 83 | 'tls_cacerts' 84 | ])); 85 | eh.setPeerAddr(ORGS[org].peers['peer1']['events'], { 86 | pem: Buffer.from(data).toString(), 87 | 'ssl-target-name-override': ORGS[org].peers['peer1']['server-hostname'] 88 | }); 89 | eh.connect(); 90 | 91 | let txPromise = new Promise((resolve, reject) => { 92 | let handle = setTimeout(() => { 93 | eh.disconnect(); 94 | reject(); 95 | }, 30000); 96 | 97 | eh.registerTxEvent(deployId, (tx, code) => { 98 | logger.info( 99 | 'The chaincode upgrade transaction has been committed on peer ' + 100 | eh._ep._endpoint.addr); 101 | clearTimeout(handle); 102 | eh.unregisterTxEvent(deployId); 103 | eh.disconnect(); 104 | 105 | if (code !== 'VALID') { 106 | logger.error('The chaincode upgrade transaction was invalid, code = ' + code); 107 | reject(); 108 | } else { 109 | logger.info('The chaincode upgrade transaction was valid.'); 110 | resolve(); 111 | } 112 | }); 113 | }); 114 | 115 | var sendPromise = channel.sendTransaction(request); 116 | return Promise.all([sendPromise].concat([txPromise])).then((results) => { 117 | logger.debug('Event promise all complete and testing complete'); 118 | return results[0]; // the first returned value is from the 'sendPromise' which is from the 'sendTransaction()' call 119 | }).catch((err) => { 120 | logger.error( 121 | util.format('Failed to send upgrade transaction and get notifications within the timeout period. %s', err) 122 | ); 123 | return 'Failed to send upgrade transaction and get notifications within the timeout period.'; 124 | }); 125 | } else { 126 | logger.error( 127 | 'Failed to send upgrade Proposal or receive valid response. Response null or status is not 200. exiting...' 128 | ); 129 | return 'Failed to send upgrade Proposal or receive valid response. Response null or status is not 200. exiting...'; 130 | } 131 | }, (err) => { 132 | logger.error('Failed to send upgrade proposal due to error: ' + err.stack ? 133 | err.stack : err); 134 | return 'Failed to send upgrade proposal due to error: ' + err.stack ? 135 | err.stack : err; 136 | }).then((response) => { 137 | if (response.status === 'SUCCESS') { 138 | logger.info('Successfully sent transaction to the orderer.'); 139 | return 'Chaincode Instantiation is SUCCESS'; 140 | } else { 141 | logger.error('Failed to order the transaction. Error code: ' + response.status); 142 | return 'Failed to order the transaction. Error code: ' + response.status; 143 | } 144 | }, (err) => { 145 | logger.error('Failed to send upgrade due to error: ' + err.stack ? err 146 | .stack : err); 147 | return 'Failed to send upgrade due to error: ' + err.stack ? err.stack : 148 | err; 149 | }); 150 | }; 151 | 152 | 153 | var getEndorsementpolicy = function() { 154 | var orgs = helper.ORGS; 155 | var endorse_policy = {}; 156 | var identities = []; 157 | var oneof = []; 158 | var i = 0; 159 | for (let org in ORGS) { 160 | if (org != 'orderer') { 161 | let role = {role: {name: 'member', mspId: org + 'MSP'}} 162 | let sign = {'signed-by': i}; 163 | i++; 164 | identities.push(role); 165 | oneof.push(sign); 166 | } 167 | } 168 | endorse_policy['identities'] = identities; 169 | endorse_policy['policy'] = {"1-of": oneof} 170 | 171 | //console.log(JSON.stringify(endorse_policy)); 172 | 173 | return endorse_policy; 174 | } 175 | 176 | exports.instantiateChaincode = instantiateChaincode; 177 | -------------------------------------------------------------------------------- /add-org/artifacts/crypto-new-org-template.yaml: -------------------------------------------------------------------------------- 1 | PeerOrgs: 2 | - Name: ORG_NAME 3 | Domain: DOMAIN 4 | CA: 5 | Hostname: ca 6 | Template: 7 | Count: NUM 8 | SANS: 9 | - "localhost" 10 | Users: 11 | Count: 1 12 | -------------------------------------------------------------------------------- /add-org/artifacts/new_org.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | CUR_ORG="org1" # one of current orgs in network 4 | TOKEN= 5 | ORG_NAME= 6 | DOMAIN= 7 | NUM=2 8 | DEL_ORG= 9 | 10 | function printHelp() { 11 | echo "Only use this script when you need to add an org in a channel" 12 | echo "Usage: new_org.sh --add domain --number num add an new org" 13 | echo " new_org.sh --del orgname delete an existing org" 14 | } 15 | 16 | function startConfigtxlator() { 17 | ./configtxlator start & 18 | } 19 | 20 | function closeConfigtxlator() { 21 | kill -9 $(ps -aux|grep "configtxlator"|grep -v "grep"|awk '{print $2}') 22 | } 23 | 24 | function generateCrypto() { 25 | if [[ -f "crypto-new-org.yaml" ]]; then 26 | rm crypto-new-org.yaml 27 | fi 28 | cp crypto-new-org-template.yaml crypto-new-org.yaml 29 | sed -i "s/ORG_NAME/$ORG_NAME/g" crypto-new-org.yaml 30 | sed -i "s/DOMAIN/$DOMAIN/g" crypto-new-org.yaml 31 | sed -i "s/NUM/$NUM/g" crypto-new-org.yaml 32 | 33 | ./channel/cryptogen generate --config=./crypto-new-org.yaml --output ./../artifacts/channel/crypto-config 34 | } 35 | 36 | function getToken(){ 37 | echo "POST request Enroll on Org1 ..." 38 | echo 39 | TOKEN=$(curl -s -X POST \ 40 | http://localhost:4000/users \ 41 | -H "content-type: application/x-www-form-urlencoded" \ 42 | -d 'username=Jim&orgName=$CUR_ORG&password=123') 43 | echo $TOKEN 44 | TOKEN=$(echo $TOKEN | jq ".token" | sed "s/\"//g") 45 | echo 46 | echo "token is $TOKEN" 47 | echo 48 | } 49 | 50 | function addOrg() { 51 | curl -s -X POST \ 52 | http://localhost:4000/channels/mychannel/addNewOrg \ 53 | -H "authorization: Bearer $TOKEN" \ 54 | -H "content-type: application/json" \ 55 | -d '{ 56 | "domain": "'$DOMAIN'", 57 | "fcn": "add" 58 | }' 59 | } 60 | 61 | function delOrg() { 62 | curl -s -X POST \ 63 | http://localhost:4000/channels/mychannel/addNewOrg \ 64 | -H "authorization: Bearer $TOKEN" \ 65 | -H "content-type: application/json" \ 66 | -d '{ 67 | "domain": "'$DEL_ORG'", 68 | "fcn": "delete" 69 | }' 70 | } 71 | 72 | 73 | if [[ $# -eq 4 && "$1" = "--add" && "$3" = "--number" && -n "$2" && -n "$4" ]]; then 74 | DOMAIN=$2 75 | NUM=$4 76 | ORG_NAME=${DOMAIN%%.*} 77 | echo "Add org" 78 | echo "Domain: $DOMAIN" 79 | echo "Number: $NUM" 80 | echo "Orgname: $ORG_NAME" 81 | echo 82 | startConfigtxlator 83 | generateCrypto 84 | getToken 85 | addOrg 86 | closeConfigtxlator 87 | 88 | 89 | elif [[ $# -eq 2 && "$1" = "--del" && -n "$2" ]]; then 90 | DEL_ORG=$2 91 | echo "Delete org" 92 | echo "Orgname: $DEL_ORG" 93 | startConfigtxlator 94 | getToken 95 | delOrg 96 | closeConfigtxlator 97 | else 98 | printHelp 99 | fi 100 | -------------------------------------------------------------------------------- /modify-org/app/network-config-template.json: -------------------------------------------------------------------------------- 1 | { 2 | "network-config": { 3 | "orderer": { 4 | "url": "grpcs://localhost:7050", 5 | "server-hostname": "orderer.example.com", 6 | "tls_cacerts": "../artifacts/channel/crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/tls/ca.crt" 7 | }, 8 | "ORG_NAME": { 9 | "name": "peerORG_NAME", 10 | "mspid": "ORG_NAMEMSP", 11 | "ca": "https://localhost:7054", 12 | "peers": { 13 | "peer1": { 14 | "requests": "grpcs://localhost:7051", 15 | "events": "grpcs://localhost:7053", 16 | "server-hostname": "peer0.ORG_NAME.example.com", 17 | "tls_cacerts": "../artifacts/channel/crypto-config/peerOrganizations/ORG_NAME.example.com/peers/peer0.ORG_NAME.example.com/tls/ca.crt" 18 | }, 19 | "peer2": { 20 | "requests": "grpcs://localhost:7056", 21 | "events": "grpcs://localhost:7058", 22 | "server-hostname": "peer1.ORG_NAME.example.com", 23 | "tls_cacerts": "../artifacts/channel/crypto-config/peerOrganizations/ORG_NAME.example.com/peers/peer1.ORG_NAME.example.com/tls/ca.crt" 24 | } 25 | }, 26 | "admin": { 27 | "key": "../artifacts/channel/crypto-config/peerOrganizations/ORG_NAME.example.com/users/Admin@ORG_NAME.example.com/msp/keystore", 28 | "cert": "../artifacts/channel/crypto-config/peerOrganizations/ORG_NAME.example.com/users/Admin@ORG_NAME.example.com/msp/signcerts" 29 | } 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /modify-org/artifacts/channel/configtx-template.yaml: -------------------------------------------------------------------------------- 1 | 2 | 3 | --- 4 | ################################################################################ 5 | # 6 | # Profile 7 | # 8 | # - Different configuration profiles may be encoded here to be specified 9 | # as parameters to the configtxgen tool 10 | # 11 | ################################################################################ 12 | Profiles: 13 | 14 | TwoOrgsOrdererGenesis: 15 | Orderer: 16 | <<: *OrdererDefaults 17 | Organizations: 18 | - *OrdererOrg 19 | Consortiums: 20 | SampleConsortium: 21 | Organizations: 22 | - *ORG_NAME 23 | TwoOrgsChannel: 24 | Consortium: SampleConsortium 25 | Application: 26 | <<: *ApplicationDefaults 27 | Organizations: 28 | - *ORG_NAME 29 | 30 | ################################################################################ 31 | # 32 | # Section: Organizations 33 | # 34 | # - This section defines the different organizational identities which will 35 | # be referenced later in the configuration. 36 | # 37 | ################################################################################ 38 | Organizations: 39 | 40 | # SampleOrg defines an MSP using the sampleconfig. It should never be used 41 | # in production but may be used as a template for other definitions 42 | - &OrdererOrg 43 | # DefaultOrg defines the organization which is used in the sampleconfig 44 | # of the fabric.git development environment 45 | Name: OrdererMSP 46 | 47 | # ID to load the MSP definition as 48 | ID: OrdererMSP 49 | 50 | # MSPDir is the filesystem path which contains the MSP configuration 51 | MSPDir: ./crypto-config/ordererOrganizations/example.com/msp 52 | 53 | - &ORG_NAME 54 | # DefaultOrg defines the organization which is used in the sampleconfig 55 | # of the fabric.git development environment 56 | Name: ORG_NAMEMSP 57 | 58 | # ID to load the MSP definition as 59 | ID: ORG_NAMEMSP 60 | 61 | MSPDir: ./crypto-config/peerOrganizations/ORG_NAME.example.com/msp 62 | 63 | AnchorPeers: 64 | # AnchorPeers defines the location of peers which can be used 65 | # for cross org gossip communication. Note, this value is only 66 | # encoded in the genesis block in the Application section context 67 | - Host: peer0.ORG_NAME.example.com 68 | Port: 7051 69 | 70 | 71 | ################################################################################ 72 | # 73 | # SECTION: Orderer 74 | # 75 | # - This section defines the values to encode into a config transaction or 76 | # genesis block for orderer related parameters 77 | # 78 | ################################################################################ 79 | Orderer: &OrdererDefaults 80 | 81 | # Orderer Type: The orderer implementation to start 82 | # Available types are "solo" and "kafka" 83 | OrdererType: solo 84 | 85 | Addresses: 86 | - orderer.example.com:7050 87 | 88 | # Batch Timeout: The amount of time to wait before creating a batch 89 | BatchTimeout: 2s 90 | 91 | # Batch Size: Controls the number of messages batched into a block 92 | BatchSize: 93 | 94 | # Max Message Count: The maximum number of messages to permit in a batch 95 | MaxMessageCount: 10 96 | 97 | # Absolute Max Bytes: The absolute maximum number of bytes allowed for 98 | # the serialized messages in a batch. 99 | AbsoluteMaxBytes: 98 MB 100 | 101 | # Preferred Max Bytes: The preferred maximum number of bytes allowed for 102 | # the serialized messages in a batch. A message larger than the preferred 103 | # max bytes will result in a batch larger than preferred max bytes. 104 | PreferredMaxBytes: 512 KB 105 | 106 | Kafka: 107 | # Brokers: A list of Kafka brokers to which the orderer connects 108 | # NOTE: Use IP:port notation 109 | Brokers: 110 | - 127.0.0.1:9092 111 | 112 | # Organizations is the list of orgs which are defined as participants on 113 | # the orderer side of the network 114 | Organizations: 115 | 116 | ################################################################################ 117 | # 118 | # SECTION: Application 119 | # 120 | # - This section defines the values to encode into a config transaction or 121 | # genesis block for application related parameters 122 | # 123 | ################################################################################ 124 | Application: &ApplicationDefaults 125 | 126 | # Organizations is the list of orgs which are defined as participants on 127 | # the application side of the network 128 | Organizations: 129 | -------------------------------------------------------------------------------- /modify-org/artifacts/channel/cryptogen-template.yaml: -------------------------------------------------------------------------------- 1 | # --------------------------------------------------------------------------- 2 | # "OrdererOrgs" - Definition of organizations managing orderer nodes 3 | # --------------------------------------------------------------------------- 4 | OrdererOrgs: 5 | # --------------------------------------------------------------------------- 6 | # Orderer 7 | # --------------------------------------------------------------------------- 8 | - Name: Orderer 9 | Domain: example.com 10 | 11 | # --------------------------------------------------------------------------- 12 | # "Specs" - See PeerOrgs below for complete description 13 | # --------------------------------------------------------------------------- 14 | Specs: 15 | - Hostname: orderer 16 | 17 | # --------------------------------------------------------------------------- 18 | # "PeerOrgs" - Definition of organizations managing peer nodes 19 | # --------------------------------------------------------------------------- 20 | PeerOrgs: 21 | # --------------------------------------------------------------------------- 22 | # ORG_NAME 23 | # --------------------------------------------------------------------------- 24 | - Name: ORG_NAME 25 | Domain: ORG_NAME.example.com 26 | 27 | # --------------------------------------------------------------------------- 28 | # "CA" 29 | # --------------------------------------------------------------------------- 30 | # Uncomment this section to enable the explicit definition of the CA for this 31 | # organization. This entry is a Spec. See "Specs" section below for details. 32 | # --------------------------------------------------------------------------- 33 | CA: 34 | Hostname: ca # implicitly ca.ORG_NAME.example.com 35 | 36 | # --------------------------------------------------------------------------- 37 | # "Specs" 38 | # --------------------------------------------------------------------------- 39 | # Uncomment this section to enable the explicit definition of hosts in your 40 | # configuration. Most users will want to use Template, below 41 | # 42 | # Specs is an array of Spec entries. Each Spec entry consists of two fields: 43 | # - Hostname: (Required) The desired hostname, sans the domain. 44 | # - CommonName: (Optional) Specifies the template or explicit override for 45 | # the CN. By default, this is the template: 46 | # 47 | # "{{.Hostname}}.{{.Domain}}" 48 | # 49 | # which obtains its values from the Spec.Hostname and 50 | # Org.Domain, respectively. 51 | # - SANS: (Optional) Specifies one or more Subject Alternative Names 52 | # the be set in the resulting x509. Accepts template 53 | # variables {{.Hostname}}, {{.Domain}}, {{.CommonName}} 54 | # NOTE: Two implicit entries are created for you: 55 | # - {{ .CommonName }} 56 | # - {{ .Hostname }} 57 | # --------------------------------------------------------------------------- 58 | # Specs: 59 | # - Hostname: foo # implicitly "foo.ORG_NAME.example.com" 60 | # CommonName: foo27.org5.example.com # overrides Hostname-based FQDN set above 61 | # SANS: 62 | # - "bar.{{.Domain}}" 63 | # - "altfoo.{{.Domain}}" 64 | # - "{{.Hostname}}.org6.net" 65 | # - Hostname: bar 66 | # - Hostname: baz 67 | 68 | # --------------------------------------------------------------------------- 69 | # "Template" 70 | # --------------------------------------------------------------------------- 71 | # Allows for the definition of 1 or more hosts that are created sequentially 72 | # from a template. By default, this looks like "peer%d" from 0 to Count-1. 73 | # You may override the number of nodes (Count), the starting index (Start) 74 | # or the template used to construct the name (Hostname). 75 | # 76 | # Note: Template and Specs are not mutually exclusive. You may define both 77 | # sections and the aggregate nodes will be created for you. Take care with 78 | # name collisions 79 | # --------------------------------------------------------------------------- 80 | Template: 81 | Count: 2 82 | # Start: 5 83 | # Hostname: {{.Prefix}}{{.Index}} # default 84 | SANS: 85 | - "localhost" 86 | 87 | # --------------------------------------------------------------------------- 88 | # "Users" 89 | # --------------------------------------------------------------------------- 90 | # Count: The number of user accounts _in addition_ to Admin 91 | # --------------------------------------------------------------------------- 92 | Users: 93 | Count: 1 94 | 95 | -------------------------------------------------------------------------------- /modify-org/artifacts/docker-compose-template.yaml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | 3 | networks: 4 | default: 5 | 6 | services: 7 | 8 | ca.ORG_NAME.example.com: 9 | image: hyperledger/fabric-ca 10 | environment: 11 | - FABRIC_CA_HOME=/etc/hyperledger/fabric-ca-server 12 | - FABRIC_CA_SERVER_CA_CERTFILE=/etc/hyperledger/fabric-ca-server-config/ca.ORG_NAME.example.com-cert.pem 13 | - FABRIC_CA_SERVER_CA_KEYFILE=/etc/hyperledger/fabric-ca-server-config/CA_PRIVATE_KEY 14 | - FABRIC_CA_SERVER_TLS_ENABLED=true 15 | - FABRIC_CA_SERVER_TLS_CERTFILE=/etc/hyperledger/fabric-ca-server-config/ca.ORG_NAME.example.com-cert.pem 16 | - FABRIC_CA_SERVER_TLS_KEYFILE=/etc/hyperledger/fabric-ca-server-config/CA_PRIVATE_KEY 17 | ports: 18 | - "7054:7054" 19 | command: sh -c 'fabric-ca-server start -b admin:adminpw -d' 20 | volumes: 21 | - ./channel/crypto-config/peerOrganizations/ORG_NAME.example.com/ca/:/etc/hyperledger/fabric-ca-server-config 22 | - ./fabric-ca-server-config.yaml:/etc/hyperledger/fabric-ca-server/fabric-ca-server-config.yaml 23 | container_name: ca_peerORG_NAME 24 | networks: 25 | - default 26 | 27 | 28 | orderer.example.com: 29 | container_name: orderer.example.com 30 | image: hyperledger/fabric-orderer 31 | environment: 32 | - ORDERER_GENERAL_LOGLEVEL=debug 33 | - ORDERER_GENERAL_LISTENADDRESS=0.0.0.0 34 | - ORDERER_GENERAL_GENESISMETHOD=file 35 | - ORDERER_GENERAL_GENESISFILE=/etc/hyperledger/configtx/genesis.block 36 | - ORDERER_GENERAL_LOCALMSPID=OrdererMSP 37 | - ORDERER_GENERAL_LOCALMSPDIR=/etc/hyperledger/crypto/orderer/msp 38 | - ORDERER_GENERAL_TLS_ENABLED=true 39 | - ORDERER_GENERAL_TLS_PRIVATEKEY=/etc/hyperledger/crypto/orderer/tls/server.key 40 | - ORDERER_GENERAL_TLS_CERTIFICATE=/etc/hyperledger/crypto/orderer/tls/server.crt 41 | - ORDERER_GENERAL_TLS_ROOTCAS=[/etc/hyperledger/crypto/orderer/tls/ca.crt, /etc/hyperledger/crypto/peerORG_NAME/tls/ca.crt] 42 | working_dir: /opt/gopath/src/github.com/hyperledger/fabric/orderers 43 | command: orderer 44 | ports: 45 | - 7050:7050 46 | volumes: 47 | - ./channel:/etc/hyperledger/configtx 48 | - ./channel/crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/:/etc/hyperledger/crypto/orderer 49 | - ./channel/crypto-config/peerOrganizations/ORG_NAME.example.com/peers/peer0.ORG_NAME.example.com/:/etc/hyperledger/crypto/peerORG_NAME 50 | networks: 51 | - default 52 | 53 | peer0.ORG_NAME.example.com: 54 | container_name: peer0.ORG_NAME.example.com 55 | image: hyperledger/fabric-peer 56 | extends: 57 | file: base.yaml 58 | service: peer-base 59 | environment: 60 | - CORE_PEER_ID=peer0.ORG_NAME.example.com 61 | - CORE_PEER_LOCALMSPID=ORG_NAMEMSP 62 | - CORE_PEER_ADDRESS=peer0.ORG_NAME.example.com:7051 63 | - CORE_LEDGER_STATE_STATEDATABASE=CouchDB 64 | - CORE_LEDGER_STATE_COUCHDBCONFIG_COUCHDBADDRESS=couchdb:5984 65 | - CORE_LEDGER_STATE_COUCHDBCONFIG_USERNAME= 66 | - CORE_LEDGER_STATE_COUCHDBCONFIG_PASSWORD= 67 | ports: 68 | - 7051:7051 69 | - 7053:7053 70 | volumes: 71 | - ./channel/crypto-config/peerOrganizations/ORG_NAME.example.com/peers/peer0.ORG_NAME.example.com/:/etc/hyperledger/crypto/peer 72 | depends_on: 73 | - orderer.example.com 74 | - couchdb 75 | 76 | 77 | couchdb: 78 | container_name: couchdb 79 | image: hyperledger/fabric-couchdb 80 | # Populate the COUCHDB_USER and COUCHDB_PASSWORD to set an admin user and password 81 | # for CouchDB. This will prevent CouchDB from operating in an "Admin Party" mode. 82 | environment: 83 | - COUCHDB_USER= 84 | - COUCHDB_PASSWORD= 85 | ports: 86 | - 5984:5984 87 | networks: 88 | - default 89 | 90 | 91 | 92 | peer1.ORG_NAME.example.com: 93 | container_name: peer1.ORG_NAME.example.com 94 | image: hyperledger/fabric-peer 95 | extends: 96 | file: base.yaml 97 | service: peer-base 98 | environment: 99 | - CORE_PEER_ID=peer1.ORG_NAME.example.com 100 | - CORE_PEER_LOCALMSPID=ORG_NAMEMSP 101 | - CORE_PEER_ADDRESS=peer1.ORG_NAME.example.com:7051 102 | - CORE_LEDGER_STATE_STATEDATABASE=CouchDB 103 | - CORE_LEDGER_STATE_COUCHDBCONFIG_COUCHDBADDRESS=couchdb1:5984 104 | - CORE_LEDGER_STATE_COUCHDBCONFIG_USERNAME= 105 | - CORE_LEDGER_STATE_COUCHDBCONFIG_PASSWORD= 106 | ports: 107 | - 7056:7051 108 | - 7058:7053 109 | volumes: 110 | - ./channel/crypto-config/peerOrganizations/ORG_NAME.example.com/peers/peer1.ORG_NAME.example.com/:/etc/hyperledger/crypto/peer 111 | depends_on: 112 | - orderer.example.com 113 | - couchdb1 114 | 115 | couchdb1: 116 | container_name: couchdb1 117 | image: hyperledger/fabric-couchdb 118 | # Populate the COUCHDB_USER and COUCHDB_PASSWORD to set an admin user and password 119 | # for CouchDB. This will prevent CouchDB from operating in an "Admin Party" mode. 120 | environment: 121 | - COUCHDB_USER= 122 | - COUCHDB_PASSWORD= 123 | ports: 124 | - 5989:5984 125 | networks: 126 | - default 127 | 128 | 129 | -------------------------------------------------------------------------------- /modify-org/artifacts/set_config.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Execute this script to change orgName and channelName Aatomatically. 4 | # But the normally running depends on current fixed directory. Just need 5 | # to modify the script slightly and you can run it in new environment. 6 | 7 | ORG_NAME= 8 | CHANNEL_NAME= 9 | export FABRIC_CFG_PATH=$PWD/channel 10 | 11 | function printHelp() { 12 | echo "Only use this script when you need to modify the orgName or channelName" 13 | echo "Usage: set_config.sh " 14 | } 15 | 16 | # create crypto-config directory 17 | function createCrypto() { 18 | rm -rf ./channel/crypto-config ./channel/*.block ./channel/*.tx 19 | cd channel 20 | if [[ -f "configtx.yaml" ]]; then 21 | rm configtx.yaml 22 | fi 23 | if [[ -f "cryptogen.yaml" ]]; then 24 | rm cryptogen.yaml 25 | fi 26 | cp cryptogen-template.yaml cryptogen.yaml 27 | cp configtx-template.yaml configtx.yaml 28 | sed -i "s/ORG_NAME/$ORG_NAME/g" ./cryptogen.yaml ./configtx.yaml 29 | ./cryptogen generate --config=./cryptogen.yaml 30 | ./configtxgen -profile TwoOrgsOrdererGenesis -outputBlock ./genesis.block 31 | ./configtxgen -profile TwoOrgsChannel -outputCreateChannelTx ./"$CHANNEL_NAME.tx" -channelID "$CHANNEL_NAME" 32 | cd .. 33 | } 34 | 35 | function changeConfigFile() { 36 | # docker-compose.yaml 37 | CA_PRIVATE_KEY=$(ls ./channel/crypto-config/peerOrganizations/$ORG_NAME.example.com/ca/*_sk) 38 | CA_PRIVATE_KEY=${CA_PRIVATE_KEY##*/} 39 | if [[ -f "docker-compose.yaml" ]]; then 40 | rm docker-compose.yaml 41 | fi 42 | cp docker-compose-template.yaml docker-compose.yaml 43 | sed -i "s/ORG_NAME/$ORG_NAME/g" docker-compose.yaml 44 | sed -i "s/CA_PRIVATE_KEY/$CA_PRIVATE_KEY/g" docker-compose.yaml 45 | 46 | # config.json 47 | cd .. 48 | if [[ -f "config.json" ]]; then 49 | rm config.json 50 | fi 51 | cp config-template.json config.json 52 | sed -i "s/CHANNEL_NAME/$CHANNEL_NAME/g" config.json 53 | cd app 54 | 55 | # network-config.json 56 | if [[ -f "network-config.json" ]]; then 57 | rm network-config.json 58 | fi 59 | cp network-config-template.json network-config.json 60 | sed -i "s/ORG_NAME/$ORG_NAME/g" network-config.json 61 | 62 | # remove local crypto key 63 | ls /tmp/fabric-client-kvs_peer* > /dev/null 64 | if [[ $? -eq 0 ]]; then 65 | rm -rf /tmp/fabric-client-kvs_peer* 66 | fi 67 | } 68 | 69 | function modifyConfig() { 70 | createCrypto 71 | changeConfigFile 72 | } 73 | 74 | if [[ $# -eq 2 && -n "$1" && -n "$2" ]]; then 75 | echo "new orgName: $1" 76 | echo "new channelName: $2" 77 | ORG_NAME=$1 78 | CHANNEL_NAME=$2 79 | 80 | modifyConfig 81 | echo 82 | echo 83 | else 84 | printHelp 85 | fi 86 | -------------------------------------------------------------------------------- /modify-org/config-template.json: -------------------------------------------------------------------------------- 1 | { 2 | "host":"localhost", 3 | "port":"4000", 4 | "jwt_expiretime": "36000", 5 | "channelName":"CHANNEL_NAME", 6 | "CC_SRC_PATH":"../artifacts", 7 | "keyValueStore":"/tmp/fabric-client-kvs", 8 | "eventWaitTime":"30000", 9 | "admins":[ 10 | { 11 | "username":"admin", 12 | "secret":"adminpw" 13 | } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /multi-machine-deploy/deploy/artifacts/base.yaml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | services: 3 | peer-base: 4 | image: hyperledger/fabric-peer 5 | environment: 6 | - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock 7 | # the following setting starts chaincode containers on the same 8 | # bridge network as the peers 9 | # https://docs.docker.com/compose/networking/ 10 | - CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=artifacts_default 11 | - CORE_LOGGING_LEVEL=DEBUG 12 | - CORE_PEER_GOSSIP_USELEADERELECTION=true 13 | - CORE_PEER_GOSSIP_ORGLEADER=false 14 | # The following setting skips the gossip handshake since we are 15 | # are not doing mutual TLS 16 | - CORE_PEER_GOSSIP_SKIPHANDSHAKE=true 17 | - CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/crypto/peer/msp 18 | - CORE_PEER_TLS_ENABLED=true 19 | - CORE_PEER_TLS_KEY_FILE=/etc/hyperledger/crypto/peer/tls/server.key 20 | - CORE_PEER_TLS_CERT_FILE=/etc/hyperledger/crypto/peer/tls/server.crt 21 | - CORE_PEER_TLS_ROOTCERT_FILE=/etc/hyperledger/crypto/peer/tls/ca.crt 22 | working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer 23 | command: peer node start 24 | volumes: 25 | - /var/run/:/host/var/run/ 26 | -------------------------------------------------------------------------------- /multi-machine-deploy/deploy/artifacts/crypto-template.yaml: -------------------------------------------------------------------------------- 1 | PeerOrgs: 2 | - Name: ORG_NAME 3 | Domain: DOMAIN 4 | CA: 5 | Hostname: ca 6 | Template: 7 | Count: 2 8 | SANS: 9 | - "localhost" 10 | Users: 11 | Count: 1 12 | -------------------------------------------------------------------------------- /multi-machine-deploy/deploy/artifacts/docker-compose-template.yaml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | 3 | networks: 4 | default: 5 | 6 | services: 7 | 8 | ca.DOMAIN: 9 | image: hyperledger/fabric-ca 10 | environment: 11 | - FABRIC_CA_HOME=/etc/hyperledger/fabric-ca-server 12 | - FABRIC_CA_SERVER_CA_CERTFILE=/etc/hyperledger/fabric-ca-server-config/ca.DOMAIN-cert.pem 13 | - FABRIC_CA_SERVER_CA_KEYFILE=/etc/hyperledger/fabric-ca-server-config/CA_PRIVATE_KEY 14 | - FABRIC_CA_SERVER_TLS_ENABLED=true 15 | - FABRIC_CA_SERVER_TLS_CERTFILE=/etc/hyperledger/fabric-ca-server-config/ca.DOMAIN-cert.pem 16 | - FABRIC_CA_SERVER_TLS_KEYFILE=/etc/hyperledger/fabric-ca-server-config/CA_PRIVATE_KEY 17 | ports: 18 | - "7054:7054" 19 | command: sh -c 'fabric-ca-server start -b admin:adminpw -d' 20 | volumes: 21 | - ./DOMAIN/ca/:/etc/hyperledger/fabric-ca-server-config 22 | - ./fabric-ca-server-config.yaml:/etc/hyperledger/fabric-ca-server/fabric-ca-server-config.yaml 23 | container_name: ca_peerORG_NAME 24 | networks: 25 | - default 26 | 27 | peer0.DOMAIN: 28 | container_name: peer0.DOMAIN 29 | image: hyperledger/fabric-peer 30 | extends: 31 | file: base.yaml 32 | service: peer-base 33 | environment: 34 | - CORE_PEER_ID=peer0.DOMAIN 35 | - CORE_PEER_LOCALMSPID=ORG_NAMEMSP 36 | - CORE_PEER_ADDRESS=peer0.DOMAIN:7051 37 | - CORE_LEDGER_STATE_STATEDATABASE=CouchDB 38 | - CORE_LEDGER_STATE_COUCHDBCONFIG_COUCHDBADDRESS=couchdb:5984 39 | - CORE_LEDGER_STATE_COUCHDBCONFIG_USERNAME= 40 | - CORE_LEDGER_STATE_COUCHDBCONFIG_PASSWORD= 41 | ports: 42 | - 7051:7051 43 | - 7053:7053 44 | volumes: 45 | - ./DOMAIN/peers/peer0.DOMAIN/:/etc/hyperledger/crypto/peer 46 | depends_on: 47 | - couchdb 48 | extra_hosts: 49 | - "orderer.example.com:ORDERER_IP" 50 | 51 | couchdb: 52 | container_name: couchdb 53 | image: hyperledger/fabric-couchdb 54 | environment: 55 | - COUCHDB_USER= 56 | - COUCHDB_PASSWORD= 57 | ports: 58 | - 5984:5984 59 | networks: 60 | - default 61 | 62 | peer1.DOMAIN: 63 | container_name: peer1.DOMAIN 64 | image: hyperledger/fabric-peer 65 | extends: 66 | file: base.yaml 67 | service: peer-base 68 | environment: 69 | - CORE_PEER_ID=peer1.DOMAIN 70 | - CORE_PEER_LOCALMSPID=ORG_NAMEMSP 71 | - CORE_PEER_ADDRESS=peer1.DOMAIN:7051 72 | - CORE_LEDGER_STATE_STATEDATABASE=CouchDB 73 | - CORE_LEDGER_STATE_COUCHDBCONFIG_COUCHDBADDRESS=couchdb1:5984 74 | - CORE_LEDGER_STATE_COUCHDBCONFIG_USERNAME= 75 | - CORE_LEDGER_STATE_COUCHDBCONFIG_PASSWORD= 76 | ports: 77 | - 7056:7051 78 | - 7058:7053 79 | volumes: 80 | - ./DOMAIN/peers/peer1.DOMAIN/:/etc/hyperledger/crypto/peer 81 | depends_on: 82 | - couchdb1 83 | extra_hosts: 84 | - "orderer.example.com:ORDERER_IP" 85 | 86 | couchdb1: 87 | container_name: couchdb1 88 | image: hyperledger/fabric-couchdb 89 | environment: 90 | - COUCHDB_USER= 91 | - COUCHDB_PASSWORD= 92 | ports: 93 | - 6984:5984 94 | networks: 95 | - default 96 | -------------------------------------------------------------------------------- /multi-machine-deploy/deploy/artifacts/fabric-ca-server-template.yaml: -------------------------------------------------------------------------------- 1 | ############################################################################# 2 | # This is a configuration file for the fabric-ca-server command. 3 | # 4 | # COMMAND LINE ARGUMENTS AND ENVIRONMENT VARIABLES 5 | # ------------------------------------------------ 6 | # Each configuration element can be overridden via command line 7 | # arguments or environment variables. The precedence for determining 8 | # the value of each element is as follows: 9 | # 1) command line argument 10 | # Examples: 11 | # a) --port 443 12 | # To set the listening port 13 | # b) --ca.keyfile ../mykey.pem 14 | # To set the "keyfile" element in the "ca" section below; 15 | # note the '.' separator character. 16 | # 2) environment variable 17 | # Examples: 18 | # a) FABRIC_CA_SERVER_PORT=443 19 | # To set the listening port 20 | # b) FABRIC_CA_SERVER_CA_KEYFILE="../mykey.pem" 21 | # To set the "keyfile" element in the "ca" section below; 22 | # note the '_' separator character. 23 | # 3) configuration file 24 | # 4) default value (if there is one) 25 | # All default values are shown beside each element below. 26 | # 27 | # FILE NAME ELEMENTS 28 | # ------------------ 29 | # The value of all fields whose name ends with "file" or "files" are 30 | # name or names of other files. 31 | # For example, see "tls.certfile" and "tls.clientauth.certfiles". 32 | # The value of each of these fields can be a simple filename, a 33 | # relative path, or an absolute path. If the value is not an 34 | # absolute path, it is interpretted as being relative to the location 35 | # of this configuration file. 36 | # 37 | ############################################################################# 38 | 39 | # Version of config file 40 | version: 1.1.0 41 | 42 | # Server's listening port (default: 7054) 43 | port: 7054 44 | 45 | # Enables debug logging (default: false) 46 | debug: false 47 | 48 | # Size limit of an acceptable CRL in bytes (default: 512000) 49 | crlsizelimit: 512000 50 | 51 | ############################################################################# 52 | # TLS section for the server's listening port 53 | # 54 | # The following types are supported for client authentication: NoClientCert, 55 | # RequestClientCert, RequireAnyClientCert, VerifyClientCertIfGiven, 56 | # and RequireAndVerifyClientCert. 57 | # 58 | # Certfiles is a list of root certificate authorities that the server uses 59 | # when verifying client certificates. 60 | ############################################################################# 61 | tls: 62 | # Enable TLS (default: false) 63 | enabled: false 64 | # TLS for the server's listening port 65 | certfile: 66 | keyfile: 67 | clientauth: 68 | type: noclientcert 69 | certfiles: 70 | 71 | ############################################################################# 72 | # The CA section contains information related to the Certificate Authority 73 | # including the name of the CA, which should be unique for all members 74 | # of a blockchain network. It also includes the key and certificate files 75 | # used when issuing enrollment certificates (ECerts) and transaction 76 | # certificates (TCerts). 77 | # The chainfile (if it exists) contains the certificate chain which 78 | # should be trusted for this CA, where the 1st in the chain is always the 79 | # root CA certificate. 80 | ############################################################################# 81 | ca: 82 | # Name of this CA 83 | name: 84 | # Key file (is only used to import a private key into BCCSP) 85 | keyfile: 86 | # Certificate file (default: ca-cert.pem) 87 | certfile: 88 | # Chain file 89 | chainfile: 90 | 91 | ############################################################################# 92 | # The gencrl REST endpoint is used to generate a CRL that contains revoked 93 | # certificates. This section contains configuration options that are used 94 | # during gencrl request processing. 95 | ############################################################################# 96 | crl: 97 | # Specifies expiration for the generated CRL. The number of hours 98 | # specified by this property is added to the UTC time, the resulting time 99 | # is used to set the 'Next Update' date of the CRL. 100 | expiry: 24h 101 | 102 | ############################################################################# 103 | # The registry section controls how the fabric-ca-server does two things: 104 | # 1) authenticates enrollment requests which contain a username and password 105 | # (also known as an enrollment ID and secret). 106 | # 2) once authenticated, retrieves the identity's attribute names and 107 | # values which the fabric-ca-server optionally puts into TCerts 108 | # which it issues for transacting on the Hyperledger Fabric blockchain. 109 | # These attributes are useful for making access control decisions in 110 | # chaincode. 111 | # There are two main configuration options: 112 | # 1) The fabric-ca-server is the registry. 113 | # This is true if "ldap.enabled" in the ldap section below is false. 114 | # 2) An LDAP server is the registry, in which case the fabric-ca-server 115 | # calls the LDAP server to perform these tasks. 116 | # This is true if "ldap.enabled" in the ldap section below is true, 117 | # which means this "registry" section is ignored. 118 | ############################################################################# 119 | registry: 120 | # Maximum number of times a password/secret can be reused for enrollment 121 | # (default: -1, which means there is no limit) 122 | maxenrollments: -1 123 | 124 | # Contains identity information which is used when LDAP is disabled 125 | identities: 126 | - name: admin 127 | pass: adminpw 128 | type: client 129 | affiliation: "" 130 | attrs: 131 | hf.Registrar.Roles: "peer,orderer,client,user" 132 | hf.Registrar.DelegateRoles: "peer,orderer,client,user" 133 | hf.Revoker: true 134 | hf.IntermediateCA: true 135 | hf.GenCRL: true 136 | hf.Registrar.Attributes: "*" 137 | hf.AffiliationMgr: true 138 | 139 | ############################################################################# 140 | # Database section 141 | # Supported types are: "sqlite3", "postgres", and "mysql". 142 | # The datasource value depends on the type. 143 | # If the type is "sqlite3", the datasource value is a file name to use 144 | # as the database store. Since "sqlite3" is an embedded database, it 145 | # may not be used if you want to run the fabric-ca-server in a cluster. 146 | # To run the fabric-ca-server in a cluster, you must choose "postgres" 147 | # or "mysql". 148 | ############################################################################# 149 | db: 150 | type: sqlite3 151 | datasource: fabric-ca-server.db 152 | tls: 153 | enabled: false 154 | certfiles: 155 | client: 156 | certfile: 157 | keyfile: 158 | 159 | ############################################################################# 160 | # LDAP section 161 | # If LDAP is enabled, the fabric-ca-server calls LDAP to: 162 | # 1) authenticate enrollment ID and secret (i.e. username and password) 163 | # for enrollment requests; 164 | # 2) To retrieve identity attributes 165 | ############################################################################# 166 | ldap: 167 | # Enables or disables the LDAP client (default: false) 168 | # If this is set to true, the "registry" section is ignored. 169 | enabled: false 170 | # The URL of the LDAP server 171 | url: ldap://:@:/ 172 | # TLS configuration for the client connection to the LDAP server 173 | tls: 174 | certfiles: 175 | client: 176 | certfile: 177 | keyfile: 178 | # Attribute related configuration for mapping from LDAP entries to Fabric CA attributes 179 | attribute: 180 | # 'names' is an array of strings containing the LDAP attribute names which are 181 | # requested from the LDAP server for an LDAP identity's entry 182 | names: ['uid','member'] 183 | # The 'converters' section is used to convert an LDAP entry to the value of 184 | # a fabric CA attribute. 185 | # For example, the following converts an LDAP 'uid' attribute 186 | # whose value begins with 'revoker' to a fabric CA attribute 187 | # named "hf.Revoker" with a value of "true" (because the boolean expression 188 | # evaluates to true). 189 | # converters: 190 | # - name: hf.Revoker 191 | # value: attr("uid") =~ "revoker*" 192 | converters: 193 | - name: 194 | value: 195 | # The 'maps' section contains named maps which may be referenced by the 'map' 196 | # function in the 'converters' section to map LDAP responses to arbitrary values. 197 | # For example, assume a user has an LDAP attribute named 'member' which has multiple 198 | # values which are each a distinguished name (i.e. a DN). For simplicity, assume the 199 | # values of the 'member' attribute are 'dn1', 'dn2', and 'dn3'. 200 | # Further assume the following configuration. 201 | # converters: 202 | # - name: hf.Registrar.Roles 203 | # value: map(attr("member"),"groups") 204 | # maps: 205 | # groups: 206 | # - name: dn1 207 | # value: peer 208 | # - name: dn2 209 | # value: client 210 | # The value of the user's 'hf.Registrar.Roles' attribute is then computed to be 211 | # "peer,client,dn3". This is because the value of 'attr("member")' is 212 | # "dn1,dn2,dn3", and the call to 'map' with a 2nd argument of 213 | # "group" replaces "dn1" with "peer" and "dn2" with "client". 214 | maps: 215 | groups: 216 | - name: 217 | value: 218 | 219 | ############################################################################# 220 | # Affiliations section. Fabric CA server can be bootstrapped with the 221 | # affiliations specified in this section. Affiliations are specified as maps. 222 | # For example: 223 | # businessunit1: 224 | # department1: 225 | # - team1 226 | # businessunit2: 227 | # - department2 228 | # - department3 229 | # 230 | # Affiliations are hierarchical in nature. In the above example, 231 | # department1 (used as businessunit1.department1) is the child of businessunit1. 232 | # team1 (used as businessunit1.department1.team1) is the child of department1. 233 | # department2 (used as businessunit2.department2) and department3 (businessunit2.department3) 234 | # are children of businessunit2. 235 | # Note: Affiliations are case sensitive except for the non-leaf affiliations 236 | # (like businessunit1, department1, businessunit2) that are specified in the configuration file, 237 | # which are always stored in lower case. 238 | ############################################################################# 239 | affiliations: 240 | ORG_NAME: 241 | - department1 242 | - department2 243 | 244 | ############################################################################# 245 | # Signing section 246 | # 247 | # The "default" subsection is used to sign enrollment certificates; 248 | # the default expiration ("expiry" field) is "8760h", which is 1 year in hours. 249 | # 250 | # The "ca" profile subsection is used to sign intermediate CA certificates; 251 | # the default expiration ("expiry" field) is "43800h" which is 5 years in hours. 252 | # Note that "isca" is true, meaning that it issues a CA certificate. 253 | # A maxpathlen of 0 means that the intermediate CA cannot issue other 254 | # intermediate CA certificates, though it can still issue end entity certificates. 255 | # (See RFC 5280, section 4.2.1.9) 256 | # 257 | # The "tls" profile subsection is used to sign TLS certificate requests; 258 | # the default expiration ("expiry" field) is "8760h", which is 1 year in hours. 259 | ############################################################################# 260 | signing: 261 | default: 262 | usage: 263 | - digital signature 264 | expiry: 8760h 265 | profiles: 266 | ca: 267 | usage: 268 | - cert sign 269 | - crl sign 270 | expiry: 43800h 271 | caconstraint: 272 | isca: true 273 | maxpathlen: 0 274 | tls: 275 | usage: 276 | - signing 277 | - key encipherment 278 | - server auth 279 | - client auth 280 | - key agreement 281 | expiry: 8760h 282 | 283 | ########################################################################### 284 | # Certificate Signing Request (CSR) section. 285 | # This controls the creation of the root CA certificate. 286 | # The expiration for the root CA certificate is configured with the 287 | # "ca.expiry" field below, whose default value is "131400h" which is 288 | # 15 years in hours. 289 | # The pathlength field is used to limit CA certificate hierarchy as described 290 | # in section 4.2.1.9 of RFC 5280. 291 | # Examples: 292 | # 1) No pathlength value means no limit is requested. 293 | # 2) pathlength == 1 means a limit of 1 is requested which is the default for 294 | # a root CA. This means the root CA can issue intermediate CA certificates, 295 | # but these intermediate CAs may not in turn issue other CA certificates 296 | # though they can still issue end entity certificates. 297 | # 3) pathlength == 0 means a limit of 0 is requested; 298 | # this is the default for an intermediate CA, which means it can not issue 299 | # CA certificates though it can still issue end entity certificates. 300 | ########################################################################### 301 | csr: 302 | cn: fabric-ca-server 303 | names: 304 | - C: US 305 | ST: "North Carolina" 306 | L: 307 | O: Hyperledger 308 | OU: Fabric 309 | hosts: 310 | - e526fc1180f6 311 | - localhost 312 | ca: 313 | expiry: 131400h 314 | pathlength: 1 315 | 316 | ############################################################################# 317 | # BCCSP (BlockChain Crypto Service Provider) section is used to select which 318 | # crypto library implementation to use 319 | ############################################################################# 320 | bccsp: 321 | default: SW 322 | sw: 323 | hash: SHA2 324 | security: 256 325 | filekeystore: 326 | # The directory used for the software file-based keystore 327 | keystore: msp/keystore 328 | 329 | ############################################################################# 330 | # Multi CA section 331 | # 332 | # Each Fabric CA server contains one CA by default. This section is used 333 | # to configure multiple CAs in a single server. 334 | # 335 | # 1) --cacount 336 | # Automatically generate non-default CAs. The names of these 337 | # additional CAs are "ca1", "ca2", ... "caN", where "N" is 338 | # This is particularly useful in a development environment to quickly set up 339 | # multiple CAs. 340 | # 341 | # 2) --cafiles 342 | # For each CA config file in the list, generate a separate signing CA. Each CA 343 | # config file in this list MAY contain all of the same elements as are found in 344 | # the server config file except port, debug, and tls sections. 345 | # 346 | # Examples: 347 | # fabric-ca-server start -b admin:adminpw --cacount 2 348 | # 349 | # fabric-ca-server start -b admin:adminpw --cafiles ca/ca1/fabric-ca-server-config.yaml 350 | # --cafiles ca/ca2/fabric-ca-server-config.yaml 351 | # 352 | ############################################################################# 353 | 354 | cacount: 355 | 356 | cafiles: 357 | 358 | ############################################################################# 359 | # Intermediate CA section 360 | # 361 | # The relationship between servers and CAs is as follows: 362 | # 1) A single server process may contain or function as one or more CAs. 363 | # This is configured by the "Multi CA section" above. 364 | # 2) Each CA is either a root CA or an intermediate CA. 365 | # 3) Each intermediate CA has a parent CA which is either a root CA or another intermediate CA. 366 | # 367 | # This section pertains to configuration of #2 and #3. 368 | # If the "intermediate.parentserver.url" property is set, 369 | # then this is an intermediate CA with the specified parent 370 | # CA. 371 | # 372 | # parentserver section 373 | # url - The URL of the parent server 374 | # caname - Name of the CA to enroll within the server 375 | # 376 | # enrollment section used to enroll intermediate CA with parent CA 377 | # profile - Name of the signing profile to use in issuing the certificate 378 | # label - Label to use in HSM operations 379 | # 380 | # tls section for secure socket connection 381 | # certfiles - PEM-encoded list of trusted root certificate files 382 | # client: 383 | # certfile - PEM-encoded certificate file for when client authentication 384 | # is enabled on server 385 | # keyfile - PEM-encoded key file for when client authentication 386 | # is enabled on server 387 | ############################################################################# 388 | intermediate: 389 | parentserver: 390 | url: 391 | caname: 392 | 393 | enrollment: 394 | hosts: 395 | profile: 396 | label: 397 | 398 | tls: 399 | certfiles: 400 | client: 401 | certfile: 402 | keyfile: 403 | -------------------------------------------------------------------------------- /multi-machine-deploy/deploy/deploy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ORG_NAME= 4 | DOMAIN= 5 | ORDERER_IP="192.168.1.51" 6 | 7 | function printHelp() { 8 | echo "Usage: new_org.sh --domain domain --order ordererIP deploy the new org" 9 | echo "(the default ordererIP is 192.168.1.51)" 10 | } 11 | 12 | function dockerInstall() { 13 | if [[ -d pkg ]]; then 14 | cd pkg 15 | fi 16 | echo "==> INSTALL DOCKER" 17 | docker --version > /dev/null 2>&1 18 | RES=$? 19 | if [[ -f "docker-18.03.0-ce.tgz" && $RES -ne 0 ]]; then 20 | tar -zxvf docker-18.03.0-ce.tgz 21 | cp docker/* /usr/bin/ 22 | dockerd & 23 | curl -sSL https://get.daocloud.io/daotools/set_mirror.sh | sh -s http://6e4616d7.m.daocloud.io 24 | kill -9 $(ps -aux|grep "dockerd"|grep -v "grep"|awk '{print $2}') 25 | dockerd & 26 | elif [[ $RES -ne 0 ]]; then 27 | yum -y install docker-io 28 | service docker start 29 | curl -sSL https://get.daocloud.io/daotools/set_mirror.sh | sh -s http://6e4616d7.m.daocloud.io 30 | service docker restart 31 | fi 32 | echo "DOCKER DOWNLOAD FINISH" 33 | echo 34 | echo "==> INSTALL DOCKER-COMPOSE" 35 | docker-compose --version > /dev/null 2>&1 36 | RES=$? 37 | if [[ -f docker-compose && $RES -ne 0 ]]; then 38 | cp docker-compose /usr/local/bin/docker-compose 39 | chmod +x /usr/local/bin/docker-compose 40 | elif [[ $RES -ne 0 ]]; then 41 | curl -L https://get.daocloud.io/docker/compose/releases/download/1.12.0/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose 42 | chmod +x /usr/local/bin/docker-compose 43 | fi 44 | echo "DOCKER-COMPOSE DOWNLOAD FINISH" 45 | echo 46 | if [[ ! -f "deploy.sh" ]]; then 47 | cd .. 48 | fi 49 | } 50 | 51 | function imagesPull() { 52 | if [[ -d pkg ]]; then 53 | cd pkg 54 | fi 55 | FABRIC_VERSION="x86_64-1.1.0" 56 | COUCH_VERSION="0.4.8" 57 | 58 | for IMAGES in peer ccenv ca couchdb; do 59 | echo "==> INSTALL FABRIC IMAGE: $IMAGES" 60 | if [[ -f "$IMAGES"".tar" ]]; then 61 | docker load -i "$IMAGES"".tar" 62 | else 63 | if [[ $IMAGES == "couchdb" ]]; then 64 | docker pull hyperledger/fabric-$IMAGES:$COUCH_VERSION 65 | else 66 | docker pull hyperledger/fabric-$IMAGES:$FABRIC_VERSION 67 | fi 68 | docker tag hyperledger/fabric-$IMAGES hyperledger/fabric-$IMAGES:latest 69 | fi 70 | done 71 | echo 72 | echo "==> FABRIC IMAGES DOWNLOAD FINISH" 73 | if [[ ! -f "deploy.sh" ]]; then 74 | cd .. 75 | fi 76 | } 77 | 78 | function createNetwork() { 79 | echo "==> Generate Crypto" 80 | cd artifacts 81 | if [[ -f crypto-config.yaml ]]; then 82 | rm -f crypto-config.yaml 83 | fi 84 | cp crypto-template.yaml crypto-config.yaml 85 | sed -i "s/ORG_NAME/$ORG_NAME/g" crypto-config.yaml 86 | sed -i "s/DOMAIN/$DOMAIN/g" crypto-config.yaml 87 | ./cryptogen generate --config=./crypto-config.yaml 88 | mv crypto-config/peerOrganizations/$DOMAIN . 89 | rm -rf crypto-config 90 | echo 91 | 92 | echo "==> Modify config files" 93 | if [[ -f fabric-ca-server-config.yaml ]]; then 94 | rm -f fabric-ca-server-config.yaml 95 | fi 96 | cp fabric-ca-server-template.yaml fabric-ca-server-config.yaml 97 | sed -i "s/ORG_NAME/$ORG_NAME/g" fabric-ca-server-config.yaml 98 | 99 | 100 | if [[ -f docker-compose.yaml ]]; then 101 | rm -f docker-compose.yaml 102 | fi 103 | 104 | CA_PRIVATE_KEY=$(ls ./$DOMAIN/ca/*_sk) 105 | CA_PRIVATE_KEY=${CA_PRIVATE_KEY##*/} 106 | cp docker-compose-template.yaml docker-compose.yaml 107 | sed -i "s/ORG_NAME/$ORG_NAME/g" docker-compose.yaml 108 | sed -i "s/DOMAIN/$DOMAIN/g" docker-compose.yaml 109 | sed -i "s/CA_PRIVATE_KEY/$CA_PRIVATE_KEY/g" docker-compose.yaml 110 | sed -i "s/ORDERER_IP/$ORDERER_IP/g" docker-compose.yaml 111 | 112 | docker-compose up -d 113 | } 114 | 115 | if [[ $1 = "--domain" && -n $2 ]]; then 116 | DOMAIN=$2 117 | ORG_NAME=${DOMAIN%%.*} 118 | if [[ $3 = "--order" && -n $4 ]]; then 119 | ORDERER_IP=$4 120 | fi 121 | 122 | echo "Domain: $DOMAIN" 123 | echo "Orgname: $ORG_NAME" 124 | echo "Orderer ip: $ORDERER_IP" 125 | 126 | dockerInstall 127 | imagesPull 128 | createNetwork 129 | 130 | else 131 | printHelp 132 | fi 133 | -------------------------------------------------------------------------------- /multi-machine-deploy/deploy/pkg/list.txt: -------------------------------------------------------------------------------- 1 | ca.tar 2 | peer.tar 3 | ccenv.tar 4 | couchdb.tar 5 | docker-compose 6 | docker-18.03.0-ce.tgz 7 | -------------------------------------------------------------------------------- /multi-machine-deploy/new-org/add_org.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | IP= 4 | ORG_NAME= 5 | DOMAIN= 6 | CUR_ORG="org1" # one of current orgs in network 7 | URL="localhost:4000" 8 | CHANNEL_NAME="mychannel" 9 | 10 | function printHelp() { 11 | echo "Usage:" 12 | echo " add_org.sh --org --ip " 13 | } 14 | 15 | function modifyConfig() { 16 | # move the new org's msp to crypto-config dir 17 | DOMAIN=$(ls | grep "$ORG_NAME") 18 | if [[ $? -ne 0 ]]; then 19 | echo "Please copy the msp dir to new_org dir" 20 | exit 1 21 | fi 22 | mv $DOMAIN ../artifacts/channel/crypto-config/peerOrganizations/ 23 | 24 | # modify the network-config-template.json 25 | cp network-config-template.json network-config.json 26 | sed -i "s/ORG_NAME/$ORG_NAME/g" network-config.json 27 | sed -i "s/DOMAIN/$DOMAIN/g" network-config.json 28 | sed -i "s/IP/$IP/g" network-config.json 29 | } 30 | 31 | function addOrg() { 32 | jq --version > /dev/null 2>&1 33 | if [ $? -ne 0 ]; then 34 | echo "Please Install 'jq' https://stedolan.github.io/jq/ to execute this script" 35 | echo 36 | exit 1 37 | fi 38 | # start configtxlator 39 | ./configtxlator start & 40 | 41 | # enroll by current org 42 | echo 43 | echo "POST request Enroll on $CUR_ORG ..." 44 | TOKEN=$(curl -s -X POST \ 45 | http://$URL/users \ 46 | -H "content-type: application/x-www-form-urlencoded" \ 47 | -d "username=admin&orgName=$CUR_ORG&password=123") 48 | TOKEN=$(echo $TOKEN | jq ".token" | sed "s/\"//g") 49 | 50 | # add org 51 | echo 52 | echo "Add $ORG_NAME in network ..." 53 | curl -s -X POST \ 54 | http://$URL/channels/$CHANNEL_NAME/addNewOrg \ 55 | -H "authorization: Bearer $TOKEN" \ 56 | -H "content-type: application/json" \ 57 | -d '{ 58 | "domain": "'$DOMAIN'", 59 | "fcn": "add" 60 | }' 61 | 62 | # add config of new org in network-config.json 63 | node modify-network.js $ORG_NAME 64 | rm -f network-config.json 65 | 66 | # enroll by new org 67 | echo 68 | echo "POST request Enroll on $ORG_NAME ..." 69 | TOKEN=$(curl -s -X POST \ 70 | http://$URL/users \ 71 | -H "content-type: application/x-www-form-urlencoded" \ 72 | -d "username=admin&orgName=$ORG_NAME&password=123") 73 | TOKEN=$(echo $TOKEN | jq ".token" | sed "s/\"//g") 74 | 75 | # join new peers in channel 76 | echo 77 | echo "Join $ORG_NAME in channel $CHANNEL_NAME..." 78 | curl -s -X POST \ 79 | http://$URL/channels/$CHANNEL_NAME/peers \ 80 | -H "authorization: Bearer $TOKEN" \ 81 | -H "content-type: application/json" \ 82 | -d '{ 83 | "peers": ["peer1", "peer2"] 84 | }' 85 | 86 | # install chaincode in new peers 87 | echo 88 | echo "Install chaincode in $ORG_NAME..." 89 | curl -s -X POST \ 90 | http://localhost:4000/chaincodes \ 91 | -H "authorization: Bearer $TOKEN" \ 92 | -H "content-type: application/json" \ 93 | -d '{ 94 | "peers": ["peer1", "peer2"], 95 | "chaincodeName":"mycc", 96 | "chaincodePath":"github.com/example_cc/go", 97 | "chaincodeVersion":"v0" 98 | }' 99 | 100 | # close configtxlator 101 | kill -9 $(ps -aux|grep "configtxlator"|grep -v "grep"|awk '{print $2}') 102 | echo "Add Org successfully" 103 | } 104 | 105 | if [[ $# -eq 4 && "$1" = "--org" && -n "$2" && "$3" = "--ip" && -n "$4" ]]; then 106 | ORG_NAME=$2 107 | IP=$4 108 | modifyConfig 109 | echo "Add new org" 110 | echo "Orgname: $ORG_NAME" 111 | echo "Domain: $DOMAIN" 112 | echo "IP address: $IP" 113 | echo 114 | addOrg 115 | else 116 | printHelp 117 | fi 118 | -------------------------------------------------------------------------------- /multi-machine-deploy/new-org/modify-network.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var fs = require('fs-extra'); 3 | 4 | var CONFIG_PATH = '../app/network-config.json' 5 | 6 | var config_string = fs.readFileSync("./network-config.json", "utf-8") 7 | 8 | var orgname = process.argv[2] 9 | 10 | var new_config = JSON.parse(config_string)[orgname] 11 | 12 | var all_config = JSON.parse(fs.readFileSync(CONFIG_PATH, "utf-8")) 13 | 14 | all_config['network-config'][orgname] = new_config 15 | 16 | var all_config_string = JSON.stringify(all_config, null, 4) 17 | 18 | fs.writeFileSync(CONFIG_PATH, all_config_string) 19 | -------------------------------------------------------------------------------- /multi-machine-deploy/new-org/network-config-template.json: -------------------------------------------------------------------------------- 1 | { 2 | "ORG_NAME": { 3 | "name": "peerORG_NAME", 4 | "mspid": "ORG_NAMEMSP", 5 | "ca": "https://IP:7054", 6 | "peers": { 7 | "peer1": { 8 | "requests": "grpcs://IP:7051", 9 | "events": "grpcs://IP:7053", 10 | "server-hostname": "peer0.DOMAIN", 11 | "tls_cacerts": "../artifacts/channel/crypto-config/peerOrganizations/DOMAIN/peers/peer0.DOMAIN/tls/ca.crt" 12 | }, 13 | "peer2": { 14 | "requests": "grpcs://IP:7056", 15 | "events": "grpcs://IP:7058", 16 | "server-hostname": "peer1.DOMAIN", 17 | "tls_cacerts": "../artifacts/channel/crypto-config/peerOrganizations/DOMAIN/peers/peer1.DOMAIN/tls/ca.crt" 18 | } 19 | }, 20 | "admin": { 21 | "key": "../artifacts/channel/crypto-config/peerOrganizations/DOMAIN/users/Admin@DOMAIN/msp/keystore", 22 | "cert": "../artifacts/channel/crypto-config/peerOrganizations/DOMAIN/users/Admin@DOMAIN/msp/signcerts" 23 | } 24 | } 25 | } 26 | --------------------------------------------------------------------------------