fabric-samples/test-network/network.sh
Waleed Mortaja 14dc7e1316
Fix creating channel when ${PWD} contains space. (#402)
* Fix creating channel when ${PWD} contains space.

If the path of the project contains spaces, the "test-network/scripts/envVar.sh" script sets the value of "$ORDERER_CA" to a value containg "${PWD}" which, in turn, contains space(s).

When the variable used in "test-network/scripts/createChannel.sh", The first part of the value (before the first space) is handled as the whole value for "--cafile". Other parts are considered to be part of the command!

I tried putting (escaped) quotes in the "test-network/scripts/envVar.sh" definition for the variable "$ORDERER_CA" to make the fix more general, but the quotation marks were sometime interpreted to be part of the path that consisted of concatenated parts somewhere and it did not work.

While this edit will fix this issue, I belive this is just a work around. I expect that there is a better way to solve the root cause of the problem instead of just fixing it in one place. Moreover, All variables/paths that may include spaces should be properly handled as well.

Thanks

Signed-off-by: Waleed Mortaja <waleedmortaja@protonmail.com>

* Double quote variables evaluations that depends on $PWD

I tried to handle most (if not all) of the variables evaluations in the project that depends on $PWD by wrapping them in double-quotations to avoid values that contains white spaces.

Some lines I was not sure if they are Okay or not but I left them as they are. Samples (not all lines) as follows:
- commercial-paper/network-clean.sh:15:DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
- commercial-paper/network-starter.sh:15:DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
- asset-transfer-basic/chaincode-javascript/node_modules/fabric-shim/coverage/fabric-shim/lib/chaincode.js.html:997: optsCpy.pem = fs.readFileSync(process.env.CORE_PEER_TLS_ROOTCERT_FILE).toString();
- commercial-paper/organization/digibank/digibank.sh:29:export PEER_PARMS="${PEER_CONN_PARMS##*( )}"

The next sample I was not really sure, but still edited it:
- test-network/addOrg3/fabric-ca/registerEnroll.sh:68:  cp ${PWD}/../organizations/peerOrganizations/org3.example.com/peers/peer0.org3.example.com/tls/tlscacerts/* ${PWD}/../organizations/peerOrganizations/org3.example.com/peers/peer0.org3.example.com/tls/ca.crt

I deliberately ignored some lines because I think they are not problem. These lines include:
- `export` sentences
- assignment sentences like: test-network/scripts/createChannel.sh:48:  FABRIC_CFG_PATH=$PWD/../config/
- gradlew files: the line SAVED="`pwd`"
- gradlew files: the line APP_HOME="`pwd -P`"
- gradlew files: the line CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar

Signed-off-by: Waleed Mortaja <waleedmortaja@protonmail.com>

* remove unnecessary leading space trimming

Signed-off-by: Waleed Mortaja <waleedmortaja@protonmail.com>

* resolved conflict with master

Co-authored-by: Arnaud J Le Hors <lehors@us.ibm.com>
2021-01-20 16:32:38 +01:00

493 lines
17 KiB
Bash
Executable file

#!/bin/bash
#
# Copyright IBM Corp All Rights Reserved
#
# SPDX-License-Identifier: Apache-2.0
#
# This script brings up a Hyperledger Fabric network for testing smart contracts
# and applications. The test network consists of two organizations with one
# peer each, and a single node Raft ordering service. Users can also use this
# script to create a channel deploy a chaincode on the channel
#
# prepending $PWD/../bin to PATH to ensure we are picking up the correct binaries
# this may be commented out to resolve installed version of tools if desired
export PATH=${PWD}/../bin:$PATH
export FABRIC_CFG_PATH=${PWD}/configtx
export VERBOSE=false
. scripts/utils.sh
# Obtain CONTAINER_IDS and remove them
# TODO Might want to make this optional - could clear other containers
# This function is called when you bring a network down
function clearContainers() {
CONTAINER_IDS=$(docker ps -a | awk '($2 ~ /dev-peer.*/) {print $1}')
if [ -z "$CONTAINER_IDS" -o "$CONTAINER_IDS" == " " ]; then
infoln "No containers available for deletion"
else
docker rm -f $CONTAINER_IDS
fi
}
# Delete any images that were generated as a part of this setup
# specifically the following images are often left behind:
# This function is called when you bring the network down
function removeUnwantedImages() {
DOCKER_IMAGE_IDS=$(docker images | awk '($1 ~ /dev-peer.*/) {print $3}')
if [ -z "$DOCKER_IMAGE_IDS" -o "$DOCKER_IMAGE_IDS" == " " ]; then
infoln "No images available for deletion"
else
docker rmi -f $DOCKER_IMAGE_IDS
fi
}
# Versions of fabric known not to work with the test network
NONWORKING_VERSIONS="^1\.0\. ^1\.1\. ^1\.2\. ^1\.3\. ^1\.4\."
# Do some basic sanity checking to make sure that the appropriate versions of fabric
# binaries/images are available. In the future, additional checking for the presence
# of go or other items could be added.
function checkPrereqs() {
## Check if your have cloned the peer binaries and configuration files.
peer version > /dev/null 2>&1
if [[ $? -ne 0 || ! -d "../config" ]]; then
errorln "Peer binary and configuration files not found.."
errorln
errorln "Follow the instructions in the Fabric docs to install the Fabric Binaries:"
errorln "https://hyperledger-fabric.readthedocs.io/en/latest/install.html"
exit 1
fi
# use the fabric tools container to see if the samples and binaries match your
# docker images
LOCAL_VERSION=$(peer version | sed -ne 's/ Version: //p')
DOCKER_IMAGE_VERSION=$(docker run --rm hyperledger/fabric-tools:$IMAGETAG peer version | sed -ne 's/ Version: //p' | head -1)
infoln "LOCAL_VERSION=$LOCAL_VERSION"
infoln "DOCKER_IMAGE_VERSION=$DOCKER_IMAGE_VERSION"
if [ "$LOCAL_VERSION" != "$DOCKER_IMAGE_VERSION" ]; then
warnln "Local fabric binaries and docker images are out of sync. This may cause problems."
fi
for UNSUPPORTED_VERSION in $NONWORKING_VERSIONS; do
infoln "$LOCAL_VERSION" | grep -q $UNSUPPORTED_VERSION
if [ $? -eq 0 ]; then
fatalln "Local Fabric binary version of $LOCAL_VERSION does not match the versions supported by the test network."
fi
infoln "$DOCKER_IMAGE_VERSION" | grep -q $UNSUPPORTED_VERSION
if [ $? -eq 0 ]; then
fatalln "Fabric Docker image version of $DOCKER_IMAGE_VERSION does not match the versions supported by the test network."
fi
done
## Check for fabric-ca
if [ "$CRYPTO" == "Certificate Authorities" ]; then
fabric-ca-client version > /dev/null 2>&1
if [[ $? -ne 0 ]]; then
errorln "fabric-ca-client binary not found.."
errorln
errorln "Follow the instructions in the Fabric docs to install the Fabric Binaries:"
errorln "https://hyperledger-fabric.readthedocs.io/en/latest/install.html"
exit 1
fi
CA_LOCAL_VERSION=$(fabric-ca-client version | sed -ne 's/ Version: //p')
CA_DOCKER_IMAGE_VERSION=$(docker run --rm hyperledger/fabric-ca:$CA_IMAGETAG fabric-ca-client version | sed -ne 's/ Version: //p' | head -1)
infoln "CA_LOCAL_VERSION=$CA_LOCAL_VERSION"
infoln "CA_DOCKER_IMAGE_VERSION=$CA_DOCKER_IMAGE_VERSION"
if [ "$CA_LOCAL_VERSION" != "$CA_DOCKER_IMAGE_VERSION" ]; then
warnln "Local fabric-ca binaries and docker images are out of sync. This may cause problems."
fi
fi
}
# Before you can bring up a network, each organization needs to generate the crypto
# material that will define that organization on the network. Because Hyperledger
# Fabric is a permissioned blockchain, each node and user on the network needs to
# use certificates and keys to sign and verify its actions. In addition, each user
# needs to belong to an organization that is recognized as a member of the network.
# You can use the Cryptogen tool or Fabric CAs to generate the organization crypto
# material.
# By default, the sample network uses cryptogen. Cryptogen is a tool that is
# meant for development and testing that can quickly create the certificates and keys
# that can be consumed by a Fabric network. The cryptogen tool consumes a series
# of configuration files for each organization in the "organizations/cryptogen"
# directory. Cryptogen uses the files to generate the crypto material for each
# org in the "organizations" directory.
# You can also use Fabric CAs to generate the crypto material. CAs sign the certificates
# and keys that they generate to create a valid root of trust for each organization.
# The script uses Docker Compose to bring up three CAs, one for each peer organization
# and the ordering organization. The configuration file for creating the Fabric CA
# servers are in the "organizations/fabric-ca" directory. Within the same directory,
# the "registerEnroll.sh" script uses the Fabric CA client to create the identities,
# certificates, and MSP folders that are needed to create the test network in the
# "organizations/ordererOrganizations" directory.
# Create Organization crypto material using cryptogen or CAs
function createOrgs() {
if [ -d "organizations/peerOrganizations" ]; then
rm -Rf organizations/peerOrganizations && rm -Rf organizations/ordererOrganizations
fi
# Create crypto material using cryptogen
if [ "$CRYPTO" == "cryptogen" ]; then
which cryptogen
if [ "$?" -ne 0 ]; then
fatalln "cryptogen tool not found. exiting"
fi
infoln "Generating certificates using cryptogen tool"
infoln "Creating Org1 Identities"
set -x
cryptogen generate --config=./organizations/cryptogen/crypto-config-org1.yaml --output="organizations"
res=$?
{ set +x; } 2>/dev/null
if [ $res -ne 0 ]; then
fatalln "Failed to generate certificates..."
fi
infoln "Creating Org2 Identities"
set -x
cryptogen generate --config=./organizations/cryptogen/crypto-config-org2.yaml --output="organizations"
res=$?
{ set +x; } 2>/dev/null
if [ $res -ne 0 ]; then
fatalln "Failed to generate certificates..."
fi
infoln "Creating Orderer Org Identities"
set -x
cryptogen generate --config=./organizations/cryptogen/crypto-config-orderer.yaml --output="organizations"
res=$?
{ set +x; } 2>/dev/null
if [ $res -ne 0 ]; then
fatalln "Failed to generate certificates..."
fi
fi
# Create crypto material using Fabric CA
if [ "$CRYPTO" == "Certificate Authorities" ]; then
infoln "Generating certificates using Fabric CA"
IMAGE_TAG=${CA_IMAGETAG} docker-compose -f $COMPOSE_FILE_CA up -d 2>&1
. organizations/fabric-ca/registerEnroll.sh
while :
do
if [ ! -f "organizations/fabric-ca/org1/tls-cert.pem" ]; then
sleep 1
else
break
fi
done
infoln "Creating Org1 Identities"
createOrg1
infoln "Creating Org2 Identities"
createOrg2
infoln "Creating Orderer Org Identities"
createOrderer
fi
infoln "Generating CCP files for Org1 and Org2"
./organizations/ccp-generate.sh
}
# Once you create the organization crypto material, you need to create the
# genesis block of the application channel.
# The configtxgen tool is used to create the genesis block. Configtxgen consumes a
# "configtx.yaml" file that contains the definitions for the sample network. The
# genesis block is defined using the "TwoOrgsApplicationGenesis" profile at the bottom
# of the file. This profile defines an application channel consisting of our two Peer Orgs.
# The peer and ordering organizations are defined in the "Profiles" section at the
# top of the file. As part of each organization profile, the file points to the
# location of the MSP directory for each member. This MSP is used to create the channel
# MSP that defines the root of trust for each organization. In essence, the channel
# MSP allows the nodes and users to be recognized as network members.
#
# If you receive the following warning, it can be safely ignored:
#
# [bccsp] GetDefault -> WARN 001 Before using BCCSP, please call InitFactories(). Falling back to bootBCCSP.
#
# You can ignore the logs regarding intermediate certs, we are not using them in
# this crypto implementation.
# After we create the org crypto material and the application channel genesis block,
# we can now bring up the peers and ordering service. By default, the base
# file for creating the network is "docker-compose-test-net.yaml" in the ``docker``
# folder. This file defines the environment variables and file mounts that
# point the crypto material and genesis block that were created in earlier.
# Bring up the peer and orderer nodes using docker compose.
function networkUp() {
checkPrereqs
# generate artifacts if they don't exist
if [ ! -d "organizations/peerOrganizations" ]; then
createOrgs
fi
COMPOSE_FILES="-f ${COMPOSE_FILE_BASE}"
if [ "${DATABASE}" == "couchdb" ]; then
COMPOSE_FILES="${COMPOSE_FILES} -f ${COMPOSE_FILE_COUCH}"
fi
IMAGE_TAG=$IMAGETAG docker-compose ${COMPOSE_FILES} up -d 2>&1
docker ps -a
if [ $? -ne 0 ]; then
fatalln "Unable to start network"
fi
}
# call the script to create the channel, join the peers of org1 and org2,
# and then update the anchor peers for each organization
function createChannel() {
# Bring up the network if it is not already up.
if [ ! -d "organizations/peerOrganizations" ]; then
infoln "Bringing up network"
networkUp
fi
# now run the script that creates a channel. This script uses configtxgen once
# to create the channel creation transaction and the anchor peer updates.
scripts/createChannel.sh $CHANNEL_NAME $CLI_DELAY $MAX_RETRY $VERBOSE
}
## Call the script to deploy a chaincode to the channel
function deployCC() {
scripts/deployCC.sh $CHANNEL_NAME $CC_NAME $CC_SRC_PATH $CC_SRC_LANGUAGE $CC_VERSION $CC_SEQUENCE $CC_INIT_FCN $CC_END_POLICY $CC_COLL_CONFIG $CLI_DELAY $MAX_RETRY $VERBOSE
if [ $? -ne 0 ]; then
fatalln "Deploying chaincode failed"
fi
}
# Tear down running network
function networkDown() {
# stop org3 containers also in addition to org1 and org2, in case we were running sample to add org3
docker-compose -f $COMPOSE_FILE_BASE -f $COMPOSE_FILE_COUCH -f $COMPOSE_FILE_CA down --volumes --remove-orphans
docker-compose -f $COMPOSE_FILE_COUCH_ORG3 -f $COMPOSE_FILE_ORG3 down --volumes --remove-orphans
# Don't remove the generated artifacts -- note, the ledgers are always removed
if [ "$MODE" != "restart" ]; then
# Bring down the network, deleting the volumes
#Cleanup the chaincode containers
clearContainers
#Cleanup images
removeUnwantedImages
# remove orderer block and other channel configuration transactions and certs
docker run --rm -v "$(pwd):/data" busybox sh -c 'cd /data && rm -rf system-genesis-block/*.block organizations/peerOrganizations organizations/ordererOrganizations'
## remove fabric ca artifacts
docker run --rm -v "$(pwd):/data" busybox sh -c 'cd /data && rm -rf organizations/fabric-ca/org1/msp organizations/fabric-ca/org1/tls-cert.pem organizations/fabric-ca/org1/ca-cert.pem organizations/fabric-ca/org1/IssuerPublicKey organizations/fabric-ca/org1/IssuerRevocationPublicKey organizations/fabric-ca/org1/fabric-ca-server.db'
docker run --rm -v "$(pwd):/data" busybox sh -c 'cd /data && rm -rf organizations/fabric-ca/org2/msp organizations/fabric-ca/org2/tls-cert.pem organizations/fabric-ca/org2/ca-cert.pem organizations/fabric-ca/org2/IssuerPublicKey organizations/fabric-ca/org2/IssuerRevocationPublicKey organizations/fabric-ca/org2/fabric-ca-server.db'
docker run --rm -v "$(pwd):/data" busybox sh -c 'cd /data && rm -rf organizations/fabric-ca/ordererOrg/msp organizations/fabric-ca/ordererOrg/tls-cert.pem organizations/fabric-ca/ordererOrg/ca-cert.pem organizations/fabric-ca/ordererOrg/IssuerPublicKey organizations/fabric-ca/ordererOrg/IssuerRevocationPublicKey organizations/fabric-ca/ordererOrg/fabric-ca-server.db'
docker run --rm -v "$(pwd):/data" busybox sh -c 'cd /data && rm -rf addOrg3/fabric-ca/org3/msp addOrg3/fabric-ca/org3/tls-cert.pem addOrg3/fabric-ca/org3/ca-cert.pem addOrg3/fabric-ca/org3/IssuerPublicKey addOrg3/fabric-ca/org3/IssuerRevocationPublicKey addOrg3/fabric-ca/org3/fabric-ca-server.db'
# remove channel and script artifacts
docker run --rm -v "$(pwd):/data" busybox sh -c 'cd /data && rm -rf channel-artifacts log.txt *.tar.gz'
fi
}
# Obtain the OS and Architecture string that will be used to select the correct
# native binaries for your platform, e.g., darwin-amd64 or linux-amd64
OS_ARCH=$(echo "$(uname -s | tr '[:upper:]' '[:lower:]' | sed 's/mingw64_nt.*/windows/')-$(uname -m | sed 's/x86_64/amd64/g')" | awk '{print tolower($0)}')
# Using crpto vs CA. default is cryptogen
CRYPTO="cryptogen"
# timeout duration - the duration the CLI should wait for a response from
# another container before giving up
MAX_RETRY=5
# default for delay between commands
CLI_DELAY=3
# channel name defaults to "mychannel"
CHANNEL_NAME="mychannel"
# chaincode name defaults to "NA"
CC_NAME="NA"
# chaincode path defaults to "NA"
CC_SRC_PATH="NA"
# endorsement policy defaults to "NA". This would allow chaincodes to use the majority default policy.
CC_END_POLICY="NA"
# collection configuration defaults to "NA"
CC_COLL_CONFIG="NA"
# chaincode init function defaults to "NA"
CC_INIT_FCN="NA"
# use this as the default docker-compose yaml definition
COMPOSE_FILE_BASE=docker/docker-compose-test-net.yaml
# docker-compose.yaml file if you are using couchdb
COMPOSE_FILE_COUCH=docker/docker-compose-couch.yaml
# certificate authorities compose file
COMPOSE_FILE_CA=docker/docker-compose-ca.yaml
# use this as the docker compose couch file for org3
COMPOSE_FILE_COUCH_ORG3=addOrg3/docker/docker-compose-couch-org3.yaml
# use this as the default docker-compose yaml definition for org3
COMPOSE_FILE_ORG3=addOrg3/docker/docker-compose-org3.yaml
#
# chaincode language defaults to "NA"
CC_SRC_LANGUAGE="NA"
# Chaincode version
CC_VERSION="1.0"
# Chaincode definition sequence
CC_SEQUENCE=1
# default image tag
IMAGETAG="latest"
# default ca image tag
CA_IMAGETAG="latest"
# default database
DATABASE="leveldb"
# Parse commandline args
## Parse mode
if [[ $# -lt 1 ]] ; then
printHelp
exit 0
else
MODE=$1
shift
fi
# parse a createChannel subcommand if used
if [[ $# -ge 1 ]] ; then
key="$1"
if [[ "$key" == "createChannel" ]]; then
export MODE="createChannel"
shift
fi
fi
# parse flags
while [[ $# -ge 1 ]] ; do
key="$1"
case $key in
-h )
printHelp $MODE
exit 0
;;
-c )
CHANNEL_NAME="$2"
shift
;;
-ca )
CRYPTO="Certificate Authorities"
;;
-r )
MAX_RETRY="$2"
shift
;;
-d )
CLI_DELAY="$2"
shift
;;
-s )
DATABASE="$2"
shift
;;
-ccl )
CC_SRC_LANGUAGE="$2"
shift
;;
-ccn )
CC_NAME="$2"
shift
;;
-ccv )
CC_VERSION="$2"
shift
;;
-ccs )
CC_SEQUENCE="$2"
shift
;;
-ccp )
CC_SRC_PATH="$2"
shift
;;
-ccep )
CC_END_POLICY="$2"
shift
;;
-cccg )
CC_COLL_CONFIG="$2"
shift
;;
-cci )
CC_INIT_FCN="$2"
shift
;;
-i )
IMAGETAG="$2"
shift
;;
-cai )
CA_IMAGETAG="$2"
shift
;;
-verbose )
VERBOSE=true
shift
;;
* )
errorln "Unknown flag: $key"
printHelp
exit 1
;;
esac
shift
done
# Are we generating crypto material with this command?
if [ ! -d "organizations/peerOrganizations" ]; then
CRYPTO_MODE="with crypto from '${CRYPTO}'"
else
CRYPTO_MODE=""
fi
# Determine mode of operation and printing out what we asked for
if [ "$MODE" == "up" ]; then
infoln "Starting nodes with CLI timeout of '${MAX_RETRY}' tries and CLI delay of '${CLI_DELAY}' seconds and using database '${DATABASE}' ${CRYPTO_MODE}"
elif [ "$MODE" == "createChannel" ]; then
infoln "Creating channel '${CHANNEL_NAME}'."
infoln "If network is not up, starting nodes with CLI timeout of '${MAX_RETRY}' tries and CLI delay of '${CLI_DELAY}' seconds and using database '${DATABASE} ${CRYPTO_MODE}"
elif [ "$MODE" == "down" ]; then
infoln "Stopping network"
elif [ "$MODE" == "restart" ]; then
infoln "Restarting network"
elif [ "$MODE" == "deployCC" ]; then
infoln "deploying chaincode on channel '${CHANNEL_NAME}'"
else
printHelp
exit 1
fi
if [ "${MODE}" == "up" ]; then
networkUp
elif [ "${MODE}" == "createChannel" ]; then
createChannel
elif [ "${MODE}" == "deployCC" ]; then
deployCC
elif [ "${MODE}" == "down" ]; then
networkDown
else
printHelp
exit 1
fi